github.com/llir/llvm@v0.3.6/ir/constant/expr_aggregate.go (about) 1 package constant 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/llir/llvm/ir/types" 8 ) 9 10 // --- [ Aggregate expressions ] ----------------------------------------------- 11 12 // ~~~ [ extractvalue ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 13 14 // ExprExtractValue is an LLVM IR extractvalue expression. 15 type ExprExtractValue struct { 16 // Aggregate value. 17 X Constant 18 // Element indices. 19 Indices []uint64 20 21 // extra. 22 23 // Type of result produced by the constant expression. 24 Typ types.Type 25 } 26 27 // NewExtractValue returns a new extractvalue expression based on the given 28 // aggregate value and indicies. 29 func NewExtractValue(x Constant, indices ...uint64) *ExprExtractValue { 30 e := &ExprExtractValue{X: x, Indices: indices} 31 // Compute type. 32 e.Type() 33 return e 34 } 35 36 // String returns the LLVM syntax representation of the constant expression as a 37 // type-value pair. 38 func (e *ExprExtractValue) String() string { 39 return fmt.Sprintf("%s %s", e.Type(), e.Ident()) 40 } 41 42 // Type returns the type of the constant expression. 43 func (e *ExprExtractValue) Type() types.Type { 44 // Cache type if not present. 45 if e.Typ == nil { 46 e.Typ = aggregateElemType(e.X.Type(), e.Indices) 47 } 48 return e.Typ 49 } 50 51 // Ident returns the identifier associated with the constant expression. 52 func (e *ExprExtractValue) Ident() string { 53 // 'extractvalue' '(' X=TypeConst Indices=(',' UintLit)* ')' 54 buf := &strings.Builder{} 55 fmt.Fprintf(buf, "extractvalue (%s", e.X) 56 for _, index := range e.Indices { 57 fmt.Fprintf(buf, ", %d", index) 58 } 59 buf.WriteString(")") 60 return buf.String() 61 } 62 63 // ~~~ [ insertvalue ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 64 65 // ExprInsertValue is an LLVM IR insertvalue expression. 66 type ExprInsertValue struct { 67 // Aggregate value. 68 X Constant 69 // Element to insert. 70 Elem Constant 71 // Element indices. 72 Indices []uint64 73 74 // extra. 75 76 // Type of result produced by the constant expression. 77 Typ types.Type 78 } 79 80 // NewInsertValue returns a new insertvalue expression based on the given 81 // aggregate value, element and indicies. 82 func NewInsertValue(x, elem Constant, indices ...uint64) *ExprInsertValue { 83 e := &ExprInsertValue{X: x, Elem: elem, Indices: indices} 84 // Compute type. 85 e.Type() 86 return e 87 } 88 89 // String returns the LLVM syntax representation of the constant expression as a 90 // type-value pair. 91 func (e *ExprInsertValue) String() string { 92 return fmt.Sprintf("%s %s", e.Type(), e.Ident()) 93 } 94 95 // Type returns the type of the constant expression. 96 func (e *ExprInsertValue) Type() types.Type { 97 // Cache type if not present. 98 if e.Typ == nil { 99 e.Typ = e.X.Type() 100 } 101 return e.Typ 102 } 103 104 // Ident returns the identifier associated with the constant expression. 105 func (e *ExprInsertValue) Ident() string { 106 // 'insertvalue' '(' X=TypeConst ',' Elem=TypeConst Indices=(',' UintLit)* 107 // ')' 108 buf := &strings.Builder{} 109 fmt.Fprintf(buf, "insertvalue (%s, %s", e.X, e.Elem) 110 for _, index := range e.Indices { 111 fmt.Fprintf(buf, ", %d", index) 112 } 113 buf.WriteString(")") 114 return buf.String() 115 } 116 117 // ### [ Helper functions ] #################################################### 118 119 // aggregateElemType returns the element type at the position in the aggregate 120 // type specified by the given indices. 121 func aggregateElemType(t types.Type, indices []uint64) types.Type { 122 // Base case. 123 if len(indices) == 0 { 124 return t 125 } 126 switch t := t.(type) { 127 case *types.ArrayType: 128 return aggregateElemType(t.ElemType, indices[1:]) 129 case *types.StructType: 130 return aggregateElemType(t.Fields[indices[0]], indices[1:]) 131 default: 132 panic(fmt.Errorf("support for aggregate type %T not yet implemented", t)) 133 } 134 }