diff --git a/core_lang/src/asm_generation/mod.rs b/core_lang/src/asm_generation/mod.rs index 70ee4a09973..c67ba4f2df5 100644 --- a/core_lang/src/asm_generation/mod.rs +++ b/core_lang/src/asm_generation/mod.rs @@ -642,11 +642,43 @@ pub(crate) fn compile_ast_to_asm<'sc>( comment: "main fn returns unit value".into(), }); } else { - asm_buf.push(Op { - owning_span: None, - opcode: Either::Left(VirtualOp::RET(return_register)), - comment: "main fn return value".into(), - }); + let size_of_main_func_return_bytes = check!( + main_function.return_type.force_resolution( + &MaybeResolvedType::Resolved(ResolvedType::Unit), + &main_function.return_type_span + ), + return err(warnings, errors), + warnings, + errors + ) + .stack_size_of() + * 8; + if size_of_main_func_return_bytes == 8 { + asm_buf.push(Op { + owning_span: None, + opcode: Either::Left(VirtualOp::RET(return_register)), + comment: "main fn return value".into(), + }); + } else { + // if the type is larger than one word, then we use RETD to return data + // RB is the size_in_bytes + let rb_register = register_sequencer.next(); + let size_bytes = + namespace.insert_data_value(&Literal::U64(size_of_main_func_return_bytes)); + // `return_register` is $rA + asm_buf.push(Op { + opcode: Either::Left(VirtualOp::LWDataId(rb_register.clone(), size_bytes)), + owning_span: Some(main_function.return_type_span), + comment: "loading rB for RETD".into(), + }); + + // now $rB has the size of the type in bytes + asm_buf.push(Op { + owning_span: None, + opcode: Either::Left(VirtualOp::RETD(return_register, rb_register)), + comment: "main fn return value".into(), + }); + } } HllAsmSet::ScriptMain { @@ -1099,13 +1131,13 @@ fn build_contract_abi_switch<'sc>( }); } - // if none of the selectors matched, then revert + // if none of the selectors matched, then ret asm_buf.push(Op { // see https://github.com/FuelLabs/sway/issues/97#issuecomment-875674105 opcode: Either::Left(VirtualOp::RET(VirtualRegister::Constant( ConstantRegister::Zero, ))), - comment: "revert if no selectors matched".into(), + comment: "return if no selectors matched".into(), owning_span: None, }); diff --git a/core_lang/src/asm_lang/allocated_ops.rs b/core_lang/src/asm_lang/allocated_ops.rs index 9c445e5fdc4..e6b620b06a4 100644 --- a/core_lang/src/asm_lang/allocated_ops.rs +++ b/core_lang/src/asm_lang/allocated_ops.rs @@ -88,6 +88,7 @@ pub(crate) enum AllocatedOpcode { JI(VirtualImmediate24), JNEI(AllocatedRegister, AllocatedRegister, VirtualImmediate12), RET(AllocatedRegister), + RETD(AllocatedRegister, AllocatedRegister), CFEI(VirtualImmediate24), CFSI(VirtualImmediate24), LB(AllocatedRegister, AllocatedRegister, VirtualImmediate12), @@ -201,6 +202,7 @@ impl<'sc> fmt::Display for AllocatedOp<'sc> { JI(a) => format!("ji {}", a), JNEI(a, b, c) => format!("jnei {} {} {}", a, b, c), RET(a) => format!("ret {}", a), + RETD(a, b) => format!("retd {} {}", a, b), CFEI(a) => format!("cfei {}", a), CFSI(a) => format!("cfsi {}", a), LB(a, b, c) => format!("lb {} {} {}", a, b, c), @@ -300,6 +302,7 @@ impl<'sc> AllocatedOp<'sc> { JI (a) => VmOp::JI (a.value), JNEI(a, b, c) => VmOp::JNEI(a.to_register_id(), b.to_register_id(), c.value), RET (a) => VmOp::RET (a.to_register_id()), + RETD(a, b) => VmOp::RETD (a.to_register_id(), b.to_register_id()), CFEI(a) => VmOp::CFEI(a.value), CFSI(a) => VmOp::CFSI(a.value), LB (a, b, c) => VmOp::LB (a.to_register_id(), b.to_register_id(), c.value), diff --git a/core_lang/src/asm_lang/mod.rs b/core_lang/src/asm_lang/mod.rs index 6ddf5555279..794182ba3c0 100644 --- a/core_lang/src/asm_lang/mod.rs +++ b/core_lang/src/asm_lang/mod.rs @@ -558,6 +558,15 @@ impl<'sc> Op<'sc> { ); VirtualOp::RET(r1) } + "retd" => { + let (r1, r2) = check!( + two_regs(args, immediate, whole_op_span), + return err(warnings, errors), + warnings, + errors + ); + VirtualOp::RETD(r1, r2) + } "cfei" => { let imm = check!( single_imm_24(args, immediate, whole_op_span), @@ -1254,6 +1263,7 @@ impl fmt::Display for Op<'_> { JI(a) => format!("ji {}", a), JNEI(a, b, c) => format!("jnei {} {} {}", a, b, c), RET(a) => format!("ret {}", a), + RETD(a, b) => format!("retd {} {}", a, b), CFEI(a) => format!("cfei {}", a), CFSI(a) => format!("cfsi {}", a), LB(a, b, c) => format!("lb {} {} {}", a, b, c), diff --git a/core_lang/src/asm_lang/virtual_ops.rs b/core_lang/src/asm_lang/virtual_ops.rs index 5458d32397b..3744579442d 100644 --- a/core_lang/src/asm_lang/virtual_ops.rs +++ b/core_lang/src/asm_lang/virtual_ops.rs @@ -286,6 +286,7 @@ pub(crate) enum VirtualOp { JI(VirtualImmediate24), JNEI(VirtualRegister, VirtualRegister, VirtualImmediate12), RET(VirtualRegister), + RETD(VirtualRegister, VirtualRegister), CFEI(VirtualImmediate24), CFSI(VirtualImmediate24), LB(VirtualRegister, VirtualRegister, VirtualImmediate12), @@ -396,6 +397,7 @@ impl VirtualOp { JI(_im) => vec![], JNEI(r1, r2, _i) => vec![r1, r2], RET(r1) => vec![r1], + RETD(r1, r2) => vec![r1, r2], CFEI(_imm) => vec![], CFSI(_imm) => vec![], LB(r1, r2, _i) => vec![r1, r2], @@ -635,6 +637,9 @@ impl VirtualOp { imm.clone(), ), RET(reg) => AllocatedOpcode::RET(map_reg(&mapping, reg)), + RETD(reg1, reg2) => { + AllocatedOpcode::RETD(map_reg(&mapping, reg1), map_reg(&mapping, reg2)) + } CFEI(imm) => AllocatedOpcode::CFEI(imm.clone()), CFSI(imm) => AllocatedOpcode::CFSI(imm.clone()), LB(reg1, reg2, imm) => AllocatedOpcode::LB( diff --git a/test/src/e2e_vm_tests/mod.rs b/test/src/e2e_vm_tests/mod.rs index 2f49785e083..ef22ab7b561 100644 --- a/test/src/e2e_vm_tests/mod.rs +++ b/test/src/e2e_vm_tests/mod.rs @@ -18,6 +18,21 @@ pub fn run() { ("main_returns_unit", ProgramState::Return(0)), ("unary_not_basic", ProgramState::Return(1)), // 1 == true ("unary_not_basic_2", ProgramState::Return(1)), // 1 == true + ( + "retd_b256", + ProgramState::ReturnData(Bytes32::from([ + 102, 104, 122, 173, 248, 98, 189, 119, 108, 143, 193, 139, 142, 159, 142, 32, 8, + 151, 20, 133, 110, 226, 51, 179, 144, 42, 89, 29, 13, 95, 41, 37, + ])), + ), + ( + "retd_struct", + ProgramState::ReturnData(Bytes32::from([ + 2, 23, 32, 21, 62, 98, 71, 190, 175, 43, 135, 133, 106, 105, 116, 64, 126, 40, 204, + 235, 151, 159, 245, 170, 112, 203, 40, 158, 9, 238, 188, 213, + ])), + ), + ("op_precedence", ProgramState::Return(0)), ("asm_without_return", ProgramState::Return(0)), ("op_precedence", ProgramState::Return(0)), // 1 == false ]; diff --git a/test/src/e2e_vm_tests/test_programs/retd_b256/Forc.toml b/test/src/e2e_vm_tests/test_programs/retd_b256/Forc.toml new file mode 100644 index 00000000000..15ef0c0bff7 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/retd_b256/Forc.toml @@ -0,0 +1,5 @@ +[project] +author = "Alexander Hansen" +license = "MIT" +name = "retd_b256" +entry = "main.sw" diff --git a/test/src/e2e_vm_tests/test_programs/retd_b256/src/main.sw b/test/src/e2e_vm_tests/test_programs/retd_b256/src/main.sw new file mode 100644 index 00000000000..a28cae1ad34 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/retd_b256/src/main.sw @@ -0,0 +1,11 @@ +script; + +// a b256 is bigger than a word, so RETD should be used instead of RET. +fn main() -> b256 { + let a = 0x0000000000000000000000000000000000000000000000000000000000000000 ; + asm(r1: a, r2: 0x0000000000000000000000000000000000000000000000000000000000000000 ) { + log r1 r2 zero zero; + zero + }; + return a; +} diff --git a/test/src/e2e_vm_tests/test_programs/retd_struct/Forc.toml b/test/src/e2e_vm_tests/test_programs/retd_struct/Forc.toml new file mode 100644 index 00000000000..f84d373b332 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/retd_struct/Forc.toml @@ -0,0 +1,5 @@ +[project] +author = "Alexander Hansen" +license = "MIT" +name = "retd_struct" +entry = "main.sw" diff --git a/test/src/e2e_vm_tests/test_programs/retd_struct/src/main.sw b/test/src/e2e_vm_tests/test_programs/retd_struct/src/main.sw new file mode 100644 index 00000000000..ae5613d4a58 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/retd_struct/src/main.sw @@ -0,0 +1,13 @@ +script; + +struct BiggerThanAWord { + field_1: u64, + field_2: b256, +} + +fn main() -> BiggerThanAWord { + BiggerThanAWord { + field_1: 99999u64, + field_2: 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff + } +}