compiler: insert basic blocks at an appropriate location

For example, this commit moves the 'throw' branch of an assertion (nil
check, slice index check, etc) to the end of the function while
inserting the "continue" branch right after the insert location. This
makes the resulting IR easier to follow.

For some reason, this also reduces code size a bit on average. The
TinyGo smoke tests saw a reduction of 0.22%, mainly from WebAssembly.
The drivers repo saw little average change in code size (-0.01%).

This commit also adds a few compiler tests for the defer keyword.
Этот коммит содержится в:
Ayke van Laethem 2021-11-29 14:51:49 +01:00 коммит произвёл Ron Evans
родитель 2fb5174910
коммит 79ba6a50c3
13 изменённых файлов: 272 добавлений и 89 удалений

Просмотреть файл

@ -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") 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 b.blockExits[b.currentBlock] = nextBlock // adjust outgoing block for phi nodes
// Now branch to the out-of-bounds or the regular block. // Now branch to the out-of-bounds or the regular block.

Просмотреть файл

@ -49,6 +49,7 @@ func TestCompiler(t *testing.T) {
{"float.go", "", ""}, {"float.go", "", ""},
{"interface.go", "", ""}, {"interface.go", "", ""},
{"func.go", "", ""}, {"func.go", "", ""},
{"defer.go", "cortex-m-qemu", ""},
{"pragma.go", "", ""}, {"pragma.go", "", ""},
{"goroutine.go", "wasm", "asyncify"}, {"goroutine.go", "wasm", "asyncify"},
{"goroutine.go", "cortex-m-qemu", "tasks"}, {"goroutine.go", "cortex-m-qemu", "tasks"},

Просмотреть файл

@ -15,6 +15,7 @@ package compiler
import ( import (
"go/types" "go/types"
"strconv"
"github.com/tinygo-org/tinygo/compiler/llvmutil" "github.com/tinygo-org/tinygo/compiler/llvmutil"
"golang.org/x/tools/go/ssa" "golang.org/x/tools/go/ssa"
@ -248,11 +249,11 @@ func (b *builder) createRunDefers() {
// } // }
// } // }
// Create loop. // Create loop, in the order: loophead, loop, callback0, callback1, ..., unreachable, end.
loophead := b.ctx.AddBasicBlock(b.llvmFn, "rundefers.loophead") end := b.insertBasicBlock("rundefers.end")
loop := b.ctx.AddBasicBlock(b.llvmFn, "rundefers.loop") unreachable := b.ctx.InsertBasicBlock(end, "rundefers.default")
unreachable := b.ctx.AddBasicBlock(b.llvmFn, "rundefers.default") loop := b.ctx.InsertBasicBlock(unreachable, "rundefers.loop")
end := b.ctx.AddBasicBlock(b.llvmFn, "rundefers.end") loophead := b.ctx.InsertBasicBlock(loop, "rundefers.loophead")
b.CreateBr(loophead) b.CreateBr(loophead)
// Create loop head: // Create loop head:
@ -284,7 +285,7 @@ func (b *builder) createRunDefers() {
// Create switch case, for example: // Create switch case, for example:
// case 0: // case 0:
// // run first deferred call // // 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) sw.AddCase(llvm.ConstInt(b.uintptrType, uint64(i), false), block)
b.SetInsertPointAtEnd(block) b.SetInsertPointAtEnd(block)
switch callback := callback.(type) { switch callback := callback.(type) {

Просмотреть файл

@ -389,8 +389,8 @@ func (b *builder) createTypeAssert(expr *ssa.TypeAssert) llvm.Value {
// value. // value.
prevBlock := b.GetInsertBlock() prevBlock := b.GetInsertBlock()
okBlock := b.ctx.AddBasicBlock(b.llvmFn, "typeassert.ok") okBlock := b.insertBasicBlock("typeassert.ok")
nextBlock := b.ctx.AddBasicBlock(b.llvmFn, "typeassert.next") nextBlock := b.insertBasicBlock("typeassert.next")
b.blockExits[b.currentBlock] = nextBlock // adjust outgoing block for phi nodes b.blockExits[b.currentBlock] = nextBlock // adjust outgoing block for phi nodes
b.CreateCondBr(commaOk, okBlock, nextBlock) b.CreateCondBr(commaOk, okBlock, nextBlock)

Просмотреть файл

@ -23,6 +23,23 @@ func (b *builder) createTemporaryAlloca(t llvm.Type, name string) (alloca, bitca
return llvmutil.CreateTemporaryAlloca(b.Builder, b.mod, t, name) 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 // emitLifetimeEnd signals the end of an (alloca) lifetime by calling the
// llvm.lifetime.end intrinsic. It is commonly used together with // llvm.lifetime.end intrinsic. It is commonly used together with
// createTemporaryAlloca. // createTemporaryAlloca.

32
compiler/testdata/basic.ll предоставленный
Просмотреть файл

@ -36,10 +36,6 @@ entry:
%0 = icmp eq i32 %y, 0 %0 = icmp eq i32 %y, 0
br i1 %0, label %divbyzero.throw, label %divbyzero.next 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 divbyzero.next: ; preds = %entry
%1 = icmp eq i32 %y, -1 %1 = icmp eq i32 %y, -1
%2 = icmp eq i32 %x, -2147483648 %2 = icmp eq i32 %x, -2147483648
@ -47,6 +43,10 @@ divbyzero.next: ; preds = %entry
%4 = select i1 %3, i32 1, i32 %y %4 = select i1 %3, i32 1, i32 %y
%5 = sdiv i32 %x, %4 %5 = sdiv i32 %x, %4
ret i32 %5 ret i32 %5
divbyzero.throw: ; preds = %entry
call void @runtime.divideByZeroPanic(i8* undef) #0
unreachable
} }
declare void @runtime.divideByZeroPanic(i8*) declare void @runtime.divideByZeroPanic(i8*)
@ -57,13 +57,13 @@ entry:
%0 = icmp eq i32 %y, 0 %0 = icmp eq i32 %y, 0
br i1 %0, label %divbyzero.throw, label %divbyzero.next 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 divbyzero.next: ; preds = %entry
%1 = udiv i32 %x, %y %1 = udiv i32 %x, %y
ret i32 %1 ret i32 %1
divbyzero.throw: ; preds = %entry
call void @runtime.divideByZeroPanic(i8* undef) #0
unreachable
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
@ -72,10 +72,6 @@ entry:
%0 = icmp eq i32 %y, 0 %0 = icmp eq i32 %y, 0
br i1 %0, label %divbyzero.throw, label %divbyzero.next 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 divbyzero.next: ; preds = %entry
%1 = icmp eq i32 %y, -1 %1 = icmp eq i32 %y, -1
%2 = icmp eq i32 %x, -2147483648 %2 = icmp eq i32 %x, -2147483648
@ -83,6 +79,10 @@ divbyzero.next: ; preds = %entry
%4 = select i1 %3, i32 1, i32 %y %4 = select i1 %3, i32 1, i32 %y
%5 = srem i32 %x, %4 %5 = srem i32 %x, %4
ret i32 %5 ret i32 %5
divbyzero.throw: ; preds = %entry
call void @runtime.divideByZeroPanic(i8* undef) #0
unreachable
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
@ -91,13 +91,13 @@ entry:
%0 = icmp eq i32 %y, 0 %0 = icmp eq i32 %y, 0
br i1 %0, label %divbyzero.throw, label %divbyzero.next 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 divbyzero.next: ; preds = %entry
%1 = urem i32 %x, %y %1 = urem i32 %x, %y
ret i32 %1 ret i32 %1
divbyzero.throw: ; preds = %entry
call void @runtime.divideByZeroPanic(i8* undef) #0
unreachable
} }
; Function Attrs: nounwind ; Function Attrs: nounwind

142
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 }

20
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()
}

8
compiler/testdata/func.ll предоставленный
Просмотреть файл

@ -19,14 +19,14 @@ entry:
%0 = icmp eq void ()* %callback.funcptr, null %0 = icmp eq void ()* %callback.funcptr, null
br i1 %0, label %fpcall.throw, label %fpcall.next 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 fpcall.next: ; preds = %entry
%1 = bitcast void ()* %callback.funcptr to void (i32, i8*)* %1 = bitcast void ()* %callback.funcptr to void (i32, i8*)*
call void %1(i32 3, i8* %callback.context) #0 call void %1(i32 3, i8* %callback.context) #0
ret void ret void
fpcall.throw: ; preds = %entry
call void @runtime.nilPanic(i8* undef) #0
unreachable
} }
declare void @runtime.nilPanic(i8*) declare void @runtime.nilPanic(i8*)

46
compiler/testdata/go1.17.ll предоставленный
Просмотреть файл

@ -36,13 +36,13 @@ entry:
%0 = icmp ult i32 %s.len, 4 %0 = icmp ult i32 %s.len, 4
br i1 %0, label %slicetoarray.throw, label %slicetoarray.next 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 slicetoarray.next: ; preds = %entry
%1 = bitcast i32* %s.data to [4 x i32]* %1 = bitcast i32* %s.data to [4 x i32]*
ret [4 x i32]* %1 ret [4 x i32]* %1
slicetoarray.throw: ; preds = %entry
call void @runtime.sliceToArrayPointerPanic(i8* undef) #0
unreachable
} }
declare void @runtime.sliceToArrayPointerPanic(i8*) declare void @runtime.sliceToArrayPointerPanic(i8*)
@ -54,12 +54,12 @@ entry:
call void @runtime.trackPointer(i8* nonnull %makeslice, i8* undef) #0 call void @runtime.trackPointer(i8* nonnull %makeslice, i8* undef) #0
br i1 false, label %slicetoarray.throw, label %slicetoarray.next br i1 false, label %slicetoarray.throw, label %slicetoarray.next
slicetoarray.throw: ; preds = %entry
unreachable
slicetoarray.next: ; preds = %entry slicetoarray.next: ; preds = %entry
%0 = bitcast i8* %makeslice to [4 x i32]* %0 = bitcast i8* %makeslice to [4 x i32]*
ret [4 x i32]* %0 ret [4 x i32]* %0
slicetoarray.throw: ; preds = %entry
unreachable
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
@ -72,10 +72,6 @@ entry:
%4 = or i1 %3, %0 %4 = or i1 %3, %0
br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next 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 unsafe.Slice.next: ; preds = %entry
%5 = insertvalue { i32*, i32, i32 } undef, i32* %ptr, 0 %5 = insertvalue { i32*, i32, i32 } undef, i32* %ptr, 0
%6 = insertvalue { i32*, i32, i32 } %5, i32 %len, 1 %6 = insertvalue { i32*, i32, i32 } %5, i32 %len, 1
@ -83,6 +79,10 @@ unsafe.Slice.next: ; preds = %entry
%8 = bitcast i32* %ptr to i8* %8 = bitcast i32* %ptr to i8*
call void @runtime.trackPointer(i8* %8, i8* undef) #0 call void @runtime.trackPointer(i8* %8, i8* undef) #0
ret { i32*, i32, i32 } %7 ret { i32*, i32, i32 } %7
unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(i8* undef) #0
unreachable
} }
declare void @runtime.unsafeSlicePanic(i8*) declare void @runtime.unsafeSlicePanic(i8*)
@ -95,10 +95,6 @@ entry:
%2 = and i1 %0, %1 %2 = and i1 %0, %1
br i1 %2, label %unsafe.Slice.throw, label %unsafe.Slice.next 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 unsafe.Slice.next: ; preds = %entry
%3 = zext i16 %len to i32 %3 = zext i16 %len to i32
%4 = insertvalue { i8*, i32, i32 } undef, i8* %ptr, 0 %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 %6 = insertvalue { i8*, i32, i32 } %5, i32 %3, 2
call void @runtime.trackPointer(i8* %ptr, i8* undef) #0 call void @runtime.trackPointer(i8* %ptr, i8* undef) #0
ret { i8*, i32, i32 } %6 ret { i8*, i32, i32 } %6
unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(i8* undef) #0
unreachable
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
@ -118,10 +118,6 @@ entry:
%4 = or i1 %3, %0 %4 = or i1 %3, %0
br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next 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 unsafe.Slice.next: ; preds = %entry
%5 = trunc i64 %len to i32 %5 = trunc i64 %len to i32
%6 = insertvalue { i32*, i32, i32 } undef, i32* %ptr, 0 %6 = insertvalue { i32*, i32, i32 } undef, i32* %ptr, 0
@ -130,6 +126,10 @@ unsafe.Slice.next: ; preds = %entry
%9 = bitcast i32* %ptr to i8* %9 = bitcast i32* %ptr to i8*
call void @runtime.trackPointer(i8* %9, i8* undef) #0 call void @runtime.trackPointer(i8* %9, i8* undef) #0
ret { i32*, i32, i32 } %8 ret { i32*, i32, i32 } %8
unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(i8* undef) #0
unreachable
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
@ -142,10 +142,6 @@ entry:
%4 = or i1 %3, %0 %4 = or i1 %3, %0
br i1 %4, label %unsafe.Slice.throw, label %unsafe.Slice.next 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 unsafe.Slice.next: ; preds = %entry
%5 = trunc i64 %len to i32 %5 = trunc i64 %len to i32
%6 = insertvalue { i32*, i32, i32 } undef, i32* %ptr, 0 %6 = insertvalue { i32*, i32, i32 } undef, i32* %ptr, 0
@ -154,6 +150,10 @@ unsafe.Slice.next: ; preds = %entry
%9 = bitcast i32* %ptr to i8* %9 = bitcast i32* %ptr to i8*
call void @runtime.trackPointer(i8* %9, i8* undef) #0 call void @runtime.trackPointer(i8* %9, i8* undef) #0
ret { i32*, i32, i32 } %8 ret { i32*, i32, i32 } %8
unsafe.Slice.throw: ; preds = %entry
call void @runtime.unsafeSlicePanic(i8* undef) #0
unreachable
} }
attributes #0 = { nounwind } attributes #0 = { nounwind }

18
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 %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 br i1 %typecode, label %typeassert.ok, label %typeassert.next
typeassert.ok: ; preds = %entry
br label %typeassert.next
typeassert.next: ; preds = %typeassert.ok, %entry typeassert.next: ; preds = %typeassert.ok, %entry
ret i1 %typecode ret i1 %typecode
typeassert.ok: ; preds = %entry
br label %typeassert.next
} }
declare i1 @runtime.typeAssert(i32, i8* dereferenceable_or_null(1), i8*) 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 %0 = call i1 @"interface:{Error:func:{}{basic:string}}.$typeassert"(i32 %itf.typecode) #0
br i1 %0, label %typeassert.ok, label %typeassert.next br i1 %0, label %typeassert.ok, label %typeassert.next
typeassert.ok: ; preds = %entry
br label %typeassert.next
typeassert.next: ; preds = %typeassert.ok, %entry typeassert.next: ; preds = %typeassert.ok, %entry
ret i1 %0 ret i1 %0
typeassert.ok: ; preds = %entry
br label %typeassert.next
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
@ -98,11 +98,11 @@ entry:
%0 = call i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(i32 %itf.typecode) #0 %0 = call i1 @"interface:{String:func:{}{basic:string}}.$typeassert"(i32 %itf.typecode) #0
br i1 %0, label %typeassert.ok, label %typeassert.next br i1 %0, label %typeassert.ok, label %typeassert.next
typeassert.ok: ; preds = %entry
br label %typeassert.next
typeassert.next: ; preds = %typeassert.ok, %entry typeassert.next: ; preds = %typeassert.ok, %entry
ret i1 %0 ret i1 %0
typeassert.ok: ; preds = %entry
br label %typeassert.next
} }
; Function Attrs: nounwind ; Function Attrs: nounwind

40
compiler/testdata/slice.ll предоставленный
Просмотреть файл

@ -31,14 +31,14 @@ entry:
%.not = icmp ult i32 %index, %ints.len %.not = icmp ult i32 %index, %ints.len
br i1 %.not, label %lookup.next, label %lookup.throw 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 lookup.next: ; preds = %entry
%0 = getelementptr inbounds i32, i32* %ints.data, i32 %index %0 = getelementptr inbounds i32, i32* %ints.data, i32 %index
%1 = load i32, i32* %0, align 4 %1 = load i32, i32* %0, align 4
ret i32 %1 ret i32 %1
lookup.throw: ; preds = %entry
call void @runtime.lookupPanic(i8* undef) #0
unreachable
} }
declare void @runtime.lookupPanic(i8*) declare void @runtime.lookupPanic(i8*)
@ -105,10 +105,6 @@ entry:
%slice.maxcap = icmp slt i32 %len, 0 %slice.maxcap = icmp slt i32 %len, 0
br i1 %slice.maxcap, label %slice.throw, label %slice.next 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 slice.next: ; preds = %entry
%makeslice.buf = call i8* @runtime.alloc(i32 %len, i8* nonnull inttoptr (i32 3 to i8*), i8* undef) #0 %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 %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 %2 = insertvalue { i8*, i32, i32 } %1, i32 %len, 2
call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #0 call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #0
ret { i8*, i32, i32 } %2 ret { i8*, i32, i32 } %2
slice.throw: ; preds = %entry
call void @runtime.slicePanic(i8* undef) #0
unreachable
} }
declare void @runtime.slicePanic(i8*) declare void @runtime.slicePanic(i8*)
@ -126,10 +126,6 @@ entry:
%slice.maxcap = icmp slt i32 %len, 0 %slice.maxcap = icmp slt i32 %len, 0
br i1 %slice.maxcap, label %slice.throw, label %slice.next 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 slice.next: ; preds = %entry
%makeslice.cap = shl i32 %len, 1 %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 %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 %2 = insertvalue { i16*, i32, i32 } %1, i32 %len, 2
call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #0 call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #0
ret { i16*, i32, i32 } %2 ret { i16*, i32, i32 } %2
slice.throw: ; preds = %entry
call void @runtime.slicePanic(i8* undef) #0
unreachable
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
@ -147,10 +147,6 @@ entry:
%slice.maxcap = icmp ugt i32 %len, 1431655765 %slice.maxcap = icmp ugt i32 %len, 1431655765
br i1 %slice.maxcap, label %slice.throw, label %slice.next 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 slice.next: ; preds = %entry
%makeslice.cap = mul i32 %len, 3 %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 %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 %2 = insertvalue { [3 x i8]*, i32, i32 } %1, i32 %len, 2
call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #0 call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #0
ret { [3 x i8]*, i32, i32 } %2 ret { [3 x i8]*, i32, i32 } %2
slice.throw: ; preds = %entry
call void @runtime.slicePanic(i8* undef) #0
unreachable
} }
; Function Attrs: nounwind ; Function Attrs: nounwind
@ -168,10 +168,6 @@ entry:
%slice.maxcap = icmp ugt i32 %len, 1073741823 %slice.maxcap = icmp ugt i32 %len, 1073741823
br i1 %slice.maxcap, label %slice.throw, label %slice.next 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 slice.next: ; preds = %entry
%makeslice.cap = shl i32 %len, 2 %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 %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 %2 = insertvalue { i32*, i32, i32 } %1, i32 %len, 2
call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #0 call void @runtime.trackPointer(i8* nonnull %makeslice.buf, i8* undef) #0
ret { i32*, i32, i32 } %2 ret { i32*, i32, i32 } %2
slice.throw: ; preds = %entry
call void @runtime.slicePanic(i8* undef) #0
unreachable
} }
attributes #0 = { nounwind } attributes #0 = { nounwind }

16
compiler/testdata/string.ll предоставленный
Просмотреть файл

@ -41,14 +41,14 @@ entry:
%.not = icmp ult i32 %index, %s.len %.not = icmp ult i32 %index, %s.len
br i1 %.not, label %lookup.next, label %lookup.throw 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 lookup.next: ; preds = %entry
%0 = getelementptr inbounds i8, i8* %s.data, i32 %index %0 = getelementptr inbounds i8, i8* %s.data, i32 %index
%1 = load i8, i8* %0, align 1 %1 = load i8, i8* %0, align 1
ret i8 %1 ret i8 %1
lookup.throw: ; preds = %entry
call void @runtime.lookupPanic(i8* undef) #0
unreachable
} }
declare void @runtime.lookupPanic(i8*) declare void @runtime.lookupPanic(i8*)
@ -86,14 +86,14 @@ entry:
%.not = icmp ult i32 %0, %s.len %.not = icmp ult i32 %0, %s.len
br i1 %.not, label %lookup.next, label %lookup.throw 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 lookup.next: ; preds = %entry
%1 = getelementptr inbounds i8, i8* %s.data, i32 %0 %1 = getelementptr inbounds i8, i8* %s.data, i32 %0
%2 = load i8, i8* %1, align 1 %2 = load i8, i8* %1, align 1
ret i8 %2 ret i8 %2
lookup.throw: ; preds = %entry
call void @runtime.lookupPanic(i8* undef) #0
unreachable
} }
attributes #0 = { nounwind } attributes #0 = { nounwind }