Skip to content
New issue

Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? # to your account

[asmgen] generate code for stack argument access differently #6651

Merged
merged 12 commits into from
Oct 24, 2024
Merged
87 changes: 46 additions & 41 deletions sway-core/src/asm_generation/fuel/functions.rs
Original file line number Diff line number Diff line change
Expand Up @@ -84,49 +84,9 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> {
));
}
} else {
// Put NUM_ARG_REGISTERS - 1 arguments into arg registers and rest into the stack.
for (idx, arg_val) in args.iter().enumerate() {
let arg_reg = self.value_to_register(arg_val)?;
// Except for the last arg register, the others hold an argument.
if idx < compiler_constants::NUM_ARG_REGISTERS as usize - 1 {
self.cur_bytecode.push(Op::register_move(
VirtualRegister::Constant(ConstantRegister::ARG_REGS[idx]),
arg_reg,
format!("[call]: pass argument {idx}"),
self.md_mgr.val_to_span(self.context, *arg_val),
));
} else {
// All arguments [NUM_ARG_REGISTERS - 1 ..] go into the stack.
assert!(
self.locals_size_bytes() % 8 == 0,
"The size of locals is not word aligned"
);
let stack_offset_bytes = self.locals_size_bytes()
+ (((idx as u64 + 1) - compiler_constants::NUM_ARG_REGISTERS as u64) * 8);
assert!(
stack_offset_bytes
< self.locals_size_bytes() + (self.max_num_extra_args() * 8)
);
self.cur_bytecode.push(Op {
opcode: Either::Left(VirtualOp::SW(
VirtualRegister::Constant(ConstantRegister::LocalsBase),
arg_reg,
VirtualImmediate12::new(
// The VM multiples the offset by 8, so we divide it by 8.
stack_offset_bytes / 8,
self.md_mgr
.val_to_span(self.context, *arg_val)
.unwrap_or(Span::dummy()),
)
.expect("Too many arguments, cannot handle."),
)),
comment: format!("[call]: pass argument {idx} via its stack slot"),
owning_span: self.md_mgr.val_to_span(self.context, *arg_val),
});
}
}
// Register ARG_REGS[NUM_ARG_REGISTERS-1] must contain LocalsBase + locals_size
// so that the callee can index the stack arguments from there.
// It's also useful for us to save the arguments to the stack next.
if self.locals_size_bytes() <= TWELVE_BITS {
self.cur_bytecode.push(Op {
opcode: Either::Left(VirtualOp::ADDI(
Expand Down Expand Up @@ -172,6 +132,51 @@ impl<'ir, 'eng> FuelAsmBuilder<'ir, 'eng> {
owning_span: self.md_mgr.val_to_span(self.context, *instr_val),
});
}

// Put NUM_ARG_REGISTERS - 1 arguments into arg registers and rest into the stack.
for (idx, arg_val) in args.iter().enumerate() {
let arg_reg = self.value_to_register(arg_val)?;
// Except for the last arg register, the others hold an argument.
if idx < compiler_constants::NUM_ARG_REGISTERS as usize - 1 {
self.cur_bytecode.push(Op::register_move(
VirtualRegister::Constant(ConstantRegister::ARG_REGS[idx]),
arg_reg,
format!("[call]: pass argument {idx}"),
self.md_mgr.val_to_span(self.context, *arg_val),
));
} else {
// All arguments [NUM_ARG_REGISTERS - 1 ..] go into the stack.
assert!(
self.locals_size_bytes() % 8 == 0,
"The size of locals is not word aligned"
);
let stack_offset =
(idx as u64 + 1) - compiler_constants::NUM_ARG_REGISTERS as u64;
let stack_offset_bytes = self.locals_size_bytes() + (stack_offset * 8);
assert!(
stack_offset_bytes
< self.locals_size_bytes() + (self.max_num_extra_args() * 8)
);
self.cur_bytecode.push(Op {
opcode: Either::Left(VirtualOp::SW(
VirtualRegister::Constant(
ConstantRegister::ARG_REGS
[compiler_constants::NUM_ARG_REGISTERS as usize - 1],
),
arg_reg,
VirtualImmediate12::new(
stack_offset,
self.md_mgr
.val_to_span(self.context, *arg_val)
.unwrap_or(Span::dummy()),
)
.expect("Too many arguments, cannot handle."),
)),
comment: format!("[call]: pass argument {idx} via its stack slot"),
owning_span: self.md_mgr.val_to_span(self.context, *arg_val),
});
}
}
}

// Set a new return address.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use contract_with_type_aliases_abi::*;
#[cfg(experimental_new_encoding = false)]
const CONTRACT_ID = 0x0cbeb6efe3104b460be769bdc4ea101ebf16ccc16f2d7b667ec3e1c7f5ce35b5;
#[cfg(experimental_new_encoding = true)]
const CONTRACT_ID = 0x514dae6ddad19623646033458f970d1286ef111806145daf80d06ca679604a96; // AUTO-CONTRACT-ID ../../test_contracts/contract_with_type_aliases --release
const CONTRACT_ID = 0x741e73148cf8c2f12b620adb9a15275eeabe703a5c058b0e786117e92024fde2; // AUTO-CONTRACT-ID ../../test_contracts/contract_with_type_aliases --release

fn main() {
let caller = abi(MyContract, CONTRACT_ID);
Expand Down
Loading