Reproducer
Tested at xgo-dev/llgo@551626a1de6b6c47a4dcfad7190b074ae9b0d809.
package main
import "unsafe"
type nested[T any] struct {
first, second T
}
type value[T any] struct {
first T
word int32
nested nested[T]
}
func showOffset[T any](item *value[T]) {
println(unsafe.Offsetof(item.nested))
}
func main() {
showOffset(&value[bool]{})
}
One way to inspect the generated IR is to build chore/llgen, run it on the reproducer module, and inspect llgo_autogen.ll:
go build -o /tmp/llgen ./chore/llgen
(cd /path/to/reproducer && /tmp/llgen .)
rg 'Print(Int|Uint)' /path/to/reproducer/llgo_autogen.ll
Actual result
The instantiated generic function contains:
call void @"github.com/goplus/llgo/runtime/internal/runtime.PrintInt"(i64 8)
Expected result
unsafe.Offsetof has result type uintptr, so the value should retain the unsigned uintptr LLGo type and println should lower through PrintUint:
call void @"github.com/goplus/llgo/runtime/internal/runtime.PrintUint"(i64 8)
Cause and impact
The generic field-layout fast path in context.offsetOfBuiltinArg currently returns p.prog.Val(int(offset)). That creates a signed int LLSSA expression even though the Go SSA call result is uintptr. The non-generic constant-folded path does not show the problem.
Besides selecting the wrong print helper, losing signedness/type at this boundary can select signed operations for direct consumers of the result. The lowering should construct the constant with p.prog.Uintptr() (as the Sizeof/Alignof lowering already does), and a regression test should assert the returned LLSSA RawType is types.Uintptr.
Reproducer
Tested at
xgo-dev/llgo@551626a1de6b6c47a4dcfad7190b074ae9b0d809.One way to inspect the generated IR is to build
chore/llgen, run it on the reproducer module, and inspectllgo_autogen.ll:Actual result
The instantiated generic function contains:
Expected result
unsafe.Offsetofhas result typeuintptr, so the value should retain the unsigneduintptrLLGo type andprintlnshould lower throughPrintUint:Cause and impact
The generic field-layout fast path in
context.offsetOfBuiltinArgcurrently returnsp.prog.Val(int(offset)). That creates a signedintLLSSA expression even though the Go SSA call result isuintptr. The non-generic constant-folded path does not show the problem.Besides selecting the wrong print helper, losing signedness/type at this boundary can select signed operations for direct consumers of the result. The lowering should construct the constant with
p.prog.Uintptr()(as theSizeof/Alignoflowering already does), and a regression test should assert the returned LLSSARawTypeistypes.Uintptr.