github.com/llir/llvm@v0.3.6/ir/inst_aggregate.go (about) 1 package ir 2 3 import ( 4 "fmt" 5 "strings" 6 7 "github.com/llir/llvm/ir/types" 8 "github.com/llir/llvm/ir/value" 9 ) 10 11 // --- [ Aggregate instructions ] ---------------------------------------------- 12 13 // ~~~ [ extractvalue ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 14 15 // InstExtractValue is an LLVM IR extractvalue instruction. 16 type InstExtractValue struct { 17 // Name of local variable associated with the result. 18 LocalIdent 19 // Aggregate value. 20 X value.Value // array or struct 21 // Element indices. 22 Indices []uint64 23 24 // extra. 25 26 // Type of result produced by the instruction. 27 Typ types.Type 28 // (optional) Metadata. 29 Metadata 30 } 31 32 // NewExtractValue returns a new extractvalue instruction based on the given 33 // aggregate value and indicies. 34 func NewExtractValue(x value.Value, indices ...uint64) *InstExtractValue { 35 inst := &InstExtractValue{X: x, Indices: indices} 36 // Compute type. 37 inst.Type() 38 return inst 39 } 40 41 // String returns the LLVM syntax representation of the instruction as a 42 // type-value pair. 43 func (inst *InstExtractValue) String() string { 44 return fmt.Sprintf("%s %s", inst.Type(), inst.Ident()) 45 } 46 47 // Type returns the type of the instruction. 48 func (inst *InstExtractValue) Type() types.Type { 49 // Cache type if not present. 50 if inst.Typ == nil { 51 inst.Typ = aggregateElemType(inst.X.Type(), inst.Indices) 52 } 53 return inst.Typ 54 } 55 56 // LLString returns the LLVM syntax representation of the instruction. 57 // 58 // 'extractvalue' X=TypeValue Indices=(',' UintLit)+ Metadata=(',' MetadataAttachment)+? 59 func (inst *InstExtractValue) LLString() string { 60 buf := &strings.Builder{} 61 fmt.Fprintf(buf, "%s = ", inst.Ident()) 62 fmt.Fprintf(buf, "extractvalue %s", inst.X) 63 for _, index := range inst.Indices { 64 fmt.Fprintf(buf, ", %d", index) 65 } 66 for _, md := range inst.Metadata { 67 fmt.Fprintf(buf, ", %s", md) 68 } 69 return buf.String() 70 } 71 72 // Operands returns a mutable list of operands of the given instruction. 73 func (inst *InstExtractValue) Operands() []*value.Value { 74 return []*value.Value{&inst.X} 75 } 76 77 // ~~~ [ insertvalue ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 78 79 // InstInsertValue is an LLVM IR insertvalue instruction. 80 type InstInsertValue struct { 81 // Name of local variable associated with the result. 82 LocalIdent 83 // Aggregate value. 84 X value.Value // array or struct 85 // Element to insert. 86 Elem value.Value 87 // Element indices. 88 Indices []uint64 89 90 // extra. 91 92 // Type of result produced by the instruction. 93 Typ types.Type 94 // (optional) Metadata. 95 Metadata 96 } 97 98 // NewInsertValue returns a new insertvalue instruction based on the given 99 // aggregate value, element and indicies. 100 func NewInsertValue(x, elem value.Value, indices ...uint64) *InstInsertValue { 101 elemType := aggregateElemType(x.Type(), indices) 102 if !elemType.Equal(elem.Type()) { 103 panic(fmt.Errorf("insertvalue elem type mismatch, expected %v, got %v", elemType, elem.Type())) 104 } 105 inst := &InstInsertValue{X: x, Elem: elem, Indices: indices} 106 // Compute type. 107 inst.Type() 108 return inst 109 } 110 111 // String returns the LLVM syntax representation of the instruction as a 112 // type-value pair. 113 func (inst *InstInsertValue) String() string { 114 return fmt.Sprintf("%s %s", inst.Type(), inst.Ident()) 115 } 116 117 // Type returns the type of the instruction. 118 func (inst *InstInsertValue) Type() types.Type { 119 // Cache type if not present. 120 if inst.Typ == nil { 121 inst.Typ = inst.X.Type() 122 } 123 return inst.Typ 124 } 125 126 // LLString returns the LLVM syntax representation of the instruction. 127 // 128 // 'insertvalue' X=TypeValue ',' Elem=TypeValue Indices=(',' UintLit)+ Metadata=(',' MetadataAttachment)+? 129 func (inst *InstInsertValue) LLString() string { 130 buf := &strings.Builder{} 131 fmt.Fprintf(buf, "%s = ", inst.Ident()) 132 fmt.Fprintf(buf, "insertvalue %s, %s", inst.X, inst.Elem) 133 for _, index := range inst.Indices { 134 fmt.Fprintf(buf, ", %d", index) 135 } 136 for _, md := range inst.Metadata { 137 fmt.Fprintf(buf, ", %s", md) 138 } 139 return buf.String() 140 } 141 142 // Operands returns a mutable list of operands of the given instruction. 143 func (inst *InstInsertValue) Operands() []*value.Value { 144 return []*value.Value{&inst.X, &inst.Elem} 145 } 146 147 // ### [ Helper functions ] #################################################### 148 149 // aggregateElemType returns the element type at the position in the aggregate 150 // type specified by the given indices. 151 func aggregateElemType(t types.Type, indices []uint64) types.Type { 152 // Base case. 153 if len(indices) == 0 { 154 return t 155 } 156 switch t := t.(type) { 157 case *types.ArrayType: 158 return aggregateElemType(t.ElemType, indices[1:]) 159 case *types.StructType: 160 return aggregateElemType(t.Fields[indices[0]], indices[1:]) 161 case *types.PointerType: 162 return aggregateElemType(t.ElemType, indices[1:]) 163 default: 164 panic(fmt.Errorf("support for aggregate type %T not yet implemented", t)) 165 } 166 }