Skip to content
This repository has been archived by the owner on Oct 20, 2024. It is now read-only.

Commit

Permalink
Compile 0 literals to the PUSH0 opcode (#280)
Browse files Browse the repository at this point in the history
* feat: make literal gen reusable and default to push0

* feat: update tests to reflect push0 codegen change

* fix: make `literal_gen` more idiomatic
  • Loading branch information
Philogy authored Jul 8, 2023
1 parent 25f04d9 commit 10aa9d0
Show file tree
Hide file tree
Showing 13 changed files with 73 additions and 32 deletions.
7 changes: 2 additions & 5 deletions huff_codegen/src/irgen/constants.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use huff_utils::prelude::{
bytes32_to_string, AstSpan, CodegenError, CodegenErrorKind, ConstVal, Contract,
literal_gen, AstSpan, CodegenError, CodegenErrorKind, ConstVal, Contract,
};

/// Transforms a constant definition into it's respective bytecode
Expand Down Expand Up @@ -30,10 +30,7 @@ pub fn constant_gen(
// prior to generating the IR bytes.
tracing::info!(target: "codegen", "FOUND CONSTANT DEFINITION: {}", constant.name);
let push_bytes = match &constant.value {
ConstVal::Literal(l) => {
let hex_literal: String = bytes32_to_string(l, false);
format!("{:02x}{hex_literal}", 95 + hex_literal.len() / 2)
}
ConstVal::Literal(l) => literal_gen(l),
ConstVal::FreeStoragePointer(fsp) => {
// If this is reached in codegen stage, the `derive_storage_pointers`
// method was not called on the AST.
Expand Down
2 changes: 1 addition & 1 deletion huff_core/tests/alternative_constructor_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ fn test_alternative_constructor_macro_provided() {

// Create constructor bytecode
match Codegen::generate_constructor_bytecode(&contract, alternative_constructor_label) {
Ok((mb, _)) => assert_eq!(mb, "6004356000602435".to_string()),
Ok((mb, _)) => assert_eq!(mb, "6004355f602435".to_string()),
Err(_) => panic!("moose"),
}
}
2 changes: 1 addition & 1 deletion huff_core/tests/alternative_main_macro.rs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ fn test_alternative_main_macro_provided() {

// Createconstructor bytecode
match Codegen::generate_main_bytecode(&contract, alternative_main) {
Ok(mb) => assert_eq!(mb, "6004356000602435".to_string()),
Ok(mb) => assert_eq!(mb, "6004355f602435".to_string()),
Err(_) => panic!("moose"),
}
}
2 changes: 1 addition & 1 deletion huff_core/tests/breaking_jumptable.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,5 +151,5 @@ fn test_breaking_jump_table() {

// Have the Codegen create the main macro bytecode
let mbytes = Codegen::generate_main_bytecode(&contract, None).unwrap();
assert_eq!(mbytes, String::from("60fe6100cc600039600080fd5b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b80000c000e00100012001400160018001a001c001e00200022002400260028002a002c002e00300032003400360038003a003c003e00400042004400460048004a004c004e00500052005400560058005a005c005e00600062006400660068006a006c006e00700072007400760078007a007c007e00800082008400860088008a008c008e00900092009400960098009a009c009e00a000a200a400a600a800aa00ac00ae00b000b200b400b600b800ba00bc00be00c000c200c400c600c800ca00ac00ae00b000b200b400b600b800ba00bc00be00c000c200c400c600c800ca00ac00ae00b000b200b400b600b800ba00bc00be00c000c200c400c600c8"));
assert_eq!(mbytes, String::from("60fe6100ca5f395f80fd5b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b805b80000a000c000e00100012001400160018001a001c001e00200022002400260028002a002c002e00300032003400360038003a003c003e00400042004400460048004a004c004e00500052005400560058005a005c005e00600062006400660068006a006c006e00700072007400760078007a007c007e00800082008400860088008a008c008e00900092009400960098009a009c009e00a000a200a400a600a800aa00ac00ae00b000b200b400b600b800ba00bc00be00c000c200c400c600c800aa00ac00ae00b000b200b400b600b800ba00bc00be00c000c200c400c600c800aa00ac00ae00b000b200b400b600b800ba00bc00be00c000c200c400c6"));
}
26 changes: 13 additions & 13 deletions huff_core/tests/builtins.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ fn test_codesize_builtin() {
// Have the Codegen create the constructor bytecode
let (cbytes, custom_bootstrap) =
Codegen::generate_constructor_bytecode(&contract, None).unwrap();
assert_eq!(cbytes, String::from("6004"));
assert_eq!(cbytes, String::from("6003"));
assert!(!custom_bootstrap);
}

Expand Down Expand Up @@ -167,7 +167,7 @@ fn test_tablesize_builtin() {

// Have the Codegen create the constructor bytecode
let mbytes = Codegen::generate_main_bytecode(&contract, None).unwrap();
assert_eq!(mbytes, String::from("6008608061002c60003960205b60006000f35b60006000f35b60006000f35b60006000f3000c00120018001e000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018000000000000000000000000000000000000000000000000000000000000001eDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF"));
assert_eq!(mbytes, String::from("600860806100235f3960205b5f5ff35b5f5ff35b5f5ff35b5f5ff3000b000f00130017000000000000000000000000000000000000000000000000000000000000000b000000000000000000000000000000000000000000000000000000000000000f00000000000000000000000000000000000000000000000000000000000000130000000000000000000000000000000000000000000000000000000000000017DEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEFDEADBEEF"));
}

#[test]
Expand Down Expand Up @@ -232,7 +232,7 @@ fn test_tablestart_builtin() {
// Have the Codegen create the constructor bytecode
let (cbytes, custom_bootstrap) =
Codegen::generate_constructor_bytecode(&contract, None).unwrap();
assert_eq!(cbytes, String::from("61001e6100265b60006000f35b60006000f35b60006000f35b60006000f30006000c001200180000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000c00000000000000000000000000000000000000000000000000000000000000120000000000000000000000000000000000000000000000000000000000000018"));
assert_eq!(cbytes, String::from("61001661001e5b5f5ff35b5f5ff35b5f5ff35b5f5ff30006000a000e00120000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000000000000000000000000a000000000000000000000000000000000000000000000000000000000000000e0000000000000000000000000000000000000000000000000000000000000012"));
assert!(custom_bootstrap);
}

Expand Down Expand Up @@ -296,7 +296,7 @@ fn test_jump_table_exhaustive_usage() {

// Have the Codegen create the constructor bytecode
let mbytes = Codegen::generate_main_bytecode(&contract, None).unwrap();
assert_eq!(mbytes, String::from("608061004060003960003560e01c8063a9059cbb14610019575b60208703516202ffe016806020015b60206020015b60206020015b60206020015b60206020010000000000000000000000000000000000000000000000000000000000000028000000000000000000000000000000000000000000000000000000000000002e0000000000000000000000000000000000000000000000000000000000000034000000000000000000000000000000000000000000000000000000000000003a"));
assert_eq!(mbytes, String::from("608061003e5f395f3560e01c8063a9059cbb14610017575b60208703516202ffe016806020015b60206020015b60206020015b60206020015b60206020010000000000000000000000000000000000000000000000000000000000000026000000000000000000000000000000000000000000000000000000000000002c00000000000000000000000000000000000000000000000000000000000000320000000000000000000000000000000000000000000000000000000000000038"));
}

#[test]
Expand Down Expand Up @@ -356,7 +356,7 @@ fn test_jump_table_packed_exhaustive_usage() {

// Have the Codegen create the main macro bytecode
let mbytes = Codegen::generate_main_bytecode(&contract, None).unwrap();
assert_eq!(mbytes, String::from("600861004060003960003560e01c8063a9059cbb14610019575b60208703516202ffe016806020015b60206020015b60206020015b60206020015b60206020010028002e0034003a"));
assert_eq!(mbytes, String::from("600861003e5f395f3560e01c8063a9059cbb14610017575b60208703516202ffe016806020015b60206020015b60206020015b60206020015b60206020010026002c00320038"));
}

#[test]
Expand Down Expand Up @@ -423,7 +423,7 @@ fn test_label_clashing() {

// Have the Codegen create the main macro bytecode
let mbytes = Codegen::generate_main_bytecode(&contract, None).unwrap();
assert_eq!(mbytes, String::from("6008610048600039608061005060003960003560e01c8063a9059cbb14610021575b60208703516202ffe016806020015b60206020015b60206020015b60206020015b602060200100300036003c004200000000000000000000000000000000000000000000000000000000000000300000000000000000000000000000000000000000000000000000000000000036000000000000000000000000000000000000000000000000000000000000003c0000000000000000000000000000000000000000000000000000000000000042"));
assert_eq!(mbytes, String::from("60086100455f39608061004d5f395f3560e01c8063a9059cbb1461001e575b60208703516202ffe016806020015b60206020015b60206020015b60206020015b6020602001002d00330039003f000000000000000000000000000000000000000000000000000000000000002d00000000000000000000000000000000000000000000000000000000000000330000000000000000000000000000000000000000000000000000000000000039000000000000000000000000000000000000000000000000000000000000003f"));
}

#[test]
Expand Down Expand Up @@ -468,13 +468,13 @@ fn test_func_sig_builtin() {
// Have the Codegen create the constructor bytecode
let cbytes = Codegen::generate_main_bytecode(&contract, None).unwrap();
// `transfer(address,uint256) signature = 0xa9059cbb
assert_eq!(&cbytes[16..24], "a9059cbb");
assert_eq!(&cbytes[38..46], "a9059cbb");
assert_eq!(&cbytes[60..68], "a9059cbb");
assert_eq!(&cbytes[14..22], "a9059cbb");
assert_eq!(&cbytes[36..44], "a9059cbb");
assert_eq!(&cbytes[58..66], "a9059cbb");
assert_eq!(
cbytes,
String::from(
"60003560e01c8063a9059cbb14610027578063a9059cbb14610027578063a9059cbb14610027575b"
"5f3560e01c8063a9059cbb14610026578063a9059cbb14610026578063a9059cbb14610026575b"
)
);
}
Expand Down Expand Up @@ -525,7 +525,7 @@ fn test_event_hash_builtin() {
);
assert_eq!(
cbytes,
String::from("7fbeabacc8ffedac16e9a60acdb2ca743d80c2ebb44977a93fa8e483c74d2b35a87fbeabacc8ffedac16e9a60acdb2ca743d80c2ebb44977a93fa8e483c74d2b35a87fbeabacc8ffedac16e9a60acdb2ca743d80c2ebb44977a93fa8e483c74d2b35a8600055")
String::from("7fbeabacc8ffedac16e9a60acdb2ca743d80c2ebb44977a93fa8e483c74d2b35a87fbeabacc8ffedac16e9a60acdb2ca743d80c2ebb44977a93fa8e483c74d2b35a87fbeabacc8ffedac16e9a60acdb2ca743d80c2ebb44977a93fa8e483c74d2b35a85f55")
);
}

Expand Down Expand Up @@ -588,11 +588,11 @@ fn test_error_selector_builtin() {
// Have Codegen create the runtime bytecode
let r_bytes = Codegen::generate_main_bytecode(&contract, None).unwrap();
assert_eq!(&r_bytes[2..66], "be20788c00000000000000000000000000000000000000000000000000000000");
assert_eq!(&r_bytes[98..106], "08c379a0");
assert_eq!(&r_bytes[94..102], "08c379a0");
assert_eq!(
r_bytes,
String::from(
"7fbe20788c0000000000000000000000000000000000000000000000000000000060005260045260246000fd610048576308c379a0600052602060045260245260445260646000fd5b50"
"7fbe20788c000000000000000000000000000000000000000000000000000000005f5260045260245ffd610044576308c379a05f52602060045260245260445260645ffd5b50"
)
);
}
Expand Down
4 changes: 2 additions & 2 deletions huff_core/tests/compiling.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ fn compiles_constructor_bytecode() {
let (cbytes, custom_bootstrap) =
Codegen::generate_constructor_bytecode(&contract, None).unwrap();
println!("Constructor Bytecode Result: {cbytes:?}");
assert_eq!(cbytes, String::from("33600055"));
assert_eq!(cbytes, String::from("335f55"));
assert!(!custom_bootstrap);
}

Expand All @@ -84,7 +84,7 @@ fn compiles_runtime_bytecode() {

// Have the Codegen create the constructor bytecode
let (cbytes, cbootstrap) = Codegen::generate_constructor_bytecode(&contract, None).unwrap();
assert_eq!(cbytes, String::from("33600055"));
assert_eq!(cbytes, String::from("335f55"));
assert!(!cbootstrap);

let inputs: Vec<ethers_core::abi::Token> = vec![];
Expand Down
4 changes: 2 additions & 2 deletions huff_core/tests/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ fn test_function() {
let mut cg = Codegen::new();
let artifact =
cg.churn(Arc::clone(&Arc::new(FileSource::default())), vec![], &rbytes, "", false).unwrap();
assert_eq!(artifact.bytecode, String::from("60ad8060093d393df360003560e01c8063075900201461002757806319715c0d1461004457806327902d6914610061575b60443560243560043561003b92919061007e565b60005260206000f35b60443560243560043561005892919061007e565b60005260206000f35b60443560243560043561007592919061007e565b60005260206000f35b828282026000521515908015906000510483141716156100a457506000510460016100aa575b60006000fd5b9056"));
assert_eq!(artifact.bytecode, String::from("60a18060093d393df35f3560e01c8063075900201461002657806319715c0d1461004157806327902d691461005c575b60443560243560043561003a929190610077565b5f5260205ff35b604435602435600435610055929190610077565b5f5260205ff35b604435602435600435610070929190610077565b5f5260205ff35b828282025f521515908015905f5104831417161561009a57505f5104600161009e575b5f5ffd5b9056"));
}

#[test]
Expand Down Expand Up @@ -209,5 +209,5 @@ fn test_nested_function() {
let mut cg = Codegen::new();
let artifact =
cg.churn(Arc::clone(&Arc::new(FileSource::default())), vec![], &rbytes, "", false).unwrap();
assert_eq!(artifact.bytecode, String::from("606b8060093d393df360003560e01c80630759002014610011575b60443560243560043561002592919061005d565b60005260206000f35b82828202600052151590801590600051048314171615610054575060005104600161005a575b60006000fd5b90565b61006892919061002e565b9056"));
assert_eq!(artifact.bytecode, String::from("60638060093d393df35f3560e01c80630759002014610010575b604435602435600435610024929190610055565b5f5260205ff35b828282025f521515908015905f5104831417161561004e57505f51046001610052575b5f5ffd5b90565b61006092919061002b565b9056"));
}
3 changes: 1 addition & 2 deletions huff_core/tests/gen_artifact.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,8 +40,7 @@ fn test_missing_constructor() {
assert_eq!(artifact.file, arc_source);
assert_eq!(
artifact.bytecode,
"601a8060093d393df360003560e01c806340c10f1914610011575b6004356000602435"
.to_string()
"60188060093d393df35f3560e01c806340c10f1914610010575b6004355f602435".to_string()
);
}
_ => panic!("moose"),
Expand Down
2 changes: 1 addition & 1 deletion huff_core/tests/in_memory.rs
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,6 @@ fn test_in_memory_compiler() {

assert_eq!(
artifact.bytecode,
"601a8060093d393df360003560e01c806340c10f1914610011575b6004356000602435".to_string()
"60188060093d393df35f3560e01c806340c10f1914610010575b6004355f602435".to_string()
);
}
37 changes: 37 additions & 0 deletions huff_core/tests/push_overrides.rs
Original file line number Diff line number Diff line change
Expand Up @@ -124,3 +124,40 @@ fn test_fails_on_push_underflow() {
let mut parser = Parser::new(tokens, None);
parser.parse().unwrap();
}

#[test]
fn test_literal_to_push0() {
const LITERAL_PUSH: &str = r#"
#define constant ALICE = 0x0000
#define constant BOB = 0x0001
#define macro MAIN() = {
push0
0x00
0x000000
push1 0x00
[ALICE]
[BOB]
}
"#;

let flattened_source = FullFileSource { source: LITERAL_PUSH, file: None, spans: vec![] };
let lexer = Lexer::new(flattened_source.source);
let tokens = lexer.into_iter().map(|x| x.unwrap()).collect::<Vec<Token>>();
let mut parser = Parser::new(tokens, None);

// Grab the first macro
let mut contract = parser.parse().unwrap();
// Derive storage pointers
contract.derive_storage_pointers();

// Instantiate Codegen
let cg = Codegen::new();

// The codegen instance should have no artifact
assert!(cg.artifact.is_none());

// Have the Codegen create the constructor bytecode
let cbytes = Codegen::generate_main_bytecode(&contract, None).unwrap();
assert_eq!(cbytes, String::from("5f5f5f60005f6001"));
}
2 changes: 1 addition & 1 deletion huff_core/tests/recurse_bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,7 @@ fn recurse_macro_bytecode() {
assert!(!has_custom_bootstrap);

// Full expected bytecode output (generated from huffc) (placed here as a reference)
let expected_bytecode = "61003f8061000d6000396000f360003560E01c8063a9059cbb1461001c57806340c10f191461002e575b60043533602435600160005260206000f35b60043560006024358060005401600055";
let expected_bytecode = "6100398061000d6000396000f35f3560e01c8063a9059cbb1461001b57806340c10f191461002b575b6004353360243560015f5260205ff35b6004355f602435805f54015f55";

// Construct the expected output
let mut artifact = Artifact::default();
Expand Down
3 changes: 1 addition & 2 deletions huff_utils/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -588,8 +588,7 @@ impl MacroDefinition {
while let Some(statement) = statement_iter.next() {
match &statement.ty {
StatementType::Literal(l) => {
let hex_literal: String = bytes32_to_string(l, false);
let push_bytes = format!("{:02x}{hex_literal}", 95 + hex_literal.len() / 2);
let push_bytes = literal_gen(l);
inner_irbytes.push(IRBytes {
ty: IRByteType::Bytes(Bytes(push_bytes)),
span: &statement.span,
Expand Down
11 changes: 10 additions & 1 deletion huff_utils/src/bytes_util.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
use crate::evm::Opcode;
use std::num::ParseIntError;

use tiny_keccak::{Hasher, Keccak};

/// Convert a string slice to a `[u8; 32]`
Expand Down Expand Up @@ -68,3 +68,12 @@ pub fn hash_bytes(dest: &mut [u8], to_hash: &String) {
hasher.update(to_hash.as_bytes());
hasher.finalize(dest);
}

/// Converts a value literal to its smallest equivalent `PUSHX` bytecode
pub fn literal_gen(l: &[u8; 32]) -> String {
let hex_literal: String = bytes32_to_string(l, false);
match hex_literal.as_str() {
"00" => Opcode::Push0.to_string(),
_ => format!("{:02x}{hex_literal}", 95 + hex_literal.len() / 2),
}
}

0 comments on commit 10aa9d0

Please sign in to comment.