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() {
|
||||
// The //go:nobounds pragma was added to the function to avoid bounds
|
||||
// checking.
|
||||
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.
|
||||
// LLVM would do this anyway with interprocedural optimizations, but it
|
||||
// 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
|
||||
}
|
||||
}
|
||||
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) {
|
||||
|
@ -2371,7 +2388,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
|||
// Check bounds.
|
||||
arrayLen := expr.X.Type().(*types.Array).Len()
|
||||
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
|
||||
// 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.
|
||||
// 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) {
|
||||
case *types.Pointer:
|
||||
|
@ -2447,7 +2464,7 @@ func (c *Compiler) parseExpr(frame *Frame, expr ssa.Value) (llvm.Value, error) {
|
|||
if err != nil {
|
||||
return llvm.Value{}, err // shouldn't happen
|
||||
}
|
||||
c.emitBoundsCheck(frame, length, index)
|
||||
c.emitBoundsCheck(frame, length, index, expr.Index.Type())
|
||||
|
||||
// Lookup byte
|
||||
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.
|
||||
func sliceBoundsCheck(length lenType, low, high uint) {
|
||||
if !(0 <= low && low <= high && high <= uint(length)) {
|
||||
|
|
Загрузка…
Создание таблицы
Сослаться в новой задаче