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.
Этот коммит содержится в:
родитель
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")
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче