Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -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=
Expand Down
3 changes: 1 addition & 2 deletions internal/dcepass/dcepass.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
54 changes: 54 additions & 0 deletions internal/dcepass/dcepass_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -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)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Minor: value is declared in the outer loop and reassigned here (value = srcCtx.ConstStruct(...)) inside the inner nested loop. It's correct — value is re-read from global.Initializer() at the top of each outer iteration, so the struct wrapping doesn't compound across globals — but it's subtle. Consider a distinct local (e.g. nested := srcCtx.ConstStruct([]llvm.Value{value}, false)) to make the non-compounding behavior obvious at a glance.

}
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)
Expand Down
Loading