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.
This commit is contained in:
Ayke van Laethem
2019-04-25 11:21:14 +02:00
committed by Ron Evans
parent d155e31b64
commit 9a3d0683b3
3 changed files with 21 additions and 17 deletions
+13 -9
View File
@@ -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(), uint64(expr.Field), false),
}
return c.builder.CreateGEP(val, indices, ""), nil
return c.builder.CreateInBoundsGEP(val, indices, ""), nil
}
case *ssa.Function:
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")
c.builder.CreateStore(array, alloca)
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
case *ssa.IndexAddr:
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),
index,
}
return c.builder.CreateGEP(bufptr, indices, ""), nil
return c.builder.CreateInBoundsGEP(bufptr, indices, ""), nil
case *types.Slice:
return c.builder.CreateGEP(bufptr, []llvm.Value{index}, ""), nil
return c.builder.CreateInBoundsGEP(bufptr, []llvm.Value{index}, ""), nil
default:
panic("unreachable")
}
@@ -1407,7 +1407,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
// Lookup byte
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
case *types.Map:
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")
slicePtr := c.builder.CreateGEP(value, indices, "slice.ptr")
slicePtr := c.builder.CreateInBoundsGEP(value, indices, "slice.ptr")
sliceCap := c.builder.CreateSub(llvmLen, low, "slice.cap")
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, "")
}
newPtr := c.builder.CreateGEP(oldPtr, []llvm.Value{low}, "")
newPtr := c.builder.CreateInBoundsGEP(oldPtr, []llvm.Value{low}, "")
newLen := c.builder.CreateSub(high, low, "")
newCap := c.builder.CreateSub(oldCap, low, "")
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, "")
}
newPtr := c.builder.CreateGEP(oldPtr, []llvm.Value{low}, "")
newPtr := c.builder.CreateInBoundsGEP(oldPtr, []llvm.Value{low}, "")
newLen := c.builder.CreateSub(high, low, "")
str := llvm.Undef(c.mod.GetTypeByName("runtime._string"))
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
// ptrtoint instruction with a GEP. The leftover inttoptr
// 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
}
}
}
+5 -5
View File
@@ -172,13 +172,13 @@ func (c *Compiler) emitRunDefers(frame *Frame) {
// stack = stack.next
// switch stack.callback {
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(), 1, false), // .next field
}, "stack.next.gep")
nextStack := c.builder.CreateLoad(nextStackGEP, "stack.next")
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), // .callback field
}, "callback.gep")
@@ -211,7 +211,7 @@ func (c *Compiler) emitRunDefers(frame *Frame) {
forwardParams := []llvm.Value{}
zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false)
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")
forwardParams = append(forwardParams, forwardParam)
}
@@ -242,7 +242,7 @@ func (c *Compiler) emitRunDefers(frame *Frame) {
forwardParams := []llvm.Value{}
zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false)
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")
forwardParams = append(forwardParams, forwardParam)
}
@@ -273,7 +273,7 @@ func (c *Compiler) emitRunDefers(frame *Frame) {
forwardParams := []llvm.Value{}
zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false)
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")
forwardParams = append(forwardParams, forwardParam)
}
+3 -3
View File
@@ -485,7 +485,7 @@ func (c *Compiler) markAsyncFunctions() (needsScheduler bool, err error) {
llvm.ConstInt(c.ctx.Int1Type(), 0, false),
}, "task.promise.raw")
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(), 2, false),
}, "task.promise.data")
@@ -546,13 +546,13 @@ func (c *Compiler) markAsyncFunctions() (needsScheduler bool, err error) {
llvm.ConstInt(c.ctx.Int1Type(), 0, false),
}, "task.promise.raw")
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(), 2, false),
}, "task.promise.data")
valueAlloca.ReplaceAllUsesWith(c.builder.CreateBitCast(dataPtr, valueAlloca.Type(), ""))
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(), 1, false),
}, "task.promise.comma-ok")