diff --git a/go.mod b/go.mod index d3b414c3d4..b2593d3a38 100644 --- a/go.mod +++ b/go.mod @@ -10,7 +10,7 @@ require ( github.com/mattn/go-tty v0.0.8 github.com/qiniu/x v1.18.3 github.com/xgo-dev/llgo/runtime v0.0.0-00010101000000-000000000000 - github.com/xgo-dev/llvm v0.9.9 + github.com/xgo-dev/llvm v0.10.0 github.com/xgo-dev/plan9asm v0.5.2 go.bug.st/serial v1.6.4 go.yaml.in/yaml/v3 v3.0.5 diff --git a/go.sum b/go.sum index 7c70052fd5..fa5fa764cb 100644 --- a/go.sum +++ b/go.sum @@ -22,8 +22,8 @@ github.com/qiniu/x v1.18.3 h1:trrBKBNszHGwV8XynnbddJr+A7Vca8/xlWP4F/Z4my8= github.com/qiniu/x v1.18.3/go.mod h1:Sx3Wy+0GI9OsX4a53mYj6A0o7mHJ94PUvraqGYb4EIs= github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk= github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo= -github.com/xgo-dev/llvm v0.9.9 h1:u4RZvy0vxu8nNt4oTrhttyMSyscYtmiy9geP+Kl/RYg= -github.com/xgo-dev/llvm v0.9.9/go.mod h1:42vav2/cI5BAIcL543DZSMO9do8/aCK2z7JERH+AE+M= +github.com/xgo-dev/llvm v0.10.0 h1:o27kypAGI7DrLFckrsUVjWChXqHUBDAFtZbwMiDFs50= +github.com/xgo-dev/llvm v0.10.0/go.mod h1:42vav2/cI5BAIcL543DZSMO9do8/aCK2z7JERH+AE+M= github.com/xgo-dev/plan9asm v0.5.2 h1:P5eGHZiuKNcL2tlkkICa2XcxghUSnp6QzfN52x0HW1g= github.com/xgo-dev/plan9asm v0.5.2/go.mod h1:ZzybDk59y/AXoQeYUEqxVkKWqalmCfmcfCtM9y85kQU= go.bug.st/serial v1.6.4 h1:7FmqNPgVp3pu2Jz5PoPtbZ9jJO5gnEnZIvnI1lzve8A= diff --git a/internal/dcepass/dcepass.go b/internal/dcepass/dcepass.go index 23437f2f24..e63d688aaf 100644 --- a/internal/dcepass/dcepass.go +++ b/internal/dcepass/dcepass.go @@ -129,8 +129,7 @@ func (e *overrideEmitter) cloneConst(v llvm.Value) llvm.Value { return llvm.ConstInt(dstTy, v.ZExtValue(), false) } if !v.IsAConstantFP().IsNil() { - value, _ := v.DoubleValue() - return llvm.ConstFloat(dstTy, value) + return llvm.ConstFloatFromBits(dstTy, v.FloatBits()) } if v.IsConstantString() { return e.dst.Context().ConstString(v.ConstGetAsString(), false) diff --git a/internal/dcepass/dcepass_test.go b/internal/dcepass/dcepass_test.go index 261183b62d..069e92e38b 100644 --- a/internal/dcepass/dcepass_test.go +++ b/internal/dcepass/dcepass_test.go @@ -323,6 +323,60 @@ declare half @unsupported_type() }) } +func TestCloneFloatConstantsAcrossContexts(t *testing.T) { + // Wider significands and NaN payloads must survive without converting to + // float64. Use parsed source IR so construction is independent of cloning. + ir := ` +@negative_zero = constant double 0x8000000000000000 +@signaling_nan = constant double 0x7FF0000000000001 +@float_nan = constant float 0x7FF82468A0000000 +@infinity = constant double 0x7FF0000000000000 +@subnormal = constant double 0x0000000000000001 +@fp80_precision = constant x86_fp80 0xK3FFF8000000000000001 +@fp80_nan = constant x86_fp80 0xK7FFFC000000000000123 +@fp128_precision = constant fp128 0xL00000000000000013FFF000000000000 +@fp128_nan = constant fp128 0xL00000000000001237FFF800000000000 +@ppc_low_only = constant ppc_fp128 0xM00000000000000003FF0000000000000 +@ppc_precision = constant ppc_fp128 0xM3FF00000000000003C90000000000000 +` + path := filepath.Join(t.TempDir(), "floats.ll") + if err := os.WriteFile(path, []byte(ir), 0600); err != nil { + t.Fatal(err) + } + srcCtx, dstCtx := llvm.NewContext(), llvm.NewContext() + defer dstCtx.Dispose() + src := parseModule(t, &srcCtx, path) + dst := dstCtx.NewModule("cloned-floats") + defer dst.Dispose() + emitter := newOverrideEmitter(dst) + want := make(map[string]string) + for global := src.FirstGlobal(); !global.IsNil(); global = llvm.NextGlobal(global) { + value := global.Initializer() + // Also exercise the recursive path used by ABI metadata initializers. + for _, nested := range []bool{false, true} { + name := global.Name() + if nested { + name += "_nested" + value = srcCtx.ConstStruct([]llvm.Value{value}, false) + } + want[name] = value.String() + cloned := emitter.cloneConst(value) + out := llvm.AddGlobal(dst, cloned.Type(), name) + out.SetInitializer(cloned) + } + } + src.Dispose() + srcCtx.Dispose() + for name, expected := range want { + if got := dst.NamedGlobal(name).Initializer().String(); got != expected { + t.Errorf("%s: cloned %s, want %s", name, got, expected) + } + } + if err := llvm.VerifyModule(dst, llvm.ReturnStatusAction); err != nil { + t.Fatal(err) + } +} + func parseModule(t *testing.T, ctx *llvm.Context, path string) llvm.Module { t.Helper() buf, err := llvm.NewMemoryBufferFromFile(path)