diff options
author | Ayke van Laethem <[email protected]> | 2020-03-11 19:27:44 +0100 |
---|---|---|
committer | Ron Evans <[email protected]> | 2020-03-13 16:15:36 -0700 |
commit | 571a4122669c0f314de7e016b8a302207c803a54 (patch) | |
tree | 39783bae5c0d030199549abfd86b310a71ea1cd3 /compiler/asserts.go | |
parent | 79dae62c781bc3fe6df76d5a609f62fcc7a43310 (diff) | |
download | tinygo-571a4122669c0f314de7e016b8a302207c803a54.tar.gz tinygo-571a4122669c0f314de7e016b8a302207c803a54.zip |
compiler: merge some redundant assertion code
Diffstat (limited to 'compiler/asserts.go')
-rw-r--r-- | compiler/asserts.go | 91 |
1 files changed, 31 insertions, 60 deletions
diff --git a/compiler/asserts.go b/compiler/asserts.go index ab519842a..daeecadb9 100644 --- a/compiler/asserts.go +++ b/compiler/asserts.go @@ -34,21 +34,9 @@ func (c *Compiler) emitLookupBoundsCheck(frame *Frame, arrayLen, index llvm.Valu arrayLen = c.builder.CreateZExt(arrayLen, index.Type(), "") } - faultBlock := c.ctx.AddBasicBlock(frame.fn.LLVMFn, "lookup.outofbounds") - nextBlock := c.ctx.AddBasicBlock(frame.fn.LLVMFn, "lookup.next") - frame.blockExits[frame.currentBlock] = nextBlock // adjust outgoing block for phi nodes - // Now do the bounds check: index >= arrayLen outOfBounds := c.builder.CreateICmp(llvm.IntUGE, index, arrayLen, "") - c.builder.CreateCondBr(outOfBounds, faultBlock, nextBlock) - - // Fail: this is a nil pointer, exit with a panic. - c.builder.SetInsertPointAtEnd(faultBlock) - c.createRuntimeCall("lookupPanic", nil, "") - c.builder.CreateUnreachable() - - // Ok: this is a valid pointer. - c.builder.SetInsertPointAtEnd(nextBlock) + c.createRuntimeAssert(frame, outOfBounds, "lookup", "lookupPanic") } // emitSliceBoundsCheck emits a bounds check before a slicing operation to make @@ -103,25 +91,13 @@ func (c *Compiler) emitSliceBoundsCheck(frame *Frame, capacity, low, high, max l } } - faultBlock := c.ctx.AddBasicBlock(frame.fn.LLVMFn, "slice.outofbounds") - nextBlock := c.ctx.AddBasicBlock(frame.fn.LLVMFn, "slice.next") - frame.blockExits[frame.currentBlock] = nextBlock // adjust outgoing block for phi nodes - // Now do the bounds check: low > high || high > capacity outOfBounds1 := c.builder.CreateICmp(llvm.IntUGT, low, high, "slice.lowhigh") outOfBounds2 := c.builder.CreateICmp(llvm.IntUGT, high, max, "slice.highmax") outOfBounds3 := c.builder.CreateICmp(llvm.IntUGT, max, capacity, "slice.maxcap") outOfBounds := c.builder.CreateOr(outOfBounds1, outOfBounds2, "slice.lowmax") outOfBounds = c.builder.CreateOr(outOfBounds, outOfBounds3, "slice.lowcap") - c.builder.CreateCondBr(outOfBounds, faultBlock, nextBlock) - - // Fail: this is a nil pointer, exit with a panic. - c.builder.SetInsertPointAtEnd(faultBlock) - c.createRuntimeCall("slicePanic", nil, "") - c.builder.CreateUnreachable() - - // Ok: this is a valid pointer. - c.builder.SetInsertPointAtEnd(nextBlock) + c.createRuntimeAssert(frame, outOfBounds, "slice", "slicePanic") } // emitChanBoundsCheck emits a bounds check before creating a new channel to @@ -167,32 +143,9 @@ func (c *Compiler) emitChanBoundsCheck(frame *Frame, elementSize uint64, bufSize maxBufSize = llvm.ConstZExt(maxBufSize, bufSize.Type()) } + // Do the check for a too large (or negative) buffer size. bufSizeTooBig := c.builder.CreateICmp(llvm.IntUGE, bufSize, maxBufSize, "") - // Check whether we can resolve this check at compile time. - if !bufSizeTooBig.IsAConstantInt().IsNil() { - val := bufSizeTooBig.ZExtValue() - if val == 0 { - // Everything is constant so the check does not have to be emitted - // in IR. This avoids emitting some redundant IR in the vast - // majority of cases. - return - } - } - - faultBlock := c.ctx.AddBasicBlock(frame.fn.LLVMFn, "chan.outofbounds") - nextBlock := c.ctx.AddBasicBlock(frame.fn.LLVMFn, "chan.next") - frame.blockExits[frame.currentBlock] = nextBlock // adjust outgoing block for phi nodes - - // Now branch to the out-of-bounds or the regular block. - c.builder.CreateCondBr(bufSizeTooBig, faultBlock, nextBlock) - - // Fail: this channel is created with an invalid size parameter. - c.builder.SetInsertPointAtEnd(faultBlock) - c.createRuntimeCall("chanMakePanic", nil, "") - c.builder.CreateUnreachable() - - // Ok: this channel value is not too big. - c.builder.SetInsertPointAtEnd(nextBlock) + c.createRuntimeAssert(frame, bufSizeTooBig, "chan", "chanMakePanic") } // emitNilCheck checks whether the given pointer is nil, and panics if it is. It @@ -204,11 +157,6 @@ func (c *Compiler) emitNilCheck(frame *Frame, ptr llvm.Value, blockPrefix string return } - // Check whether this is a nil pointer. - faultBlock := c.ctx.AddBasicBlock(frame.fn.LLVMFn, blockPrefix+".nil") - nextBlock := c.ctx.AddBasicBlock(frame.fn.LLVMFn, blockPrefix+".next") - frame.blockExits[frame.currentBlock] = nextBlock // adjust outgoing block for phi nodes - // Compare against nil. var isnil llvm.Value if ptr.Type().PointerAddressSpace() == 0 { @@ -227,13 +175,36 @@ func (c *Compiler) emitNilCheck(frame *Frame, ptr llvm.Value, blockPrefix string nilptr := llvm.ConstPointerNull(ptr.Type()) isnil = c.builder.CreateICmp(llvm.IntEQ, ptr, nilptr, "") } - c.builder.CreateCondBr(isnil, faultBlock, nextBlock) - // Fail: this is a nil pointer, exit with a panic. + // Emit the nil check in IR. + c.createRuntimeAssert(frame, isnil, blockPrefix, "nilPanic") +} + +// createRuntimeAssert is a common function to create a new branch on an assert +// bool, calling an assert func if the assert value is true (1). +func (c *Compiler) createRuntimeAssert(frame *Frame, assert llvm.Value, blockPrefix, assertFunc string) { + // Check whether we can resolve this check at compile time. + if !assert.IsAConstantInt().IsNil() { + val := assert.ZExtValue() + if val == 0 { + // Everything is constant so the check does not have to be emitted + // in IR. This avoids emitting some redundant IR. + return + } + } + + faultBlock := c.ctx.AddBasicBlock(frame.fn.LLVMFn, blockPrefix+".throw") + nextBlock := c.ctx.AddBasicBlock(frame.fn.LLVMFn, blockPrefix+".next") + frame.blockExits[frame.currentBlock] = nextBlock // adjust outgoing block for phi nodes + + // Now branch to the out-of-bounds or the regular block. + c.builder.CreateCondBr(assert, faultBlock, nextBlock) + + // Fail: the assert triggered so panic. c.builder.SetInsertPointAtEnd(faultBlock) - c.createRuntimeCall("nilPanic", nil, "") + c.createRuntimeCall(assertFunc, nil, "") c.builder.CreateUnreachable() - // Ok: this is a valid pointer. + // Ok: assert didn't trigger so continue normally. c.builder.SetInsertPointAtEnd(nextBlock) } |