diff --git a/compiler/asserts.go b/compiler/asserts.go index acd605fab1..8d9efdde70 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 cbf89fe20a..ba427ec5c8 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", "", "coroutines"}, + {"defer.go", "", ""}, {"pragma.go", "", ""}, {"goroutine.go", "wasm", "asyncify"}, {"goroutine.go", "wasm", "coroutines"}, diff --git a/compiler/defer.go b/compiler/defer.go index 6edcc14232..2a367e468a 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 7460c65837..ddd663b05c 100644 --- a/compiler/interface.go +++ b/compiler/interface.go @@ -400,8 +400,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 9b5d40fc28..6bd29bb25b 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 56baf3a771..b1fe44c9ca 100644 --- a/compiler/testdata/basic.ll +++ b/compiler/testdata/basic.ll @@ -34,10 +34,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, i8* null) #0 - unreachable - divbyzero.next: ; preds = %entry %1 = icmp eq i32 %y, -1 %2 = icmp eq i32 %x, -2147483648 @@ -45,6 +41,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, i8* null) #0 + unreachable } declare void @runtime.divideByZeroPanic(i8*, i8*) @@ -55,13 +55,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, i8* null) #0 - unreachable - divbyzero.next: ; preds = %entry %1 = udiv i32 %x, %y ret i32 %1 + +divbyzero.throw: ; preds = %entry + call void @runtime.divideByZeroPanic(i8* undef, i8* null) #0 + unreachable } ; Function Attrs: nounwind @@ -70,10 +70,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, i8* null) #0 - unreachable - divbyzero.next: ; preds = %entry %1 = icmp eq i32 %y, -1 %2 = icmp eq i32 %x, -2147483648 @@ -81,6 +77,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, i8* null) #0 + unreachable } ; Function Attrs: nounwind @@ -89,13 +89,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, i8* null) #0 - unreachable - divbyzero.next: ; preds = %entry %1 = urem i32 %x, %y ret i32 %1 + +divbyzero.throw: ; preds = %entry + call void @runtime.divideByZeroPanic(i8* undef, i8* null) #0 + unreachable } ; Function Attrs: nounwind diff --git a/compiler/testdata/defer.go b/compiler/testdata/defer.go new file mode 100644 index 0000000000..ae334a6568 --- /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/defer.ll b/compiler/testdata/defer.ll new file mode 100644 index 0000000000..4961533365 --- /dev/null +++ b/compiler/testdata/defer.ll @@ -0,0 +1,146 @@ +; ModuleID = 'defer.go' +source_filename = "defer.go" +target datalayout = "e-m:e-p:32:32-i64:64-n32:64-S128" +target triple = "wasm32-unknown-wasi" + +%runtime._defer = type { i32, %runtime._defer* } + +declare noalias nonnull i8* @runtime.alloc(i32, i8*, i8*, i8*) + +; Function Attrs: nounwind +define hidden void @main.init(i8* %context, i8* %parentHandle) unnamed_addr #0 { +entry: + ret void +} + +declare void @main.external(i8*, i8*) + +; Function Attrs: nounwind +define hidden void @main.deferSimple(i8* %context, i8* %parentHandle) unnamed_addr #0 { +entry: + %defer.alloca = alloca { i32, %runtime._defer* }, align 8 + %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 8 + %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, 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 + %2 = bitcast %runtime._defer** %stack.next.gep to i32* + %stack.next2 = load i32, i32* %2, align 4 + %3 = bitcast %runtime._defer** %deferPtr to i32* + store i32 %stack.next2, i32* %3, 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, 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, i8* %parentHandle) unnamed_addr #0 { +entry: + call void @runtime.printint32(i32 3, i8* undef, i8* null) #0 + ret void +} + +declare void @runtime.printint32(i32, i8*, i8*) + +; Function Attrs: nounwind +define hidden void @main.deferMultiple(i8* %context, i8* %parentHandle) unnamed_addr #0 { +entry: + %defer.alloca2 = alloca { i32, %runtime._defer* }, align 8 + %defer.alloca = alloca { i32, %runtime._defer* }, align 8 + %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 8 + %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 8 + %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, 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 + %4 = bitcast %runtime._defer** %stack.next.gep to i32* + %stack.next8 = load i32, i32* %4, align 4 + %5 = bitcast %runtime._defer** %deferPtr to i32* + store i32 %stack.next8, i32* %5, 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, i8* undef) + br label %rundefers.loophead + +rundefers.callback1: ; preds = %rundefers.loop + call void @"main.deferMultiple$2"(i8* undef, 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, i8* %parentHandle) unnamed_addr #0 { +entry: + call void @runtime.printint32(i32 3, i8* undef, i8* null) #0 + ret void +} + +; Function Attrs: nounwind +define hidden void @"main.deferMultiple$2"(i8* %context, i8* %parentHandle) unnamed_addr #0 { +entry: + call void @runtime.printint32(i32 5, i8* undef, i8* null) #0 + ret void +} + +attributes #0 = { nounwind } diff --git a/compiler/testdata/func-coroutines.ll b/compiler/testdata/func-coroutines.ll index eeefa43cfb..2cadbe6180 100644 --- a/compiler/testdata/func-coroutines.ll +++ b/compiler/testdata/func-coroutines.ll @@ -23,14 +23,14 @@ entry: %1 = icmp eq i32 %0, 0 br i1 %1, label %fpcall.throw, label %fpcall.next -fpcall.throw: ; preds = %entry - call void @runtime.nilPanic(i8* undef, i8* null) #0 - unreachable - fpcall.next: ; preds = %entry %2 = inttoptr i32 %0 to void (i32, i8*, i8*)* call void %2(i32 3, i8* %callback.context, i8* undef) #0 ret void + +fpcall.throw: ; preds = %entry + call void @runtime.nilPanic(i8* undef, i8* null) #0 + unreachable } declare i32 @runtime.getFuncPtr(i8*, i32, i8* dereferenceable_or_null(1), i8*, i8*) diff --git a/compiler/testdata/go1.17.ll b/compiler/testdata/go1.17.ll index 5c26166aa1..21d01cdfeb 100644 --- a/compiler/testdata/go1.17.ll +++ b/compiler/testdata/go1.17.ll @@ -32,13 +32,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, i8* null) #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, i8* null) #0 + unreachable } declare void @runtime.sliceToArrayPointerPanic(i8*, i8*) @@ -49,12 +49,12 @@ entry: %makeslice = call i8* @runtime.alloc(i32 24, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #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 @@ -67,15 +67,15 @@ 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, i8* null) #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 %7 = insertvalue { i32*, i32, i32 } %6, i32 %len, 2 ret { i32*, i32, i32 } %7 + +unsafe.Slice.throw: ; preds = %entry + call void @runtime.unsafeSlicePanic(i8* undef, i8* null) #0 + unreachable } declare void @runtime.unsafeSlicePanic(i8*, i8*) @@ -88,16 +88,16 @@ 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, i8* null) #0 - unreachable - unsafe.Slice.next: ; preds = %entry %3 = zext i16 %len to i32 %4 = insertvalue { i8*, i32, i32 } undef, i8* %ptr, 0 %5 = insertvalue { i8*, i32, i32 } %4, i32 %3, 1 %6 = insertvalue { i8*, i32, i32 } %5, i32 %3, 2 ret { i8*, i32, i32 } %6 + +unsafe.Slice.throw: ; preds = %entry + call void @runtime.unsafeSlicePanic(i8* undef, i8* null) #0 + unreachable } ; Function Attrs: nounwind @@ -110,16 +110,16 @@ 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, i8* null) #0 - unreachable - unsafe.Slice.next: ; preds = %entry %5 = trunc i64 %len to i32 %6 = insertvalue { i32*, i32, i32 } undef, i32* %ptr, 0 %7 = insertvalue { i32*, i32, i32 } %6, i32 %5, 1 %8 = insertvalue { i32*, i32, i32 } %7, i32 %5, 2 ret { i32*, i32, i32 } %8 + +unsafe.Slice.throw: ; preds = %entry + call void @runtime.unsafeSlicePanic(i8* undef, i8* null) #0 + unreachable } ; Function Attrs: nounwind @@ -132,16 +132,16 @@ 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, i8* null) #0 - unreachable - unsafe.Slice.next: ; preds = %entry %5 = trunc i64 %len to i32 %6 = insertvalue { i32*, i32, i32 } undef, i32* %ptr, 0 %7 = insertvalue { i32*, i32, i32 } %6, i32 %5, 1 %8 = insertvalue { i32*, i32, i32 } %7, i32 %5, 2 ret { i32*, i32, i32 } %8 + +unsafe.Slice.throw: ; preds = %entry + call void @runtime.unsafeSlicePanic(i8* undef, i8* null) #0 + unreachable } attributes #0 = { nounwind } diff --git a/compiler/testdata/interface.ll b/compiler/testdata/interface.ll index f5afb0f38b..433134abc3 100644 --- a/compiler/testdata/interface.ll +++ b/compiler/testdata/interface.ll @@ -64,11 +64,11 @@ entry: %typecode = call i1 @runtime.typeAssert(i32 %itf.typecode, i8* nonnull @"reflect/types.typeid:basic:int", i8* undef, i8* null) #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*, i8*) @@ -79,11 +79,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 @@ -92,11 +92,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 847d29fb64..cc65784b49 100644 --- a/compiler/testdata/slice.ll +++ b/compiler/testdata/slice.ll @@ -29,14 +29,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, i8* null) #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, i8* null) #0 + unreachable } declare void @runtime.lookupPanic(i8*, i8*) @@ -100,16 +100,16 @@ 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, i8* null) #0 - unreachable - slice.next: ; preds = %entry %makeslice.buf = call i8* @runtime.alloc(i32 %len, i8* nonnull inttoptr (i32 3 to i8*), i8* undef, i8* null) #0 %0 = insertvalue { i8*, i32, i32 } undef, i8* %makeslice.buf, 0 %1 = insertvalue { i8*, i32, i32 } %0, i32 %len, 1 %2 = insertvalue { i8*, i32, i32 } %1, i32 %len, 2 ret { i8*, i32, i32 } %2 + +slice.throw: ; preds = %entry + call void @runtime.slicePanic(i8* undef, i8* null) #0 + unreachable } declare void @runtime.slicePanic(i8*, i8*) @@ -120,10 +120,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, i8* null) #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, i8* null) #0 @@ -132,6 +128,10 @@ slice.next: ; preds = %entry %1 = insertvalue { i16*, i32, i32 } %0, i32 %len, 1 %2 = insertvalue { i16*, i32, i32 } %1, i32 %len, 2 ret { i16*, i32, i32 } %2 + +slice.throw: ; preds = %entry + call void @runtime.slicePanic(i8* undef, i8* null) #0 + unreachable } ; Function Attrs: nounwind @@ -140,10 +140,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, i8* null) #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, i8* null) #0 @@ -152,6 +148,10 @@ slice.next: ; preds = %entry %1 = insertvalue { [3 x i8]*, i32, i32 } %0, i32 %len, 1 %2 = insertvalue { [3 x i8]*, i32, i32 } %1, i32 %len, 2 ret { [3 x i8]*, i32, i32 } %2 + +slice.throw: ; preds = %entry + call void @runtime.slicePanic(i8* undef, i8* null) #0 + unreachable } ; Function Attrs: nounwind @@ -160,10 +160,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, i8* null) #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, i8* null) #0 @@ -172,6 +168,10 @@ slice.next: ; preds = %entry %1 = insertvalue { i32*, i32, i32 } %0, i32 %len, 1 %2 = insertvalue { i32*, i32, i32 } %1, i32 %len, 2 ret { i32*, i32, i32 } %2 + +slice.throw: ; preds = %entry + call void @runtime.slicePanic(i8* undef, i8* null) #0 + unreachable } attributes #0 = { nounwind } diff --git a/compiler/testdata/string.ll b/compiler/testdata/string.ll index e8d6e63112..09b7e3b155 100644 --- a/compiler/testdata/string.ll +++ b/compiler/testdata/string.ll @@ -39,14 +39,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, i8* null) #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, i8* null) #0 + unreachable } declare void @runtime.lookupPanic(i8*, i8*) @@ -84,14 +84,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, i8* null) #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, i8* null) #0 + unreachable } attributes #0 = { nounwind }