diff --git a/sway-ast/src/intrinsics.rs b/sway-ast/src/intrinsics.rs index 26be640d90e..d530c9cf47e 100644 --- a/sway-ast/src/intrinsics.rs +++ b/sway-ast/src/intrinsics.rs @@ -14,6 +14,10 @@ pub enum Intrinsic { StateLoadQuad, StateStoreQuad, Log, + Add, + Sub, + Mul, + Div, } impl fmt::Display for Intrinsic { @@ -31,6 +35,10 @@ impl fmt::Display for Intrinsic { Intrinsic::StateLoadQuad => "state_load_quad", Intrinsic::StateStoreQuad => "state_store_quad", Intrinsic::Log => "log", + Intrinsic::Add => "add", + Intrinsic::Sub => "sub", + Intrinsic::Mul => "mul", + Intrinsic::Div => "div", }; write!(f, "{}", s) } @@ -52,6 +60,10 @@ impl Intrinsic { "__state_load_quad" => StateLoadQuad, "__state_store_quad" => StateStoreQuad, "__log" => Log, + "__add" => Add, + "__sub" => Sub, + "__mul" => Mul, + "__div" => Div, _ => return None, }) } diff --git a/sway-core/src/asm_generation/from_ir.rs b/sway-core/src/asm_generation/from_ir.rs index 042cf933607..e9409dd0d0d 100644 --- a/sway-core/src/asm_generation/from_ir.rs +++ b/sway-core/src/asm_generation/from_ir.rs @@ -521,6 +521,9 @@ impl<'ir> AsmBuilder<'ir> { ) } Instruction::BitCast(val, ty) => self.compile_bitcast(instr_val, val, ty), + Instruction::BinaryOp { op, arg1, arg2 } => { + self.compile_binary_op(instr_val, op, arg1, arg2) + } Instruction::Branch(to_block) => self.compile_branch(block, to_block), Instruction::Call(..) => { errors.push(CompileError::Internal( @@ -810,6 +813,31 @@ impl<'ir> AsmBuilder<'ir> { self.reg_map.insert(*instr_val, reg); } + fn compile_binary_op( + &mut self, + instr_val: &Value, + op: &BinaryOpKind, + arg1: &Value, + arg2: &Value, + ) { + let val1_reg = self.value_to_register(arg1); + let val2_reg = self.value_to_register(arg2); + let res_reg = self.reg_seqr.next(); + let opcode = match op { + BinaryOpKind::Add => Either::Left(VirtualOp::ADD(res_reg.clone(), val1_reg, val2_reg)), + BinaryOpKind::Sub => Either::Left(VirtualOp::SUB(res_reg.clone(), val1_reg, val2_reg)), + BinaryOpKind::Mul => Either::Left(VirtualOp::MUL(res_reg.clone(), val1_reg, val2_reg)), + BinaryOpKind::Div => Either::Left(VirtualOp::DIV(res_reg.clone(), val1_reg, val2_reg)), + }; + self.bytecode.push(Op { + opcode, + comment: String::new(), + owning_span: self.md_mgr.val_to_span(self.context, *instr_val), + }); + + self.reg_map.insert(*instr_val, res_reg); + } + fn compile_branch(&mut self, from_block: &Block, to_block: &Block) { self.compile_branch_to_phi_value(from_block, to_block); diff --git a/sway-core/src/ir_generation/function.rs b/sway-core/src/ir_generation/function.rs index a9c4cc630d0..ebb363277f6 100644 --- a/sway-core/src/ir_generation/function.rs +++ b/sway-core/src/ir_generation/function.rs @@ -627,6 +627,23 @@ impl FnCompiler { } } } + Intrinsic::Add | Intrinsic::Sub | Intrinsic::Mul | Intrinsic::Div => { + let op = match kind { + Intrinsic::Add => BinaryOpKind::Add, + Intrinsic::Sub => BinaryOpKind::Sub, + Intrinsic::Mul => BinaryOpKind::Mul, + Intrinsic::Div => BinaryOpKind::Div, + _ => unreachable!(), + }; + let lhs = arguments[0].clone(); + let rhs = arguments[1].clone(); + let lhs_value = self.compile_expression(context, md_mgr, lhs)?; + let rhs_value = self.compile_expression(context, md_mgr, rhs)?; + Ok(self + .current_block + .ins(context) + .binary_op(op, lhs_value, rhs_value)) + } } } diff --git a/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs b/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs index f68d5e190e2..bea3c5f625a 100644 --- a/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs +++ b/sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs @@ -541,6 +541,69 @@ impl TypedIntrinsicFunctionKind { let return_type = insert_type(TypeInfo::Tuple(vec![])); (intrinsic_function, return_type) } + Intrinsic::Add | Intrinsic::Sub | Intrinsic::Mul | Intrinsic::Div => { + if arguments.len() != 2 { + errors.push(CompileError::IntrinsicIncorrectNumArgs { + name: kind.to_string(), + expected: 2, + span, + }); + return err(warnings, errors); + } + if !type_arguments.is_empty() { + errors.push(CompileError::IntrinsicIncorrectNumTArgs { + name: kind.to_string(), + expected: 0, + span, + }); + return err(warnings, errors); + } + + let mut ctx = ctx + .by_ref() + .with_type_annotation(insert_type(TypeInfo::Unknown)); + + let lhs = arguments[0].clone(); + let lhs = check!( + TypedExpression::type_check(ctx.by_ref(), lhs), + return err(warnings, errors), + warnings, + errors + ); + + // Check for supported argument types + let arg_ty = resolve_type(lhs.return_type, &lhs.span).unwrap(); + let is_valid_arg_ty = matches!(arg_ty, TypeInfo::UnsignedInteger(_)); + if !is_valid_arg_ty { + errors.push(CompileError::IntrinsicUnsupportedArgType { + name: kind.to_string(), + span: lhs.span, + hint: Hint::empty(), + }); + return err(warnings, errors); + } + + let rhs = arguments[1].clone(); + let ctx = ctx + .by_ref() + .with_help_text("Incorrect argument type") + .with_type_annotation(lhs.return_type); + let rhs = check!( + TypedExpression::type_check(ctx, rhs), + return err(warnings, errors), + warnings, + errors + ); + ( + TypedIntrinsicFunctionKind { + kind, + arguments: vec![lhs, rhs], + type_arguments: vec![], + span, + }, + insert_type(arg_ty), + ) + } }; ok((intrinsic_function, return_type), warnings, errors) } diff --git a/sway-core/tests/ir_to_asm/binops.asm b/sway-core/tests/ir_to_asm/binops.asm new file mode 100644 index 00000000000..bfd20744987 --- /dev/null +++ b/sway-core/tests/ir_to_asm/binops.asm @@ -0,0 +1,46 @@ +.program: +ji i4 +noop +DATA_SECTION_OFFSET[0..32] +DATA_SECTION_OFFSET[32..64] +lw $ds $is 1 +add $$ds $$ds $is +move $r2 $sp ; save locals base register +cfei i48 ; allocate 48 bytes for all locals +addi $r0 $r2 i0 ; get offset reg for get_ptr +lw $r0 data_0 ; literal instantiation +sw $r2 $r0 i0 ; store value +addi $r0 $r2 i8 ; get offset reg for get_ptr +lw $r0 data_1 ; literal instantiation +sw $r2 $r0 i1 ; store value +addi $r0 $r2 i0 ; get offset reg for get_ptr +lw $r1 $r2 i0 ; load value +addi $r0 $r2 i8 ; get offset reg for get_ptr +lw $r0 $r2 i1 ; load value +add $r0 $r1 $r0 +addi $r1 $r2 i16 ; get offset reg for get_ptr +sw $r2 $r0 i2 ; store value +addi $r0 $r2 i16 ; get offset reg for get_ptr +lw $r1 $r2 i2 ; load value +lw $r0 data_2 ; literal instantiation +mul $r1 $r1 $r0 +addi $r0 $r2 i24 ; get offset reg for get_ptr +sw $r2 $r1 i3 ; store value +addi $r0 $r2 i24 ; get offset reg for get_ptr +lw $r0 $r2 i3 ; load value +sub $r1 $r0 $one +addi $r0 $r2 i32 ; get offset reg for get_ptr +sw $r2 $r1 i4 ; store value +addi $r0 $r2 i32 ; get offset reg for get_ptr +lw $r1 $r2 i4 ; load value +lw $r0 data_2 ; literal instantiation +div $r1 $r1 $r0 +addi $r0 $r2 i40 ; get offset reg for get_ptr +sw $r2 $r1 i5 ; store value +addi $r0 $r2 i40 ; get offset reg for get_ptr +lw $r0 $r2 i5 ; load value +ret $r0 +.data: +data_0 .u64 0x16 +data_1 .u64 0x2c +data_2 .u64 0x02 diff --git a/sway-core/tests/ir_to_asm/binops.ir b/sway-core/tests/ir_to_asm/binops.ir new file mode 100644 index 00000000000..dbde366962b --- /dev/null +++ b/sway-core/tests/ir_to_asm/binops.ir @@ -0,0 +1,66 @@ +script { + fn main() -> u64, !1 { + local ptr u64 a + local ptr u64 b + local ptr u64 res1 + local ptr u64 res2 + local ptr u64 res3 + local ptr u64 res4 + + entry: + v0 = get_ptr ptr u64 a, ptr u64, 0, !2 + v1 = const u64 22, !3 + store v1, ptr v0, !2 + v2 = get_ptr ptr u64 b, ptr u64, 0, !4 + v3 = const u64 44, !5 + store v3, ptr v2, !4 + v4 = get_ptr ptr u64 a, ptr u64, 0, !6 + v5 = load ptr v4, !6 + v6 = get_ptr ptr u64 b, ptr u64, 0, !7 + v7 = load ptr v6, !7 + v8 = add v5, v7 + v9 = get_ptr ptr u64 res1, ptr u64, 0, !8 + store v8, ptr v9, !8 + v10 = get_ptr ptr u64 res1, ptr u64, 0, !9 + v11 = load ptr v10, !9 + v12 = const u64 2, !10 + v13 = mul v11, v12 + v14 = get_ptr ptr u64 res2, ptr u64, 0, !11 + store v13, ptr v14, !11 + v15 = get_ptr ptr u64 res2, ptr u64, 0, !12 + v16 = load ptr v15, !12 + v17 = const u64 1, !13 + v18 = sub v16, v17 + v19 = get_ptr ptr u64 res3, ptr u64, 0, !14 + store v18, ptr v19, !14 + v20 = get_ptr ptr u64 res3, ptr u64, 0, !15 + v21 = load ptr v20, !15 + v22 = const u64 2, !16 + v23 = div v21, v22 + v24 = get_ptr ptr u64 res4, ptr u64, 0, !17 + store v23, ptr v24, !17 + v25 = get_ptr ptr u64 res4, ptr u64, 0, !18 + v26 = load ptr v25, !18 + ret u64 v26 + } +} + +!0 = "sway-core/tests/ir_to_asm/binops.ir" +!1 = span !0 35 216 +!2 = span !0 57 73 +!3 = span !0 70 72 +!4 = span !0 76 92 +!5 = span !0 89 91 +!6 = span !0 113 114 +!7 = span !0 116 117 +!8 = span !0 96 119 +!9 = span !0 139 143 +!10 = span !0 145 146 +!11 = span !0 122 148 +!12 = span !0 168 172 +!13 = span !0 174 175 +!14 = span !0 151 177 +!15 = span !0 197 201 +!16 = span !0 203 204 +!17 = span !0 180 206 +!18 = span !0 210 214 diff --git a/sway-ir/src/error.rs b/sway-ir/src/error.rs index 512f3b34194..d7882b2b6a9 100644 --- a/sway-ir/src/error.rs +++ b/sway-ir/src/error.rs @@ -28,6 +28,7 @@ pub enum IrError { VerifyBitcastFromNonCopyType(String), VerifyBitcastToNonCopyType(String), VerifyBitcastBetweenInvalidTypes(String, String), + VerifyBinaryOpIncorrectArgType, VerifyBranchToMissingBlock(String), VerifyCallArgTypeMismatch(String), VerifyCallToMissingFunction(String), @@ -158,6 +159,12 @@ impl fmt::Display for IrError { f, "Verification failed: Bitcast not allowed from a {from_ty} to a {to_ty}." ), + IrError::VerifyBinaryOpIncorrectArgType => { + write!( + f, + "Verification failed: Incorrect argument type(s) for binary op" + ) + } IrError::VerifyBranchToMissingBlock(label) => { write!( f, diff --git a/sway-ir/src/instruction.rs b/sway-ir/src/instruction.rs index f9b9600b3c9..0f5983e6917 100644 --- a/sway-ir/src/instruction.rs +++ b/sway-ir/src/instruction.rs @@ -27,6 +27,12 @@ pub enum Instruction { AddrOf(Value), /// An opaque list of ASM instructions passed directly to codegen. AsmBlock(AsmBlock, Vec), + /// Binary arithmetic operations + BinaryOp { + op: BinaryOpKind, + arg1: Value, + arg2: Value, + }, /// Cast the type of a value without changing its actual content. BitCast(Value, Type), /// An unconditional jump. @@ -139,6 +145,14 @@ pub enum Predicate { // More soon. NotEqual, LessThan, LessThanOrEqual, GreaterThan, GreaterThanOrEqual. } +#[derive(Debug, Clone, Copy)] +pub enum BinaryOpKind { + Add, + Sub, + Mul, + Div, +} + /// Special registers in the Fuel Virtual Machine. #[derive(Debug, Clone, Copy)] pub enum Register { @@ -181,6 +195,7 @@ impl Instruction { match self { Instruction::AddrOf(_) => Some(Type::Uint(64)), Instruction::AsmBlock(asm_block, _) => Some(asm_block.get_type(context)), + Instruction::BinaryOp { arg1, .. } => arg1.get_type(context), Instruction::BitCast(_, ty) => Some(*ty), Instruction::Call(function, _) => Some(context.functions[function.0].return_type), Instruction::Cmp(..) => Some(Type::Bool), @@ -278,6 +293,10 @@ impl Instruction { .for_each(|init_val| replace(init_val)) }), Instruction::BitCast(value, _) => replace(value), + Instruction::BinaryOp { op: _, arg1, arg2 } => { + replace(arg1); + replace(arg2); + } Instruction::Branch(_) => (), Instruction::Call(_, args) => args.iter_mut().for_each(replace), Instruction::Cmp(_, lhs_val, rhs_val) => { @@ -372,6 +391,7 @@ impl Instruction { | Instruction::InsertValue { .. } => true, | Instruction::AddrOf(_) | Instruction::BitCast(..) + | Instruction::BinaryOp { .. } | Instruction::Cmp(..) | Instruction::ExtractElement { .. } | Instruction::ExtractValue { .. } @@ -491,6 +511,15 @@ impl<'a> InstructionInserter<'a> { bitcast_val } + pub fn binary_op(self, op: BinaryOpKind, arg1: Value, arg2: Value) -> Value { + let binop_val = + Value::new_instruction(self.context, Instruction::BinaryOp { op, arg1, arg2 }); + self.context.blocks[self.block.0] + .instructions + .push(binop_val); + binop_val + } + pub fn int_to_ptr(self, value: Value, ty: Type) -> Value { let int_to_ptr_val = Value::new_instruction(self.context, Instruction::IntToPtr(value, ty)); self.context.blocks[self.block.0] diff --git a/sway-ir/src/optimize/dce.rs b/sway-ir/src/optimize/dce.rs index 31cdcab2ffa..ddcb5bf7304 100644 --- a/sway-ir/src/optimize/dce.rs +++ b/sway-ir/src/optimize/dce.rs @@ -27,6 +27,7 @@ pub fn dce(context: &mut Context, function: &Function) -> Result Instruction::AddrOf(v) => vec![*v], Instruction::AsmBlock(_, args) => args.iter().filter_map(|aa| aa.initializer).collect(), Instruction::BitCast(v, _) => vec![*v], + Instruction::BinaryOp { op: _, arg1, arg2 } => vec![*arg1, *arg2], Instruction::Branch(_) => vec![], Instruction::Call(_, vs) => vs.clone(), Instruction::Cmp(_, lhs, rhs) => vec![*lhs, *rhs], diff --git a/sway-ir/src/optimize/inline.rs b/sway-ir/src/optimize/inline.rs index dc0adf1f9ee..debf9ac0f66 100644 --- a/sway-ir/src/optimize/inline.rs +++ b/sway-ir/src/optimize/inline.rs @@ -306,6 +306,11 @@ fn inline_instruction( } Instruction::AddrOf(arg) => new_block.ins(context).addr_of(map_value(arg)), Instruction::BitCast(value, ty) => new_block.ins(context).bitcast(map_value(value), ty), + Instruction::BinaryOp { op, arg1, arg2 } => { + new_block + .ins(context) + .binary_op(op, map_value(arg1), map_value(arg2)) + } // For `br` and `cbr` below we don't need to worry about the phi values, they're // adjusted later in `inline_function_call()`. Instruction::Branch(b) => new_block.ins(context).branch(map_block(b), None), diff --git a/sway-ir/src/parser.rs b/sway-ir/src/parser.rs index cc3d10bc549..6acacebd54e 100644 --- a/sway-ir/src/parser.rs +++ b/sway-ir/src/parser.rs @@ -121,11 +121,18 @@ mod ir_builder { mdi } + rule binary_op_kind() -> BinaryOpKind + = "add" _ { BinaryOpKind::Add } + / "sub" _ { BinaryOpKind::Sub } + / "mul" _ { BinaryOpKind::Mul } + / "div" _ { BinaryOpKind::Div } + rule operation() -> IrAstOperation = op_addr_of() / op_asm() / op_branch() / op_bitcast() + / op_binary() / op_call() / op_cbr() / op_cmp() @@ -174,6 +181,11 @@ mod ir_builder { IrAstOperation::BitCast(val, ty) } + rule op_binary() -> IrAstOperation + = op: binary_op_kind() arg1:id() comma() arg2:id() { + IrAstOperation::BinaryOp(op, arg1, arg2) + } + rule op_branch() -> IrAstOperation = "br" _ to_block:id() { IrAstOperation::Br(to_block) @@ -559,6 +571,7 @@ mod ir_builder { module::{Kind, Module}, pointer::Pointer, value::Value, + BinaryOpKind, }; #[derive(Debug)] @@ -603,6 +616,7 @@ mod ir_builder { Option, ), BitCast(String, IrAstTy), + BinaryOp(BinaryOpKind, String, String), Br(String), Call(String, Vec), Cbr(String, String, String), @@ -940,6 +954,14 @@ mod ir_builder { .bitcast(*val_map.get(&val).unwrap(), to_ty) .add_metadatum(context, opt_metadata) } + IrAstOperation::BinaryOp(op, arg1, arg2) => block + .ins(context) + .binary_op( + op, + *val_map.get(&arg1).unwrap(), + *val_map.get(&arg2).unwrap(), + ) + .add_metadatum(context, opt_metadata), IrAstOperation::Br(to_block_name) => { let to_block = named_blocks.get(&to_block_name).unwrap(); block diff --git a/sway-ir/src/printer.rs b/sway-ir/src/printer.rs index f59bbbb4019..b83c7da022c 100644 --- a/sway-ir/src/printer.rs +++ b/sway-ir/src/printer.rs @@ -17,6 +17,7 @@ use crate::{ metadata::{MetadataIndex, Metadatum}, module::{Kind, ModuleContent}, value::{Value, ValueContent, ValueDatum}, + BinaryOpKind, }; #[derive(Debug)] @@ -334,6 +335,25 @@ fn instruction_to_doc<'a>( .append(md_namer.md_idx_to_doc(context, metadata)), )) } + Instruction::BinaryOp { op, arg1, arg2 } => { + let op_str = match op { + BinaryOpKind::Add => "add", + BinaryOpKind::Sub => "sub", + BinaryOpKind::Mul => "mul", + BinaryOpKind::Div => "div", + }; + maybe_constant_to_doc(context, md_namer, namer, arg1) + .append(maybe_constant_to_doc(context, md_namer, namer, arg2)) + .append(Doc::line( + Doc::text(format!( + "{} = {op_str} {}, {}", + namer.name(context, ins_value), + namer.name(context, arg1), + namer.name(context, arg2), + )) + .append(md_namer.md_idx_to_doc(context, metadata)), + )) + } Instruction::Branch(to_block) => maybe_constant_phi_to_doc( context, md_namer, namer, block, to_block, ) diff --git a/sway-ir/src/verify.rs b/sway-ir/src/verify.rs index fbed3cf785c..1e01697e8c2 100644 --- a/sway-ir/src/verify.rs +++ b/sway-ir/src/verify.rs @@ -16,6 +16,7 @@ use crate::{ module::ModuleContent, pointer::Pointer, value::{Value, ValueDatum}, + BinaryOpKind, }; impl Context { @@ -132,6 +133,9 @@ impl<'a> InstructionVerifier<'a> { Instruction::AddrOf(arg) => self.verify_addr_of(arg)?, Instruction::AsmBlock(..) => (), Instruction::BitCast(value, ty) => self.verify_bitcast(value, ty)?, + Instruction::BinaryOp { op, arg1, arg2 } => { + self.verify_binary_op(op, arg1, arg2)? + } Instruction::Branch(block) => self.verify_br(block)?, Instruction::Call(func, args) => self.verify_call(func, args)?, Instruction::Cmp(pred, lhs_value, rhs_value) => { @@ -268,6 +272,25 @@ impl<'a> InstructionVerifier<'a> { } } + fn verify_binary_op( + &self, + _op: &BinaryOpKind, + arg1: &Value, + arg2: &Value, + ) -> Result<(), IrError> { + let arg1_ty = arg1 + .get_type(self.context) + .ok_or(IrError::VerifyBinaryOpIncorrectArgType)?; + let arg2_ty = arg2 + .get_type(self.context) + .ok_or(IrError::VerifyBinaryOpIncorrectArgType)?; + if !arg1_ty.eq(self.context, &arg2_ty) || !matches!(arg1_ty, Type::Uint(_)) { + return Err(IrError::VerifyBinaryOpIncorrectArgType); + } + + Ok(()) + } + fn verify_br(&self, dest_block: &Block) -> Result<(), IrError> { if !self.cur_function.blocks.contains(dest_block) { Err(IrError::VerifyBranchToMissingBlock( diff --git a/sway-lib-core/src/ops.sw b/sway-lib-core/src/ops.sw index f152b8dfca0..28fa3a6ae19 100644 --- a/sway-lib-core/src/ops.sw +++ b/sway-lib-core/src/ops.sw @@ -6,37 +6,25 @@ pub trait Add { impl Add for u64 { fn add(self, other: Self) -> Self { - asm(r1: self, r2: other, r3) { - add r3 r2 r1; - r3: u64 - } + __add(self, other) } } impl Add for u32 { fn add(self, other: Self) -> Self { - asm(r1: self, r2: other, r3) { - add r3 r2 r1; - r3: u32 - } + __add(self, other) } } impl Add for u16 { fn add(self, other: Self) -> Self { - asm(r1: self, r2: other, r3) { - add r3 r2 r1; - r3: u16 - } + __add(self, other) } } impl Add for u8 { fn add(self, other: Self) -> Self { - asm(r1: self, r2: other, r3) { - add r3 r2 r1; - r3: u8 - } + __add(self, other) } } @@ -46,37 +34,25 @@ pub trait Subtract { impl Subtract for u64 { fn subtract(self, other: Self) -> Self { - asm(r1: self, r2: other, r3) { - sub r3 r1 r2; - r3 - } + __sub(self, other) } } impl Subtract for u32 { fn subtract(self, other: Self) -> Self { - asm(r1: self, r2: other, r3) { - sub r3 r1 r2; - r3: u32 - } + __sub(self, other) } } impl Subtract for u16 { fn subtract(self, other: Self) -> Self { - asm(r1: self, r2: other, r3) { - sub r3 r1 r2; - r3: u16 - } + __sub(self, other) } } impl Subtract for u8 { fn subtract(self, other: Self) -> Self { - asm(r1: self, r2: other, r3) { - sub r3 r1 r2; - r3: u8 - } + __sub(self, other) } } @@ -86,37 +62,25 @@ pub trait Multiply { impl Multiply for u64 { fn multiply(self, other: Self) -> Self { - asm(r1: self, r2: other, r3) { - mul r3 r1 r2; - r3 - } + __mul(self, other) } } impl Multiply for u32 { fn multiply(self, other: Self) -> Self { - asm(r1: self, r2: other, r3) { - mul r3 r1 r2; - r3: u32 - } + __mul(self, other) } } impl Multiply for u16 { fn multiply(self, other: Self) -> Self { - asm(r1: self, r2: other, r3) { - mul r3 r1 r2; - r3: u16 - } + __mul(self, other) } } impl Multiply for u8 { fn multiply(self, other: Self) -> Self { - asm(r1: self, r2: other, r3) { - mul r3 r1 r2; - r3: u8 - } + __mul(self, other) } } @@ -126,37 +90,25 @@ pub trait Divide { impl Divide for u64 { fn divide(self, other: Self) -> Self { - asm(r1: self, r2: other, r3) { - div r3 r1 r2; - r3 - } + __div(self, other) } } impl Divide for u32 { fn divide(self, other: Self) -> Self { - asm(r1: self, r2: other, r3) { - div r3 r1 r2; - r3: u32 - } + __div(self, other) } } impl Divide for u16 { fn divide(self, other: Self) -> Self { - asm(r1: self, r2: other, r3) { - div r3 r1 r2; - r3: u16 - } + __div(self, other) } } impl Divide for u8 { fn divide(self, other: Self) -> Self { - asm(r1: self, r2: other, r3) { - div r3 r1 r2; - r3: u8 - } + __div(self, other) } } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/binop_intrinsics/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_fail/binop_intrinsics/Forc.lock new file mode 100644 index 00000000000..11dd7d1f4b8 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/binop_intrinsics/Forc.lock @@ -0,0 +1,14 @@ +[[package]] +name = 'binop_intrinsics' +source = 'root' +dependencies = ['std'] + +[[package]] +name = 'core' +source = 'path+from-root-FFF9D021FD8E57E3' +dependencies = [] + +[[package]] +name = 'std' +source = 'path+from-root-FFF9D021FD8E57E3' +dependencies = ['core'] diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/binop_intrinsics/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_fail/binop_intrinsics/Forc.toml new file mode 100644 index 00000000000..177055a4b7a --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/binop_intrinsics/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "binop_intrinsics" + +[dependencies] +std = { path = "../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/binop_intrinsics/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_fail/binop_intrinsics/json_abi_oracle.json new file mode 100644 index 00000000000..905c3bd1034 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/binop_intrinsics/json_abi_oracle.json @@ -0,0 +1,14 @@ +[ + { + "inputs": [], + "name": "main", + "outputs": [ + { + "components": null, + "name": "", + "type": "u64" + } + ], + "type": "function" + } +] \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/binop_intrinsics/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_fail/binop_intrinsics/src/main.sw new file mode 100644 index 00000000000..723a63c7ba7 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/binop_intrinsics/src/main.sw @@ -0,0 +1,13 @@ +script; + +struct A { + a: u64, +} + +fn main() { + let _ = __add(A { a: 32 }, 32); + let _ = __add("Hello", 22); + let _ = __add("Hello", "Hello"); + let _ = __add(false, true); + let _ = __add::(0, 1); +} diff --git a/test/src/e2e_vm_tests/test_programs/should_fail/binop_intrinsics/test.toml b/test/src/e2e_vm_tests/test_programs/should_fail/binop_intrinsics/test.toml new file mode 100644 index 00000000000..d57ccbfb9af --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_fail/binop_intrinsics/test.toml @@ -0,0 +1,21 @@ +category = "fail" + +# check: $()error +# check: $()__add(A { a: 32 }, 32); +# nextln: $()Unsupported argument type to intrinsic "add" + +# check: $()error +# check: $()__add("Hello", 22); +# nextln: $()Unsupported argument type to intrinsic "add" + +# check: $()error +# check: $()__add("Hello", "Hello") +# nextln: $()Unsupported argument type to intrinsic "add" + +# check: $()error +# check: $()__add(false, true) +# nextln: $()Unsupported argument type to intrinsic "add" + +# check: $()error +# check: $()__add::(0, 1) +# nextln: $()Call to "add" expects 0 type arguments \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/binop_intrinsics/Forc.lock b/test/src/e2e_vm_tests/test_programs/should_pass/language/binop_intrinsics/Forc.lock new file mode 100644 index 00000000000..11dd7d1f4b8 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/binop_intrinsics/Forc.lock @@ -0,0 +1,14 @@ +[[package]] +name = 'binop_intrinsics' +source = 'root' +dependencies = ['std'] + +[[package]] +name = 'core' +source = 'path+from-root-FFF9D021FD8E57E3' +dependencies = [] + +[[package]] +name = 'std' +source = 'path+from-root-FFF9D021FD8E57E3' +dependencies = ['core'] diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/binop_intrinsics/Forc.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/binop_intrinsics/Forc.toml new file mode 100644 index 00000000000..f13c3158d77 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/binop_intrinsics/Forc.toml @@ -0,0 +1,8 @@ +[project] +authors = ["Fuel Labs "] +entry = "main.sw" +license = "Apache-2.0" +name = "binop_intrinsics" + +[dependencies] +std = { path = "../../../../../../../sway-lib-std" } diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/binop_intrinsics/json_abi_oracle.json b/test/src/e2e_vm_tests/test_programs/should_pass/language/binop_intrinsics/json_abi_oracle.json new file mode 100644 index 00000000000..8c3df8121d6 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/binop_intrinsics/json_abi_oracle.json @@ -0,0 +1,22 @@ +{ + "functions": [ + { + "inputs": [], + "name": "main", + "output": { + "name": "", + "type": 0, + "typeArguments": null + } + } + ], + "loggedTypes": [], + "types": [ + { + "components": null, + "type": "u64", + "typeId": 0, + "typeParameters": null + } + ] +} \ No newline at end of file diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/binop_intrinsics/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/language/binop_intrinsics/src/main.sw new file mode 100644 index 00000000000..b31c0a68ba1 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/binop_intrinsics/src/main.sw @@ -0,0 +1,37 @@ +script; + +use std::assert::assert; + +fn main() -> u64 { + + let a: u8 = 2; + let b: u8 = 22; + assert(__add(a, b) == 24); + assert(__sub(b, a) == 20); + assert(__mul(a, b) == 44); + assert(__div(b, a) == 11); + + let a: u16 = 22; + let b: u16 = 44; + assert(__add(a, b) == 66); + assert(__sub(b, a) == 22); + assert(__mul(a, b) == 968); + assert(__div(b, a) == 2); + + let a: u32 = 22; + let b: u32 = 44; + assert(__add(a, b) == 66); + assert(__sub(b, a) == 22); + assert(__mul(a, b) == 968); + assert(__div(b, a) == 2); + + let a: u64 = 22; + let b: u64 = 44; + assert(__add(a, b) == 66); + assert(__sub(b, a) == 22); + assert(__mul(a, b) == 968); + assert(__div(b, a) == 2); + + + 2 +} diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/language/binop_intrinsics/test.toml b/test/src/e2e_vm_tests/test_programs/should_pass/language/binop_intrinsics/test.toml new file mode 100644 index 00000000000..5617bb5d0a9 --- /dev/null +++ b/test/src/e2e_vm_tests/test_programs/should_pass/language/binop_intrinsics/test.toml @@ -0,0 +1,3 @@ +category = "run" +expected_result = { action = "return", value = 2 } +validate_abi = true diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw index b9498aa5756..df1c22ede94 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_basic_storage/src/main.sw @@ -3,7 +3,7 @@ use basic_storage_abi::{StoreU64, Quad}; use std::assert::assert; fn main() -> u64 { - let addr = abi(StoreU64, 0x2c307eee0eb8ac5ef0bb3136f0bbb02bd86aba252c49faae0056531545b13e73); + let addr = abi(StoreU64, 0xd992b1febc69f6102915ea1102fde7b88f3e484ec55a02b4539c91615dca84e7); let key = 0xffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff; let value = 4242; diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/src/main.sw index 250ab55a7e7..ad944cda49c 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/call_increment_contract/src/main.sw @@ -4,7 +4,7 @@ use increment_abi::Incrementor; use std::assert::assert; fn main() -> bool { - let the_abi = abi(Incrementor, 0x0bb4d41501aed8a57965e65946157c401a1acfe30df3326a660d7b3288457ddd); + let the_abi = abi(Incrementor,0x2fa39fe61cb782b27091ad143f1d7a6e5eddd22d044cf1ab754dcc1218e182a9 ); the_abi.increment(5); the_abi.increment(5); let result = the_abi.get(); diff --git a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw index e4d2ecdc486..1320cdaabec 100644 --- a/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw +++ b/test/src/e2e_vm_tests/test_programs/should_pass/require_contract_deployment/storage_access_caller/src/main.sw @@ -3,7 +3,7 @@ use storage_access_abi::*; use std::{assert::assert, hash::sha256, revert::revert}; fn main() -> bool { - let contract_id = 0xcda49fd4e5a7c02b771df294bddfcc8adfa339dcd98a5c659eaf87317823d94d; + let contract_id = 0x874b633b6d9a900580e920afa2cdb1400de23b7056324974eb6f1ed7b1e05ce1; let caller = abi(StorageAccess, contract_id); // Test initializers