compiler: support 64-bit numbers in bounds check
Этот коммит содержится в:
родитель
17e8c850f6
коммит
96f74ec153
2 изменённых файлов: 30 добавлений и 5 удалений
|
@ -2197,12 +2197,23 @@ func (c *Compiler) parseCall(frame *Frame, instr *ssa.CallCommon, parentHandle l
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compiler) emitBoundsCheck(frame *Frame, arrayLen, index llvm.Value) {
|
func (c *Compiler) emitBoundsCheck(frame *Frame, arrayLen, index llvm.Value, indexType types.Type) {
|
||||||
if frame.fn.IsNoBounds() {
|
if frame.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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Sometimes, the index can be e.g. an uint8 or int8, and we have to
|
||||||
|
// correctly extend that type.
|
||||||
|
if index.Type().IntTypeWidth() < arrayLen.Type().IntTypeWidth() {
|
||||||
|
if indexType.(*types.Basic).Info()&types.IsUnsigned == 0 {
|
||||||
|
index = c.builder.CreateZExt(index, arrayLen.Type(), "")
|
||||||
|
} else {
|
||||||
|
index = c.builder.CreateSExt(index, arrayLen.Type(), "")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Optimize away trivial cases.
|
// Optimize away trivial cases.
|
||||||
// LLVM would do this anyway with interprocedural optimizations, but it
|
// LLVM would do this anyway with interprocedural optimizations, but it
|
||||||
// helps to see cases where bounds check elimination would really help.
|
// helps to see cases where bounds check elimination would really help.
|
||||||
|
@ -2213,7 +2224,13 @@ func (c *Compiler) emitBoundsCheck(frame *Frame, arrayLen, index llvm.Value) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
c.createRuntimeCall("lookupBoundsCheck", []llvm.Value{arrayLen, index}, "")
|
|
||||||
|
if index.Type().IntTypeWidth() > c.intType.IntTypeWidth() {
|
||||||
|
// Index is too big for the regular bounds check. Use the one for int64.
|
||||||
|
c.createRuntimeCall("lookupBoundsCheckLong", []llvm.Value{arrayLen, index}, "")
|
||||||
|
} else {
|
||||||
|
c.createRuntimeCall("lookupBoundsCheck", []llvm.Value{arrayLen, index}, "")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compiler) emitSliceBoundsCheck(frame *Frame, length, low, high llvm.Value) {
|
func (c *Compiler) emitSliceBoundsCheck(frame *Frame, length, low, high llvm.Value) {
|
||||||
|
@ -2371,7 +2388,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.lenType, uint64(arrayLen), false)
|
arrayLenLLVM := llvm.ConstInt(c.lenType, uint64(arrayLen), false)
|
||||||
c.emitBoundsCheck(frame, arrayLenLLVM, index)
|
c.emitBoundsCheck(frame, 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.
|
||||||
|
@ -2411,7 +2428,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
|
|
||||||
// Bounds check.
|
// Bounds check.
|
||||||
// LLVM optimizes this away in most cases.
|
// LLVM optimizes this away in most cases.
|
||||||
c.emitBoundsCheck(frame, buflen, index)
|
c.emitBoundsCheck(frame, buflen, index, expr.Index.Type())
|
||||||
|
|
||||||
switch expr.X.Type().Underlying().(type) {
|
switch expr.X.Type().Underlying().(type) {
|
||||||
case *types.Pointer:
|
case *types.Pointer:
|
||||||
|
@ -2447,7 +2464,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return llvm.Value{}, err // shouldn't happen
|
return llvm.Value{}, err // shouldn't happen
|
||||||
}
|
}
|
||||||
c.emitBoundsCheck(frame, length, index)
|
c.emitBoundsCheck(frame, length, index, expr.Index.Type())
|
||||||
|
|
||||||
// Lookup byte
|
// Lookup byte
|
||||||
buf := c.builder.CreateExtractValue(value, 0, "")
|
buf := c.builder.CreateExtractValue(value, 0, "")
|
||||||
|
|
|
@ -29,6 +29,14 @@ func lookupBoundsCheck(length lenType, index int) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Check for bounds in *ssa.Index, *ssa.IndexAddr and *ssa.Lookup.
|
||||||
|
// Supports 64-bit indexes.
|
||||||
|
func lookupBoundsCheckLong(length lenType, index int64) {
|
||||||
|
if index < 0 || index >= int64(length) {
|
||||||
|
runtimePanic("index out of range")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Check for bounds in *ssa.Slice.
|
// Check for bounds in *ssa.Slice.
|
||||||
func sliceBoundsCheck(length lenType, low, high uint) {
|
func sliceBoundsCheck(length lenType, low, high uint) {
|
||||||
if !(0 <= low && low <= high && high <= uint(length)) {
|
if !(0 <= low && low <= high && high <= uint(length)) {
|
||||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче