From 936760fcf715d301dbfa62760687cae5ff7c721a Mon Sep 17 00:00:00 2001 From: jakbyte Date: Tue, 14 Apr 2020 16:58:50 -0400 Subject: [PATCH 1/3] feat: remainder operator --- crates/mun_codegen/src/ir/body.rs | 2 + .../snapshots/test__binary_expressions.snap | 14 +++++- .../src/snapshots/test__update_operators.snap | 8 ++- crates/mun_codegen/src/test.rs | 14 ++++++ crates/mun_hir/src/expr.rs | 10 ++-- .../ty/snapshots/tests__update_operators.snap | 50 +++++++++++-------- crates/mun_hir/src/ty/tests.rs | 2 + crates/mun_syntax/src/ast/expr_extensions.rs | 8 +-- .../src/parsing/grammar/expressions.rs | 2 + crates/mun_syntax/src/parsing/parser.rs | 4 +- 10 files changed, 80 insertions(+), 34 deletions(-) diff --git a/crates/mun_codegen/src/ir/body.rs b/crates/mun_codegen/src/ir/body.rs index 737eed185..86cda5d62 100644 --- a/crates/mun_codegen/src/ir/body.rs +++ b/crates/mun_codegen/src/ir/body.rs @@ -734,6 +734,7 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> { ArithOp::Subtract => self.builder.build_int_sub(lhs, rhs, "sub"), ArithOp::Divide => self.builder.build_int_signed_div(lhs, rhs, "div"), ArithOp::Multiply => self.builder.build_int_mul(lhs, rhs, "mul"), + ArithOp::Remainder => self.builder.build_int_signed_rem(lhs, rhs, "rem"), } } @@ -748,6 +749,7 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> { ArithOp::Subtract => self.builder.build_float_sub(lhs, rhs, "sub"), ArithOp::Divide => self.builder.build_float_div(lhs, rhs, "div"), ArithOp::Multiply => self.builder.build_float_mul(lhs, rhs, "mul"), + ArithOp::Remainder => self.builder.build_float_rem(lhs, rhs, "rem"), } } diff --git a/crates/mun_codegen/src/snapshots/test__binary_expressions.snap b/crates/mun_codegen/src/snapshots/test__binary_expressions.snap index 27fcfc974..10afc40c8 100644 --- a/crates/mun_codegen/src/snapshots/test__binary_expressions.snap +++ b/crates/mun_codegen/src/snapshots/test__binary_expressions.snap @@ -1,6 +1,6 @@ --- source: crates/mun_codegen/src/test.rs -expression: "pub fn add(a:int, b:int) -> int {\n a+b\n}\n\npub fn subtract(a:int, b:int) -> int {\n a-b\n}\n\npub fn multiply(a:int, b:int) -> int {\n a*b\n}" +expression: "pub fn add(a:int, b:int) -> int {\n a+b\n}\n\npub fn subtract(a:int, b:int) -> int {\n a-b\n}\n\npub fn multiply(a:int, b:int) -> int {\n a*b\n}\n\npub fn divide(a:int, b:int) -> int {\n a/b\n}\n\npub fn remainder(a:int, b:int) -> int {\n a%b\n}" --- ; == FILE IR ===================================== ; ModuleID = 'main.mun' @@ -28,6 +28,18 @@ body: ret i64 %mul } +define i64 @divide(i64, i64) { +body: + %div = sdiv i64 %0, %1 + ret i64 %div +} + +define i64 @remainder(i64, i64) { +body: + %rem = srem i64 %0, %1 + ret i64 %rem +} + ; == GROUP IR ==================================== ; ModuleID = 'group_name' diff --git a/crates/mun_codegen/src/snapshots/test__update_operators.snap b/crates/mun_codegen/src/snapshots/test__update_operators.snap index 8bb8d382e..2be2e5a80 100644 --- a/crates/mun_codegen/src/snapshots/test__update_operators.snap +++ b/crates/mun_codegen/src/snapshots/test__update_operators.snap @@ -1,6 +1,6 @@ --- source: crates/mun_codegen/src/test.rs -expression: "pub fn add(a:int, b:int) -> int {\n let result = a\n result += b\n result\n}\n\npub fn subtract(a:int, b:int) -> int {\n let result = a\n result -= b\n result\n}\n\npub fn multiply(a:int, b:int) -> int {\n let result = a\n result *= b\n result\n}\n\npub fn divide(a:int, b:int) -> int {\n let result = a\n result /= b\n result\n}" +expression: "pub fn add(a:int, b:int) -> int {\n let result = a\n result += b\n result\n}\n\npub fn subtract(a:int, b:int) -> int {\n let result = a\n result -= b\n result\n}\n\npub fn multiply(a:int, b:int) -> int {\n let result = a\n result *= b\n result\n}\n\npub fn divide(a:int, b:int) -> int {\n let result = a\n result /= b\n result\n}\n\npub fn remainder(a:int, b:int) -> int {\n let result = a\n result %= b\n result\n}" --- ; == FILE IR ===================================== ; ModuleID = 'main.mun' @@ -34,6 +34,12 @@ body: ret i64 %div } +define i64 @remainder(i64, i64) { +body: + %rem = srem i64 %0, %1 + ret i64 %rem +} + ; == GROUP IR ==================================== ; ModuleID = 'group_name' diff --git a/crates/mun_codegen/src/test.rs b/crates/mun_codegen/src/test.rs index c81d0c01e..fc913320f 100644 --- a/crates/mun_codegen/src/test.rs +++ b/crates/mun_codegen/src/test.rs @@ -88,6 +88,14 @@ fn binary_expressions() { pub fn multiply(a:int, b:int) -> int { a*b } + + pub fn divide(a:int, b:int) -> int { + a/b + } + + pub fn remainder(a:int, b:int) -> int { + a%b + } "#, ); } @@ -143,6 +151,12 @@ fn update_operators() { result /= b result } + + pub fn remainder(a:int, b:int) -> int { + let result = a + result %= b + result + } "#, ); } diff --git a/crates/mun_hir/src/expr.rs b/crates/mun_hir/src/expr.rs index be0dba351..efa8d7f81 100644 --- a/crates/mun_hir/src/expr.rs +++ b/crates/mun_hir/src/expr.rs @@ -271,7 +271,7 @@ pub enum ArithOp { Multiply, Subtract, Divide, - //Remainder, + Remainder, //Power, } @@ -549,7 +549,7 @@ where | op @ BinOp::LessEqual | op @ BinOp::Greater | op @ BinOp::GreatEqual - //| op @ BinOp::Remainder + | op @ BinOp::Remainder //| op @ BinOp::Power => { let op = match op { @@ -563,7 +563,7 @@ where BinOp::LessEqual => BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Less, strict: false } ), BinOp::Greater => BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: true } ), BinOp::GreatEqual => BinaryOp::CmpOp(CmpOp::Ord { ordering: Ordering::Greater, strict: false } ), - //BinOp::Remainder => BinaryOp::ArithOp(ArithOp::Remainder), + BinOp::Remainder => BinaryOp::ArithOp(ArithOp::Remainder), //BinOp::Power => BinaryOp::ArithOp(ArithOp::Power), _ => unreachable!(), }; @@ -582,7 +582,8 @@ where | op @ BinOp::AddAssign | op @ BinOp::SubtractAssign | op @ BinOp::MultiplyAssign - | op @ BinOp::DivideAssign => { + | op @ BinOp::DivideAssign + | op @ BinOp::RemainderAssign => { let assign_op = match op { BinOp::Assign => None, @@ -590,6 +591,7 @@ where BinOp::SubtractAssign => Some(ArithOp::Subtract), BinOp::MultiplyAssign => Some(ArithOp::Multiply), BinOp::DivideAssign => Some(ArithOp::Divide), + BinOp::RemainderAssign => Some(ArithOp::Remainder), _ => unreachable!("invalid assignment operator") } ; diff --git a/crates/mun_hir/src/ty/snapshots/tests__update_operators.snap b/crates/mun_hir/src/ty/snapshots/tests__update_operators.snap index 19ed7b85d..942613dcd 100644 --- a/crates/mun_hir/src/ty/snapshots/tests__update_operators.snap +++ b/crates/mun_hir/src/ty/snapshots/tests__update_operators.snap @@ -1,12 +1,12 @@ --- source: crates/mun_hir/src/ty/tests.rs -expression: "fn foo(a:int, b:float) {\n a += 3;\n a -= 3;\n a *= 3;\n a /= 3;\n b += 3.0;\n b -= 3.0;\n b *= 3.0;\n b /= 3.0;\n a *= 3.0; // mismatched type\n b *= 3; // mismatched type\n}" +expression: "fn foo(a:int, b:float) {\n a += 3;\n a -= 3;\n a *= 3;\n a /= 3;\n a %= 3;\n b += 3.0;\n b -= 3.0;\n b *= 3.0;\n b /= 3.0;\n b %= 3.0;\n a *= 3.0; // mismatched type\n b *= 3; // mismatched type\n}" --- -[138; 141): mismatched type -[171; 172): mismatched type +[164; 167): mismatched type +[197; 198): mismatched type [7; 8) 'a': int [14; 15) 'b': float -[23; 194) '{ ...type }': nothing +[23; 220) '{ ...type }': nothing [29; 30) 'a': int [29; 35) 'a += 3': nothing [34; 35) '3': int @@ -19,21 +19,27 @@ expression: "fn foo(a:int, b:float) {\n a += 3;\n a -= 3;\n a *= 3;\n [65; 66) 'a': int [65; 71) 'a /= 3': nothing [70; 71) '3': int -[77; 78) 'b': float -[77; 85) 'b += 3.0': nothing -[82; 85) '3.0': float -[91; 92) 'b': float -[91; 99) 'b -= 3.0': nothing -[96; 99) '3.0': float -[105; 106) 'b': float -[105; 113) 'b *= 3.0': nothing -[110; 113) '3.0': float -[119; 120) 'b': float -[119; 127) 'b /= 3.0': nothing -[124; 127) '3.0': float -[133; 134) 'a': int -[133; 141) 'a *= 3.0': nothing -[138; 141) '3.0': float -[166; 167) 'b': float -[166; 172) 'b *= 3': nothing -[171; 172) '3': int +[77; 78) 'a': int +[77; 83) 'a %= 3': nothing +[82; 83) '3': int +[89; 90) 'b': float +[89; 97) 'b += 3.0': nothing +[94; 97) '3.0': float +[103; 104) 'b': float +[103; 111) 'b -= 3.0': nothing +[108; 111) '3.0': float +[117; 118) 'b': float +[117; 125) 'b *= 3.0': nothing +[122; 125) '3.0': float +[131; 132) 'b': float +[131; 139) 'b /= 3.0': nothing +[136; 139) '3.0': float +[145; 146) 'b': float +[145; 153) 'b %= 3.0': nothing +[150; 153) '3.0': float +[159; 160) 'a': int +[159; 167) 'a *= 3.0': nothing +[164; 167) '3.0': float +[192; 193) 'b': float +[192; 198) 'b *= 3': nothing +[197; 198) '3': int diff --git a/crates/mun_hir/src/ty/tests.rs b/crates/mun_hir/src/ty/tests.rs index 982530b5b..258e4ccca 100644 --- a/crates/mun_hir/src/ty/tests.rs +++ b/crates/mun_hir/src/ty/tests.rs @@ -116,10 +116,12 @@ fn update_operators() { a -= 3; a *= 3; a /= 3; + a %= 3; b += 3.0; b -= 3.0; b *= 3.0; b /= 3.0; + b %= 3.0; a *= 3.0; // mismatched type b *= 3; // mismatched type } diff --git a/crates/mun_syntax/src/ast/expr_extensions.rs b/crates/mun_syntax/src/ast/expr_extensions.rs index 95e063eca..be631116f 100644 --- a/crates/mun_syntax/src/ast/expr_extensions.rs +++ b/crates/mun_syntax/src/ast/expr_extensions.rs @@ -34,14 +34,14 @@ pub enum BinOp { Subtract, Divide, Multiply, - // Remainder, + Remainder, // Power, Assign, AddAssign, SubtractAssign, DivideAssign, MultiplyAssign, - // RemainderAssign, + RemainderAssign, // PowerAssign, Equals, NotEquals, @@ -62,14 +62,14 @@ impl BinExpr { MINUS => Some((c, BinOp::Subtract)), SLASH => Some((c, BinOp::Divide)), STAR => Some((c, BinOp::Multiply)), - // PERCENT => Some((c, BinOp::Remainder)), + PERCENT => Some((c, BinOp::Remainder)), // CARET => Some((c, BinOp::Power)), T![=] => Some((c, BinOp::Assign)), PLUSEQ => Some((c, BinOp::AddAssign)), MINUSEQ => Some((c, BinOp::SubtractAssign)), SLASHEQ => Some((c, BinOp::DivideAssign)), STAREQ => Some((c, BinOp::MultiplyAssign)), - // PERCENTEQ => Some((c, BinOp::RemainderAssign)), + PERCENTEQ => Some((c, BinOp::RemainderAssign)), // CARETEQ => Some((c, BinOp::PowerAssign)), EQEQ => Some((c, BinOp::Equals)), NEQ => Some((c, BinOp::NotEquals)), diff --git a/crates/mun_syntax/src/parsing/grammar/expressions.rs b/crates/mun_syntax/src/parsing/grammar/expressions.rs index c1a7e2d9b..84396a6a8 100644 --- a/crates/mun_syntax/src/parsing/grammar/expressions.rs +++ b/crates/mun_syntax/src/parsing/grammar/expressions.rs @@ -161,6 +161,8 @@ fn current_op(p: &Parser) -> (u8, SyntaxKind) { T![*] => (11, T![*]), T![/] if p.at(T![/=]) => (1, T![/=]), T![/] => (11, T![/]), + T![%] if p.at(T![%=]) => (1, T![%=]), + T![%] => (11, T![%]), T![=] if p.at(T![==]) => (5, T![==]), T![=] => (1, T![=]), T![!] if p.at(T![!=]) => (5, T![!=]), diff --git a/crates/mun_syntax/src/parsing/parser.rs b/crates/mun_syntax/src/parsing/parser.rs index ad5d90882..9561cfbfe 100644 --- a/crates/mun_syntax/src/parsing/parser.rs +++ b/crates/mun_syntax/src/parsing/parser.rs @@ -64,7 +64,7 @@ impl<'t> Parser<'t> { T![/=] => self.at_composite2(n, T![/], T![=]), //T![&&] => self.at_composite2(n, T![&], T![&]), //T![&=] => self.at_composite2(n, T![&], T![=]), - //T![%=] => self.at_composite2(n, T![%], T![=]), + T![%=] => self.at_composite2(n, T![%], T![=]), //T![^=] => self.at_composite2(n, T![^], T![=]), T![+=] => self.at_composite2(n, T![+], T![=]), //T![<<] => self.at_composite2(n, T![<], T![<]), @@ -193,7 +193,7 @@ impl<'t> Parser<'t> { | T![/=] //| T![&&] //| T![&=] - //| T![%=] + | T![%=] //| T![^=] | T![+=] //| T![<<] From a562ecc969b02b4b8fcb7c3bb022f326960dd868 Mon Sep 17 00:00:00 2001 From: jakbyte Date: Wed, 15 Apr 2020 07:29:16 -0400 Subject: [PATCH 2/3] fix(codegen): gen different IR for int div and rem depending on sign --- crates/mun_codegen/src/ir/body.rs | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/crates/mun_codegen/src/ir/body.rs b/crates/mun_codegen/src/ir/body.rs index 86cda5d62..44b2d8794 100644 --- a/crates/mun_codegen/src/ir/body.rs +++ b/crates/mun_codegen/src/ir/body.rs @@ -663,7 +663,9 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> { .expect("no rhs value") .into_int_value(); match op { - BinaryOp::ArithOp(op) => Some(self.gen_arith_bin_op_int(lhs, rhs, op).into()), + BinaryOp::ArithOp(op) => { + Some(self.gen_arith_bin_op_int(lhs, rhs, op, signedness).into()) + } BinaryOp::CmpOp(op) => { let (name, predicate) = match op { CmpOp::Eq { negated: false } => ("eq", IntPredicate::EQ), @@ -717,7 +719,7 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> { } BinaryOp::Assignment { op } => { let rhs = match op { - Some(op) => self.gen_arith_bin_op_int(lhs, rhs, op), + Some(op) => self.gen_arith_bin_op_int(lhs, rhs, op, signedness), None => rhs, }; let place = self.gen_place_expr(lhs_expr); @@ -728,13 +730,25 @@ impl<'a, 'b, D: IrDatabase> BodyIrGenerator<'a, 'b, D> { } } - fn gen_arith_bin_op_int(&mut self, lhs: IntValue, rhs: IntValue, op: ArithOp) -> IntValue { + fn gen_arith_bin_op_int( + &mut self, + lhs: IntValue, + rhs: IntValue, + op: ArithOp, + signedness: hir::Signedness, + ) -> IntValue { match op { ArithOp::Add => self.builder.build_int_add(lhs, rhs, "add"), ArithOp::Subtract => self.builder.build_int_sub(lhs, rhs, "sub"), - ArithOp::Divide => self.builder.build_int_signed_div(lhs, rhs, "div"), + ArithOp::Divide => match signedness { + hir::Signedness::Signed => self.builder.build_int_signed_div(lhs, rhs, "div"), + hir::Signedness::Unsigned => self.builder.build_int_unsigned_div(lhs, rhs, "div"), + }, ArithOp::Multiply => self.builder.build_int_mul(lhs, rhs, "mul"), - ArithOp::Remainder => self.builder.build_int_signed_rem(lhs, rhs, "rem"), + ArithOp::Remainder => match signedness { + hir::Signedness::Signed => self.builder.build_int_signed_rem(lhs, rhs, "rem"), + hir::Signedness::Unsigned => self.builder.build_int_unsigned_rem(lhs, rhs, "rem"), + }, } } From bc52b764733e23f6d845ed78ecff6ad4aab7ac12 Mon Sep 17 00:00:00 2001 From: jakbyte Date: Wed, 15 Apr 2020 14:01:08 -0400 Subject: [PATCH 3/3] test(runtime): check that the output of rem is valid --- crates/mun_runtime/src/test.rs | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/crates/mun_runtime/src/test.rs b/crates/mun_runtime/src/test.rs index f24abc82f..8dc2964d0 100644 --- a/crates/mun_runtime/src/test.rs +++ b/crates/mun_runtime/src/test.rs @@ -790,3 +790,21 @@ fn can_add_external_without_return() { .insert_fn("foo", foo as extern "C" fn(i64) -> ()); let _: () = invoke_fn!(driver.runtime_mut(), "main").unwrap(); } + +#[test] +fn signed_and_unsigned_rem() { + let mut driver = TestDriver::new( + r#" + pub fn signed() -> int { + (0 - 2) % 5 + } + + pub fn unsigned() -> int { + 2 % 5 + } + "#, + ); + + assert_invoke_eq!(i64, -2, driver, "signed"); + assert_invoke_eq!(i64, 2, driver, "unsigned"); +}