Skip to content

Commit 38e9911

Browse files
committed
compiler: share recoverable fault blocks
1 parent 8367716 commit 38e9911

5 files changed

Lines changed: 70 additions & 78 deletions

File tree

builder/sizes_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@ func TestBinarySize(t *testing.T) {
4343
tests := []sizeTest{
4444
// microcontrollers
4545
{"hifive1b", "examples/echo", 3817, 299, 0, 2252},
46-
{"microbit", "examples/serial", 2816, 356, 8, 2248},
46+
{"microbit", "examples/serial", 2820, 356, 8, 2248},
4747
{"wioterminal", "examples/pininterrupt", 7206, 1510, 120, 7248},
4848

4949
// TODO: also check wasm. Right now this is difficult, because

compiler/asserts.go

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -241,25 +241,35 @@ func (b *builder) createRuntimeAssert(assert llvm.Value, blockPrefix, assertFunc
241241
}
242242
}
243243

244-
// Put the fault block at the end of the function and the next block at the
245-
// current insert position.
246-
faultBlock := b.ctx.AddBasicBlock(b.llvmFn, blockPrefix+".throw")
244+
faultBlock := b.getRuntimeAssertBlock(blockPrefix, assertFunc)
247245
nextBlock := b.insertBasicBlock(blockPrefix + ".next")
248246
b.currentBlockInfo.exit = nextBlock // adjust outgoing block for phi nodes
249247

250248
// Now branch to the out-of-bounds or the regular block.
251249
b.CreateCondBr(assert, faultBlock, nextBlock)
252250

253-
// Fail: the assert triggered so panic.
254-
b.SetInsertPointAtEnd(faultBlock)
251+
// Ok: assert didn't trigger so continue normally.
252+
b.SetInsertPointAtEnd(nextBlock)
253+
}
254+
255+
func (b *builder) getRuntimeAssertBlock(blockPrefix, assertFunc string) llvm.BasicBlock {
256+
if b.runtimeAssertBlocks == nil {
257+
b.runtimeAssertBlocks = make(map[string]llvm.BasicBlock)
258+
}
259+
if block := b.runtimeAssertBlocks[assertFunc]; !block.IsNil() {
260+
return block
261+
}
262+
savedBlock := b.GetInsertBlock()
263+
block := b.ctx.AddBasicBlock(b.llvmFn, blockPrefix+".throw")
264+
b.runtimeAssertBlocks[assertFunc] = block
265+
b.SetInsertPointAtEnd(block)
255266
if b.hasDeferFrame() {
256267
b.createFaultCheckpoint()
257268
}
258269
b.createRuntimeCall(assertFunc, nil, "")
259270
b.CreateUnreachable()
260-
261-
// Ok: assert didn't trigger so continue normally.
262-
b.SetInsertPointAtEnd(nextBlock)
271+
b.SetInsertPointAtEnd(savedBlock)
272+
return block
263273
}
264274

265275
// extendInteger extends the value to at least targetType using a zero or sign

compiler/compiler.go

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,9 @@ type builder struct {
176176
deferBuiltinFuncs map[ssa.Value]deferBuiltin
177177
runDefersBlock []llvm.BasicBlock
178178
afterDefersBlock []llvm.BasicBlock
179+
180+
runtimeAssertBlocks map[string]llvm.BasicBlock
181+
interfaceAssertBlock llvm.BasicBlock
179182
}
180183

181184
func newBuilder(c *compilerContext, irbuilder llvm.Builder, f *ssa.Function) *builder {

compiler/interface.go

Lines changed: 18 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -828,18 +828,10 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
828828
return tuple
829829
} else {
830830
// Type assert without comma-ok. If it fails, panic.
831-
faultBlock := b.ctx.AddBasicBlock(b.llvmFn, "typeassert.throw")
831+
faultBlock := b.getInterfaceAssertBlock()
832832
b.currentBlockInfo.exit = okBlock
833833
b.CreateCondBr(commaOk, okBlock, faultBlock)
834834

835-
// Fault: emit a checkpoint (for recover) and panic.
836-
b.SetInsertPointAtEnd(faultBlock)
837-
if b.hasDeferFrame() {
838-
b.createFaultCheckpoint()
839-
}
840-
b.createRuntimeCall("interfaceTypeAssert", []llvm.Value{llvm.ConstInt(b.ctx.Int1Type(), 0, false)}, "")
841-
b.CreateUnreachable()
842-
843835
// OK: extract the value from the interface.
844836
b.SetInsertPointAtEnd(okBlock)
845837
if _, ok := expr.AssertedType.Underlying().(*types.Interface); ok {
@@ -849,6 +841,23 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
849841
}
850842
}
851843

844+
func (b *builder) getInterfaceAssertBlock() llvm.BasicBlock {
845+
if !b.interfaceAssertBlock.IsNil() {
846+
return b.interfaceAssertBlock
847+
}
848+
savedBlock := b.GetInsertBlock()
849+
block := b.ctx.AddBasicBlock(b.llvmFn, "typeassert.throw")
850+
b.interfaceAssertBlock = block
851+
b.SetInsertPointAtEnd(block)
852+
if b.hasDeferFrame() {
853+
b.createFaultCheckpoint()
854+
}
855+
b.createRuntimeCall("interfaceTypeAssert", []llvm.Value{llvm.ConstInt(b.ctx.Int1Type(), 0, false)}, "")
856+
b.CreateUnreachable()
857+
b.SetInsertPointAtEnd(savedBlock)
858+
return block
859+
}
860+
852861
// getMethodsString returns a string to be used in the "tinygo-methods" string
853862
// attribute for interface functions.
854863
func (c *compilerContext) getMethodsString(itf *types.Interface) string {

compiler/testdata/generics.ll

Lines changed: 30 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -29,43 +29,43 @@ entry:
2929
%a = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
3030
call void @runtime.trackPointer(ptr nonnull %a, ptr nonnull %stackalloc, ptr undef) #3
3131
store float %a.X, ptr %a, align 4
32-
%a.repack9 = getelementptr inbounds nuw i8, ptr %a, i32 4
33-
store float %a.Y, ptr %a.repack9, align 4
32+
%a.repack5 = getelementptr inbounds nuw i8, ptr %a, i32 4
33+
store float %a.Y, ptr %a.repack5, align 4
3434
%b = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
3535
call void @runtime.trackPointer(ptr nonnull %b, ptr nonnull %stackalloc, ptr undef) #3
3636
store float %b.X, ptr %b, align 4
37-
%b.repack11 = getelementptr inbounds nuw i8, ptr %b, i32 4
38-
store float %b.Y, ptr %b.repack11, align 4
37+
%b.repack7 = getelementptr inbounds nuw i8, ptr %b, i32 4
38+
store float %b.Y, ptr %b.repack7, align 4
3939
call void @main.checkSize(i32 4, ptr undef) #3
4040
call void @main.checkSize(i32 8, ptr undef) #3
4141
%complit = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
4242
call void @runtime.trackPointer(ptr nonnull %complit, ptr nonnull %stackalloc, ptr undef) #3
4343
br i1 false, label %deref.throw, label %deref.next
4444

4545
deref.next: ; preds = %entry
46-
br i1 false, label %deref.throw1, label %deref.next2
46+
br i1 false, label %deref.throw, label %deref.next1
4747

48-
deref.next2: ; preds = %deref.next
48+
deref.next1: ; preds = %deref.next
4949
%0 = load float, ptr %a, align 4
5050
%1 = load float, ptr %b, align 4
5151
%2 = fadd float %0, %1
52-
br i1 false, label %deref.throw3, label %deref.next4
52+
br i1 false, label %deref.throw, label %deref.next2
5353

54-
deref.next4: ; preds = %deref.next2
55-
br i1 false, label %deref.throw5, label %deref.next6
54+
deref.next2: ; preds = %deref.next1
55+
br i1 false, label %deref.throw, label %deref.next3
5656

57-
deref.next6: ; preds = %deref.next4
57+
deref.next3: ; preds = %deref.next2
5858
%3 = getelementptr inbounds nuw i8, ptr %b, i32 4
5959
%4 = getelementptr inbounds nuw i8, ptr %a, i32 4
6060
%5 = load float, ptr %4, align 4
6161
%6 = load float, ptr %3, align 4
62-
br i1 false, label %store.throw, label %store.next
62+
br i1 false, label %deref.throw, label %store.next
6363

64-
store.next: ; preds = %deref.next6
64+
store.next: ; preds = %deref.next3
6565
store float %2, ptr %complit, align 4
66-
br i1 false, label %store.throw7, label %store.next8
66+
br i1 false, label %deref.throw, label %store.next4
6767

68-
store.next8: ; preds = %store.next
68+
store.next4: ; preds = %store.next
6969
%7 = getelementptr inbounds nuw i8, ptr %complit, i32 4
7070
%8 = fadd float %5, %6
7171
store float %8, ptr %7, align 4
@@ -74,22 +74,7 @@ store.next8: ; preds = %store.next
7474
%10 = insertvalue %"main.Point[float32]" %9, float %8, 1
7575
ret %"main.Point[float32]" %10
7676

77-
deref.throw: ; preds = %entry
78-
unreachable
79-
80-
deref.throw1: ; preds = %deref.next
81-
unreachable
82-
83-
deref.throw3: ; preds = %deref.next2
84-
unreachable
85-
86-
deref.throw5: ; preds = %deref.next4
87-
unreachable
88-
89-
store.throw: ; preds = %deref.next6
90-
unreachable
91-
92-
store.throw7: ; preds = %store.next
77+
deref.throw: ; preds = %store.next, %deref.next3, %deref.next2, %deref.next1, %deref.next, %entry
9378
unreachable
9479
}
9580

@@ -107,43 +92,43 @@ entry:
10792
%a = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
10893
call void @runtime.trackPointer(ptr nonnull %a, ptr nonnull %stackalloc, ptr undef) #3
10994
store i32 %a.X, ptr %a, align 4
110-
%a.repack9 = getelementptr inbounds nuw i8, ptr %a, i32 4
111-
store i32 %a.Y, ptr %a.repack9, align 4
95+
%a.repack5 = getelementptr inbounds nuw i8, ptr %a, i32 4
96+
store i32 %a.Y, ptr %a.repack5, align 4
11297
%b = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
11398
call void @runtime.trackPointer(ptr nonnull %b, ptr nonnull %stackalloc, ptr undef) #3
11499
store i32 %b.X, ptr %b, align 4
115-
%b.repack11 = getelementptr inbounds nuw i8, ptr %b, i32 4
116-
store i32 %b.Y, ptr %b.repack11, align 4
100+
%b.repack7 = getelementptr inbounds nuw i8, ptr %b, i32 4
101+
store i32 %b.Y, ptr %b.repack7, align 4
117102
call void @main.checkSize(i32 4, ptr undef) #3
118103
call void @main.checkSize(i32 8, ptr undef) #3
119104
%complit = call align 4 dereferenceable(8) ptr @runtime.alloc(i32 8, ptr nonnull inttoptr (i32 3 to ptr), ptr undef) #3
120105
call void @runtime.trackPointer(ptr nonnull %complit, ptr nonnull %stackalloc, ptr undef) #3
121106
br i1 false, label %deref.throw, label %deref.next
122107

123108
deref.next: ; preds = %entry
124-
br i1 false, label %deref.throw1, label %deref.next2
109+
br i1 false, label %deref.throw, label %deref.next1
125110

126-
deref.next2: ; preds = %deref.next
111+
deref.next1: ; preds = %deref.next
127112
%0 = load i32, ptr %a, align 4
128113
%1 = load i32, ptr %b, align 4
129114
%2 = add i32 %0, %1
130-
br i1 false, label %deref.throw3, label %deref.next4
115+
br i1 false, label %deref.throw, label %deref.next2
131116

132-
deref.next4: ; preds = %deref.next2
133-
br i1 false, label %deref.throw5, label %deref.next6
117+
deref.next2: ; preds = %deref.next1
118+
br i1 false, label %deref.throw, label %deref.next3
134119

135-
deref.next6: ; preds = %deref.next4
120+
deref.next3: ; preds = %deref.next2
136121
%3 = getelementptr inbounds nuw i8, ptr %b, i32 4
137122
%4 = getelementptr inbounds nuw i8, ptr %a, i32 4
138123
%5 = load i32, ptr %4, align 4
139124
%6 = load i32, ptr %3, align 4
140-
br i1 false, label %store.throw, label %store.next
125+
br i1 false, label %deref.throw, label %store.next
141126

142-
store.next: ; preds = %deref.next6
127+
store.next: ; preds = %deref.next3
143128
store i32 %2, ptr %complit, align 4
144-
br i1 false, label %store.throw7, label %store.next8
129+
br i1 false, label %deref.throw, label %store.next4
145130

146-
store.next8: ; preds = %store.next
131+
store.next4: ; preds = %store.next
147132
%7 = getelementptr inbounds nuw i8, ptr %complit, i32 4
148133
%8 = add i32 %5, %6
149134
store i32 %8, ptr %7, align 4
@@ -152,22 +137,7 @@ store.next8: ; preds = %store.next
152137
%10 = insertvalue %"main.Point[int]" %9, i32 %8, 1
153138
ret %"main.Point[int]" %10
154139

155-
deref.throw: ; preds = %entry
156-
unreachable
157-
158-
deref.throw1: ; preds = %deref.next
159-
unreachable
160-
161-
deref.throw3: ; preds = %deref.next2
162-
unreachable
163-
164-
deref.throw5: ; preds = %deref.next4
165-
unreachable
166-
167-
store.throw: ; preds = %deref.next6
168-
unreachable
169-
170-
store.throw7: ; preds = %store.next
140+
deref.throw: ; preds = %store.next, %deref.next3, %deref.next2, %deref.next1, %deref.next, %entry
171141
unreachable
172142
}
173143

0 commit comments

Comments
 (0)