github.com/llir/llvm@v0.3.6/internal/gep/gep.go (about) 1 // Package gep computes the result type of getelementptr instructions and 2 // constant expressions. 3 // 4 // ref: https://llvm.org/docs/GetElementPtr.html 5 // ref: https://llvm.org/docs/LangRef.html#getelementptr-instruction 6 package gep 7 8 import ( 9 "fmt" 10 "log" 11 12 "github.com/llir/llvm/ir/types" 13 ) 14 15 // Index is a gep index. 16 type Index struct { 17 // HasVal specifies whether Val has a valid value. If index is a constant 18 // integer or a constant integer vector of which all elements have the same 19 // value, then HasVal is set. Note, this is a requirement to index into 20 // structure types. 21 HasVal bool 22 // Index integer value. Val is only valid if HasVal is set. 23 Val int64 24 // Length of index vector; or 0 if index is scalar. VectorLen may be non-zero 25 // even if HasVal is false. 26 VectorLen uint64 27 } 28 29 // NewIndex returns a new constant index with the given value. 30 func NewIndex(val int64) Index { 31 return Index{ 32 HasVal: true, 33 Val: val, 34 } 35 } 36 37 // ResultType computes the result type of a getelementptr instruction or 38 // constant expression. 39 // 40 // getelementptr (ElemType, Src, Indices) 41 func ResultType(elemType, src types.Type, indices []Index) types.Type { 42 // ref: http://llvm.org/docs/GetElementPtr.html#what-effect-do-address-spaces-have-on-geps 43 // 44 // > the address space qualifier on the second operand pointer type always 45 // > matches the address space qualifier on the result type. 46 var ( 47 // Address space of src pointer type or src vector element pointer type. 48 addrSpace types.AddrSpace 49 // Length of vector of pointers result type; or 0 if pointer result type. 50 resultVectorLength uint64 51 ) 52 // ref: https://llvm.org/docs/LangRef.html#getelementptr-instruction 53 // 54 // > The second argument is always a pointer or a vector of pointers. 55 switch src := src.(type) { 56 case *types.PointerType: 57 addrSpace = src.AddrSpace 58 case *types.VectorType: 59 vectorElemType, ok := src.ElemType.(*types.PointerType) 60 if !ok { 61 panic(fmt.Errorf("invalid gep source vector element type; expected *types.PointerType, got %T", src.ElemType)) 62 } 63 addrSpace = vectorElemType.AddrSpace 64 resultVectorLength = src.Len 65 default: 66 panic(fmt.Errorf("invalid gep source type; expected pointer or vector of pointers type, got %T", src)) 67 } 68 // ref: https://llvm.org/docs/LangRef.html#getelementptr-instruction 69 // 70 // > The first argument is always a type used as the basis for the 71 // > calculations. 72 e := elemType 73 for i, index := range indices { 74 // ref: https://llvm.org/docs/LangRef.html#getelementptr-instruction 75 // 76 // > The getelementptr returns a vector of pointers, instead of a single 77 // > address, when one or more of its arguments is a vector. In such 78 // > cases, all vector arguments should have the same number of elements, 79 // > and every scalar argument will be effectively broadcast into a vector 80 // > during address calculation. 81 if index.VectorLen != 0 && resultVectorLength != 0 && index.VectorLen != resultVectorLength { 82 panic(fmt.Errorf("vector length mismatch of index vector (%d) and result type vector (%d)", index.VectorLen, resultVectorLength)) 83 } 84 if resultVectorLength == 0 && index.VectorLen != 0 { 85 resultVectorLength = index.VectorLen 86 } 87 // ref: https://llvm.org/docs/GetElementPtr.html#why-is-the-extra-0-index-required 88 // 89 // > Since the second argument to the GEP instruction must always be a 90 // > value of pointer type, the first index steps through that pointer. 91 if i == 0 { 92 continue 93 } 94 switch elm := e.(type) { 95 case *types.PointerType: 96 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)) 97 case *types.VectorType: 98 // ref: https://llvm.org/docs/GetElementPtr.html#can-gep-index-into-vector-elements 99 // 100 // > This hasn’t always been forcefully disallowed, though it’s not 101 // > recommended. It leads to awkward special cases in the optimizers, 102 // > and fundamental inconsistency in the IR. In the future, it will 103 // > probably be outright disallowed. 104 log.Printf("using gep to index into vector types will be disallowed in a future release or llir/llvm; see https://llvm.org/docs/GetElementPtr.html#can-gep-index-into-vector-elements") 105 e = elm.ElemType 106 case *types.ArrayType: 107 e = elm.ElemType 108 case *types.StructType: 109 // ref: https://llvm.org/docs/LangRef.html#getelementptr-instruction 110 // 111 // > When indexing into a (optionally packed) structure, only i32 112 // > integer constants are allowed (when using a vector of indices they 113 // > must all be the same i32 integer constant). 114 if !index.HasVal { 115 panic(fmt.Errorf("unable to index into struct type `%v` using gep with non-constant index", e)) 116 } 117 e = elm.Fields[index.Val] 118 default: 119 panic(fmt.Errorf("cannot index into type %T using gep", e)) 120 } 121 } 122 ptr := types.NewPointer(e) 123 ptr.AddrSpace = addrSpace 124 if resultVectorLength != 0 { 125 vec := types.NewVector(resultVectorLength, ptr) 126 return vec 127 } 128 return ptr 129 }