diff --git a/lib/std/math/trunc.zig b/lib/std/math/trunc.zig index eab9a8b0c7..32bd7fb0aa 100644 --- a/lib/std/math/trunc.zig +++ b/lib/std/math/trunc.zig @@ -21,6 +21,10 @@ pub fn trunc(x: anytype) @TypeOf(x) { f32 => trunc32(x), f64 => trunc64(x), f128 => trunc128(x), + + // TODO this is not correct for some targets + c_longdouble => @floatCast(c_longdouble, trunc128(x)), + else => @compileError("trunc not implemented for " ++ @typeName(T)), }; } diff --git a/lib/std/special/c_stage1.zig b/lib/std/special/c_stage1.zig index c0323b1ae7..1bb28e79df 100644 --- a/lib/std/special/c_stage1.zig +++ b/lib/std/special/c_stage1.zig @@ -763,6 +763,13 @@ export fn truncf(a: f32) f32 { return math.trunc(a); } +export fn truncl(a: c_longdouble) c_longdouble { + if (!long_double_is_f128) { + @panic("TODO implement this"); + } + return math.trunc(a); +} + export fn round(a: f64) f64 { return math.round(a); } diff --git a/src/codegen/llvm.zig b/src/codegen/llvm.zig index aa0a99ea6c..80f2d8b653 100644 --- a/src/codegen/llvm.zig +++ b/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(); diff --git a/src/stage1/codegen.cpp b/src/stage1/codegen.cpp index 2a9ac84286..91e9f55aa7 100644 --- a/src/stage1/codegen.cpp +++ b/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); } diff --git a/test/behavior/math.zig b/test/behavior/math.zig index 158e144f5d..1073183a3c 100644 --- a/test/behavior/math.zig +++ b/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);