diff --git a/compiler/asserts.go b/compiler/asserts.go index acd605fa..8d9efdde 100644 --- a/compiler/asserts.go +++ b/compiler/asserts.go @@ -240,8 +240,10 @@ func (b *builder) createRuntimeAssert(assert llvm.Value, blockPrefix, assertFunc } } + // Put the fault block at the end of the function and the next block at the + // current insert position. faultBlock := b.ctx.AddBasicBlock(b.llvmFn, blockPrefix+".throw") - nextBlock := b.ctx.AddBasicBlock(b.llvmFn, blockPrefix+".next") + nextBlock := b.insertBasicBlock(blockPrefix + ".next") b.blockExits[b.currentBlock] = nextBlock // adjust outgoing block for phi nodes // Now branch to the out-of-bounds or the regular block. diff --git a/compiler/compiler_test.go b/compiler/compiler_test.go index 9b0c6eff..96797ea7 100644 --- a/compiler/compiler_test.go +++ b/compiler/compiler_test.go @@ -49,6 +49,7 @@ func TestCompiler(t *testing.T) { {"float.go", "", ""}, {"interface.go", "", ""}, {"func.go", "", ""}, + {"defer.go", "cortex-m-qemu", ""}, {"pragma.go", "", ""}, {"goroutine.go", "wasm", "asyncify"}, {"goroutine.go", "cortex-m-qemu", "tasks"}, diff --git a/compiler/defer.go b/compiler/defer.go index 1207ce64..235ffaab 100644 --- a/compiler/defer.go +++ b/compiler/defer.go @@ -15,6 +15,7 @@ package compiler import ( "go/types" + "strconv" "github.com/tinygo-org/tinygo/compiler/llvmutil" "golang.org/x/tools/go/ssa" @@ -248,11 +249,11 @@ func (b *builder) createRunDefers() { // } // } - // Create loop. - loophead := b.ctx.AddBasicBlock(b.llvmFn, "rundefers.loophead") - loop := b.ctx.AddBasicBlock(b.llvmFn, "rundefers.loop") - unreachable := b.ctx.AddBasicBlock(b.llvmFn, "rundefers.default") - end := b.ctx.AddBasicBlock(b.llvmFn, "rundefers.end") + // Create loop, in the order: loophead, loop, callback0, callback1, ..., unreachable, end. + end := b.insertBasicBlock("rundefers.end") + unreachable := b.ctx.InsertBasicBlock(end, "rundefers.default") + loop := b.ctx.InsertBasicBlock(unreachable, "rundefers.loop") + loophead := b.ctx.InsertBasicBlock(loop, "rundefers.loophead") b.CreateBr(loophead) // Create loop head: @@ -284,7 +285,7 @@ func (b *builder) createRunDefers() { // Create switch case, for example: // case 0: // // run first deferred call - block := b.ctx.AddBasicBlock(b.llvmFn, "rundefers.callback") + block := b.insertBasicBlock("rundefers.callback" + strconv.Itoa(i)) sw.AddCase(llvm.ConstInt(b.uintptrType, uint64(i), false), block) b.SetInsertPointAtEnd(block) switch callback := callback.(type) { diff --git a/compiler/interface.go b/compiler/interface.go index e98285a2..03a9e150 100644 --- a/compiler/interface.go +++ b/compiler/interface.go @@ -389,8 +389,8 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value { // value. prevBlock := b.GetInsertBlock() - okBlock := b.ctx.AddBasicBlock(b.llvmFn, "typeassert.ok") - nextBlock := b.ctx.AddBasicBlock(b.llvmFn, "typeassert.next") + okBlock := b.insertBasicBlock("typeassert.ok") + nextBlock := b.insertBasicBlock("typeassert.next") b.blockExits[b.currentBlock] = nextBlock // adjust outgoing block for phi nodes b.CreateCondBr(commaOk, okBlock, nextBlock) diff --git a/compiler/llvm.go b/compiler/llvm.go index 81bd0b1f..2e786f94 100644 --- a/compiler/llvm.go +++ b/compiler/llvm.go @@ -23,6 +23,23 @@ func (b *builder) createTemporaryAlloca(t llvm.Type, name string) (alloca, bitca return llvmutil.CreateTemporaryAlloca(b.Builder, b.mod, t, name) } +// insertBasicBlock inserts a new basic block after the current basic block. +// This is useful when inserting new basic blocks while converting a +// *ssa.BasicBlock to a llvm.BasicBlock and the LLVM basic block needs some +// extra blocks. +// It does not update b.blockExits, this must be done by the caller. +func (b *builder) insertBasicBlock(name string) llvm.BasicBlock { + currentBB := b.Builder.GetInsertBlock() + nextBB := llvm.NextBasicBlock(currentBB) + if nextBB.IsNil() { + // Last basic block in the function, so add one to the end. + return b.ctx.AddBasicBlock(b.llvmFn, name) + } + // Insert a basic block before the next basic block - that is, at the + // current insert location. + return b.ctx.InsertBasicBlock(nextBB, name) +} + // emitLifetimeEnd signals the end of an (alloca) lifetime by calling the // llvm.lifetime.end intrinsic. It is commonly used together with // createTemporaryAlloca. diff --git a/compiler/testdata/basic.ll b/compiler/testdata/basic.ll index 549205a7..9f82ddb4 100644 --- a/compiler/testdata/basic.ll +++ b/compiler/testdata/basic.ll @@ -36,10 +36,6 @@ entry: %0 = icmp eq i32 %y, 0 br i1 %0, label %divbyzero.throw, label %divbyzero.next -divbyzero.throw: ; preds = %entry - call void @runtime.divideByZeroPanic(i8* undef) #0 - unreachable - divbyzero.next: ; preds = %entry %1 = icmp eq i32 %y, -1 %2 = icmp eq i32 %x, -2147483648 @@ -47,6 +43,10 @@ divbyzero.next: ; preds = %entry %4 = select i1 %3, i32 1, i32 %y %5 = sdiv i32 %x, %4 ret i32 %5 + +divbyzero.throw: ; preds = %entry + call void @runtime.divideByZeroPanic(i8* undef) #0 + unreachable } declare void @runtime.divideByZeroPanic(i8*) @@ -57,13 +57,13 @@ entry: %0 = icmp eq i32 %y, 0 br i1 %0, label %divbyzero.throw, label %divbyzero.next -divbyzero.throw: ; preds = %entry - call void @runtime.divideByZeroPanic(i8* undef) #0 - unreachable - divbyzero.next: ; preds = %entry %1 = udiv i32 %x, %y ret i32 %1 + +divbyzero.throw: ; preds = %entry + call void @runtime.divideByZeroPanic(i8* undef) #0 + unreachable } ; Function Attrs: nounwind @@ -72,10 +72,6 @@ entry: %0 = icmp eq i32 %y, 0 br i1 %0, label %divbyzero.throw, label %divbyzero.next -divbyzero.throw: ; preds = %entry - call void @runtime.divideByZeroPanic(i8* undef) #0 - unreachable - divbyzero.next: ; preds = %entry %1 = icmp eq i32 %y, -1 %2 = icmp eq i32 %x, -2147483648 @@ -83,6 +79,10 @@ divbyzero.next: ; preds = %entry %4 = select i1 %3, i32 1, i32 %y %5 = srem i32 %x, %4 ret i32 %5 + +divbyzero.throw: ; preds = %entry + call void @runtime.divideByZeroPanic(i8* undef) #0 + unreachable } ; Function Attrs: nounwind @@ -91,13 +91,13 @@ entry: %0 = icmp eq i32 %y, 0 br i1 %0, label %divbyzero.throw, label %divbyzero.next -divbyzero.throw: ; preds = %entry - call void @runtime.divideByZeroPanic(i8* undef) #0 - unreachable - divbyzero.next: ; preds = %entry %1 = urem i32 %x, %y ret i32 %1 + +divbyzero.throw: ; preds = %entry + call void @runtime.divideByZeroPanic(i8* undef) #0 + unreachable } ; Function Attrs: nounwind diff --git a/compiler/testdata/defer-cortex-m-qemu.ll b/compiler/testdata/defer-cortex-m-qemu.ll new file mode 100644 index 00000000..ddb830da --- /dev/null +++ b/compiler/testdata/defer-cortex-m-qemu.ll @@ -0,0 +1,142 @@ +; ModuleID = 'defer.go' +source_filename = "defer.go" +target datalayout = "e-m:e-p:32:32-Fi8-i64:64-v128:64:128-a:0:32-n32-S64" +target triple = "thumbv7m-unknown-unknown-eabi" + +%runtime._defer = type { i32, %runtime._defer* } + +declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*) + +; Function Attrs: nounwind +define hidden void @main.init(i8* %context) unnamed_addr #0 { +entry: + ret void +} + +declare void @main.external(i8*) + +; Function Attrs: nounwind +define hidden void @main.deferSimple(i8* %context) unnamed_addr #0 { +entry: + %defer.alloca = alloca { i32, %runtime._defer* }, align 4 + %deferPtr = alloca %runtime._defer*, align 4 + store %runtime._defer* null, %runtime._defer** %deferPtr, align 4 + %defer.alloca.repack = getelementptr inbounds { i32, %runtime._defer* }, { i32, %runtime._defer* }* %defer.alloca, i32 0, i32 0 + store i32 0, i32* %defer.alloca.repack, align 4 + %defer.alloca.repack1 = getelementptr inbounds { i32, %runtime._defer* }, { i32, %runtime._defer* }* %defer.alloca, i32 0, i32 1 + store %runtime._defer* null, %runtime._defer** %defer.alloca.repack1, align 4 + %0 = bitcast %runtime._defer** %deferPtr to { i32, %runtime._defer* }** + store { i32, %runtime._defer* }* %defer.alloca, { i32, %runtime._defer* }** %0, align 4 + call void @main.external(i8* undef) #0 + br label %rundefers.loophead + +rundefers.loophead: ; preds = %rundefers.callback0, %entry + %1 = load %runtime._defer*, %runtime._defer** %deferPtr, align 4 + %stackIsNil = icmp eq %runtime._defer* %1, null + br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop + +rundefers.loop: ; preds = %rundefers.loophead + %stack.next.gep = getelementptr inbounds %runtime._defer, %runtime._defer* %1, i32 0, i32 1 + %stack.next = load %runtime._defer*, %runtime._defer** %stack.next.gep, align 4 + store %runtime._defer* %stack.next, %runtime._defer** %deferPtr, align 4 + %callback.gep = getelementptr inbounds %runtime._defer, %runtime._defer* %1, i32 0, i32 0 + %callback = load i32, i32* %callback.gep, align 4 + switch i32 %callback, label %rundefers.default [ + i32 0, label %rundefers.callback0 + ] + +rundefers.callback0: ; preds = %rundefers.loop + call void @"main.deferSimple$1"(i8* undef) + br label %rundefers.loophead + +rundefers.default: ; preds = %rundefers.loop + unreachable + +rundefers.end: ; preds = %rundefers.loophead + ret void + +recover: ; No predecessors! + ret void +} + +; Function Attrs: nounwind +define hidden void @"main.deferSimple$1"(i8* %context) unnamed_addr #0 { +entry: + call void @runtime.printint32(i32 3, i8* undef) #0 + ret void +} + +declare void @runtime.printint32(i32, i8*) + +; Function Attrs: nounwind +define hidden void @main.deferMultiple(i8* %context) unnamed_addr #0 { +entry: + %defer.alloca2 = alloca { i32, %runtime._defer* }, align 4 + %defer.alloca = alloca { i32, %runtime._defer* }, align 4 + %deferPtr = alloca %runtime._defer*, align 4 + store %runtime._defer* null, %runtime._defer** %deferPtr, align 4 + %defer.alloca.repack = getelementptr inbounds { i32, %runtime._defer* }, { i32, %runtime._defer* }* %defer.alloca, i32 0, i32 0 + store i32 0, i32* %defer.alloca.repack, align 4 + %defer.alloca.repack5 = getelementptr inbounds { i32, %runtime._defer* }, { i32, %runtime._defer* }* %defer.alloca, i32 0, i32 1 + store %runtime._defer* null, %runtime._defer** %defer.alloca.repack5, align 4 + %0 = bitcast %runtime._defer** %deferPtr to { i32, %runtime._defer* }** + store { i32, %runtime._defer* }* %defer.alloca, { i32, %runtime._defer* }** %0, align 4 + %defer.alloca2.repack = getelementptr inbounds { i32, %runtime._defer* }, { i32, %runtime._defer* }* %defer.alloca2, i32 0, i32 0 + store i32 1, i32* %defer.alloca2.repack, align 4 + %defer.alloca2.repack6 = getelementptr inbounds { i32, %runtime._defer* }, { i32, %runtime._defer* }* %defer.alloca2, i32 0, i32 1 + %1 = bitcast %runtime._defer** %defer.alloca2.repack6 to { i32, %runtime._defer* }** + store { i32, %runtime._defer* }* %defer.alloca, { i32, %runtime._defer* }** %1, align 4 + %2 = bitcast %runtime._defer** %deferPtr to { i32, %runtime._defer* }** + store { i32, %runtime._defer* }* %defer.alloca2, { i32, %runtime._defer* }** %2, align 4 + call void @main.external(i8* undef) #0 + br label %rundefers.loophead + +rundefers.loophead: ; preds = %rundefers.callback1, %rundefers.callback0, %entry + %3 = load %runtime._defer*, %runtime._defer** %deferPtr, align 4 + %stackIsNil = icmp eq %runtime._defer* %3, null + br i1 %stackIsNil, label %rundefers.end, label %rundefers.loop + +rundefers.loop: ; preds = %rundefers.loophead + %stack.next.gep = getelementptr inbounds %runtime._defer, %runtime._defer* %3, i32 0, i32 1 + %stack.next = load %runtime._defer*, %runtime._defer** %stack.next.gep, align 4 + store %runtime._defer* %stack.next, %runtime._defer** %deferPtr, align 4 + %callback.gep = getelementptr inbounds %runtime._defer, %runtime._defer* %3, i32 0, i32 0 + %callback = load i32, i32* %callback.gep, align 4 + switch i32 %callback, label %rundefers.default [ + i32 0, label %rundefers.callback0 + i32 1, label %rundefers.callback1 + ] + +rundefers.callback0: ; preds = %rundefers.loop + call void @"main.deferMultiple$1"(i8* undef) + br label %rundefers.loophead + +rundefers.callback1: ; preds = %rundefers.loop + call void @"main.deferMultiple$2"(i8* undef) + br label %rundefers.loophead + +rundefers.default: ; preds = %rundefers.loop + unreachable + +rundefers.end: ; preds = %rundefers.loophead + ret void + +recover: ; No predecessors! + ret void +} + +; Function Attrs: nounwind +define hidden void @"main.deferMultiple$1"(i8* %context) unnamed_addr #0 { +entry: + call void @runtime.printint32(i32 3, i8* undef) #0 + ret void +} + +; Function Attrs: nounwind +define hidden void @"main.deferMultiple$2"(i8* %context) unnamed_addr #0 { +entry: + call void @runtime.printint32(i32 5, i8* undef) #0 + ret void +} + +attributes #0 = { nounwind } diff --git a/compiler/testdata/defer.go b/compiler/testdata/defer.go new file mode 100644 index 00000000..ae334a65 --- /dev/null +++ b/compiler/testdata/defer.go @@ -0,0 +1,20 @@ +package main + +func external() + +func deferSimple() { + defer func() { + print(3) + }() + external() +} + +func deferMultiple() { + defer func() { + print(3) + }() + defer func() { + print(5) + }() + external() +} diff --git a/compiler/testdata/func.ll b/compiler/testdata/func.ll index b497ee7c..405eddfd 100644 --- a/compiler/testdata/func.ll +++ b/compiler/testdata/func.ll @@ -19,14 +19,14 @@ entry: %0 = icmp eq void ()* %callback.funcptr, null br i1 %0, label %fpcall.throw, label %fpcall.next -fpcall.throw: ; preds = %entry - call void @runtime.nilPanic(i8* undef) #0 - unreachable - fpcall.next: ; preds = %entry %1 = bitcast void ()* %callback.funcptr to void (i32, i8*)* call void %1(i32 3, i8* %callback.context) #0 ret void + +fpcall.throw: ; preds = %entry + call void @runtime.nilPanic(i8* undef) #0 + unreachable } declare void @runtime.nilPanic(i8*) diff --git a/compiler/testdata/go1.17.ll b/compiler/testdata/go1.17.ll index dc83e36e..56ff52fb 100644 --- a/compiler/testdata/go1.17.ll +++ b/compiler/testdata/go1.17.ll @@ -36,13 +36,13 @@ entry: %0 = icmp ult i32 %s.len, 4 br i1 %0, label %slicetoarray.throw, label %slicetoarray.next -slicetoarray.throw: ; preds = %entry - call void @runtime.sliceToArrayPointerPanic(i8* undef) #0 - unreachable - slicetoarray.next: ; preds = %entry %1 = bitcast i32* %s.data to [4 x i32]* ret [4 x i32]* %1 + +slicetoarray.throw: ; preds = %entry + call void @runtime.sliceToArrayPointerPanic(i8* undef) #0 + unreachable } declare void @runtime.sliceToArrayPointerPanic(i8*) @@ -54,12 +54,12 @@ entry: call void @runtime.trackPointer(i8* nonnull %makeslice, i8* undef) #0 br i1 false, label %slicetoarray.throw, label %slicetoarray.next -slicetoarray.throw: ; preds = %entry - unreachable - slicetoarray.next: ; preds = %entry %0 = bitcast i8* %makeslice to [4 x i32]* ret [4 x i32]* %0 + +slicetoarray.throw: ; preds = %entry + unreachable } ; Function Attrs: nounwind @@ -72,10 +72,6 @@ entry: %4 = or i1 %3, %0 br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next -unsafe.Slice.throw: ; preds = %entry - call void @runtime.unsafeSlicePanic(i8* undef) #0 - unreachable - unsafe.Slice.next: ; preds = %entry %5 = insertvalue { i32*, i32, i32 } undef, i32* %ptr, 0 %6 = insertvalue { i32*, i32, i32 } %5, i32 %len, 1 @@ -83,6 +79,10 @@ unsafe.Slice.next: ; preds = %entry %8 = bitcast i32* %ptr to i8* call void @runtime.trackPointer(i8* %8, i8* undef) #0 ret { i32*, i32, i32 } %7 + +unsafe.Slice.throw: ; preds = %entry + call void @runtime.unsafeSlicePanic(i8* undef) #0 + unreachable } declare void @runtime.unsafeSlicePanic(i8*) @@ -95,10 +95,6 @@ entry: %2 = and i1 %0, %1 br i1 %2, label %unsafe.Slice.throw, label %unsafe.Slice.next -unsafe.Slice.throw: ; preds = %entry - call void @runtime.unsafeSlicePanic(i8* undef) #0 - unreachable - unsafe.Slice.next: ; preds = %entry %3 = zext i16 %len to i32 %4 = insertvalue { i8*, i32, i32 } undef, i8* %ptr, 0 @@ -106,6 +102,10 @@ unsafe.Slice.next: ; preds = %entry %6 = insertvalue { i8*, i32, i32 } %5, i32 %3, 2 call void @runtime.trackPointer(i8* %ptr, i8* undef) #0 ret { i8*, i32, i32 } %6 + +unsafe.Slice.throw: ; preds = %entry + call void @runtime.unsafeSlicePanic(i8* undef) #0 + unreachable } ; Function Attrs: nounwind @@ -118,10 +118,6 @@ entry: %4 = or i1 %3, %0 br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next -unsafe.Slice.throw: ; preds = %entry - call void @runtime.unsafeSlicePanic(i8* undef) #0 - unreachable - unsafe.Slice.next: ; preds = %entry %5 = trunc i64 %len to i32 %6 = insertvalue { i32*, i32, i32 } undef, i32* %ptr, 0 @@ -130,6 +126,10 @@ unsafe.Slice.next: ; preds = %entry %9 = bitcast i32* %ptr to i8* call void @runtime.trackPointer(i8* %9, i8* undef) #0 ret { i32*, i32, i32 } %8 + +unsafe.Slice.throw: ; preds = %entry + call void @runtime.unsafeSlicePanic(i8* undef) #0 + unreachable } ; Function Attrs: nounwind @@ -142,10 +142,6 @@ entry: %4 = or i1 %3, %0 br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next -unsafe.Slice.throw: ; preds = %entry - call void @runtime.unsafeSlicePanic(i8* undef) #0 - unreachable - unsafe.Slice.next: ; preds = %entry %5 = trunc i64 %len to i32 %6 = insertvalue { i32*, i32, i32 } undef, i32* %ptr, 0 @@ -154,6 +150,10 @@ unsafe.Slice.next: ; preds = %entry %9 = bitcast i32* %ptr to i8* call void @runtime.trackPointer(i8* %9, i8* undef) #0 ret { i32*, i32, i32 } %8 + +unsafe.Slice.throw: ; preds = %entry + call void @runtime.unsafeSlicePanic(i8* undef) #0 + unreachable } attributes #0 = { nounwind } diff --git a/compiler/testdata/interface.ll b/compiler/testdata/interface.ll index 609b91fe..986854c2 100644 --- a/compiler/testdata/interface.ll +++ b/compiler/testdata/interface.ll @@ -70,11 +70,11 @@ entry: %typecode = call i1 @runtime.typeAssert(i32 %itf.typecode, i8* nonnull @"reflect/types.typeid:basic:int", i8* undef) #0 br i1 %typecode, label %typeassert.ok, label %typeassert.next -typeassert.ok: ; preds = %entry - br label %typeassert.next - typeassert.next: ; preds = %typeassert.ok, %entry ret i1 %typecode + +typeassert.ok: ; preds = %entry + br label %typeassert.next } declare i1 @runtime.typeAssert(i32, i8* dereferenceable_or_null(1), i8*) @@ -85,11 +85,11 @@ entry: %0 = call i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(i32 %itf.typecode) #0 br i1 %0, label %typeassert.ok, label %typeassert.next -typeassert.ok: ; preds = %entry - br label %typeassert.next - typeassert.next: ; preds = %typeassert.ok, %entry ret i1 %0 + +typeassert.ok: ; preds = %entry + br label %typeassert.next } ; Function Attrs: nounwind @@ -98,11 +98,11 @@ entry: %0 = call i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(i32 %itf.typecode) #0 br i1 %0, label %typeassert.ok, label %typeassert.next -typeassert.ok: ; preds = %entry - br label %typeassert.next - typeassert.next: ; preds = %typeassert.ok, %entry ret i1 %0 + +typeassert.ok: ; preds = %entry + br label %typeassert.next } ; Function Attrs: nounwind diff --git a/compiler/testdata/slice.ll b/compiler/testdata/slice.ll index eb5fcd6c..f5947c68 100644 --- a/compiler/testdata/slice.ll +++ b/compiler/testdata/slice.ll @@ -31,14 +31,14 @@ entry: %.not = icmp ult i32 %index, %ints.len br i1 %.not, label %lookup.next, label %lookup.throw -lookup.throw: ; preds = %entry - call void @runtime.lookupPanic(i8* undef) #0 - unreachable - lookup.next: ; preds = %entry %0 = getelementptr inbounds i32, i32* %ints.data, i32 %index %1 = load i32, i32* %0, align 4 ret i32 %1 + +lookup.throw: ; preds = %entry + call void @runtime.lookupPanic(i8* undef) #0 + unreachable } declare void @runtime.lookupPanic(i8*) @@ -105,10 +105,6 @@ entry: %slice.maxcap = icmp slt i32 %len, 0 br i1 %slice.maxcap, label %slice.throw, label %slice.next -slice.throw: ; preds = %entry - call void @runtime.slicePanic(i8* undef) #0 - unreachable - slice.next: ; preds = %entry %makeslice.buf = call i8* @runtime.alloc(i32 %len, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0 %0 = insertvalue { i8*, i32, i32 } undef, i8* %makeslice.buf, 0 @@ -116,6 +112,10 @@ slice.next: ; preds = %entry %2 = insertvalue { i8*, i32, i32 } %1, i32 %len, 2 call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #0 ret { i8*, i32, i32 } %2 + +slice.throw: ; preds = %entry + call void @runtime.slicePanic(i8* undef) #0 + unreachable } declare void @runtime.slicePanic(i8*) @@ -126,10 +126,6 @@ entry: %slice.maxcap = icmp slt i32 %len, 0 br i1 %slice.maxcap, label %slice.throw, label %slice.next -slice.throw: ; preds = %entry - call void @runtime.slicePanic(i8* undef) #0 - unreachable - slice.next: ; preds = %entry %makeslice.cap = shl i32 %len, 1 %makeslice.buf = call i8* @runtime.alloc(i32 %makeslice.cap, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0 @@ -139,6 +135,10 @@ slice.next: ; preds = %entry %2 = insertvalue { i16*, i32, i32 } %1, i32 %len, 2 call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #0 ret { i16*, i32, i32 } %2 + +slice.throw: ; preds = %entry + call void @runtime.slicePanic(i8* undef) #0 + unreachable } ; Function Attrs: nounwind @@ -147,10 +147,6 @@ entry: %slice.maxcap = icmp ugt i32 %len, 1431655765 br i1 %slice.maxcap, label %slice.throw, label %slice.next -slice.throw: ; preds = %entry - call void @runtime.slicePanic(i8* undef) #0 - unreachable - slice.next: ; preds = %entry %makeslice.cap = mul i32 %len, 3 %makeslice.buf = call i8* @runtime.alloc(i32 %makeslice.cap, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0 @@ -160,6 +156,10 @@ slice.next: ; preds = %entry %2 = insertvalue { [3 x i8]*, i32, i32 } %1, i32 %len, 2 call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #0 ret { [3 x i8]*, i32, i32 } %2 + +slice.throw: ; preds = %entry + call void @runtime.slicePanic(i8* undef) #0 + unreachable } ; Function Attrs: nounwind @@ -168,10 +168,6 @@ entry: %slice.maxcap = icmp ugt i32 %len, 1073741823 br i1 %slice.maxcap, label %slice.throw, label %slice.next -slice.throw: ; preds = %entry - call void @runtime.slicePanic(i8* undef) #0 - unreachable - slice.next: ; preds = %entry %makeslice.cap = shl i32 %len, 2 %makeslice.buf = call i8* @runtime.alloc(i32 %makeslice.cap, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0 @@ -181,6 +177,10 @@ slice.next: ; preds = %entry %2 = insertvalue { i32*, i32, i32 } %1, i32 %len, 2 call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #0 ret { i32*, i32, i32 } %2 + +slice.throw: ; preds = %entry + call void @runtime.slicePanic(i8* undef) #0 + unreachable } attributes #0 = { nounwind } diff --git a/compiler/testdata/string.ll b/compiler/testdata/string.ll index 99d81bab..6d25a35f 100644 --- a/compiler/testdata/string.ll +++ b/compiler/testdata/string.ll @@ -41,14 +41,14 @@ entry: %.not = icmp ult i32 %index, %s.len br i1 %.not, label %lookup.next, label %lookup.throw -lookup.throw: ; preds = %entry - call void @runtime.lookupPanic(i8* undef) #0 - unreachable - lookup.next: ; preds = %entry %0 = getelementptr inbounds i8, i8* %s.data, i32 %index %1 = load i8, i8* %0, align 1 ret i8 %1 + +lookup.throw: ; preds = %entry + call void @runtime.lookupPanic(i8* undef) #0 + unreachable } declare void @runtime.lookupPanic(i8*) @@ -86,14 +86,14 @@ entry: %.not = icmp ult i32 %0, %s.len br i1 %.not, label %lookup.next, label %lookup.throw -lookup.throw: ; preds = %entry - call void @runtime.lookupPanic(i8* undef) #0 - unreachable - lookup.next: ; preds = %entry %1 = getelementptr inbounds i8, i8* %s.data, i32 %0 %2 = load i8, i8* %1, align 1 ret i8 %2 + +lookup.throw: ; preds = %entry + call void @runtime.lookupPanic(i8* undef) #0 + unreachable } attributes #0 = { nounwind }