diff --git a/src/cmd/compile/internal/ssa/ssa2llvm.go b/src/cmd/compile/internal/ssa/ssa2llvm.go index 3a8d130d36cab5..5b9d4fa02e81c5 100644 --- a/src/cmd/compile/internal/ssa/ssa2llvm.go +++ b/src/cmd/compile/internal/ssa/ssa2llvm.go @@ -1107,6 +1107,8 @@ func (lfc *LLVMFuncContext) GenLV(v *Value) llvm.Value { lVal = lfc.llvmUnaryFloat64Intrinsic(v, "llvm.sqrt.f64") case OpAbs: lVal = lfc.llvmUnaryFloat64Intrinsic(v, "llvm.fabs.f64") + case OpTrunc: + lVal = lfc.llvmUnaryFloat64Intrinsic(v, "llvm.trunc.f64") case OpEq64, OpEq32, OpEq16, OpEq8, OpEqB: lVal = lfc.goBool(lfc.b.CreateICmp(llvm.IntEQ, arg0(), arg1(), v.String()+".i1"), v.String()) case OpEqPtr: diff --git a/test/codegen/llvm_trunc.go b/test/codegen/llvm_trunc.go new file mode 100644 index 00000000000000..8ae4d46cff708e --- /dev/null +++ b/test/codegen/llvm_trunc.go @@ -0,0 +1,17 @@ +// asmcheck -gcflags=-d=ssa/check/on + +// Copyright 2026 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +package codegen + +import "math" + +// LLVM-LABEL: define goabiinternal double @codegen.llvmTrunc64(double %x) +// LLVM: call double @llvm.trunc.f64(double %x) +// LLVM-OPT-LABEL: define goabiinternal double @codegen.llvmTrunc64(double %x) +// LLVM-OPT: call double @llvm.trunc.f64(double %x) +func llvmTrunc64(x float64) float64 { + return math.Trunc(x) +} diff --git a/test/llvm_float_intrinsics.go b/test/llvm_float_intrinsics.go index 3cbd29110ffa25..2b5b3fe5d8b487 100644 --- a/test/llvm_float_intrinsics.go +++ b/test/llvm_float_intrinsics.go @@ -18,6 +18,11 @@ func abs64(x float64) float64 { return math.Abs(x) } +//go:noinline +func trunc64(x float64) float64 { + return math.Trunc(x) +} + //go:noinline func round64(x float64) float64 { return float64(x) @@ -55,6 +60,27 @@ func main() { panic("abs NaN payload") } + for _, tc := range []struct { + in, want uint64 + }{ + {0x0000000000000000, 0x0000000000000000}, // +0 + {0x8000000000000000, 0x8000000000000000}, // -0 + {0x400e000000000000, 0x4008000000000000}, // 3.75 -> 3 + {0xc00e000000000000, 0xc008000000000000}, // -3.75 -> -3 + {0x0000000000000001, 0x0000000000000000}, // smallest subnormal -> +0 + {0x8000000000000001, 0x8000000000000000}, // negative subnormal -> -0 + {0x43efffffffffffff, 0x43efffffffffffff}, // largest finite value below 2^64 + {0x7ff0000000000000, 0x7ff0000000000000}, // +Inf + {0xfff0000000000000, 0xfff0000000000000}, // -Inf + } { + if got := math.Float64bits(trunc64(math.Float64frombits(tc.in))); got != tc.want { + panic("trunc semantics") + } + } + if !math.IsNaN(trunc64(math.Float64frombits(nanBits))) { + panic("trunc NaN") + } + for _, bits := range []uint64{0, 1 << 63, 0x3ff0000000000000, nanBits} { if got := math.Float64bits(round64(math.Float64frombits(bits))); got != bits { panic("float64 rounding identity") diff --git a/test/llvm_tests.json b/test/llvm_tests.json index 07c024fb6a5d4f..9bd98d54c3078d 100644 --- a/test/llvm_tests.json +++ b/test/llvm_tests.json @@ -42,6 +42,7 @@ "codegen/llvm_round64.go": "non-contracting Round64F identity on strict LLVM double values", "codegen/llvm_selectnaddr.go": "caller-owned aligned memory home for address-selected stack call results", "codegen/llvm_sqrt.go": "float64 square root through the LLVM sqrt intrinsic", + "codegen/llvm_trunc.go": "SSA-verified float64 truncation toward zero through the LLVM trunc intrinsic", "codegen/llvm_memops.go": "pointer-free zero and overlap-safe move intrinsics, runtime memequal, and native-int slice masks", "codegen/llvm_memory_order.go": "preserve Go SSA Memory-token order when LLVM emission precedes native scheduling", "codegen/llvm_newproc.go": "pointer-typed funcval argument for the runtime.newproc raw ABI call", @@ -69,7 +70,8 @@ }, "platform_blacklist": { "linux/amd64": { - "codegen/llvm_abs.go": "the native AMD64 frontend does not form OpAbs for math.Abs" + "codegen/llvm_abs.go": "the native AMD64 frontend does not form OpAbs for math.Abs", + "codegen/llvm_trunc.go": "GOAMD64=v1 guards OpTrunc with unsupported HasCPUFeature lowering" } } }, @@ -258,6 +260,7 @@ "fixedbugs/issue57309.go": "upstream regression repeatedly qualified through LLVM compile, link, and execution", "fixedbugs/issue64565.go": "upstream regression repeatedly qualified through LLVM compile, link, and execution", "fixedbugs/issue66585.go": "upstream regression repeatedly qualified through LLVM compile, link, and execution", + "fixedbugs/issue68322.go": "large float64 truncation above the signed integer range through LLVM compile, link, and execution", "fixedbugs/issue68415.go": "upstream regression repeatedly qualified through LLVM compile, link, and execution", "fixedbugs/issue68525.go": "upstream regression repeatedly qualified through LLVM compile, link, and execution", "fixedbugs/issue68809.go": "upstream regression repeatedly qualified through LLVM compile, link, and execution", @@ -422,6 +425,10 @@ "blacklist": { "*": "LLVM lowering or runtime ABI support has not reached this test yet" }, - "platform_blacklist": {} + "platform_blacklist": { + "linux/amd64": { + "fixedbugs/issue68322.go": "GOAMD64=v1 guards OpTrunc with unsupported HasCPUFeature lowering" + } + } } }