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

Make Codegen Faster Through Less Allocations #269

Merged
merged 5 commits into from
Apr 4, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 13 additions & 11 deletions huff_codegen/src/irgen/arg_calls.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ pub fn bubble_arg_call(
bytes: &mut Vec<(usize, Bytes)>,
macro_def: &MacroDefinition,
contract: &Contract,
scope: &mut Vec<MacroDefinition>,
scope: &mut [&MacroDefinition],
offset: &mut usize,
// mis: Parent macro invocations and their indices
mis: &mut Vec<(usize, MacroInvocation)>,
mis: &mut [(usize, MacroInvocation)],
jump_table: &mut JumpTable,
) -> Result<(), CodegenError> {
let starting_offset = *offset;
Expand Down Expand Up @@ -46,9 +46,10 @@ pub fn bubble_arg_call(
MacroArg::ArgCall(ac) => {
tracing::info!(target: "codegen", "GOT ARG CALL \"{}\" ARG FROM MACRO INVOCATION", ac);
tracing::debug!(target: "codegen", "~~~ BUBBLING UP ARG CALL");
let mut new_scope = Vec::from(&scope[..scope.len().saturating_sub(1)]);
let bubbled_macro_invocation = new_scope.last().unwrap().clone();
tracing::debug!(target: "codegen", "BUBBLING UP WITH MACRO DEF: {}", bubbled_macro_invocation.name);
let scope_len = scope.len();
let new_scope = &mut scope[..scope_len.saturating_sub(1)];
let bubbled_macro_invocation = new_scope.last().unwrap();
tracing::debug!(target: "codegen", "BUBBLING UP WITH MACRO DEF: {}", &bubbled_macro_invocation.name);
tracing::debug!(target: "codegen", "CURRENT MACRO DEF: {}", macro_def.name);

// Only remove an invocation if not at bottom level, otherwise we'll
Expand All @@ -60,29 +61,30 @@ pub fn bubble_arg_call(
kind: CodegenErrorKind::MissingMacroInvocation(
macro_def.name.clone(),
),
span: bubbled_macro_invocation.span,
span: bubbled_macro_invocation.span.clone(),
token: None,
})
}
};
let mis_len = mis.len();
return if last_mi.1.macro_name.eq(&macro_def.name) {
bubble_arg_call(
arg_name,
bytes,
&bubbled_macro_invocation,
bubbled_macro_invocation,
contract,
&mut new_scope,
new_scope,
offset,
&mut Vec::from(&mis[..mis.len().saturating_sub(1)]),
&mut mis[..mis_len.saturating_sub(1)],
jump_table,
)
} else {
bubble_arg_call(
arg_name,
bytes,
&bubbled_macro_invocation,
bubbled_macro_invocation,
contract,
&mut new_scope,
new_scope,
offset,
mis,
jump_table,
Expand Down
4 changes: 2 additions & 2 deletions huff_codegen/src/irgen/constants.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ use huff_utils::prelude::{
pub fn constant_gen(
name: &str,
contract: &Contract,
ir_byte_span: AstSpan,
ir_byte_span: &AstSpan,
) -> Result<String, CodegenError> {
// Get the first `ConstantDefinition` that matches the constant's name
let constants = contract
Expand All @@ -20,7 +20,7 @@ pub fn constant_gen(

return Err(CodegenError {
kind: CodegenErrorKind::MissingConstantDefinition(name.to_string()),
span: ir_byte_span,
span: ir_byte_span.clone(),
token: None,
})
};
Expand Down
14 changes: 7 additions & 7 deletions huff_codegen/src/irgen/statements.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,11 @@ use crate::Codegen;

/// Generates the respective Bytecode for a given Statement
#[allow(clippy::too_many_arguments)]
pub fn statement_gen(
pub fn statement_gen<'a>(
s: &Statement,
contract: &Contract,
contract: &'a Contract,
macro_def: &MacroDefinition,
scope: &mut Vec<MacroDefinition>,
scope: &mut Vec<&'a MacroDefinition>,
offset: &mut usize,
mis: &mut Vec<(usize, MacroInvocation)>,
jump_table: &mut JumpTable,
Expand Down Expand Up @@ -47,7 +47,7 @@ pub fn statement_gen(
tracing::error!(target: "codegen", "Tests may not be invoked: {}", ir_macro.name);
return Err(CodegenError {
kind: CodegenErrorKind::TestInvocation(ir_macro.name.clone()),
span: ir_macro.span,
span: ir_macro.span.clone(),
token: None,
})
}
Expand Down Expand Up @@ -93,11 +93,11 @@ pub fn statement_gen(
*offset += stack_swaps.len() + 8;
} else {
// Recurse into macro invocation
scope.push(ir_macro.clone());
scope.push(ir_macro);
mis.push((*offset, mi.clone()));

let mut res: BytecodeRes = match Codegen::macro_to_bytecode(
ir_macro.clone(),
ir_macro,
contract,
scope,
*offset,
Expand Down Expand Up @@ -205,7 +205,7 @@ pub fn statement_gen(
} else {
// We will still need to recurse to get accurate values
let res: BytecodeRes = match Codegen::macro_to_bytecode(
ir_macro.clone(),
ir_macro,
contract,
scope,
*offset,
Expand Down
44 changes: 22 additions & 22 deletions huff_codegen/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ impl Codegen {

// For each MacroInvocation Statement, recurse into bytecode
let bytecode_res: BytecodeRes = Codegen::macro_to_bytecode(
m_macro.clone(),
m_macro,
contract,
&mut vec![m_macro],
0,
Expand Down Expand Up @@ -96,7 +96,7 @@ impl Codegen {

// For each MacroInvocation Statement, recurse into bytecode
let bytecode_res: BytecodeRes = Codegen::macro_to_bytecode(
c_macro.clone(),
c_macro,
contract,
&mut vec![c_macro],
0,
Expand All @@ -116,10 +116,10 @@ impl Codegen {
}

/// Helper function to find a macro or generate a CodegenError
pub(crate) fn get_macro_by_name(
pub(crate) fn get_macro_by_name<'a>(
name: &str,
contract: &Contract,
) -> Result<MacroDefinition, CodegenError> {
contract: &'a Contract,
) -> Result<&'a MacroDefinition, CodegenError> {
if let Some(m) = contract.find_macro_by_name(name) {
Ok(m)
} else {
Expand Down Expand Up @@ -272,10 +272,10 @@ impl Codegen {
/// * `scope` - Current scope of the recursion. Contains all macro definitions recursed so far.
/// * `offset` - Current bytecode offset
/// * `mis` - Vector of tuples containing parent macro invocations as well as their offsets.
pub fn macro_to_bytecode(
macro_def: MacroDefinition,
contract: &Contract,
scope: &mut Vec<MacroDefinition>,
pub fn macro_to_bytecode<'a>(
macro_def: &'a MacroDefinition,
contract: &'a Contract,
scope: &mut Vec<&'a MacroDefinition>,
mut offset: usize,
mis: &mut Vec<(usize, MacroInvocation)>,
recursing_constructor: bool,
Expand All @@ -294,15 +294,15 @@ impl Codegen {
let circular_codesize_invocations = circular_codesize_invocations.unwrap_or(&mut ccsi);

// Loop through all intermediate bytecode representations generated from the AST
for (_ir_bytes_index, ir_byte) in ir_bytes.into_iter().enumerate() {
for (_ir_bytes_index, ir_byte) in ir_bytes.iter().enumerate() {
let starting_offset = offset;
match ir_byte.ty {
match &ir_byte.ty {
IRByteType::Bytes(b) => {
offset += b.0.len() / 2;
bytes.push((starting_offset, b));
bytes.push((starting_offset, b.to_owned()));
}
IRByteType::Constant(name) => {
let push_bytes = constant_gen(&name, contract, ir_byte.span)?;
let push_bytes = constant_gen(name, contract, ir_byte.span)?;
offset += push_bytes.len() / 2;
tracing::debug!(target: "codegen", "OFFSET: {}, PUSH BYTES: {:?}", offset, push_bytes);
bytes.push((starting_offset, Bytes(push_bytes)));
Expand All @@ -314,9 +314,9 @@ impl Codegen {
continue
}
let mut push_bytes = statement_gen(
&s,
s,
contract,
&macro_def,
macro_def,
scope,
&mut offset,
mis,
Expand All @@ -333,9 +333,9 @@ impl Codegen {
// Bubble up arg call by looking through the previous scopes.
// Once the arg value is found, add it to `bytes`
bubble_arg_call(
&arg_name,
arg_name,
&mut bytes,
&macro_def,
macro_def,
contract,
scope,
&mut offset,
Expand Down Expand Up @@ -534,9 +534,9 @@ impl Codegen {
/// On success, passes ownership of `bytes` back to the caller.
/// On failure, returns a CodegenError.
#[allow(clippy::too_many_arguments)]
pub fn append_functions(
contract: &Contract,
scope: &mut Vec<MacroDefinition>,
pub fn append_functions<'a>(
contract: &'a Contract,
scope: &mut Vec<&'a MacroDefinition>,
offset: &mut usize,
mis: &mut Vec<(usize, MacroInvocation)>,
jump_table: &mut JumpTable,
Expand All @@ -546,11 +546,11 @@ impl Codegen {
) -> Result<Vec<(usize, Bytes)>, CodegenError> {
for macro_def in contract.macros.iter().filter(|m| m.outlined) {
// Push the function to the scope
scope.push(macro_def.clone());
scope.push(macro_def);

// Add 1 to starting offset to account for the JUMPDEST opcode
let mut res = Codegen::macro_to_bytecode(
macro_def.clone(),
macro_def,
contract,
scope,
*offset + 1,
Expand Down
4 changes: 2 additions & 2 deletions huff_tests/src/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,9 +174,9 @@ impl TestRunner {

// Compile the passed test macro
match Codegen::macro_to_bytecode(
m.to_owned(),
m,
contract,
&mut vec![m.to_owned()],
&mut vec![m],
0,
&mut Vec::default(),
false,
Expand Down
28 changes: 14 additions & 14 deletions huff_utils/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -106,9 +106,9 @@ pub struct Contract {

impl Contract {
/// Returns the first macro that matches the provided name
pub fn find_macro_by_name(&self, name: &str) -> Option<MacroDefinition> {
pub fn find_macro_by_name(&self, name: &str) -> Option<&MacroDefinition> {
if let Some(m) = self.macros.iter().find(|m| m.name == name) {
Some(m.clone())
Some(m)
} else {
tracing::warn!("Failed to find macro \"{}\" in contract", name);
None
Expand All @@ -133,7 +133,7 @@ impl Contract {
// Derive Constructor Storage Pointers
match self.find_macro_by_name("CONSTRUCTOR") {
Some(m) => self.recurse_ast_constants(
&m,
m,
&mut storage_pointers,
&mut last_assigned_free_pointer,
false,
Expand All @@ -147,7 +147,7 @@ impl Contract {
// Derive Main Storage Pointers
match self.find_macro_by_name("MAIN") {
Some(m) => self.recurse_ast_constants(
&m,
m,
&mut storage_pointers,
&mut last_assigned_free_pointer,
false,
Expand Down Expand Up @@ -592,14 +592,14 @@ impl MacroDefinition {
let push_bytes = format!("{:02x}{hex_literal}", 95 + hex_literal.len() / 2);
inner_irbytes.push(IRBytes {
ty: IRByteType::Bytes(Bytes(push_bytes)),
span: statement.span.clone(),
span: &statement.span,
});
}
StatementType::Opcode(o) => {
let opcode_str = o.string();
inner_irbytes.push(IRBytes {
ty: IRByteType::Bytes(Bytes(opcode_str)),
span: statement.span.clone(),
span: &statement.span,
});
// If the opcode is a push, we need to consume the next statement, which must be
// a literal as checked in the parser
Expand All @@ -610,7 +610,7 @@ impl MacroDefinition {
let prefixed_hex_literal = o.prefix_push_literal(&hex_literal);
inner_irbytes.push(IRBytes {
ty: IRByteType::Bytes(Bytes(prefixed_hex_literal)),
span: statement.span.clone(),
span: &statement.span,
});
}
_ => {
Expand All @@ -624,7 +624,7 @@ impl MacroDefinition {
StatementType::Code(c) => {
inner_irbytes.push(IRBytes {
ty: IRByteType::Bytes(Bytes(c.to_owned())),
span: statement.span.clone(),
span: &statement.span,
});
}
StatementType::MacroInvocation(mi) => {
Expand All @@ -633,21 +633,21 @@ impl MacroDefinition {
ty: StatementType::MacroInvocation(mi.clone()),
span: statement.span.clone(),
}),
span: statement.span.clone(),
span: &statement.span,
});
}
StatementType::Constant(name) => {
// Constant needs to be evaluated at the top-level
inner_irbytes.push(IRBytes {
ty: IRByteType::Constant(name.to_owned()),
span: statement.span.clone(),
span: &statement.span,
});
}
StatementType::ArgCall(arg_name) => {
// Arg call needs to use a destination defined in the calling macro context
inner_irbytes.push(IRBytes {
ty: IRByteType::ArgCall(arg_name.to_owned()),
span: statement.span.clone(),
span: &statement.span,
});
}
StatementType::LabelCall(jump_to) => {
Expand All @@ -657,7 +657,7 @@ impl MacroDefinition {
ty: StatementType::LabelCall(jump_to.to_string()),
span: statement.span.clone(),
}),
span: statement.span.clone(),
span: &statement.span,
});
}
StatementType::Label(l) => {
Expand All @@ -667,7 +667,7 @@ impl MacroDefinition {
ty: StatementType::Label(l.clone()),
span: statement.span.clone(),
}),
span: statement.span.clone(),
span: &statement.span,
});

// Recurse label statements to IRBytes Bytes
Expand All @@ -679,7 +679,7 @@ impl MacroDefinition {
ty: StatementType::BuiltinFunctionCall(builtin.clone()),
span: statement.span.clone(),
}),
span: statement.span.clone(),
span: &statement.span,
});
}
}
Expand Down
6 changes: 3 additions & 3 deletions huff_utils/src/bytecode.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,11 @@ pub struct Bytes(pub String);

/// Intermediate Bytecode Representation
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct IRBytes {
pub struct IRBytes<'a> {
/// The type of IRByte
pub ty: IRByteType,
/// The Span of the IRBytes
pub span: AstSpan,
pub span: &'a AstSpan,
}

/// IRBytes Type
Expand All @@ -36,7 +36,7 @@ pub enum IRByteType {

/// Full Intermediate Bytecode Representation
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct IRBytecode(pub Vec<IRBytes>);
pub struct IRBytecode<'a>(pub Vec<IRBytes<'a>>);

/// ToIRBytecode
///
Expand Down