192 lines
6.1 KiB
Go
192 lines
6.1 KiB
Go
package llvm
|
|
|
|
import "fmt"
|
|
|
|
type gepIndex struct {
|
|
HasVal bool
|
|
Val int64
|
|
VectorLen uint64
|
|
}
|
|
|
|
func gepInstType (elemType, src Type, indices []Value) Type {
|
|
var idxs []gepIndex
|
|
for _, index := range indices {
|
|
var idx gepIndex
|
|
switch index := index.(type) {
|
|
case Const:
|
|
idx = getIndex(index)
|
|
default:
|
|
idx = gepIndex{HasVal: false}
|
|
// Check if index is of vector type.
|
|
if indexType, ok := index.Type().(*TypeVector); ok {
|
|
idx.VectorLen = indexType.Length
|
|
}
|
|
}
|
|
idxs = append(idxs, idx)
|
|
}
|
|
return resultType(elemType, src, idxs)
|
|
}
|
|
|
|
func getIndex (index Const) gepIndex {
|
|
// unpack inrange indices.
|
|
if idx, ok := index.(*ConstIndex); ok {
|
|
index = idx.Const
|
|
}
|
|
// TODO: figure out how to simplify expressions for GEP instructions without
|
|
// creating import cycle on irutil.
|
|
|
|
// Use index.Simplify() to simplify the constant expression to a concrete
|
|
// integer constant or vector of integers constant.
|
|
//if idx, ok := index.(constant.Expression); ok {
|
|
// index = idx.Simplify()
|
|
//}
|
|
switch index := index.(type) {
|
|
case *ConstInt:
|
|
return gepIndex {
|
|
HasVal: true,
|
|
Val: index.Value.Int64(),
|
|
}
|
|
case *ConstZeroInitializer:
|
|
return gepIndex {
|
|
HasVal: true,
|
|
Val: 0,
|
|
}
|
|
case *ConstVector:
|
|
// ref: https://llvm.org/docs/LangRef.html#getelementptr-instruction
|
|
//
|
|
// > The getelementptr returns a vector of pointers, instead of a single
|
|
// > address, when one or more of its arguments is a vector. In such
|
|
// > cases, all vector arguments should have the same number of elements,
|
|
// > and every scalar argument will be effectively broadcast into a vector
|
|
// > during address calculation.
|
|
if len(index.Elements) == 0 {
|
|
return gepIndex { HasVal: false }
|
|
}
|
|
// Sanity check. All vector elements must be integers, and must have the
|
|
// same value.
|
|
var val int64
|
|
for i, elem := range index.Elements {
|
|
switch elem := elem.(type) {
|
|
case *ConstInt:
|
|
x := elem.Value.Int64()
|
|
if i == 0 {
|
|
val = x
|
|
} else if x != val {
|
|
// since all elements were not identical, we must conclude that
|
|
// the index vector does not have a concrete value.
|
|
return gepIndex {
|
|
HasVal: false,
|
|
VectorLen: uint64(len(index.Elements)),
|
|
}
|
|
}
|
|
default:
|
|
// TODO: remove debug output.
|
|
panic(fmt.Errorf("support for gep index vector element type %T not yet implemented", elem))
|
|
//return gep.Index{HasVal: false}
|
|
}
|
|
}
|
|
return gepIndex {
|
|
HasVal: true,
|
|
Val: val,
|
|
VectorLen: uint64(len(index.Elements)),
|
|
}
|
|
case *ConstUndef:
|
|
return gepIndex { HasVal: false }
|
|
case *ConstPoison:
|
|
return gepIndex { HasVal: false }
|
|
case ConstExpr:
|
|
// should already have been simplified to a form we can handle.
|
|
return gepIndex { HasVal: false }
|
|
default:
|
|
// TODO: add support for more constant expressions.
|
|
// TODO: remove debug output.
|
|
panic(fmt.Errorf("support for gep index type %T not yet implemented", index))
|
|
//return gep.Index{HasVal: false}
|
|
}
|
|
}
|
|
|
|
func resultType (elemType, src Type, indices []gepIndex) Type {
|
|
// ref: http://llvm.org/docs/GetElementPtr.html#what-effect-do-address-spaces-have-on-geps
|
|
//
|
|
// > the address space qualifier on the second operand pointer type always
|
|
// > matches the address space qualifier on the result type.
|
|
var (
|
|
// Address space of src pointer type or src vector element pointer type.
|
|
addrSpace AddressSpace
|
|
// Length of vector of pointers result type; or 0 if pointer result type.
|
|
resultVectorLength uint64
|
|
)
|
|
// ref: https://llvm.org/docs/LangRef.html#getelementptr-instruction
|
|
//
|
|
// > The second argument is always a pointer or a vector of pointers.
|
|
switch src := src.(type) {
|
|
case *TypePointer:
|
|
addrSpace = src.AddressSpace
|
|
case *TypeVector:
|
|
vectorElemType, ok := src.Element.(*TypePointer)
|
|
if !ok {
|
|
panic(fmt.Errorf("invalid gep source vector element type %T", src.Element))
|
|
}
|
|
addrSpace = vectorElemType.AddressSpace
|
|
resultVectorLength = src.Length
|
|
default:
|
|
panic(fmt.Errorf("invalid gep source type %T", src))
|
|
}
|
|
// ref: https://llvm.org/docs/LangRef.html#getelementptr-instruction
|
|
//
|
|
// > The first argument is always a type used as the basis for the
|
|
// > calculations.
|
|
e := elemType
|
|
for i, index := range indices {
|
|
// ref: https://llvm.org/docs/LangRef.html#getelementptr-instruction
|
|
//
|
|
// > The getelementptr returns a vector of pointers, instead of a single
|
|
// > address, when one or more of its arguments is a vector. In such
|
|
// > cases, all vector arguments should have the same number of elements,
|
|
// > and every scalar argument will be effectively broadcast into a vector
|
|
// > during address calculation.
|
|
if index.VectorLen != 0 && resultVectorLength != 0 && index.VectorLen != resultVectorLength {
|
|
panic(fmt.Errorf("vector length mismatch of index vector (%d) and result type vector (%d)", index.VectorLen, resultVectorLength))
|
|
}
|
|
if resultVectorLength == 0 && index.VectorLen != 0 {
|
|
resultVectorLength = index.VectorLen
|
|
}
|
|
// ref: https://llvm.org/docs/GetElementPtr.html#why-is-the-extra-0-index-required
|
|
//
|
|
// > Since the second argument to the GEP instruction must always be a
|
|
// > value of pointer type, the first index steps through that pointer.
|
|
if i == 0 {
|
|
continue
|
|
}
|
|
switch elm := e.(type) {
|
|
case *TypePointer:
|
|
panic(fmt.Errorf("cannot index into pointer type at %d:th gep index, only valid at 0:th gep index; see https://llvm.org/docs/GetElementPtr.html#what-is-dereferenced-by-gep", i))
|
|
case *TypeArray:
|
|
e = elm.Element
|
|
case *TypeStruct:
|
|
// ref: https://llvm.org/docs/LangRef.html#getelementptr-instruction
|
|
//
|
|
// > When indexing into a (optionally packed) structure, only i32
|
|
// > integer constants are allowed (when using a vector of indices they
|
|
// > must all be the same i32 integer constant).
|
|
if !index.HasVal {
|
|
panic(fmt.Errorf("unable to index into struct type `%v` using gep with non-constant index", e))
|
|
}
|
|
e = elm.Fields[index.Val]
|
|
case *TypeDefined:
|
|
continue
|
|
default:
|
|
panic(fmt.Errorf("cannot index into type %T using gep", e))
|
|
}
|
|
}
|
|
ptr := &TypePointer { AddressSpace: addrSpace }
|
|
if resultVectorLength != 0 {
|
|
vec := &TypeVector {
|
|
Element: ptr,
|
|
Length: resultVectorLength,
|
|
}
|
|
return vec
|
|
}
|
|
return ptr
|
|
}
|