aboutsummaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorAyke van Laethem <[email protected]>2021-04-05 14:46:08 +0200
committerRon Evans <[email protected]>2021-04-08 11:40:59 +0200
commit61243f6c57b4158c28666ebadc6344e143ca02f1 (patch)
tree1be50b83b9cbcbe7b7928eefe739bc116c628a14
parent49ec3eb58e3ae2fd373b1c65883dcd05c588357a (diff)
downloadtinygo-61243f6c57b4158c28666ebadc6344e143ca02f1.tar.gz
tinygo-61243f6c57b4158c28666ebadc6344e143ca02f1.zip
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.
-rw-r--r--compiler/compiler.go2
-rw-r--r--compiler/interface.go2
-rw-r--r--compiler/testdata/interface.ll4
-rw-r--r--interp/interpreter.go2
-rw-r--r--interp/testdata/interface.ll4
-rw-r--r--transform/interface-lowering.go18
-rw-r--r--transform/testdata/interface.ll8
-rw-r--r--transform/testdata/interface.out.ll8
8 files changed, 21 insertions, 27 deletions
diff --git a/compiler/compiler.go b/compiler/compiler.go
index 29e6e0a90..be15f7890 100644
--- a/compiler/compiler.go
+++ b/compiler/compiler.go
@@ -23,7 +23,7 @@ import (
// Version of the compiler pacakge. Must be incremented each time the compiler
// package changes in a way that affects the generated LLVM module.
// This version is independent of the TinyGo version number.
-const Version = 6 // last change: fix issue 1304
+const Version = 7 // last change: don't rely on runtime.typecodeID struct type name
func init() {
llvm.InitializeAllTargets()
diff --git a/compiler/interface.go b/compiler/interface.go
index 6cca78766..8b3988a12 100644
--- a/compiler/interface.go
+++ b/compiler/interface.go
@@ -341,7 +341,7 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
commaOk = b.createRuntimeCall("interfaceImplements", []llvm.Value{actualTypeNum, methodSet}, "")
} else {
- globalName := "reflect/types.type:" + getTypeCodeName(expr.AssertedType) + "$id"
+ globalName := "reflect/types.typeid:" + getTypeCodeName(expr.AssertedType)
assertedTypeCodeGlobal := b.mod.NamedGlobal(globalName)
if assertedTypeCodeGlobal.IsNil() {
// Create a new typecode global.
diff --git a/compiler/testdata/interface.ll b/compiler/testdata/interface.ll
index 1405abf18..e5aa7eef1 100644
--- a/compiler/testdata/interface.ll
+++ b/compiler/testdata/interface.ll
@@ -19,7 +19,7 @@ target triple = "i686--linux"
@"reflect/types.type:interface:{String:func:{}{basic:string}}" = linkonce_odr constant %runtime.typecodeID { %runtime.typecodeID* bitcast ([1 x i8*]* @"reflect/types.interface:interface{String() string}$interface" to %runtime.typecodeID*), i32 0, %runtime.interfaceMethodInfo* null }
@"func String() string" = external constant i8
@"reflect/types.interface:interface{String() string}$interface" = linkonce_odr constant [1 x i8*] [i8* @"func String() string"]
-@"reflect/types.type:basic:int$id" = external constant i8
+@"reflect/types.typeid:basic:int" = external constant i8
@"error$interface" = linkonce_odr constant [1 x i8*] [i8* @"func Error() string"]
declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*)
@@ -51,7 +51,7 @@ entry:
define hidden i1 @main.isInt(i32 %itf.typecode, i8* %itf.value, i8* %context, i8* %parentHandle) unnamed_addr {
entry:
- %typecode = call i1 @runtime.typeAssert(i32 %itf.typecode, i8* nonnull @"reflect/types.type:basic:int$id", i8* undef, i8* null)
+ %typecode = call i1 @runtime.typeAssert(i32 %itf.typecode, i8* nonnull @"reflect/types.typeid:basic:int", i8* undef, i8* null)
br i1 %typecode, label %typeassert.ok, label %typeassert.next
typeassert.ok: ; preds = %entry
diff --git a/interp/interpreter.go b/interp/interpreter.go
index 3bbf9e5f9..c0dc45d93 100644
--- a/interp/interpreter.go
+++ b/interp/interpreter.go
@@ -328,7 +328,7 @@ func (r *runner) run(fn *function, params []value, parentMem *memoryView, indent
return nil, mem, r.errorAt(inst, err)
}
actualType := actualTypePtrToInt.Operand(0)
- if actualType.Name()+"$id" == assertedType.Name() {
+ if strings.TrimPrefix(actualType.Name(), "reflect/types.type:") == strings.TrimPrefix(assertedType.Name(), "reflect/types.typeid:") {
locals[inst.localIndex] = literalValue{uint8(1)}
} else {
locals[inst.localIndex] = literalValue{uint8(0)}
diff --git a/interp/testdata/interface.ll b/interp/testdata/interface.ll
index 8031632f7..060256d22 100644
--- a/interp/testdata/interface.ll
+++ b/interp/testdata/interface.ll
@@ -6,7 +6,7 @@ target triple = "x86_64--linux"
@main.v1 = global i1 0
@"reflect/types.type:named:main.foo" = private constant %runtime.typecodeID { %runtime.typecodeID* @"reflect/types.type:basic:int", i64 0, %runtime.interfaceMethodInfo* null }
-@"reflect/types.type:named:main.foo$id" = external constant i8
+@"reflect/types.typeid:named:main.foo" = external constant i8
@"reflect/types.type:basic:int" = external constant %runtime.typecodeID
@@ -21,7 +21,7 @@ entry:
define internal void @main.init() unnamed_addr {
entry:
; Test type asserts.
- %typecode = call i1 @runtime.typeAssert(i64 ptrtoint (%runtime.typecodeID* @"reflect/types.type:named:main.foo" to i64), i8* @"reflect/types.type:named:main.foo$id", i8* undef, i8* null)
+ %typecode = call i1 @runtime.typeAssert(i64 ptrtoint (%runtime.typecodeID* @"reflect/types.type:named:main.foo" to i64), i8* @"reflect/types.typeid:named:main.foo", i8* undef, i8* null)
store i1 %typecode, i1* @main.v1
ret void
}
diff --git a/transform/interface-lowering.go b/transform/interface-lowering.go
index e8b6deecf..c39765f60 100644
--- a/transform/interface-lowering.go
+++ b/transform/interface-lowering.go
@@ -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
diff --git a/transform/testdata/interface.ll b/transform/testdata/interface.ll
index 487ecbb2c..e00d1b23c 100644
--- a/transform/testdata/interface.ll
+++ b/transform/testdata/interface.ll
@@ -5,8 +5,8 @@ target triple = "armv7m-none-eabi"
%runtime.interfaceMethodInfo = type { i8*, i32 }
@"reflect/types.type:basic:uint8" = external constant %runtime.typecodeID
-@"reflect/types.type:basic:uint8$id" = external constant i8
-@"reflect/types.type:basic:int16$id" = external constant i8
+@"reflect/types.typeid:basic:uint8" = external constant i8
+@"reflect/types.typeid:basic:int16" = external constant i8
@"reflect/types.type:basic:int" = external constant %runtime.typecodeID
@"func NeverImplementedMethod()" = external constant i8
@"Unmatched$interface" = private constant [1 x i8*] [i8* @"func NeverImplementedMethod()"]
@@ -55,7 +55,7 @@ typeswitch.Doubler:
ret void
typeswitch.notDoubler:
- %isByte = call i1 @runtime.typeAssert(i32 %typecode, i8* nonnull @"reflect/types.type:basic:uint8$id")
+ %isByte = call i1 @runtime.typeAssert(i32 %typecode, i8* nonnull @"reflect/types.typeid:basic:uint8")
br i1 %isByte, label %typeswitch.byte, label %typeswitch.notByte
typeswitch.byte:
@@ -66,7 +66,7 @@ typeswitch.byte:
typeswitch.notByte:
; this is a type assert that always fails
- %isInt16 = call i1 @runtime.typeAssert(i32 %typecode, i8* nonnull @"reflect/types.type:basic:int16$id")
+ %isInt16 = call i1 @runtime.typeAssert(i32 %typecode, i8* nonnull @"reflect/types.typeid:basic:int16")
br i1 %isInt16, label %typeswitch.int16, label %typeswitch.notInt16
typeswitch.int16:
diff --git a/transform/testdata/interface.out.ll b/transform/testdata/interface.out.ll
index faff12541..44d3145e0 100644
--- a/transform/testdata/interface.out.ll
+++ b/transform/testdata/interface.out.ll
@@ -5,8 +5,8 @@ target triple = "armv7m-none-eabi"
%runtime.interfaceMethodInfo = type { i8*, i32 }
@"reflect/types.type:basic:uint8" = external constant %runtime.typecodeID
-@"reflect/types.type:basic:uint8$id" = external constant i8
-@"reflect/types.type:basic:int16$id" = external constant i8
+@"reflect/types.typeid:basic:uint8" = external constant i8
+@"reflect/types.typeid:basic:int16" = external constant i8
@"reflect/types.type:basic:int" = external constant %runtime.typecodeID
@"func NeverImplementedMethod()" = external constant i8
@"func Double() int" = external constant i8
@@ -93,14 +93,14 @@ define i32 @"(Number).Double$invoke"(i8* %receiverPtr, i8* %parentHandle) {
define internal i32 @"(Doubler).Double"(i8* %0, i8* %1, i32 %actualType, i8* %parentHandle) unnamed_addr {
entry:
switch i32 %actualType, label %default [
- i32 68, label %"reflect/types.type:named:Number"
+ i32 68, label %"named:Number"
]
default: ; preds = %entry
call void @runtime.nilPanic(i8* undef, i8* undef)
unreachable
-"reflect/types.type:named:Number": ; preds = %entry
+"named:Number": ; preds = %entry
%2 = call i32 @"(Number).Double$invoke"(i8* %0, i8* %1)
ret i32 %2
}