authorgravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2021-10-24 17:11:43+02:00
committergravatar for thatlemon@gmail.comLemonBoy <thatlemon@gmail.com> 2021-10-24 17:11:43+02:00
log811766e1cf0ad2fad73fbb82690969ce430ba1a5
tree5f550e0115e5dcc9f6178be03c0dc8af63e86d58
parent94879506ea8fe51310f38b3db1bc1ea1e71a4389

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

3 files changed, 14 insertions(+), 33 deletions(-)

src/codegen/llvm.zig+5-6
...@@ -2874,13 +2874,8 @@ pub const FuncGen = struct {...@@ -2874,13 +2874,8 @@ pub const FuncGen = struct {
2874 const inst_ty = self.air.typeOfIndex(inst);2874 const inst_ty = self.air.typeOfIndex(inst);
28752875
2876 if (inst_ty.isRuntimeFloat()) {2876 if (inst_ty.isRuntimeFloat()) {
2877 const result_llvm_ty = try self.dg.llvmType(inst_ty);
2878 const zero = result_llvm_ty.constNull();
2879 const result = self.builder.buildFDiv(lhs, rhs, "");2877 const result = self.builder.buildFDiv(lhs, rhs, "");
2880 const ceiled = try self.callCeil(result, inst_ty);2878 return self.callTrunc(result, inst_ty);
2881 const floored = try self.callFloor(result, inst_ty);
2882 const ltz = self.builder.buildFCmp(.OLT, lhs, zero, "");
2883 return self.builder.buildSelect(ltz, ceiled, floored, "");
2884 }2879 }
2885 if (inst_ty.isSignedInt()) return self.builder.buildSDiv(lhs, rhs, "");2880 if (inst_ty.isSignedInt()) return self.builder.buildSDiv(lhs, rhs, "");
2886 return self.builder.buildUDiv(lhs, rhs, "");2881 return self.builder.buildUDiv(lhs, rhs, "");
...@@ -3641,6 +3636,10 @@ pub const FuncGen = struct {...@@ -3641,6 +3636,10 @@ pub const FuncGen = struct {
3641 return self.callFloatUnary(arg, ty, "ceil");3636 return self.callFloatUnary(arg, ty, "ceil");
3642 }3637 }
36433638
3639 fn callTrunc(self: *FuncGen, arg: *const llvm.Value, ty: Type) !*const llvm.Value {
3640 return self.callFloatUnary(arg, ty, "trunc");
3641 }
3642
3644 fn callFloatUnary(self: *FuncGen, arg: *const llvm.Value, ty: Type, name: []const u8) !*const llvm.Value {3643 fn callFloatUnary(self: *FuncGen, arg: *const llvm.Value, ty: Type, name: []const u8) !*const llvm.Value {
3645 const target = self.dg.module.getTarget();3644 const target = self.dg.module.getTarget();
36463645
src/stage1/codegen.cpp+1-27
...@@ -2964,33 +2964,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast...@@ -2964,33 +2964,7 @@ static LLVMValueRef gen_div(CodeGen *g, bool want_runtime_safety, bool want_fast
2964 }2964 }
2965 return result;2965 return result;
2966 case DivKindTrunc:2966 case DivKindTrunc:
2967 {2967 return gen_float_op(g, result, operand_type, BuiltinFnIdTrunc);
2968 LLVMBasicBlockRef ltz_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivTruncLTZero");
2969 LLVMBasicBlockRef gez_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivTruncGEZero");
2970 LLVMBasicBlockRef end_block = LLVMAppendBasicBlock(g->cur_fn_val, "DivTruncEnd");
2971 LLVMValueRef ltz = LLVMBuildFCmp(g->builder, LLVMRealOLT, val1, zero, "");
2972 if (operand_type->id == ZigTypeIdVector) {
2973 ltz = ZigLLVMBuildOrReduce(g->builder, ltz);
2974 }
2975 LLVMBuildCondBr(g->builder, ltz, ltz_block, gez_block);
2976
2977 LLVMPositionBuilderAtEnd(g->builder, ltz_block);
2978 LLVMValueRef ceiled = gen_float_op(g, result, operand_type, BuiltinFnIdCeil);
2979 LLVMBasicBlockRef ceiled_end_block = LLVMGetInsertBlock(g->builder);
2980 LLVMBuildBr(g->builder, end_block);
2981
2982 LLVMPositionBuilderAtEnd(g->builder, gez_block);
2983 LLVMValueRef floored = gen_float_op(g, result, operand_type, BuiltinFnIdFloor);
2984 LLVMBasicBlockRef floored_end_block = LLVMGetInsertBlock(g->builder);
2985 LLVMBuildBr(g->builder, end_block);
2986
2987 LLVMPositionBuilderAtEnd(g->builder, end_block);
2988 LLVMValueRef phi = LLVMBuildPhi(g->builder, get_llvm_type(g, operand_type), "");
2989 LLVMValueRef incoming_values[] = { ceiled, floored };
2990 LLVMBasicBlockRef incoming_blocks[] = { ceiled_end_block, floored_end_block };
2991 LLVMAddIncoming(phi, incoming_values, incoming_blocks, 2);
2992 return phi;
2993 }
2994 case DivKindFloor:2968 case DivKindFloor:
2995 return gen_float_op(g, result, operand_type, BuiltinFnIdFloor);2969 return gen_float_op(g, result, operand_type, BuiltinFnIdFloor);
2996 }2970 }
test/behavior/math.zig+8
...@@ -282,12 +282,20 @@ fn testDivision() !void {...@@ -282,12 +282,20 @@ fn testDivision() !void {
282282
283 try expect(divTrunc(i32, 5, 3) == 1);283 try expect(divTrunc(i32, 5, 3) == 1);
284 try expect(divTrunc(i32, -5, 3) == -1);284 try expect(divTrunc(i32, -5, 3) == -1);
285 try expect(divTrunc(i32, 9, -10) == 0);
286 try expect(divTrunc(i32, -9, 10) == 0);
285 try expect(divTrunc(f16, 5.0, 3.0) == 1.0);287 try expect(divTrunc(f16, 5.0, 3.0) == 1.0);
286 try expect(divTrunc(f16, -5.0, 3.0) == -1.0);288 try expect(divTrunc(f16, -5.0, 3.0) == -1.0);
289 try expect(divTrunc(f16, 9.0, -10.0) == 0.0);
290 try expect(divTrunc(f16, -9.0, 10.0) == 0.0);
287 try expect(divTrunc(f32, 5.0, 3.0) == 1.0);291 try expect(divTrunc(f32, 5.0, 3.0) == 1.0);
288 try expect(divTrunc(f32, -5.0, 3.0) == -1.0);292 try expect(divTrunc(f32, -5.0, 3.0) == -1.0);
293 try expect(divTrunc(f32, 9.0, -10.0) == 0.0);
294 try expect(divTrunc(f32, -9.0, 10.0) == 0.0);
289 try expect(divTrunc(f64, 5.0, 3.0) == 1.0);295 try expect(divTrunc(f64, 5.0, 3.0) == 1.0);
290 try expect(divTrunc(f64, -5.0, 3.0) == -1.0);296 try expect(divTrunc(f64, -5.0, 3.0) == -1.0);
297 try expect(divTrunc(f64, 9.0, -10.0) == 0.0);
298 try expect(divTrunc(f64, -9.0, 10.0) == 0.0);
291 try expect(divTrunc(i32, 10, 12) == 0);299 try expect(divTrunc(i32, 10, 12) == 0);
292 try expect(divTrunc(i32, -14, 12) == -1);300 try expect(divTrunc(i32, -14, 12) == -1);
293 try expect(divTrunc(i32, -2, 12) == 0);301 try expect(divTrunc(i32, -2, 12) == 0);