Skip to content

Commit 172efc2

Browse files
committed
compiler: move ReplacePanicsWithTrap pass to transforms
This moves the transformation pass to the right location, and adds tests to see that it actually works correctly.
1 parent f49e69b commit 172efc2

File tree

5 files changed

+91
-20
lines changed

5 files changed

+91
-20
lines changed

compiler/optimizer.go

Lines changed: 1 addition & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ func (c *Compiler) Optimize(optLevel, sizeLevel int, inlinerThreshold uint) erro
2020
builder.AddCoroutinePassesToExtensionPoints()
2121

2222
if c.PanicStrategy() == "trap" {
23-
c.replacePanicsWithTrap() // -panic=trap
23+
transform.ReplacePanicsWithTrap(c.mod) // -panic=trap
2424
}
2525

2626
// run a check of all of our code
@@ -147,22 +147,3 @@ func (c *Compiler) Optimize(optLevel, sizeLevel int, inlinerThreshold uint) erro
147147

148148
return nil
149149
}
150-
151-
// Replace panic calls with calls to llvm.trap, to reduce code size. This is the
152-
// -panic=trap intrinsic.
153-
func (c *Compiler) replacePanicsWithTrap() {
154-
trap := c.mod.NamedFunction("llvm.trap")
155-
for _, name := range []string{"runtime._panic", "runtime.runtimePanic"} {
156-
fn := c.mod.NamedFunction(name)
157-
if fn.IsNil() {
158-
continue
159-
}
160-
for _, use := range getUses(fn) {
161-
if use.IsACallInst().IsNil() || use.CalledValue() != fn {
162-
panic("expected use of a panic function to be a call")
163-
}
164-
c.builder.SetInsertPointBefore(use)
165-
c.builder.CreateCall(trap, nil, "")
166-
}
167-
}
168-
}

transform/panic.go

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package transform
2+
3+
import (
4+
"tinygo.org/x/go-llvm"
5+
)
6+
7+
// ReplacePanicsWithTrap replaces each call to panic (or similar functions) with
8+
// calls to llvm.trap, to reduce code size. This is the -panic=trap command-line
9+
// option.
10+
func ReplacePanicsWithTrap(mod llvm.Module) {
11+
ctx := mod.Context()
12+
builder := ctx.NewBuilder()
13+
defer builder.Dispose()
14+
15+
trap := mod.NamedFunction("llvm.trap")
16+
if trap.IsNil() {
17+
trapType := llvm.FunctionType(ctx.VoidType(), nil, false)
18+
trap = llvm.AddFunction(mod, "llvm.trap", trapType)
19+
}
20+
for _, name := range []string{"runtime._panic", "runtime.runtimePanic"} {
21+
fn := mod.NamedFunction(name)
22+
if fn.IsNil() {
23+
continue
24+
}
25+
for _, use := range getUses(fn) {
26+
if use.IsACallInst().IsNil() || use.CalledValue() != fn {
27+
panic("expected use of a panic function to be a call")
28+
}
29+
builder.SetInsertPointBefore(use)
30+
builder.CreateCall(trap, nil, "")
31+
}
32+
}
33+
}

transform/panic_test.go

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
package transform
2+
3+
import (
4+
"testing"
5+
)
6+
7+
func TestReplacePanicsWithTrap(t *testing.T) {
8+
t.Parallel()
9+
testTransform(t, "testdata/panic", ReplacePanicsWithTrap)
10+
}

transform/testdata/panic.ll

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
2+
target triple = "armv7m-none-eabi"
3+
4+
@"runtime.lookupPanic$string" = constant [18 x i8] c"index out of range"
5+
6+
declare void @runtime.runtimePanic(i8*, i32)
7+
8+
declare void @runtime._panic(i32, i8*)
9+
10+
define void @runtime.lookupPanic() {
11+
call void @runtime.runtimePanic(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @"runtime.lookupPanic$string", i64 0, i64 0), i32 18)
12+
ret void
13+
}
14+
15+
; This is equivalent to the following code:
16+
; func someFunc(x interface{}) {
17+
; panic(x)
18+
; }
19+
define void @someFunc(i32 %typecode, i8* %value) {
20+
call void @runtime._panic(i32 %typecode, i8* %value)
21+
unreachable
22+
}

transform/testdata/panic.out.ll

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
target datalayout = "e-m:e-p:32:32-i64:64-v128:64:128-a:0:32-n32-S64"
2+
target triple = "armv7m-none-eabi"
3+
4+
@"runtime.lookupPanic$string" = constant [18 x i8] c"index out of range"
5+
6+
declare void @runtime.runtimePanic(i8*, i32)
7+
8+
declare void @runtime._panic(i32, i8*)
9+
10+
define void @runtime.lookupPanic() {
11+
call void @llvm.trap()
12+
call void @runtime.runtimePanic(i8* getelementptr inbounds ([18 x i8], [18 x i8]* @"runtime.lookupPanic$string", i64 0, i64 0), i32 18)
13+
ret void
14+
}
15+
16+
define void @someFunc(i32 %typecode, i8* %value) {
17+
call void @llvm.trap()
18+
call void @runtime._panic(i32 %typecode, i8* %value)
19+
unreachable
20+
}
21+
22+
; Function Attrs: cold noreturn nounwind
23+
declare void @llvm.trap() #0
24+
25+
attributes #0 = { cold noreturn nounwind }

0 commit comments

Comments
 (0)