github.com/llir/llvm@v0.3.6/ir/inst_other.go (about)

     1  package ir
     2  
     3  import (
     4  	"fmt"
     5  	"strings"
     6  
     7  	"github.com/llir/llvm/ir/enum"
     8  	"github.com/llir/llvm/ir/types"
     9  	"github.com/llir/llvm/ir/value"
    10  )
    11  
    12  // --- [ Other instructions ] --------------------------------------------------
    13  
    14  // ~~~ [ icmp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    15  
    16  // InstICmp is an LLVM IR icmp instruction.
    17  type InstICmp struct {
    18  	// Name of local variable associated with the result.
    19  	LocalIdent
    20  	// Integer comparison predicate.
    21  	Pred enum.IPred
    22  	// Integer scalar or vector operands.
    23  	X, Y value.Value // integer scalar, pointer, integer vector or pointer vector.
    24  
    25  	// extra.
    26  
    27  	// Type of result produced by the instruction.
    28  	Typ types.Type // boolean or boolean vector
    29  	// (optional) Metadata.
    30  	Metadata
    31  }
    32  
    33  // NewICmp returns a new icmp instruction based on the given integer comparison
    34  // predicate and integer scalar or vector operands.
    35  func NewICmp(pred enum.IPred, x, y value.Value) *InstICmp {
    36  	inst := &InstICmp{Pred: pred, X: x, Y: y}
    37  	// Compute type.
    38  	inst.Type()
    39  	return inst
    40  }
    41  
    42  // String returns the LLVM syntax representation of the instruction as a
    43  // type-value pair.
    44  func (inst *InstICmp) String() string {
    45  	return fmt.Sprintf("%s %s", inst.Type(), inst.Ident())
    46  }
    47  
    48  // Type returns the type of the instruction. The result type is either boolean
    49  // type or vector of booleans type.
    50  func (inst *InstICmp) Type() types.Type {
    51  	// Cache type if not present.
    52  	if inst.Typ == nil {
    53  		switch xType := inst.X.Type().(type) {
    54  		case *types.IntType, *types.PointerType:
    55  			inst.Typ = types.I1
    56  		case *types.VectorType:
    57  			inst.Typ = types.NewVector(xType.Len, types.I1)
    58  		default:
    59  			panic(fmt.Errorf("invalid icmp operand type; expected *types.IntType, *types.PointerType or *types.VectorType, got %T", xType))
    60  		}
    61  	}
    62  	return inst.Typ
    63  }
    64  
    65  // LLString returns the LLVM syntax representation of the instruction.
    66  //
    67  // 'icmp' Pred=IPred X=TypeValue ',' Y=Value Metadata=(',' MetadataAttachment)+?
    68  func (inst *InstICmp) LLString() string {
    69  	buf := &strings.Builder{}
    70  	fmt.Fprintf(buf, "%s = ", inst.Ident())
    71  	fmt.Fprintf(buf, "icmp %s %s, %s", inst.Pred, inst.X, inst.Y.Ident())
    72  	for _, md := range inst.Metadata {
    73  		fmt.Fprintf(buf, ", %s", md)
    74  	}
    75  	return buf.String()
    76  }
    77  
    78  // Operands returns a mutable list of operands of the given instruction.
    79  func (inst *InstICmp) Operands() []*value.Value {
    80  	return []*value.Value{&inst.X, &inst.Y}
    81  }
    82  
    83  // ~~~ [ fcmp ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    84  
    85  // InstFCmp is an LLVM IR fcmp instruction.
    86  type InstFCmp struct {
    87  	// Name of local variable associated with the result.
    88  	LocalIdent
    89  	// Floating-point comparison predicate.
    90  	Pred enum.FPred
    91  	// Floating-point scalar or vector operands.
    92  	X, Y value.Value // floating-point scalar or floating-point vector
    93  
    94  	// extra.
    95  
    96  	// Type of result produced by the instruction.
    97  	Typ types.Type // boolean or boolean vector
    98  	// (optional) Fast math flags.
    99  	FastMathFlags []enum.FastMathFlag
   100  	// (optional) Metadata.
   101  	Metadata
   102  }
   103  
   104  // NewFCmp returns a new fcmp instruction based on the given floating-point
   105  // comparison predicate and floating-point scalar or vector operands.
   106  func NewFCmp(pred enum.FPred, x, y value.Value) *InstFCmp {
   107  	inst := &InstFCmp{Pred: pred, X: x, Y: y}
   108  	// Compute type.
   109  	inst.Type()
   110  	return inst
   111  }
   112  
   113  // String returns the LLVM syntax representation of the instruction as a
   114  // type-value pair.
   115  func (inst *InstFCmp) String() string {
   116  	return fmt.Sprintf("%s %s", inst.Type(), inst.Ident())
   117  }
   118  
   119  // Type returns the type of the instruction. The result type is either boolean
   120  // type or vector of booleans type.
   121  func (inst *InstFCmp) Type() types.Type {
   122  	// Cache type if not present.
   123  	if inst.Typ == nil {
   124  		switch xType := inst.X.Type().(type) {
   125  		case *types.FloatType:
   126  			inst.Typ = types.I1
   127  		case *types.VectorType:
   128  			inst.Typ = types.NewVector(xType.Len, types.I1)
   129  		default:
   130  			panic(fmt.Errorf("invalid fcmp operand type; expected *types.FloatType or *types.VectorType, got %T", xType))
   131  		}
   132  	}
   133  	return inst.Typ
   134  }
   135  
   136  // LLString returns the LLVM syntax representation of the instruction.
   137  //
   138  // 'fcmp' FastMathFlags=FastMathFlag* Pred=FPred X=TypeValue ',' Y=Value Metadata=(',' MetadataAttachment)+?
   139  func (inst *InstFCmp) LLString() string {
   140  	buf := &strings.Builder{}
   141  	fmt.Fprintf(buf, "%s = ", inst.Ident())
   142  	buf.WriteString("fcmp")
   143  	for _, flag := range inst.FastMathFlags {
   144  		fmt.Fprintf(buf, " %s", flag)
   145  	}
   146  	fmt.Fprintf(buf, " %s %s, %s", inst.Pred, inst.X, inst.Y.Ident())
   147  	for _, md := range inst.Metadata {
   148  		fmt.Fprintf(buf, ", %s", md)
   149  	}
   150  	return buf.String()
   151  }
   152  
   153  // Operands returns a mutable list of operands of the given instruction.
   154  func (inst *InstFCmp) Operands() []*value.Value {
   155  	return []*value.Value{&inst.X, &inst.Y}
   156  }
   157  
   158  // ~~~ [ phi ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   159  
   160  // InstPhi is an LLVM IR phi instruction.
   161  type InstPhi struct {
   162  	// Name of local variable associated with the result.
   163  	LocalIdent
   164  	// Incoming values.
   165  	Incs []*Incoming
   166  
   167  	// extra.
   168  
   169  	// Type of result produced by the instruction.
   170  	Typ types.Type // type of incoming value
   171  	// (optional) Fast math flags.
   172  	FastMathFlags []enum.FastMathFlag
   173  	// (optional) Metadata.
   174  	Metadata
   175  }
   176  
   177  // NewPhi returns a new phi instruction based on the given incoming values.
   178  func NewPhi(incs ...*Incoming) *InstPhi {
   179  	inst := &InstPhi{Incs: incs}
   180  	// Compute type.
   181  	inst.Type()
   182  	return inst
   183  }
   184  
   185  // String returns the LLVM syntax representation of the instruction as a
   186  // type-value pair.
   187  func (inst *InstPhi) String() string {
   188  	return fmt.Sprintf("%s %s", inst.Type(), inst.Ident())
   189  }
   190  
   191  // Type returns the type of the instruction. The result type is the type of the
   192  // incoming value.
   193  func (inst *InstPhi) Type() types.Type {
   194  	// Cache type if not present.
   195  	if inst.Typ == nil {
   196  		inst.Typ = inst.Incs[0].X.Type()
   197  	}
   198  	return inst.Typ
   199  }
   200  
   201  // LLString returns the LLVM syntax representation of the instruction.
   202  //
   203  // 'phi' Typ=Type Incs=(Inc separator ',')+ Metadata=(',' MetadataAttachment)+?
   204  func (inst *InstPhi) LLString() string {
   205  	buf := &strings.Builder{}
   206  	fmt.Fprintf(buf, "%s = ", inst.Ident())
   207  	buf.WriteString("phi ")
   208  	for _, flag := range inst.FastMathFlags {
   209  		buf.WriteString(flag.String())
   210  		buf.WriteString(" ")
   211  	}
   212  	buf.WriteString(inst.Typ.String())
   213  	buf.WriteString(" ")
   214  	for i, inc := range inst.Incs {
   215  		if i != 0 {
   216  			buf.WriteString(", ")
   217  		}
   218  		buf.WriteString(inc.String())
   219  	}
   220  	for _, md := range inst.Metadata {
   221  		fmt.Fprintf(buf, ", %s", md)
   222  	}
   223  	return buf.String()
   224  }
   225  
   226  // Operands returns a mutable list of operands of the given instruction.
   227  func (inst *InstPhi) Operands() []*value.Value {
   228  	ops := make([]*value.Value, 0, 2*len(inst.Incs))
   229  	for i := range inst.Incs {
   230  		ops = append(ops, &inst.Incs[i].X)
   231  		ops = append(ops, &inst.Incs[i].Pred)
   232  	}
   233  	return ops
   234  }
   235  
   236  // ___ [ Incoming value ] ______________________________________________________
   237  
   238  // Incoming is an incoming value of a phi instruction.
   239  type Incoming struct {
   240  	// Incoming value.
   241  	X value.Value
   242  	// Predecessor basic block of the incoming value.
   243  	Pred value.Value // *ir.Block
   244  }
   245  
   246  // NewIncoming returns a new incoming value based on the given value and
   247  // predecessor basic block.
   248  func NewIncoming(x value.Value, pred *Block) *Incoming {
   249  	return &Incoming{X: x, Pred: pred}
   250  }
   251  
   252  // String returns the string representation of the incoming value.
   253  func (inc *Incoming) String() string {
   254  	// '[' X=Value ',' Pred=LocalIdent ']'
   255  	return fmt.Sprintf("[ %s, %s ]", inc.X.Ident(), inc.Pred.Ident())
   256  }
   257  
   258  // ~~~ [ select ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   259  
   260  // InstSelect is an LLVM IR select instruction.
   261  type InstSelect struct {
   262  	// Name of local variable associated with the result.
   263  	LocalIdent
   264  	// Selection condition.
   265  	Cond value.Value // boolean or boolean vector
   266  	// True condition value.
   267  	ValueTrue value.Value
   268  	// False condition value.
   269  	ValueFalse value.Value
   270  
   271  	// extra.
   272  
   273  	// Type of result produced by the instruction.
   274  	Typ types.Type
   275  	// (optional) Fast math flags.
   276  	FastMathFlags []enum.FastMathFlag
   277  	// (optional) Metadata.
   278  	Metadata
   279  }
   280  
   281  // NewSelect returns a new select instruction based on the given selection
   282  // condition and true and false condition values.
   283  func NewSelect(cond, valueTrue, valueFalse value.Value) *InstSelect {
   284  	inst := &InstSelect{Cond: cond, ValueTrue: valueTrue, ValueFalse: valueFalse}
   285  	// Compute type.
   286  	inst.Type()
   287  	return inst
   288  }
   289  
   290  // String returns the LLVM syntax representation of the instruction as a
   291  // type-value pair.
   292  func (inst *InstSelect) String() string {
   293  	return fmt.Sprintf("%s %s", inst.Type(), inst.Ident())
   294  }
   295  
   296  // Type returns the type of the instruction.
   297  func (inst *InstSelect) Type() types.Type {
   298  	// Cache type if not present.
   299  	if inst.Typ == nil {
   300  		inst.Typ = inst.ValueTrue.Type()
   301  	}
   302  	return inst.Typ
   303  }
   304  
   305  // LLString returns the LLVM syntax representation of the instruction.
   306  //
   307  // 'select' FastMathFlags=FastMathFlag* Cond=TypeValue ',' ValueTrue=TypeValue ',' ValueFalse=TypeValue Metadata=(',' MetadataAttachment)+?
   308  func (inst *InstSelect) LLString() string {
   309  	buf := &strings.Builder{}
   310  	fmt.Fprintf(buf, "%s = ", inst.Ident())
   311  	buf.WriteString("select")
   312  	for _, flag := range inst.FastMathFlags {
   313  		fmt.Fprintf(buf, " %s", flag)
   314  	}
   315  	fmt.Fprintf(buf, " %s, %s, %s", inst.Cond, inst.ValueTrue, inst.ValueFalse)
   316  	for _, md := range inst.Metadata {
   317  		fmt.Fprintf(buf, ", %s", md)
   318  	}
   319  	return buf.String()
   320  }
   321  
   322  // Operands returns a mutable list of operands of the given instruction.
   323  func (inst *InstSelect) Operands() []*value.Value {
   324  	return []*value.Value{&inst.Cond, &inst.ValueTrue, &inst.ValueFalse}
   325  }
   326  
   327  // ~~~ [ freeze ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   328  
   329  // InstFreeze is an LLVM IR freeze instruction.
   330  type InstFreeze struct {
   331  	// Name of local variable associated with the result.
   332  	LocalIdent
   333  	// Operand.
   334  	X value.Value
   335  	// extra.
   336  
   337  	// Type of result produced by the instruction.
   338  	Typ types.Type
   339  	// (optional) Metadata.
   340  	Metadata
   341  }
   342  
   343  // NewInstFreeze returns a new freeze instruction based on the given
   344  // operand.
   345  func NewInstFreeze(x value.Value) *InstFreeze {
   346  	inst := &InstFreeze{X: x}
   347  	// Compute type.
   348  	inst.Type()
   349  	return inst
   350  }
   351  
   352  // String returns the LLVM syntax representation of the instruction as a
   353  // type-value pair.
   354  func (inst *InstFreeze) String() string {
   355  	return fmt.Sprintf("%s %s", inst.Type(), inst.Ident())
   356  }
   357  
   358  // Type returns the type of the instruction.
   359  func (inst *InstFreeze) Type() types.Type {
   360  	// Cache type if not present.
   361  	if inst.Typ == nil {
   362  		inst.Typ = inst.X.Type()
   363  	}
   364  	return inst.Typ
   365  }
   366  
   367  // LLString returns the LLVM syntax representation of the instruction.
   368  //
   369  // 'freeze' Type Value
   370  func (inst *InstFreeze) LLString() string {
   371  	buf := &strings.Builder{}
   372  	fmt.Fprintf(buf, "%s = ", inst.Ident())
   373  	fmt.Fprintf(buf, "freeze %s", inst.X)
   374  	for _, md := range inst.Metadata {
   375  		fmt.Fprintf(buf, ", %s", md)
   376  	}
   377  	return buf.String()
   378  }
   379  
   380  // Operands returns a mutable list of operands of the given instruction.
   381  func (inst *InstFreeze) Operands() []*value.Value {
   382  	return []*value.Value{&inst.X}
   383  }
   384  
   385  // ~~~ [ call ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   386  
   387  // InstCall is an LLVM IR call instruction.
   388  type InstCall struct {
   389  	// Name of local variable associated with the result.
   390  	LocalIdent
   391  	// Callee.
   392  	// TODO: specify the set of underlying types of Callee.
   393  	Callee value.Value
   394  	// Function arguments.
   395  	//
   396  	// Arg has one of the following underlying types:
   397  	//    value.Value
   398  	//    *ir.Arg
   399  	//    TODO: add metadata value?
   400  	Args []value.Value
   401  
   402  	// extra.
   403  
   404  	// Type of result produced by the instruction.
   405  	Typ types.Type
   406  	// (optional) Tail; zero if not present.
   407  	Tail enum.Tail
   408  	// (optional) Fast math flags.
   409  	FastMathFlags []enum.FastMathFlag
   410  	// (optional) Calling convention; zero if not present.
   411  	CallingConv enum.CallingConv
   412  	// (optional) Return attributes.
   413  	ReturnAttrs []ReturnAttribute
   414  	// (optional) Address space; zero if not present.
   415  	AddrSpace types.AddrSpace
   416  	// (optional) Function attributes.
   417  	FuncAttrs []FuncAttribute
   418  	// (optional) Operand bundles.
   419  	OperandBundles []*OperandBundle
   420  	// (optional) Metadata.
   421  	Metadata
   422  }
   423  
   424  // NewCall returns a new call instruction based on the given callee and function
   425  // arguments.
   426  //
   427  // TODO: specify the set of underlying types of callee.
   428  func NewCall(callee value.Value, args ...value.Value) *InstCall {
   429  	inst := &InstCall{Callee: callee, Args: args}
   430  	// Compute type.
   431  	inst.Type()
   432  	return inst
   433  }
   434  
   435  // String returns the LLVM syntax representation of the instruction as a
   436  // type-value pair.
   437  func (inst *InstCall) String() string {
   438  	return fmt.Sprintf("%s %s", inst.Type(), inst.Ident())
   439  }
   440  
   441  // Type returns the type of the instruction.
   442  func (inst *InstCall) Type() types.Type {
   443  	// Cache type if not present.
   444  	if inst.Typ == nil {
   445  		sig := inst.Sig()
   446  		inst.Typ = sig.RetType
   447  	}
   448  	return inst.Typ
   449  }
   450  
   451  // LLString returns the LLVM syntax representation of the instruction.
   452  //
   453  // Tailopt 'call' FastMathFlags=FastMathFlag* CallingConvopt ReturnAttrs=ReturnAttribute* AddrSpaceopt Typ=Type Callee=Value '(' Args ')' FuncAttrs=FuncAttribute* OperandBundles=('[' (OperandBundle separator ',')+ ']')? Metadata=(',' MetadataAttachment)+?
   454  func (inst *InstCall) LLString() string {
   455  	buf := &strings.Builder{}
   456  	if !inst.Type().Equal(types.Void) {
   457  		fmt.Fprintf(buf, "%s = ", inst.Ident())
   458  	}
   459  	if inst.Tail != enum.TailNone {
   460  		fmt.Fprintf(buf, "%s ", inst.Tail)
   461  	}
   462  	buf.WriteString("call")
   463  	for _, flag := range inst.FastMathFlags {
   464  		fmt.Fprintf(buf, " %s", flag)
   465  	}
   466  	if inst.CallingConv != enum.CallingConvNone {
   467  		fmt.Fprintf(buf, " %s", callingConvString(inst.CallingConv))
   468  	}
   469  	for _, attr := range inst.ReturnAttrs {
   470  		fmt.Fprintf(buf, " %s", attr)
   471  	}
   472  	// (optional) Address space.
   473  	if inst.AddrSpace != 0 {
   474  		fmt.Fprintf(buf, " %s", inst.AddrSpace)
   475  	}
   476  	// Use function signature instead of return type for variadic functions.
   477  	calleeType := inst.Type()
   478  	if sig := inst.Sig(); sig.Variadic {
   479  		calleeType = sig
   480  	}
   481  	fmt.Fprintf(buf, " %s %s(", calleeType, inst.Callee.Ident())
   482  	for i, arg := range inst.Args {
   483  		if i != 0 {
   484  			buf.WriteString(", ")
   485  		}
   486  		buf.WriteString(arg.String())
   487  	}
   488  	buf.WriteString(")")
   489  	for _, attr := range inst.FuncAttrs {
   490  		fmt.Fprintf(buf, " %s", attr)
   491  	}
   492  	if len(inst.OperandBundles) > 0 {
   493  		buf.WriteString(" [ ")
   494  		for i, operandBundle := range inst.OperandBundles {
   495  			if i != 0 {
   496  				buf.WriteString(", ")
   497  			}
   498  			buf.WriteString(operandBundle.String())
   499  		}
   500  		buf.WriteString(" ]")
   501  	}
   502  	for _, md := range inst.Metadata {
   503  		fmt.Fprintf(buf, ", %s", md)
   504  	}
   505  	return buf.String()
   506  }
   507  
   508  // Operands returns a mutable list of operands of the given instruction.
   509  func (inst *InstCall) Operands() []*value.Value {
   510  	ops := make([]*value.Value, 0, 1+len(inst.Args))
   511  	ops = append(ops, &inst.Callee)
   512  	for i := range inst.Args {
   513  		ops = append(ops, &inst.Args[i])
   514  	}
   515  	return ops
   516  }
   517  
   518  // Sig returns the function signature of the callee.
   519  func (inst *InstCall) Sig() *types.FuncType {
   520  	t, ok := inst.Callee.Type().(*types.PointerType)
   521  	if !ok {
   522  		panic(fmt.Errorf("invalid callee type; expected *types.PointerType, got %T", inst.Callee.Type()))
   523  	}
   524  	sig, ok := t.ElemType.(*types.FuncType)
   525  	if !ok {
   526  		panic(fmt.Errorf("invalid callee type; expected *types.FuncType, got %T", t.ElemType))
   527  	}
   528  	return sig
   529  }
   530  
   531  // ~~~ [ va_arg ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   532  
   533  // InstVAArg is an LLVM IR va_arg instruction.
   534  type InstVAArg struct {
   535  	// Name of local variable associated with the result.
   536  	LocalIdent
   537  	// Variable argument list.
   538  	ArgList value.Value
   539  	// Argument type.
   540  	ArgType types.Type
   541  
   542  	// extra.
   543  
   544  	// (optional) Metadata.
   545  	Metadata
   546  }
   547  
   548  // NewVAArg returns a new va_arg instruction based on the given variable
   549  // argument list and argument type.
   550  func NewVAArg(argList value.Value, argType types.Type) *InstVAArg {
   551  	return &InstVAArg{ArgList: argList, ArgType: argType}
   552  }
   553  
   554  // String returns the LLVM syntax representation of the instruction as a
   555  // type-value pair.
   556  func (inst *InstVAArg) String() string {
   557  	return fmt.Sprintf("%s %s", inst.Type(), inst.Ident())
   558  }
   559  
   560  // Type returns the type of the instruction.
   561  func (inst *InstVAArg) Type() types.Type {
   562  	return inst.ArgType
   563  }
   564  
   565  // LLString returns the LLVM syntax representation of the instruction.
   566  //
   567  // 'va_arg' ArgList=TypeValue ',' ArgType=Type Metadata=(',' MetadataAttachment)+?
   568  func (inst *InstVAArg) LLString() string {
   569  	buf := &strings.Builder{}
   570  	fmt.Fprintf(buf, "%s = ", inst.Ident())
   571  	fmt.Fprintf(buf, "va_arg %s, %s", inst.ArgList, inst.ArgType)
   572  	for _, md := range inst.Metadata {
   573  		fmt.Fprintf(buf, ", %s", md)
   574  	}
   575  	return buf.String()
   576  }
   577  
   578  // Operands returns a mutable list of operands of the given instruction.
   579  func (inst *InstVAArg) Operands() []*value.Value {
   580  	return []*value.Value{&inst.ArgList}
   581  }
   582  
   583  // ~~~ [ landingpad ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   584  
   585  // InstLandingPad is an LLVM IR landingpad instruction.
   586  type InstLandingPad struct {
   587  	// Name of local variable associated with the result.
   588  	LocalIdent
   589  	// Result type.
   590  	ResultType types.Type
   591  	// (optional) Cleanup landing pad.
   592  	Cleanup bool
   593  	// Filter and catch clauses; zero or more if Cleanup is true, otherwise one
   594  	// or more.
   595  	Clauses []*Clause
   596  
   597  	// extra.
   598  
   599  	// (optional) Metadata.
   600  	Metadata
   601  }
   602  
   603  // NewLandingPad returns a new landingpad instruction based on the given result
   604  // type and filter/catch clauses.
   605  func NewLandingPad(resultType types.Type, clauses ...*Clause) *InstLandingPad {
   606  	return &InstLandingPad{ResultType: resultType, Clauses: clauses}
   607  }
   608  
   609  // String returns the LLVM syntax representation of the instruction as a
   610  // type-value pair.
   611  func (inst *InstLandingPad) String() string {
   612  	return fmt.Sprintf("%s %s", inst.Type(), inst.Ident())
   613  }
   614  
   615  // Type returns the type of the instruction.
   616  func (inst *InstLandingPad) Type() types.Type {
   617  	return inst.ResultType
   618  }
   619  
   620  // LLString returns the LLVM syntax representation of the instruction.
   621  //
   622  // 'landingpad' ResultType=Type Cleanupopt Clauses=Clause* Metadata=(',' MetadataAttachment)+?
   623  func (inst *InstLandingPad) LLString() string {
   624  	buf := &strings.Builder{}
   625  	fmt.Fprintf(buf, "%s = ", inst.Ident())
   626  	fmt.Fprintf(buf, "landingpad %s", inst.ResultType)
   627  	if inst.Cleanup {
   628  		buf.WriteString("\n\t\tcleanup")
   629  	}
   630  	for _, clause := range inst.Clauses {
   631  		fmt.Fprintf(buf, "\n\t\t%s", clause)
   632  	}
   633  	for _, md := range inst.Metadata {
   634  		fmt.Fprintf(buf, ", %s", md)
   635  	}
   636  	return buf.String()
   637  }
   638  
   639  // Operands returns a mutable list of operands of the given instruction.
   640  func (inst *InstLandingPad) Operands() []*value.Value {
   641  	ops := make([]*value.Value, 0, len(inst.Clauses))
   642  	for i := range inst.Clauses {
   643  		ops = append(ops, &inst.Clauses[i].X)
   644  	}
   645  	return ops
   646  }
   647  
   648  // ___ [ Landingpad clause ] ___________________________________________________
   649  
   650  // Clause is a landingpad catch or filter clause.
   651  type Clause struct {
   652  	// Clause type (catch or filter).
   653  	Type enum.ClauseType
   654  	// Operand.
   655  	X value.Value
   656  }
   657  
   658  // NewClause returns a new landingpad clause based on the given clause type and
   659  // operand.
   660  func NewClause(clauseType enum.ClauseType, x value.Value) *Clause {
   661  	return &Clause{Type: clauseType, X: x}
   662  }
   663  
   664  // String returns the string representation of the landingpad clause.
   665  func (clause *Clause) String() string {
   666  	return fmt.Sprintf("%s %s", clause.Type, clause.X)
   667  }
   668  
   669  // ~~~ [ catchpad ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   670  
   671  // InstCatchPad is an LLVM IR catchpad instruction.
   672  type InstCatchPad struct {
   673  	// Name of local variable associated with the result.
   674  	LocalIdent
   675  	// Parent catchswitch terminator.
   676  	CatchSwitch value.Value // *ir.TermCatchSwitch
   677  	// Exception arguments.
   678  	//
   679  	// Arg has one of the following underlying types:
   680  	//    value.Value
   681  	//    TODO: add metadata value?
   682  	Args []value.Value
   683  
   684  	// extra.
   685  
   686  	// (optional) Metadata.
   687  	Metadata
   688  }
   689  
   690  // NewCatchPad returns a new catchpad instruction based on the given parent
   691  // catchswitch terminator and exception arguments.
   692  func NewCatchPad(catchSwitch *TermCatchSwitch, args ...value.Value) *InstCatchPad {
   693  	return &InstCatchPad{CatchSwitch: catchSwitch, Args: args}
   694  }
   695  
   696  // String returns the LLVM syntax representation of the instruction as a
   697  // type-value pair.
   698  func (inst *InstCatchPad) String() string {
   699  	return fmt.Sprintf("%s %s", inst.Type(), inst.Ident())
   700  }
   701  
   702  // Type returns the type of the instruction.
   703  func (inst *InstCatchPad) Type() types.Type {
   704  	return types.Token
   705  }
   706  
   707  // LLString returns the LLVM syntax representation of the instruction.
   708  //
   709  // 'catchpad' 'within' CatchSwitch=LocalIdent '[' Args=(ExceptionArg separator ',')* ']' Metadata=(',' MetadataAttachment)+?
   710  func (inst *InstCatchPad) LLString() string {
   711  	buf := &strings.Builder{}
   712  	fmt.Fprintf(buf, "%s = ", inst.Ident())
   713  	fmt.Fprintf(buf, "catchpad within %s [", inst.CatchSwitch.Ident())
   714  	for i, arg := range inst.Args {
   715  		if i != 0 {
   716  			buf.WriteString(", ")
   717  		}
   718  		buf.WriteString(arg.String())
   719  	}
   720  	buf.WriteString("]")
   721  	for _, md := range inst.Metadata {
   722  		fmt.Fprintf(buf, ", %s", md)
   723  	}
   724  	return buf.String()
   725  }
   726  
   727  // Operands returns a mutable list of operands of the given instruction.
   728  func (inst *InstCatchPad) Operands() []*value.Value {
   729  	ops := make([]*value.Value, 0, 1+len(inst.Args))
   730  	ops = append(ops, &inst.CatchSwitch)
   731  	for i := range inst.Args {
   732  		ops = append(ops, &inst.Args[i])
   733  	}
   734  	return ops
   735  }
   736  
   737  // ~~~ [ cleanuppad ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   738  
   739  // InstCleanupPad is an LLVM IR cleanuppad instruction.
   740  type InstCleanupPad struct {
   741  	// Name of local variable associated with the result.
   742  	LocalIdent
   743  	// Parent exception pad.
   744  	ParentPad value.Value // ir.ExceptionPad
   745  	// Exception arguments.
   746  	//
   747  	// Arg has one of the following underlying types:
   748  	//    value.Value
   749  	//    TODO: add metadata value?
   750  	Args []value.Value
   751  
   752  	// extra.
   753  
   754  	// (optional) Metadata.
   755  	Metadata
   756  }
   757  
   758  // NewCleanupPad returns a new cleanuppad instruction based on the given
   759  // parent exception pad and exception arguments.
   760  func NewCleanupPad(parentPad ExceptionPad, args ...value.Value) *InstCleanupPad {
   761  	return &InstCleanupPad{ParentPad: parentPad, Args: args}
   762  }
   763  
   764  // String returns the LLVM syntax representation of the instruction as a
   765  // type-value pair.
   766  func (inst *InstCleanupPad) String() string {
   767  	return fmt.Sprintf("%s %s", inst.Type(), inst.Ident())
   768  }
   769  
   770  // Type returns the type of the instruction.
   771  func (inst *InstCleanupPad) Type() types.Type {
   772  	return types.Token
   773  }
   774  
   775  // LLString returns the LLVM syntax representation of the instruction.
   776  //
   777  // 'cleanuppad' 'within' ParentPad=ExceptionPad '[' Args=(ExceptionArg separator ',')* ']' Metadata=(',' MetadataAttachment)+?
   778  func (inst *InstCleanupPad) LLString() string {
   779  	buf := &strings.Builder{}
   780  	fmt.Fprintf(buf, "%s = ", inst.Ident())
   781  	fmt.Fprintf(buf, "cleanuppad within %s [", inst.ParentPad.Ident())
   782  	for i, arg := range inst.Args {
   783  		if i != 0 {
   784  			buf.WriteString(", ")
   785  		}
   786  		buf.WriteString(arg.String())
   787  	}
   788  	buf.WriteString("]")
   789  	for _, md := range inst.Metadata {
   790  		fmt.Fprintf(buf, ", %s", md)
   791  	}
   792  	return buf.String()
   793  }
   794  
   795  // Operands returns a mutable list of operands of the given instruction.
   796  func (inst *InstCleanupPad) Operands() []*value.Value {
   797  	ops := make([]*value.Value, 0, 1+len(inst.Args))
   798  	ops = append(ops, &inst.ParentPad)
   799  	for i := range inst.Args {
   800  		ops = append(ops, &inst.Args[i])
   801  	}
   802  	return ops
   803  }