aboutsummaryrefslogtreecommitdiffhomepage
path: root/compiler/asserts.go
diff options
context:
space:
mode:
authorAyke van Laethem <[email protected]>2020-03-11 19:27:44 +0100
committerRon Evans <[email protected]>2020-03-13 16:15:36 -0700
commit571a4122669c0f314de7e016b8a302207c803a54 (patch)
tree39783bae5c0d030199549abfd86b310a71ea1cd3 /compiler/asserts.go
parent79dae62c781bc3fe6df76d5a609f62fcc7a43310 (diff)
downloadtinygo-571a4122669c0f314de7e016b8a302207c803a54.tar.gz
tinygo-571a4122669c0f314de7e016b8a302207c803a54.zip
compiler: merge some redundant assertion code
Diffstat (limited to 'compiler/asserts.go')
-rw-r--r--compiler/asserts.go91
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)
}