diff --git a/src/Makefile b/src/Makefile index d55a63c2797..3457864cca7 100644 --- a/src/Makefile +++ b/src/Makefile @@ -408,6 +408,7 @@ TASK_XFAILS := test/run-pass/task-comm-8.rs \ TEST_XFAILS_BOOT := $(TASK_XFAILS) \ $(NOMINAL_TAG_XFAILS) \ $(CONST_TAG_XFAILS) \ + test/run-pass/arith-unsigned.rs \ test/run-pass/child-outlives-parent.rs \ test/run-pass/clone-with-exterior.rs \ test/run-pass/constrained-type.rs \ @@ -450,6 +451,7 @@ TEST_XFAILS_RUSTC := $(filter-out \ arith-0.rs \ arith-1.rs \ arith-2.rs \ + arith-unsigned.rs \ auto-instantiate.rs \ autoderef-full-lval.rs \ bind-exterior.rs \ diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index bedfad97980..c1a4aa6f62a 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -1840,33 +1840,67 @@ fn trans_unary(@block_ctxt cx, ast.unop op, // FIXME: implement proper structural comparison. -fn trans_compare(@block_ctxt cx, ast.binop op, +fn trans_compare(@block_ctxt cx, ast.binop op, @ty.t intype, ValueRef lhs, ValueRef rhs) -> ValueRef { auto cmp = lib.llvm.LLVMIntEQ; alt (op) { case (ast.eq) { cmp = lib.llvm.LLVMIntEQ; } case (ast.ne) { cmp = lib.llvm.LLVMIntNE; } - // FIXME (issue #57): switch by signedness. - case (ast.lt) { cmp = lib.llvm.LLVMIntSLT; } - case (ast.le) { cmp = lib.llvm.LLVMIntSLE; } - case (ast.ge) { cmp = lib.llvm.LLVMIntSGE; } - case (ast.gt) { cmp = lib.llvm.LLVMIntSGT; } + case (ast.lt) { + if (ty.type_is_signed(intype)) { + cmp = lib.llvm.LLVMIntSLT; + } else { + cmp = lib.llvm.LLVMIntULT; + } + } + case (ast.le) { + if (ty.type_is_signed(intype)) { + cmp = lib.llvm.LLVMIntSLE; + } else { + cmp = lib.llvm.LLVMIntULE; + } + } + case (ast.gt) { + if (ty.type_is_signed(intype)) { + cmp = lib.llvm.LLVMIntSGT; + } else { + cmp = lib.llvm.LLVMIntUGT; + } + } + case (ast.ge) { + if (ty.type_is_signed(intype)) { + cmp = lib.llvm.LLVMIntSGE; + } else { + cmp = lib.llvm.LLVMIntUGE; + } + } } ret cx.build.ICmp(cmp, lhs, rhs); } -fn trans_eager_binop(@block_ctxt cx, ast.binop op, +fn trans_eager_binop(@block_ctxt cx, ast.binop op, @ty.t intype, ValueRef lhs, ValueRef rhs) -> ValueRef { alt (op) { case (ast.add) { ret cx.build.Add(lhs, rhs); } case (ast.sub) { ret cx.build.Sub(lhs, rhs); } - // FIXME (issue #57): switch by signedness. case (ast.mul) { ret cx.build.Mul(lhs, rhs); } - case (ast.div) { ret cx.build.SDiv(lhs, rhs); } - case (ast.rem) { ret cx.build.SRem(lhs, rhs); } + case (ast.div) { + if (ty.type_is_signed(intype)) { + ret cx.build.SDiv(lhs, rhs); + } else { + ret cx.build.UDiv(lhs, rhs); + } + } + case (ast.rem) { + if (ty.type_is_signed(intype)) { + ret cx.build.SRem(lhs, rhs); + } else { + ret cx.build.URem(lhs, rhs); + } + } case (ast.bitor) { ret cx.build.Or(lhs, rhs); } case (ast.bitand) { ret cx.build.And(lhs, rhs); } @@ -1875,7 +1909,7 @@ fn trans_eager_binop(@block_ctxt cx, ast.binop op, case (ast.lsr) { ret cx.build.LShr(lhs, rhs); } case (ast.asr) { ret cx.build.AShr(lhs, rhs); } case (_) { - ret trans_compare(cx, op, lhs, rhs); + ret trans_compare(cx, op, intype, lhs, rhs); } } fail; @@ -1950,10 +1984,12 @@ fn trans_binary(@block_ctxt cx, ast.binop op, case (_) { // Remaining cases are eager: auto lhs = trans_expr(cx, a); - lhs = autoderef(lhs.bcx, lhs.val, ty.expr_ty(a)); + auto lhty = ty.expr_ty(a); + lhs = autoderef(lhs.bcx, lhs.val, lhty); auto rhs = trans_expr(lhs.bcx, b); - rhs = autoderef(rhs.bcx, rhs.val, ty.expr_ty(b)); - ret res(rhs.bcx, trans_eager_binop(rhs.bcx, op, + auto rhty = ty.expr_ty(b); + rhs = autoderef(rhs.bcx, rhs.val, rhty); + ret res(rhs.bcx, trans_eager_binop(rhs.bcx, op, lhty, lhs.val, rhs.val)); } } @@ -2142,7 +2178,8 @@ fn trans_pat_match(@block_ctxt cx, @ast.pat pat, ValueRef llval, case (ast.pat_lit(?lt, ?ann)) { auto lllit = trans_lit(cx.fcx.ccx, *lt, ann); - auto lleq = trans_compare(cx, ast.eq, llval, lllit); + auto lltype = ty.ann_to_type(ann); + auto lleq = trans_compare(cx, ast.eq, lltype, llval, lllit); auto matched_cx = new_sub_block_ctxt(cx, "matched_cx"); cx.build.CondBr(lleq, matched_cx.llbb, next_cx.llbb); @@ -3035,7 +3072,8 @@ fn trans_expr(@block_ctxt cx, @ast.expr e) -> result { auto lhs_val = load_scalar_or_boxed(lhs_res.res.bcx, lhs_res.res.val, t); auto rhs_res = trans_expr(lhs_res.res.bcx, src); - auto v = trans_eager_binop(rhs_res.bcx, op, lhs_val, rhs_res.val); + auto v = trans_eager_binop(rhs_res.bcx, op, t, + lhs_val, rhs_res.val); // FIXME: calculate copy init-ness in typestate. ret copy_ty(rhs_res.bcx, DROP_EXISTING, lhs_res.res.val, v, t); diff --git a/src/test/run-pass/arith-unsigned.rs b/src/test/run-pass/arith-unsigned.rs new file mode 100644 index 00000000000..3fac37142f8 --- /dev/null +++ b/src/test/run-pass/arith-unsigned.rs @@ -0,0 +1,24 @@ +// Unsigned integer operations + +fn main() { + check (0u8 < 255u8); + check (0u8 <= 255u8); + check (255u8 > 0u8); + check (255u8 >= 0u8); + check (250u8 / 10u8 == 25u8); + check (255u8 % 10u8 == 5u8); + check (0u16 < 60000u16); + check (0u16 <= 60000u16); + check (60000u16 > 0u16); + check (60000u16 >= 0u16); + check (60000u16 / 10u16 == 6000u16); + check (60005u16 % 10u16 == 5u16); + check (0u32 < 4000000000u32); + check (0u32 <= 4000000000u32); + check (4000000000u32 > 0u32); + check (4000000000u32 >= 0u32); + check (4000000000u32 / 10u32 == 400000000u32); + check (4000000005u32 % 10u32 == 5u32); + + // 64-bit numbers have some flakiness yet. Not tested +}