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  }