compiler: mark all GEPs as inbounds

In Go, it is not possible to construct pointers that are out of bounds
(and not null), so let LLVM know about this fact.

This leads to a significant code size reduction, around 3% in many
cases.
Этот коммит содержится в:
Ayke van Laethem 2019-04-25 11:21:14 +02:00 коммит произвёл Ron Evans
родитель d155e31b64
коммит 9a3d0683b3
3 изменённых файлов: 21 добавлений и 17 удалений

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

@ -1324,7 +1324,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
llvm.ConstInt(c.ctx.Int32Type(), 0, false), llvm.ConstInt(c.ctx.Int32Type(), 0, false),
llvm.ConstInt(c.ctx.Int32Type(), uint64(expr.Field), false), llvm.ConstInt(c.ctx.Int32Type(), uint64(expr.Field), false),
} }
return c.builder.CreateGEP(val, indices, ""), nil return c.builder.CreateInBoundsGEP(val, indices, ""), nil
} }
case *ssa.Function: case *ssa.Function:
panic("function is not an expression") panic("function is not an expression")
@ -1344,7 +1344,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
alloca := c.builder.CreateAlloca(array.Type(), "index.alloca") alloca := c.builder.CreateAlloca(array.Type(), "index.alloca")
c.builder.CreateStore(array, alloca) c.builder.CreateStore(array, alloca)
zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false) zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false)
ptr := c.builder.CreateGEP(alloca, []llvm.Value{zero, index}, "index.gep") ptr := c.builder.CreateInBoundsGEP(alloca, []llvm.Value{zero, index}, "index.gep")
return c.builder.CreateLoad(ptr, "index.load"), nil return c.builder.CreateLoad(ptr, "index.load"), nil
case *ssa.IndexAddr: case *ssa.IndexAddr:
val := c.getValue(frame, expr.X) val := c.getValue(frame, expr.X)
@ -1385,9 +1385,9 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
llvm.ConstInt(c.ctx.Int32Type(), 0, false), llvm.ConstInt(c.ctx.Int32Type(), 0, false),
index, index,
} }
return c.builder.CreateGEP(bufptr, indices, ""), nil return c.builder.CreateInBoundsGEP(bufptr, indices, ""), nil
case *types.Slice: case *types.Slice:
return c.builder.CreateGEP(bufptr, []llvm.Value{index}, ""), nil return c.builder.CreateInBoundsGEP(bufptr, []llvm.Value{index}, ""), nil
default: default:
panic("unreachable") panic("unreachable")
} }
@ -1407,7 +1407,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
// Lookup byte // Lookup byte
buf := c.builder.CreateExtractValue(value, 0, "") buf := c.builder.CreateExtractValue(value, 0, "")
bufPtr := c.builder.CreateGEP(buf, []llvm.Value{index}, "") bufPtr := c.builder.CreateInBoundsGEP(buf, []llvm.Value{index}, "")
return c.builder.CreateLoad(bufPtr, ""), nil return c.builder.CreateLoad(bufPtr, ""), nil
case *types.Map: case *types.Map:
valueType := expr.Type() valueType := expr.Type()
@ -1608,7 +1608,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
} }
sliceLen := c.builder.CreateSub(high, low, "slice.len") sliceLen := c.builder.CreateSub(high, low, "slice.len")
slicePtr := c.builder.CreateGEP(value, indices, "slice.ptr") slicePtr := c.builder.CreateInBoundsGEP(value, indices, "slice.ptr")
sliceCap := c.builder.CreateSub(llvmLen, low, "slice.cap") sliceCap := c.builder.CreateSub(llvmLen, low, "slice.cap")
slice := c.ctx.ConstStruct([]llvm.Value{ slice := c.ctx.ConstStruct([]llvm.Value{
@ -1641,7 +1641,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
high = c.builder.CreateTrunc(high, c.uintptrType, "") high = c.builder.CreateTrunc(high, c.uintptrType, "")
} }
newPtr := c.builder.CreateGEP(oldPtr, []llvm.Value{low}, "") newPtr := c.builder.CreateInBoundsGEP(oldPtr, []llvm.Value{low}, "")
newLen := c.builder.CreateSub(high, low, "") newLen := c.builder.CreateSub(high, low, "")
newCap := c.builder.CreateSub(oldCap, low, "") newCap := c.builder.CreateSub(oldCap, low, "")
slice := c.ctx.ConstStruct([]llvm.Value{ slice := c.ctx.ConstStruct([]llvm.Value{
@ -1676,7 +1676,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
high = c.builder.CreateTrunc(high, c.uintptrType, "") high = c.builder.CreateTrunc(high, c.uintptrType, "")
} }
newPtr := c.builder.CreateGEP(oldPtr, []llvm.Value{low}, "") newPtr := c.builder.CreateInBoundsGEP(oldPtr, []llvm.Value{low}, "")
newLen := c.builder.CreateSub(high, low, "") newLen := c.builder.CreateSub(high, low, "")
str := llvm.Undef(c.mod.GetTypeByName("runtime._string")) str := llvm.Undef(c.mod.GetTypeByName("runtime._string"))
str = c.builder.CreateInsertValue(str, newPtr, 0, "") str = c.builder.CreateInsertValue(str, newPtr, 0, "")
@ -2119,7 +2119,11 @@ func (c *Compiler) parseConvert(typeFrom, typeTo types.Type, value llvm.Value, p
// This pointer can be calculated from the original // This pointer can be calculated from the original
// ptrtoint instruction with a GEP. The leftover inttoptr // ptrtoint instruction with a GEP. The leftover inttoptr
// instruction is trivial to optimize away. // instruction is trivial to optimize away.
return c.builder.CreateGEP(origptr, []llvm.Value{index}, ""), nil // Making it an in bounds GEP even though it's easy to
// create a GEP that is not in bounds. However, we're
// talking about unsafe code here so the programmer has to
// be careful anyway.
return c.builder.CreateInBoundsGEP(origptr, []llvm.Value{index}, ""), nil
} }
} }
} }

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

@ -172,13 +172,13 @@ func (c *Compiler) emitRunDefers(frame *Frame) {
// stack = stack.next // stack = stack.next
// switch stack.callback { // switch stack.callback {
c.builder.SetInsertPointAtEnd(loop) c.builder.SetInsertPointAtEnd(loop)
nextStackGEP := c.builder.CreateGEP(deferData, []llvm.Value{ nextStackGEP := c.builder.CreateInBoundsGEP(deferData, []llvm.Value{
llvm.ConstInt(c.ctx.Int32Type(), 0, false), llvm.ConstInt(c.ctx.Int32Type(), 0, false),
llvm.ConstInt(c.ctx.Int32Type(), 1, false), // .next field llvm.ConstInt(c.ctx.Int32Type(), 1, false), // .next field
}, "stack.next.gep") }, "stack.next.gep")
nextStack := c.builder.CreateLoad(nextStackGEP, "stack.next") nextStack := c.builder.CreateLoad(nextStackGEP, "stack.next")
c.builder.CreateStore(nextStack, frame.deferPtr) c.builder.CreateStore(nextStack, frame.deferPtr)
gep := c.builder.CreateGEP(deferData, []llvm.Value{ gep := c.builder.CreateInBoundsGEP(deferData, []llvm.Value{
llvm.ConstInt(c.ctx.Int32Type(), 0, false), llvm.ConstInt(c.ctx.Int32Type(), 0, false),
llvm.ConstInt(c.ctx.Int32Type(), 0, false), // .callback field llvm.ConstInt(c.ctx.Int32Type(), 0, false), // .callback field
}, "callback.gep") }, "callback.gep")
@ -211,7 +211,7 @@ func (c *Compiler) emitRunDefers(frame *Frame) {
forwardParams := []llvm.Value{} forwardParams := []llvm.Value{}
zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false) zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false)
for i := 2; i < len(valueTypes); i++ { for i := 2; i < len(valueTypes); i++ {
gep := c.builder.CreateGEP(deferFramePtr, []llvm.Value{zero, llvm.ConstInt(c.ctx.Int32Type(), uint64(i), false)}, "gep") gep := c.builder.CreateInBoundsGEP(deferFramePtr, []llvm.Value{zero, llvm.ConstInt(c.ctx.Int32Type(), uint64(i), false)}, "gep")
forwardParam := c.builder.CreateLoad(gep, "param") forwardParam := c.builder.CreateLoad(gep, "param")
forwardParams = append(forwardParams, forwardParam) forwardParams = append(forwardParams, forwardParam)
} }
@ -242,7 +242,7 @@ func (c *Compiler) emitRunDefers(frame *Frame) {
forwardParams := []llvm.Value{} forwardParams := []llvm.Value{}
zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false) zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false)
for i := range callback.Params { for i := range callback.Params {
gep := c.builder.CreateGEP(deferFramePtr, []llvm.Value{zero, llvm.ConstInt(c.ctx.Int32Type(), uint64(i+2), false)}, "gep") gep := c.builder.CreateInBoundsGEP(deferFramePtr, []llvm.Value{zero, llvm.ConstInt(c.ctx.Int32Type(), uint64(i+2), false)}, "gep")
forwardParam := c.builder.CreateLoad(gep, "param") forwardParam := c.builder.CreateLoad(gep, "param")
forwardParams = append(forwardParams, forwardParam) forwardParams = append(forwardParams, forwardParam)
} }
@ -273,7 +273,7 @@ func (c *Compiler) emitRunDefers(frame *Frame) {
forwardParams := []llvm.Value{} forwardParams := []llvm.Value{}
zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false) zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false)
for i := 2; i < len(valueTypes); i++ { for i := 2; i < len(valueTypes); i++ {
gep := c.builder.CreateGEP(deferFramePtr, []llvm.Value{zero, llvm.ConstInt(c.ctx.Int32Type(), uint64(i), false)}, "") gep := c.builder.CreateInBoundsGEP(deferFramePtr, []llvm.Value{zero, llvm.ConstInt(c.ctx.Int32Type(), uint64(i), false)}, "")
forwardParam := c.builder.CreateLoad(gep, "param") forwardParam := c.builder.CreateLoad(gep, "param")
forwardParams = append(forwardParams, forwardParam) forwardParams = append(forwardParams, forwardParam)
} }

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

@ -485,7 +485,7 @@ func (c *Compiler) markAsyncFunctions() (needsScheduler bool, err error) {
llvm.ConstInt(c.ctx.Int1Type(), 0, false), llvm.ConstInt(c.ctx.Int1Type(), 0, false),
}, "task.promise.raw") }, "task.promise.raw")
promise := c.builder.CreateBitCast(promiseRaw, llvm.PointerType(promiseType, 0), "task.promise") promise := c.builder.CreateBitCast(promiseRaw, llvm.PointerType(promiseType, 0), "task.promise")
dataPtr := c.builder.CreateGEP(promise, []llvm.Value{ dataPtr := c.builder.CreateInBoundsGEP(promise, []llvm.Value{
llvm.ConstInt(c.ctx.Int32Type(), 0, false), llvm.ConstInt(c.ctx.Int32Type(), 0, false),
llvm.ConstInt(c.ctx.Int32Type(), 2, false), llvm.ConstInt(c.ctx.Int32Type(), 2, false),
}, "task.promise.data") }, "task.promise.data")
@ -546,13 +546,13 @@ func (c *Compiler) markAsyncFunctions() (needsScheduler bool, err error) {
llvm.ConstInt(c.ctx.Int1Type(), 0, false), llvm.ConstInt(c.ctx.Int1Type(), 0, false),
}, "task.promise.raw") }, "task.promise.raw")
promise := c.builder.CreateBitCast(promiseRaw, llvm.PointerType(promiseType, 0), "task.promise") promise := c.builder.CreateBitCast(promiseRaw, llvm.PointerType(promiseType, 0), "task.promise")
dataPtr := c.builder.CreateGEP(promise, []llvm.Value{ dataPtr := c.builder.CreateInBoundsGEP(promise, []llvm.Value{
llvm.ConstInt(c.ctx.Int32Type(), 0, false), llvm.ConstInt(c.ctx.Int32Type(), 0, false),
llvm.ConstInt(c.ctx.Int32Type(), 2, false), llvm.ConstInt(c.ctx.Int32Type(), 2, false),
}, "task.promise.data") }, "task.promise.data")
valueAlloca.ReplaceAllUsesWith(c.builder.CreateBitCast(dataPtr, valueAlloca.Type(), "")) valueAlloca.ReplaceAllUsesWith(c.builder.CreateBitCast(dataPtr, valueAlloca.Type(), ""))
valueAlloca.EraseFromParentAsInstruction() valueAlloca.EraseFromParentAsInstruction()
commaOkPtr := c.builder.CreateGEP(promise, []llvm.Value{ commaOkPtr := c.builder.CreateInBoundsGEP(promise, []llvm.Value{
llvm.ConstInt(c.ctx.Int32Type(), 0, false), llvm.ConstInt(c.ctx.Int32Type(), 0, false),
llvm.ConstInt(c.ctx.Int32Type(), 1, false), llvm.ConstInt(c.ctx.Int32Type(), 1, false),
}, "task.promise.comma-ok") }, "task.promise.comma-ok")