Этот коммит содержится в:
Ayke van Laethem 2019-11-23 00:15:06 +01:00 коммит произвёл Ron Evans
родитель 7733666fa8
коммит b8d20535ba
4 изменённых файлов: 67 добавлений и 67 удалений

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

@ -11,11 +11,11 @@ import (
"tinygo.org/x/go-llvm" "tinygo.org/x/go-llvm"
) )
// emitLookupBoundsCheck emits a bounds check before doing a lookup into a // createLookupBoundsCheck emits a bounds check before doing a lookup into a
// slice. This is required by the Go language spec: an index out of bounds must // slice. This is required by the Go language spec: an index out of bounds must
// cause a panic. // cause a panic.
func (c *Compiler) emitLookupBoundsCheck(frame *Frame, arrayLen, index llvm.Value, indexType types.Type) { func (b *builder) createLookupBoundsCheck(arrayLen, index llvm.Value, indexType types.Type) {
if frame.fn.IsNoBounds() { if b.fn.IsNoBounds() {
// The //go:nobounds pragma was added to the function to avoid bounds // The //go:nobounds pragma was added to the function to avoid bounds
// checking. // checking.
return return
@ -25,29 +25,29 @@ func (c *Compiler) emitLookupBoundsCheck(frame *Frame, arrayLen, index llvm.Valu
// Sometimes, the index can be e.g. an uint8 or int8, and we have to // Sometimes, the index can be e.g. an uint8 or int8, and we have to
// correctly extend that type. // correctly extend that type.
if indexType.Underlying().(*types.Basic).Info()&types.IsUnsigned == 0 { if indexType.Underlying().(*types.Basic).Info()&types.IsUnsigned == 0 {
index = c.builder.CreateZExt(index, arrayLen.Type(), "") index = b.CreateZExt(index, arrayLen.Type(), "")
} else { } else {
index = c.builder.CreateSExt(index, arrayLen.Type(), "") index = b.CreateSExt(index, arrayLen.Type(), "")
} }
} else if index.Type().IntTypeWidth() > arrayLen.Type().IntTypeWidth() { } else if index.Type().IntTypeWidth() > arrayLen.Type().IntTypeWidth() {
// The index is bigger than the array length type, so extend it. // The index is bigger than the array length type, so extend it.
arrayLen = c.builder.CreateZExt(arrayLen, index.Type(), "") arrayLen = b.CreateZExt(arrayLen, index.Type(), "")
} }
// Now do the bounds check: index >= arrayLen // Now do the bounds check: index >= arrayLen
outOfBounds := c.builder.CreateICmp(llvm.IntUGE, index, arrayLen, "") outOfBounds := b.CreateICmp(llvm.IntUGE, index, arrayLen, "")
c.createRuntimeAssert(frame, outOfBounds, "lookup", "lookupPanic") b.createRuntimeAssert(outOfBounds, "lookup", "lookupPanic")
} }
// emitSliceBoundsCheck emits a bounds check before a slicing operation to make // createSliceBoundsCheck emits a bounds check before a slicing operation to make
// sure it is within bounds. // sure it is within bounds.
// //
// This function is both used for slicing a slice (low and high have their // This function is both used for slicing a slice (low and high have their
// normal meaning) and for creating a new slice, where 'capacity' means the // normal meaning) and for creating a new slice, where 'capacity' means the
// biggest possible slice capacity, 'low' means len and 'high' means cap. The // biggest possible slice capacity, 'low' means len and 'high' means cap. The
// logic is the same in both cases. // logic is the same in both cases.
func (c *Compiler) emitSliceBoundsCheck(frame *Frame, capacity, low, high, max llvm.Value, lowType, highType, maxType *types.Basic) { func (b *builder) createSliceBoundsCheck(capacity, low, high, max llvm.Value, lowType, highType, maxType *types.Basic) {
if frame.fn.IsNoBounds() { if b.fn.IsNoBounds() {
// The //go:nobounds pragma was added to the function to avoid bounds // The //go:nobounds pragma was added to the function to avoid bounds
// checking. // checking.
return return
@ -65,45 +65,45 @@ func (c *Compiler) emitSliceBoundsCheck(frame *Frame, capacity, low, high, max l
capacityType = max.Type() capacityType = max.Type()
} }
if capacityType != capacity.Type() { if capacityType != capacity.Type() {
capacity = c.builder.CreateZExt(capacity, capacityType, "") capacity = b.CreateZExt(capacity, capacityType, "")
} }
// Extend low and high to be the same size as capacity. // Extend low and high to be the same size as capacity.
if low.Type().IntTypeWidth() < capacityType.IntTypeWidth() { if low.Type().IntTypeWidth() < capacityType.IntTypeWidth() {
if lowType.Info()&types.IsUnsigned != 0 { if lowType.Info()&types.IsUnsigned != 0 {
low = c.builder.CreateZExt(low, capacityType, "") low = b.CreateZExt(low, capacityType, "")
} else { } else {
low = c.builder.CreateSExt(low, capacityType, "") low = b.CreateSExt(low, capacityType, "")
} }
} }
if high.Type().IntTypeWidth() < capacityType.IntTypeWidth() { if high.Type().IntTypeWidth() < capacityType.IntTypeWidth() {
if highType.Info()&types.IsUnsigned != 0 { if highType.Info()&types.IsUnsigned != 0 {
high = c.builder.CreateZExt(high, capacityType, "") high = b.CreateZExt(high, capacityType, "")
} else { } else {
high = c.builder.CreateSExt(high, capacityType, "") high = b.CreateSExt(high, capacityType, "")
} }
} }
if max.Type().IntTypeWidth() < capacityType.IntTypeWidth() { if max.Type().IntTypeWidth() < capacityType.IntTypeWidth() {
if maxType.Info()&types.IsUnsigned != 0 { if maxType.Info()&types.IsUnsigned != 0 {
max = c.builder.CreateZExt(max, capacityType, "") max = b.CreateZExt(max, capacityType, "")
} else { } else {
max = c.builder.CreateSExt(max, capacityType, "") max = b.CreateSExt(max, capacityType, "")
} }
} }
// Now do the bounds check: low > high || high > capacity // Now do the bounds check: low > high || high > capacity
outOfBounds1 := c.builder.CreateICmp(llvm.IntUGT, low, high, "slice.lowhigh") outOfBounds1 := b.CreateICmp(llvm.IntUGT, low, high, "slice.lowhigh")
outOfBounds2 := c.builder.CreateICmp(llvm.IntUGT, high, max, "slice.highmax") outOfBounds2 := b.CreateICmp(llvm.IntUGT, high, max, "slice.highmax")
outOfBounds3 := c.builder.CreateICmp(llvm.IntUGT, max, capacity, "slice.maxcap") outOfBounds3 := b.CreateICmp(llvm.IntUGT, max, capacity, "slice.maxcap")
outOfBounds := c.builder.CreateOr(outOfBounds1, outOfBounds2, "slice.lowmax") outOfBounds := b.CreateOr(outOfBounds1, outOfBounds2, "slice.lowmax")
outOfBounds = c.builder.CreateOr(outOfBounds, outOfBounds3, "slice.lowcap") outOfBounds = b.CreateOr(outOfBounds, outOfBounds3, "slice.lowcap")
c.createRuntimeAssert(frame, outOfBounds, "slice", "slicePanic") b.createRuntimeAssert(outOfBounds, "slice", "slicePanic")
} }
// emitChanBoundsCheck emits a bounds check before creating a new channel to // createChanBoundsCheck creates a bounds check before creating a new channel to
// check that the value is not too big for runtime.chanMake. // check that the value is not too big for runtime.chanMake.
func (c *Compiler) emitChanBoundsCheck(frame *Frame, elementSize uint64, bufSize llvm.Value, bufSizeType *types.Basic, pos token.Pos) { func (b *builder) createChanBoundsCheck(elementSize uint64, bufSize llvm.Value, bufSizeType *types.Basic, pos token.Pos) {
if frame.fn.IsNoBounds() { if b.fn.IsNoBounds() {
// The //go:nobounds pragma was added to the function to avoid bounds // The //go:nobounds pragma was added to the function to avoid bounds
// checking. // checking.
return return
@ -111,23 +111,23 @@ func (c *Compiler) emitChanBoundsCheck(frame *Frame, elementSize uint64, bufSize
// Check whether the bufSize parameter must be cast to a wider integer for // Check whether the bufSize parameter must be cast to a wider integer for
// comparison. // comparison.
if bufSize.Type().IntTypeWidth() < c.uintptrType.IntTypeWidth() { if bufSize.Type().IntTypeWidth() < b.uintptrType.IntTypeWidth() {
if bufSizeType.Info()&types.IsUnsigned != 0 { if bufSizeType.Info()&types.IsUnsigned != 0 {
// Unsigned, so zero-extend to uint type. // Unsigned, so zero-extend to uint type.
bufSizeType = types.Typ[types.Uint] bufSizeType = types.Typ[types.Uint]
bufSize = c.builder.CreateZExt(bufSize, c.intType, "") bufSize = b.CreateZExt(bufSize, b.intType, "")
} else { } else {
// Signed, so sign-extend to int type. // Signed, so sign-extend to int type.
bufSizeType = types.Typ[types.Int] bufSizeType = types.Typ[types.Int]
bufSize = c.builder.CreateSExt(bufSize, c.intType, "") bufSize = b.CreateSExt(bufSize, b.intType, "")
} }
} }
// Calculate (^uintptr(0)) >> 1, which is the max value that fits in an // Calculate (^uintptr(0)) >> 1, which is the max value that fits in an
// uintptr if uintptrs were signed. // uintptr if uintptrs were signed.
maxBufSize := llvm.ConstLShr(llvm.ConstNot(llvm.ConstInt(c.uintptrType, 0, false)), llvm.ConstInt(c.uintptrType, 1, false)) maxBufSize := llvm.ConstLShr(llvm.ConstNot(llvm.ConstInt(b.uintptrType, 0, false)), llvm.ConstInt(b.uintptrType, 1, false))
if elementSize > maxBufSize.ZExtValue() { if elementSize > maxBufSize.ZExtValue() {
c.addError(pos, fmt.Sprintf("channel element type is too big (%v bytes)", elementSize)) b.addError(pos, fmt.Sprintf("channel element type is too big (%v bytes)", elementSize))
return return
} }
// Avoid divide-by-zero. // Avoid divide-by-zero.
@ -136,7 +136,7 @@ func (c *Compiler) emitChanBoundsCheck(frame *Frame, elementSize uint64, bufSize
} }
// Make the maxBufSize actually the maximum allowed value (in number of // Make the maxBufSize actually the maximum allowed value (in number of
// elements in the channel buffer). // elements in the channel buffer).
maxBufSize = llvm.ConstUDiv(maxBufSize, llvm.ConstInt(c.uintptrType, elementSize, false)) maxBufSize = llvm.ConstUDiv(maxBufSize, llvm.ConstInt(b.uintptrType, elementSize, false))
// Make sure maxBufSize has the same type as bufSize. // Make sure maxBufSize has the same type as bufSize.
if maxBufSize.Type() != bufSize.Type() { if maxBufSize.Type() != bufSize.Type() {
@ -144,14 +144,14 @@ func (c *Compiler) emitChanBoundsCheck(frame *Frame, elementSize uint64, bufSize
} }
// Do the check for a too large (or negative) buffer size. // Do the check for a too large (or negative) buffer size.
bufSizeTooBig := c.builder.CreateICmp(llvm.IntUGE, bufSize, maxBufSize, "") bufSizeTooBig := b.CreateICmp(llvm.IntUGE, bufSize, maxBufSize, "")
c.createRuntimeAssert(frame, bufSizeTooBig, "chan", "chanMakePanic") b.createRuntimeAssert(bufSizeTooBig, "chan", "chanMakePanic")
} }
// emitNilCheck checks whether the given pointer is nil, and panics if it is. It // createNilCheck checks whether the given pointer is nil, and panics if it is.
// has no effect in well-behaved programs, but makes sure no uncaught nil // It has no effect in well-behaved programs, but makes sure no uncaught nil
// pointer dereferences exist in valid Go code. // pointer dereferences exist in valid Go code.
func (c *Compiler) emitNilCheck(frame *Frame, ptr llvm.Value, blockPrefix string) { func (b *builder) createNilCheck(ptr llvm.Value, blockPrefix string) {
// Check whether we need to emit this check at all. // Check whether we need to emit this check at all.
if !ptr.IsAGlobalValue().IsNil() { if !ptr.IsAGlobalValue().IsNil() {
return return
@ -167,22 +167,22 @@ func (c *Compiler) emitNilCheck(frame *Frame, ptr llvm.Value, blockPrefix string
// https://reviews.llvm.org/D60047 for details. Pointer capturing // https://reviews.llvm.org/D60047 for details. Pointer capturing
// unfortunately breaks escape analysis, so we use this trick to let the // unfortunately breaks escape analysis, so we use this trick to let the
// functionattr pass know that this pointer doesn't really escape. // functionattr pass know that this pointer doesn't really escape.
ptr = c.builder.CreateBitCast(ptr, c.i8ptrType, "") ptr = b.CreateBitCast(ptr, b.i8ptrType, "")
isnil = c.createRuntimeCall("isnil", []llvm.Value{ptr}, "") isnil = b.createRuntimeCall("isnil", []llvm.Value{ptr}, "")
} else { } else {
// Do the nil check using a regular icmp. This can happen with function // Do the nil check using a regular icmp. This can happen with function
// pointers on AVR, which don't benefit from escape analysis anyway. // pointers on AVR, which don't benefit from escape analysis anyway.
nilptr := llvm.ConstPointerNull(ptr.Type()) nilptr := llvm.ConstPointerNull(ptr.Type())
isnil = c.builder.CreateICmp(llvm.IntEQ, ptr, nilptr, "") isnil = b.CreateICmp(llvm.IntEQ, ptr, nilptr, "")
} }
// Emit the nil check in IR. // Emit the nil check in IR.
c.createRuntimeAssert(frame, isnil, blockPrefix, "nilPanic") b.createRuntimeAssert(isnil, blockPrefix, "nilPanic")
} }
// createRuntimeAssert is a common function to create a new branch on an assert // 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). // bool, calling an assert func if the assert value is true (1).
func (c *Compiler) createRuntimeAssert(frame *Frame, assert llvm.Value, blockPrefix, assertFunc string) { func (b *builder) createRuntimeAssert(assert llvm.Value, blockPrefix, assertFunc string) {
// Check whether we can resolve this check at compile time. // Check whether we can resolve this check at compile time.
if !assert.IsAConstantInt().IsNil() { if !assert.IsAConstantInt().IsNil() {
val := assert.ZExtValue() val := assert.ZExtValue()
@ -193,18 +193,18 @@ func (c *Compiler) createRuntimeAssert(frame *Frame, assert llvm.Value, blockPre
} }
} }
faultBlock := c.ctx.AddBasicBlock(frame.fn.LLVMFn, blockPrefix+".throw") faultBlock := b.ctx.AddBasicBlock(b.fn.LLVMFn, blockPrefix+".throw")
nextBlock := c.ctx.AddBasicBlock(frame.fn.LLVMFn, blockPrefix+".next") nextBlock := b.ctx.AddBasicBlock(b.fn.LLVMFn, blockPrefix+".next")
frame.blockExits[frame.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.
c.builder.CreateCondBr(assert, faultBlock, nextBlock) b.CreateCondBr(assert, faultBlock, nextBlock)
// Fail: the assert triggered so panic. // Fail: the assert triggered so panic.
c.builder.SetInsertPointAtEnd(faultBlock) b.SetInsertPointAtEnd(faultBlock)
c.createRuntimeCall(assertFunc, nil, "") b.createRuntimeCall(assertFunc, nil, "")
c.builder.CreateUnreachable() b.CreateUnreachable()
// Ok: assert didn't trigger so continue normally. // Ok: assert didn't trigger so continue normally.
c.builder.SetInsertPointAtEnd(nextBlock) b.SetInsertPointAtEnd(nextBlock)
} }

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

@ -15,7 +15,7 @@ func (c *Compiler) emitMakeChan(frame *Frame, expr *ssa.MakeChan) llvm.Value {
elementSize := c.targetData.TypeAllocSize(c.getLLVMType(expr.Type().(*types.Chan).Elem())) elementSize := c.targetData.TypeAllocSize(c.getLLVMType(expr.Type().(*types.Chan).Elem()))
elementSizeValue := llvm.ConstInt(c.uintptrType, elementSize, false) elementSizeValue := llvm.ConstInt(c.uintptrType, elementSize, false)
bufSize := frame.getValue(expr.Size) bufSize := frame.getValue(expr.Size)
c.emitChanBoundsCheck(frame, elementSize, bufSize, expr.Size.Type().Underlying().(*types.Basic), expr.Pos()) frame.createChanBoundsCheck(elementSize, bufSize, expr.Size.Type().Underlying().(*types.Basic), expr.Pos())
if bufSize.Type().IntTypeWidth() < c.uintptrType.IntTypeWidth() { if bufSize.Type().IntTypeWidth() < c.uintptrType.IntTypeWidth() {
bufSize = c.builder.CreateZExt(bufSize, c.uintptrType, "") bufSize = c.builder.CreateZExt(bufSize, c.uintptrType, "")
} else if bufSize.Type().IntTypeWidth() > c.uintptrType.IntTypeWidth() { } else if bufSize.Type().IntTypeWidth() > c.uintptrType.IntTypeWidth() {

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

@ -347,7 +347,7 @@ func (c *Compiler) Compile(mainPath string) []error {
c.mod.NamedFunction("runtime.alloc").AddAttributeAtIndex(0, getAttr(attrName)) c.mod.NamedFunction("runtime.alloc").AddAttributeAtIndex(0, getAttr(attrName))
} }
// See emitNilCheck in asserts.go. // See createNilCheck in asserts.go.
c.mod.NamedFunction("runtime.isnil").AddAttributeAtIndex(1, nocapture) c.mod.NamedFunction("runtime.isnil").AddAttributeAtIndex(1, nocapture)
// On *nix systems, the "abort" functuion in libc is used to handle fatal panics. // On *nix systems, the "abort" functuion in libc is used to handle fatal panics.
@ -1135,7 +1135,7 @@ func (c *Compiler) parseInstr(frame *Frame, instr ssa.Instruction) {
case *ssa.Store: case *ssa.Store:
llvmAddr := frame.getValue(instr.Addr) llvmAddr := frame.getValue(instr.Addr)
llvmVal := frame.getValue(instr.Val) llvmVal := frame.getValue(instr.Val)
c.emitNilCheck(frame, llvmAddr, "store") frame.createNilCheck(llvmAddr, "store")
if c.targetData.TypeAllocSize(llvmVal.Type()) == 0 { if c.targetData.TypeAllocSize(llvmVal.Type()) == 0 {
// nothing to store // nothing to store
return return
@ -1392,7 +1392,7 @@ func (c *Compiler) parseCall(frame *Frame, instr *ssa.CallCommon) (llvm.Value, e
// This is a func value, which cannot be called directly. We have to // This is a func value, which cannot be called directly. We have to
// extract the function pointer and context first from the func value. // extract the function pointer and context first from the func value.
funcPtr, context := c.decodeFuncValue(value, instr.Value.Type().Underlying().(*types.Signature)) funcPtr, context := c.decodeFuncValue(value, instr.Value.Type().Underlying().(*types.Signature))
c.emitNilCheck(frame, funcPtr, "fpcall") frame.createNilCheck(funcPtr, "fpcall")
return c.parseFunctionCall(frame, instr.Args, funcPtr, context, false), nil return c.parseFunctionCall(frame, instr.Args, funcPtr, context, false), nil
} }
} }
@ -1524,7 +1524,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
// > For an operand x of type T, the address operation &x generates a // > For an operand x of type T, the address operation &x generates a
// > pointer of type *T to x. [...] If the evaluation of x would cause a // > pointer of type *T to x. [...] If the evaluation of x would cause a
// > run-time panic, then the evaluation of &x does too. // > run-time panic, then the evaluation of &x does too.
c.emitNilCheck(frame, val, "gep") frame.createNilCheck(val, "gep")
// Do a GEP on the pointer to get the field address. // Do a GEP on the pointer to get the field address.
indices := []llvm.Value{ indices := []llvm.Value{
llvm.ConstInt(c.ctx.Int32Type(), 0, false), llvm.ConstInt(c.ctx.Int32Type(), 0, false),
@ -1542,7 +1542,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
// Check bounds. // Check bounds.
arrayLen := expr.X.Type().(*types.Array).Len() arrayLen := expr.X.Type().(*types.Array).Len()
arrayLenLLVM := llvm.ConstInt(c.uintptrType, uint64(arrayLen), false) arrayLenLLVM := llvm.ConstInt(c.uintptrType, uint64(arrayLen), false)
c.emitLookupBoundsCheck(frame, arrayLenLLVM, index, expr.Index.Type()) frame.createLookupBoundsCheck(arrayLenLLVM, index, expr.Index.Type())
// Can't load directly from array (as index is non-constant), so have to // Can't load directly from array (as index is non-constant), so have to
// do it using an alloca+gep+load. // do it using an alloca+gep+load.
@ -1572,7 +1572,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
// > generates a pointer of type *T to x. [...] If the // > generates a pointer of type *T to x. [...] If the
// > evaluation of x would cause a run-time panic, then the // > evaluation of x would cause a run-time panic, then the
// > evaluation of &x does too. // > evaluation of &x does too.
c.emitNilCheck(frame, bufptr, "gep") frame.createNilCheck(bufptr, "gep")
default: default:
return llvm.Value{}, c.makeError(expr.Pos(), "todo: indexaddr: "+typ.String()) return llvm.Value{}, c.makeError(expr.Pos(), "todo: indexaddr: "+typ.String())
} }
@ -1584,7 +1584,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
} }
// Bounds check. // Bounds check.
c.emitLookupBoundsCheck(frame, buflen, index, expr.Index.Type()) frame.createLookupBoundsCheck(buflen, index, expr.Index.Type())
switch expr.X.Type().Underlying().(type) { switch expr.X.Type().Underlying().(type) {
case *types.Pointer: case *types.Pointer:
@ -1610,7 +1610,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
// Bounds check. // Bounds check.
length := c.builder.CreateExtractValue(value, 1, "len") length := c.builder.CreateExtractValue(value, 1, "len")
c.emitLookupBoundsCheck(frame, length, index, expr.Index.Type()) frame.createLookupBoundsCheck(length, index, expr.Index.Type())
// Lookup byte // Lookup byte
buf := c.builder.CreateExtractValue(value, 0, "") buf := c.builder.CreateExtractValue(value, 0, "")
@ -1654,7 +1654,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
// Bounds checking. // Bounds checking.
lenType := expr.Len.Type().(*types.Basic) lenType := expr.Len.Type().(*types.Basic)
capType := expr.Cap.Type().(*types.Basic) capType := expr.Cap.Type().(*types.Basic)
c.emitSliceBoundsCheck(frame, maxSize, sliceLen, sliceCap, sliceCap, lenType, capType, capType) frame.createSliceBoundsCheck(maxSize, sliceLen, sliceCap, sliceCap, lenType, capType, capType)
// Allocate the backing array. // Allocate the backing array.
sliceCapCast, err := c.parseConvert(expr.Cap.Type(), types.Typ[types.Uintptr], sliceCap, expr.Pos()) sliceCapCast, err := c.parseConvert(expr.Cap.Type(), types.Typ[types.Uintptr], sliceCap, expr.Pos())
@ -1792,7 +1792,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
low, low,
} }
c.emitSliceBoundsCheck(frame, llvmLen, low, high, max, lowType, highType, maxType) frame.createSliceBoundsCheck(llvmLen, low, high, max, lowType, highType, maxType)
// Truncate ints bigger than uintptr. This is after the bounds // Truncate ints bigger than uintptr. This is after the bounds
// check so it's safe. // check so it's safe.
@ -1832,7 +1832,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
max = oldCap max = oldCap
} }
c.emitSliceBoundsCheck(frame, oldCap, low, high, max, lowType, highType, maxType) frame.createSliceBoundsCheck(oldCap, low, high, max, lowType, highType, maxType)
// Truncate ints bigger than uintptr. This is after the bounds // Truncate ints bigger than uintptr. This is after the bounds
// check so it's safe. // check so it's safe.
@ -1875,7 +1875,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
high = oldLen high = oldLen
} }
c.emitSliceBoundsCheck(frame, oldLen, low, high, high, lowType, highType, maxType) frame.createSliceBoundsCheck(oldLen, low, high, high, lowType, highType, maxType)
// Truncate ints bigger than uintptr. This is after the bounds // Truncate ints bigger than uintptr. This is after the bounds
// check so it's safe. // check so it's safe.
@ -2559,7 +2559,7 @@ func (c *Compiler) parseUnOp(frame *Frame, unop *ssa.UnOp) (llvm.Value, error) {
} }
return c.builder.CreateBitCast(fn, c.i8ptrType, ""), nil return c.builder.CreateBitCast(fn, c.i8ptrType, ""), nil
} else { } else {
c.emitNilCheck(frame, x, "deref") frame.createNilCheck(x, "deref")
load := c.builder.CreateLoad(x, "") load := c.builder.CreateLoad(x, "")
return load, nil return load, nil
} }

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

@ -10,7 +10,7 @@ import (
func (c *Compiler) emitVolatileLoad(frame *Frame, instr *ssa.CallCommon) (llvm.Value, error) { func (c *Compiler) emitVolatileLoad(frame *Frame, instr *ssa.CallCommon) (llvm.Value, error) {
addr := frame.getValue(instr.Args[0]) addr := frame.getValue(instr.Args[0])
c.emitNilCheck(frame, addr, "deref") frame.createNilCheck(addr, "deref")
val := c.builder.CreateLoad(addr, "") val := c.builder.CreateLoad(addr, "")
val.SetVolatile(true) val.SetVolatile(true)
return val, nil return val, nil
@ -19,7 +19,7 @@ func (c *Compiler) emitVolatileLoad(frame *Frame, instr *ssa.CallCommon) (llvm.V
func (c *Compiler) emitVolatileStore(frame *Frame, instr *ssa.CallCommon) (llvm.Value, error) { func (c *Compiler) emitVolatileStore(frame *Frame, instr *ssa.CallCommon) (llvm.Value, error) {
addr := frame.getValue(instr.Args[0]) addr := frame.getValue(instr.Args[0])
val := frame.getValue(instr.Args[1]) val := frame.getValue(instr.Args[1])
c.emitNilCheck(frame, addr, "deref") frame.createNilCheck(addr, "deref")
store := c.builder.CreateStore(val, addr) store := c.builder.CreateStore(val, addr)
store.SetVolatile(true) store.SetVolatile(true)
return llvm.Value{}, nil return llvm.Value{}, nil