Commit 811766e1cf

LemonBoy <thatlemon@gmail.com>
2021-10-24 17:11:43
stage1/stage2: Simplify divTrunc impl
According to the documentation, `divTrunc` is "Truncated division. Rounds toward zero". Lower it as a straightforward fdiv + trunc sequence to make it behave as expected with mixed positive/negative operands. Closes #10001
1 parent 9487950
Changed files (3)
src
codegen
stage1
test
behavior
src/codegen/llvm.zig
@@ -2874,13 +2874,8 @@ pub const FuncGen = struct {
         const inst_ty = self.air.typeOfIndex(inst);
 
         if (inst_ty.isRuntimeFloat()) {
-            const result_llvm_ty = try self.dg.llvmType(inst_ty);
-            const zero = result_llvm_ty.constNull();
             const result = self.builder.buildFDiv(lhs, rhs, "");
-            const ceiled = try self.callCeil(result, inst_ty);
-            const floored = try self.callFloor(result, inst_ty);
-            const ltz = self.builder.buildFCmp(.OLT, lhs, zero, "");
-            return self.builder.buildSelect(ltz, ceiled, floored, "");
+            return self.callTrunc(result, inst_ty);
         }
         if (inst_ty.isSignedInt()) return self.builder.buildSDiv(lhs, rhs, "");
         return self.builder.buildUDiv(lhs, rhs, "");
@@ -3641,6 +3636,10 @@ pub const FuncGen = struct {
         return self.callFloatUnary(arg, ty, "ceil");
     }
 
+    fn callTrunc(self: *FuncGen, arg: *const llvm.Value, ty: Type) !*const llvm.Value {
+        return self.callFloatUnary(arg, ty, "trunc");
+    }
+
     fn callFloatUnary(self: *FuncGen, arg: *const llvm.Value, ty: Type, name: []const u8) !*const llvm.Value {
         const target = self.dg.module.getTarget();
 
src/stage1/codegen.cpp
@@ -2964,33 +2964,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast
                 }
                 return result;
             case DivKindTrunc:
-                {
-                    LLVMBasicBlockRef ltz_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivTruncLTZero");
-                    LLVMBasicBlockRef gez_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivTruncGEZero");
-                    LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivTruncEnd");
-                    LLVMValueRef ltz = LLVMBuildFCmp(g->builder, LLVMRealOLT, val1, zero, "");
-                    if (operand_type->id == ZigTypeIdVector) {
-                        ltz = ZigLLVMBuildOrReduce(g->builder, ltz);
-                    }
-                    LLVMBuildCondBr(g->builder, ltz, ltz_block, gez_block);
-
-                    LLVMPositionBuilderAtEnd(g->builder, ltz_block);
-                    LLVMValueRef ceiled = gen_float_op(g, result, operand_type, BuiltinFnIdCeil);
-                    LLVMBasicBlockRef ceiled_end_block = LLVMGetInsertBlock(g->builder);
-                    LLVMBuildBr(g->builder, end_block);
-
-                    LLVMPositionBuilderAtEnd(g->builder, gez_block);
-                    LLVMValueRef floored = gen_float_op(g, result, operand_type, BuiltinFnIdFloor);
-                    LLVMBasicBlockRef floored_end_block = LLVMGetInsertBlock(g->builder);
-                    LLVMBuildBr(g->builder, end_block);
-
-                    LLVMPositionBuilderAtEnd(g->builder, end_block);
-                    LLVMValueRef phi = LLVMBuildPhi(g->builder, get_llvm_type(g, operand_type), "");
-                    LLVMValueRef incoming_values[] = { ceiled, floored };
-                    LLVMBasicBlockRef incoming_blocks[] = { ceiled_end_block, floored_end_block };
-                    LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
-                    return phi;
-                }
+                return gen_float_op(g, result, operand_type, BuiltinFnIdTrunc);
             case DivKindFloor:
                 return gen_float_op(g, result, operand_type, BuiltinFnIdFloor);
         }
test/behavior/math.zig
@@ -282,12 +282,20 @@ fn testDivision() !void {
 
     try expect(divTrunc(i32, 5, 3) == 1);
     try expect(divTrunc(i32, -5, 3) == -1);
+    try expect(divTrunc(i32, 9, -10) == 0);
+    try expect(divTrunc(i32, -9, 10) == 0);
     try expect(divTrunc(f16, 5.0, 3.0) == 1.0);
     try expect(divTrunc(f16, -5.0, 3.0) == -1.0);
+    try expect(divTrunc(f16, 9.0, -10.0) == 0.0);
+    try expect(divTrunc(f16, -9.0, 10.0) == 0.0);
     try expect(divTrunc(f32, 5.0, 3.0) == 1.0);
     try expect(divTrunc(f32, -5.0, 3.0) == -1.0);
+    try expect(divTrunc(f32, 9.0, -10.0) == 0.0);
+    try expect(divTrunc(f32, -9.0, 10.0) == 0.0);
     try expect(divTrunc(f64, 5.0, 3.0) == 1.0);
     try expect(divTrunc(f64, -5.0, 3.0) == -1.0);
+    try expect(divTrunc(f64, 9.0, -10.0) == 0.0);
+    try expect(divTrunc(f64, -9.0, 10.0) == 0.0);
     try expect(divTrunc(i32, 10, 12) == 0);
     try expect(divTrunc(i32, -14, 12) == -1);
     try expect(divTrunc(i32, -2, 12) == 0);