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  }