transform: don't rely on struct name of runtime.typecodeID

Sometimes, LLVM may rename named structs when merging modules.
Therefore, we can't rely on typecodeID structs to retain their struct
names.

This commit changes the interface lowering pass to not rely on these
names. The interp package does however still rely on this name, but I
hope to fix that in the future.
This commit is contained in:
Ayke van Laethem
2021-04-05 14:46:08 +02:00
committed by Ron Evans
parent 49ec3eb58e
commit 61243f6c57
8 changed files with 21 additions and 27 deletions
+6 -12
View File
@@ -163,16 +163,13 @@ func LowerInterfaces(mod llvm.Module, sizeLevel int) error {
// run runs the pass itself.
func (p *lowerInterfacesPass) run() error {
// Collect all type codes.
typecodeID := p.mod.GetTypeByName("runtime.typecodeID")
typecodeIDPtr := llvm.PointerType(typecodeID, 0)
var typecodeIDs []llvm.Value
for global := p.mod.FirstGlobal(); !global.IsNil(); global = llvm.NextGlobal(global) {
switch global.Type() {
case typecodeIDPtr:
if strings.HasPrefix(global.Name(), "reflect/types.type:") {
// Retrieve Go type information based on an opaque global variable.
// Only the name of the global is relevant, the object itself is
// discarded afterwards.
name := global.Name()
name := strings.TrimPrefix(global.Name(), "reflect/types.type:")
if _, ok := p.types[name]; !ok {
typecodeIDs = append(typecodeIDs, global)
t := &typeInfo{
@@ -196,8 +193,7 @@ func (p *lowerInterfacesPass) run() error {
typeAssertUses := getUses(typeAssert)
for _, use := range typeAssertUses {
typecode := use.Operand(1)
name := typecode.Name() // name with $id suffix
name = name[:len(name)-len("$id")] // remove $id suffix
name := strings.TrimPrefix(typecode.Name(), "reflect/types.typeid:")
if t, ok := p.types[name]; ok {
t.countTypeAsserts++
}
@@ -360,7 +356,7 @@ func (p *lowerInterfacesPass) run() error {
if use.IsAConstantExpr().IsNil() {
continue
}
t := p.types[global.Name()]
t := p.types[strings.TrimPrefix(global.Name(), "reflect/types.type:")]
typecode := llvm.ConstInt(p.uintptrType, t.num, false)
switch use.Opcode() {
case llvm.PtrToInt:
@@ -381,8 +377,7 @@ func (p *lowerInterfacesPass) run() error {
llvmFalse := llvm.ConstInt(p.ctx.Int1Type(), 0, false)
for _, use := range typeAssertUses {
actualType := use.Operand(0)
name := use.Operand(1).Name() // name with $id suffix
name = name[:len(name)-len("$id")] // remove $id suffix
name := strings.TrimPrefix(use.Operand(1).Name(), "reflect/types.typeid:")
if t, ok := p.types[name]; ok {
// The type exists in the program, so lower to a regular integer
// comparison.
@@ -423,13 +418,12 @@ func (p *lowerInterfacesPass) run() error {
// Remove most objects created for interface and reflect lowering.
// Unnecessary, but cleans up the IR for inspection and testing.
zeroTypeCode := llvm.ConstNull(typecodeID)
for _, typ := range p.types {
// Only some typecodes have an initializer.
initializer := typ.typecode.Initializer()
if !initializer.IsNil() {
references := llvm.ConstExtractValue(initializer, []uint32{0})
typ.typecode.SetInitializer(zeroTypeCode)
typ.typecode.SetInitializer(llvm.ConstNull(initializer.Type()))
if strings.HasPrefix(typ.name, "reflect/types.type:struct:") {
// Structs have a 'references' field that is not a typecode but
// a pointer to a runtime.structField array and therefore a