github.com/llir/llvm@v0.3.6/asm/helper.go (about)

     1  package asm
     2  
     3  import (
     4  	"fmt"
     5  	"strconv"
     6  	"strings"
     7  
     8  	"github.com/llir/ll/ast"
     9  	asmenum "github.com/llir/llvm/asm/enum"
    10  	"github.com/llir/llvm/internal/enc"
    11  	"github.com/llir/llvm/ir"
    12  	"github.com/llir/llvm/ir/constant"
    13  	"github.com/llir/llvm/ir/enum"
    14  	"github.com/llir/llvm/ir/metadata"
    15  	"github.com/llir/llvm/ir/types"
    16  	"github.com/llir/llvm/ir/value"
    17  	"github.com/pkg/errors"
    18  )
    19  
    20  // === [ Identifiers ] =========================================================
    21  
    22  // --- [ Global identifiers ] --------------------------------------------------
    23  
    24  // globalIdent returns the identifier (without '@' prefix) of the given global
    25  // identifier.
    26  func globalIdent(old ast.GlobalIdent) ir.GlobalIdent {
    27  	ident := old.Text()
    28  	const prefix = "@"
    29  	if !strings.HasPrefix(ident, prefix) {
    30  		panic(fmt.Errorf("invalid global identifier %q; missing '%s' prefix", ident, prefix))
    31  	}
    32  	ident = ident[len(prefix):]
    33  	// positive integer -> ID
    34  	// everything else (including negative integer) -> Name
    35  	if id, err := strconv.ParseInt(ident, 10, 64); err == nil && id >= 0 {
    36  		return ir.GlobalIdent{GlobalID: id}
    37  	}
    38  	// Unquote after trying to parse as ID, since @"42" is recognized as named
    39  	// and not unnamed.
    40  	ident = unquote(ident)
    41  	return ir.GlobalIdent{GlobalName: ident}
    42  }
    43  
    44  // --- [ Local identifiers ] ---------------------------------------------------
    45  
    46  // localIdent returns the identifier (without '%' prefix) of the given local
    47  // identifier.
    48  func localIdent(old ast.LocalIdent) ir.LocalIdent {
    49  	ident := old.Text()
    50  	const prefix = "%"
    51  	if !strings.HasPrefix(ident, prefix) {
    52  		panic(fmt.Errorf("invalid local identifier %q; missing '%s' prefix", ident, prefix))
    53  	}
    54  	ident = ident[len(prefix):]
    55  	// positive integer -> ID
    56  	// everything else (including negative integer) -> Name
    57  	if id, err := strconv.ParseInt(ident, 10, 64); err == nil && id >= 0 {
    58  		return ir.LocalIdent{LocalID: id}
    59  	}
    60  	// Unquote after trying to parse as ID, since %"42" is recognized as named
    61  	// and not unnamed.
    62  	ident = unquote(ident)
    63  	return ir.LocalIdent{LocalName: ident}
    64  }
    65  
    66  // --- [ Label identifiers ] ---------------------------------------------------
    67  
    68  // labelIdent returns the identifier (without ':' suffix) of the given label
    69  // identifier.
    70  func labelIdent(old ast.LabelIdent) ir.LocalIdent {
    71  	ident := old.Text()
    72  	const suffix = ":"
    73  	if !strings.HasSuffix(ident, suffix) {
    74  		panic(fmt.Errorf("invalid label identifier %q; missing '%s' suffix", ident, suffix))
    75  	}
    76  	ident = ident[:len(ident)-len(suffix)]
    77  	// positive integer -> ID
    78  	// everything else (including negative integer) -> Name
    79  	if id, err := strconv.ParseInt(ident, 10, 64); err == nil && id >= 0 {
    80  		return ir.LocalIdent{LocalID: id}
    81  	}
    82  	// Unquote after trying to parse as ID, since %"42" is recognized as named
    83  	// and not unnamed.
    84  	ident = unquote(ident)
    85  	return ir.LocalIdent{LocalName: ident}
    86  }
    87  
    88  // --- [ Attribute group identifiers ] -----------------------------------------
    89  
    90  // attrGroupID returns the ID (without '#' prefix) of the given attribute group
    91  // ID.
    92  func attrGroupID(old ast.AttrGroupID) int64 {
    93  	text := old.Text()
    94  	const prefix = "#"
    95  	if !strings.HasPrefix(text, prefix) {
    96  		panic(fmt.Errorf("invalid attribute group ID %q; missing '%s' prefix", text, prefix))
    97  	}
    98  	text = text[len(prefix):]
    99  	id, err := strconv.ParseInt(text, 10, 64)
   100  	if err != nil {
   101  		panic(fmt.Errorf("unable to parse attribute group ID %q; %v", text, err))
   102  	}
   103  	return id
   104  }
   105  
   106  // --- [ Comdat identifiers ] --------------------------------------------------
   107  
   108  // comdatName returns the name (without '%' prefix) of the given comdat name.
   109  func comdatName(old ast.ComdatName) string {
   110  	name := old.Text()
   111  	const prefix = "$"
   112  	if !strings.HasPrefix(name, prefix) {
   113  		panic(fmt.Errorf("invalid comdat name %q; missing '%s' prefix", name, prefix))
   114  	}
   115  	name = name[len(prefix):]
   116  	return unquote(name)
   117  }
   118  
   119  // --- [ Metadata identifiers ] ------------------------------------------------
   120  
   121  // metadataName returns the name (without '!' prefix) of the given metadata
   122  // name.
   123  func metadataName(old ast.MetadataName) string {
   124  	name := old.Text()
   125  	const prefix = "!"
   126  	if !strings.HasPrefix(name, prefix) {
   127  		panic(fmt.Errorf("invalid metadata name %q; missing '%s' prefix", name, prefix))
   128  	}
   129  	name = name[len(prefix):]
   130  	return string(enc.Unescape(name))
   131  }
   132  
   133  // metadataID returns the ID (without '!' prefix) of the given metadata ID.
   134  func metadataID(old ast.MetadataID) int64 {
   135  	text := old.Text()
   136  	const prefix = "!"
   137  	if !strings.HasPrefix(text, prefix) {
   138  		panic(fmt.Errorf("invalid metadata ID %q; missing '%s' prefix", text, prefix))
   139  	}
   140  	text = text[len(prefix):]
   141  	id, err := strconv.ParseInt(text, 10, 64)
   142  	if err != nil {
   143  		panic(fmt.Errorf("unable to parse metadata ID %q; %v", text, err))
   144  	}
   145  	return id
   146  }
   147  
   148  // === [ Literals ] ============================================================
   149  
   150  // --- [ Integer literals ] ----------------------------------------------------
   151  
   152  // boolLit returns the boolean value corresponding to the given boolean literal.
   153  func boolLit(old ast.BoolLit) bool {
   154  	text := old.Text()
   155  	switch text {
   156  	case "true":
   157  		return true
   158  	case "false":
   159  		return false
   160  	default:
   161  		panic(fmt.Errorf(`invalid boolean literal; expected "true" or "false", got %q`, text))
   162  	}
   163  }
   164  
   165  // uintLit returns the unsigned integer value corresponding to the given
   166  // unsigned integer literal.
   167  func uintLit(old ast.UintLit) uint64 {
   168  	text := old.Text()
   169  	var x uint64
   170  	var err error
   171  	switch {
   172  	// unsigned hexadecimal integer literal
   173  	case strings.HasPrefix(text, "u0x"):
   174  		text = text[len("u0x"):]
   175  		x, err = strconv.ParseUint(text, 16, 64)
   176  	// signed hexadecimal integer literal
   177  	case strings.HasPrefix(text, "s0x"):
   178  		panic(fmt.Errorf("invalid use of signed hexadecimal integer literal %q; grammar for ast.UintLit denotes unsigned integer literal", text))
   179  	default:
   180  		x, err = strconv.ParseUint(text, 10, 64)
   181  	}
   182  	if err != nil {
   183  		panic(fmt.Errorf("unable to parse unsigned integer literal %q; %v", text, err))
   184  	}
   185  	return x
   186  }
   187  
   188  // uintSlice returns the slice of unsigned integer value corresponding to the given
   189  // unsigned integer slice.
   190  func uintSlice(olds []ast.UintLit) []uint64 {
   191  	xs := make([]uint64, len(olds))
   192  	for i, old := range olds {
   193  		x := uintLit(old)
   194  		xs[i] = x
   195  	}
   196  	return xs
   197  }
   198  
   199  // intLit returns the integer value corresponding to the given integer literal.
   200  func intLit(old ast.IntLit) int64 {
   201  	text := old.Text()
   202  	var x int64
   203  	var err error
   204  	switch {
   205  	// unsigned hexadecimal integer literal
   206  	case strings.HasPrefix(text, "u0x"):
   207  		text = text[len("u0x"):]
   208  		x, err = strconv.ParseInt(text, 16, 64)
   209  	// signed hexadecimal integer literal
   210  	case strings.HasPrefix(text, "s0x"):
   211  		// Note: the grammar uses ast.IntLit only for two purposes:
   212  		//
   213  		// 1) integer constants
   214  		// 2) signed integers of specialized metadata fields
   215  		//
   216  		// Integer constants are not parsed here, they are parsed by irIntConst
   217  		// using constant.NewIntFromString.
   218  		//
   219  		// In particular, we need to know the underlying type (bit size) associated
   220  		// with the integer literal to be able to parse signed values, as they are
   221  		// represented in two's complement hexadecimal notation.
   222  		//
   223  		// Type information is available when parsing integer constant values, as
   224  		// values are denoted by type-value pairs, so constant.NewIntFromString
   225  		// has all required information.
   226  		//
   227  		// However, when parsing signed values used for specialized metadata fields,
   228  		// this information is not available. As such, rather than potentially loosing
   229  		// information, we choose to panic and report the ambiguous use of "s0x"
   230  		// notation in specialized metadata fields, where `-42` would suffice.
   231  		panic(fmt.Errorf(`ambiguous use of signed hexadecimal integer literal %q, no type information available; consider using signed integer literal representation instead (e.g. "-42")`, text))
   232  	default:
   233  		x, err = strconv.ParseInt(text, 10, 64)
   234  	}
   235  	if err != nil {
   236  		panic(fmt.Errorf("unable to parse integer literal %q; %v", text, err))
   237  	}
   238  	return x
   239  }
   240  
   241  // --- [ String literals ] -----------------------------------------------------
   242  
   243  // stringLit returns the string corresponding to the given string literal.
   244  func stringLit(old ast.StringLit) string {
   245  	return unquote(old.Text())
   246  }
   247  
   248  // ___ [ Helpers ] _____________________________________________________________
   249  
   250  // irAddrSpace returns the IR address space corresponding to the given AST
   251  // address space.
   252  func irAddrSpace(old ast.AddrSpace) types.AddrSpace {
   253  	return types.AddrSpace(uintLit(old.N()))
   254  }
   255  
   256  // irAlign returns the IR alignment corresponding to the given AST alignment.
   257  func irAlign(old ast.Align) ir.Align {
   258  	return ir.Align(uintLit(old.N()))
   259  }
   260  
   261  // irArg returns the IR argument corresponding to the given AST argument.
   262  func (fgen *funcGen) irArg(old ast.Arg) (value.Value, error) {
   263  	typ, err := fgen.gen.irType(old.Typ())
   264  	if err != nil {
   265  		return nil, errors.WithStack(err)
   266  	}
   267  	switch oldVal := old.Val().(type) {
   268  	case ast.Value:
   269  		x, err := fgen.irValue(typ, oldVal)
   270  		if err != nil {
   271  			return nil, errors.WithStack(err)
   272  		}
   273  		// (optional) Parameter attributes.
   274  		if oldAttrs := old.Attrs(); len(oldAttrs) > 0 {
   275  			attrs := make([]ir.ParamAttribute, len(oldAttrs))
   276  			for i, oldAttr := range old.Attrs() {
   277  				attr, err := fgen.gen.irParamAttribute(oldAttr)
   278  				if err != nil {
   279  					return nil, errors.WithStack(err)
   280  				}
   281  				attrs[i] = attr
   282  			}
   283  			return &ir.Arg{Attrs: attrs, Value: x}, nil
   284  		}
   285  		return x, nil
   286  	case ast.Metadata:
   287  		md, err := fgen.irMetadata(oldVal)
   288  		if err != nil {
   289  			return nil, errors.WithStack(err)
   290  		}
   291  		return &metadata.Value{Value: md}, nil
   292  	default:
   293  		panic(fmt.Errorf("support for value %T not yet implemented", oldVal))
   294  	}
   295  }
   296  
   297  // irBlock returns the IR basic block corresponding to the given AST label.
   298  func (fgen *funcGen) irBlock(old ast.Label) (*ir.Block, error) {
   299  	ident := localIdent(old.Name())
   300  	v, ok := fgen.locals[ident]
   301  	if !ok {
   302  		return nil, errors.Errorf("unable to locate local identifier %q", ident.Ident())
   303  	}
   304  	block, ok := v.(*ir.Block)
   305  	if !ok {
   306  		return nil, errors.Errorf("invalid basic block type; expected *ir.Block, got %T", v)
   307  	}
   308  	return block, nil
   309  }
   310  
   311  // irCallingConv returns the IR calling convention corresponding to the given
   312  // AST calling convention.
   313  func irCallingConv(old ast.CallingConv) enum.CallingConv {
   314  	switch old := old.(type) {
   315  	case *ast.CallingConvEnum:
   316  		return asmenum.CallingConvFromString(old.Text())
   317  	case *ast.CallingConvInt:
   318  		cc := uintLit(old.UintLit())
   319  		switch cc {
   320  		case 0:
   321  			// Note, C calling convention is defined as 0 in LLVM. To have the zero-value
   322  			// calling convention mean no calling convention, re-define C calling
   323  			// convention as 1, and use 0 for none.
   324  			return enum.CallingConvC
   325  		default:
   326  			return enum.CallingConv(cc)
   327  		}
   328  	default:
   329  		panic(fmt.Errorf("support for calling convention type %T not yet implemented", old))
   330  	}
   331  }
   332  
   333  // irCase returns the IR switch case corresponding to the given AST switch case.
   334  func (fgen *funcGen) irCase(n ast.Case) (*ir.Case, error) {
   335  	// Case comparand.
   336  	x, err := fgen.gen.irTypeConst(n.X())
   337  	if err != nil {
   338  		return nil, errors.WithStack(err)
   339  	}
   340  	// Case target branch.
   341  	target, err := fgen.irBlock(n.Target())
   342  	if err != nil {
   343  		return nil, errors.WithStack(err)
   344  	}
   345  	return ir.NewCase(x, target), nil
   346  }
   347  
   348  // irClause returns the IR clause corresponding to the given AST clause.
   349  func (fgen *funcGen) irClause(n ast.Clause) (*ir.Clause, error) {
   350  	x, err := fgen.irTypeValue(n.X())
   351  	if err != nil {
   352  		return nil, errors.WithStack(err)
   353  	}
   354  	clauseType := asmenum.ClauseTypeFromString(n.ClauseType().Text())
   355  	return ir.NewClause(clauseType, x), nil
   356  }
   357  
   358  // irExceptionArg returns the IR exception argument corresponding to the given
   359  // AST exception argument.
   360  func (fgen *funcGen) irExceptionArg(old ast.ExceptionArg) (value.Value, error) {
   361  	typ, err := fgen.gen.irType(old.Typ())
   362  	if err != nil {
   363  		return nil, errors.WithStack(err)
   364  	}
   365  	switch val := old.Val().(type) {
   366  	case ast.Value:
   367  		return fgen.irValue(typ, val)
   368  	case ast.Metadata:
   369  		md, err := fgen.irMetadata(val)
   370  		if err != nil {
   371  			return nil, errors.WithStack(err)
   372  		}
   373  		return &metadata.Value{Value: md}, nil
   374  	default:
   375  		panic(fmt.Errorf("spport for exception argument value %T not yet implemented", val))
   376  	}
   377  }
   378  
   379  // irExceptionPad returns the IR exception pad corresponding to the given AST
   380  // exception pad.
   381  func (fgen *funcGen) irExceptionPad(old ast.ExceptionPad) (ir.ExceptionPad, error) {
   382  	switch old := old.(type) {
   383  	case *ast.NoneConst:
   384  		return constant.None, nil
   385  	case *ast.LocalIdent:
   386  		ident := localIdent(*old)
   387  		v, ok := fgen.locals[ident]
   388  		if !ok {
   389  			return nil, errors.Errorf("unable to locate local identifier %q", ident.Ident())
   390  		}
   391  		return v, nil
   392  	default:
   393  		panic(fmt.Errorf("spport for exception pad %T not yet implemented", old))
   394  	}
   395  }
   396  
   397  // irFastMathFlags returns the IR fast math flags corresponding to the given AST
   398  // fast math flags.
   399  func irFastMathFlags(olds []ast.FastMathFlag) []enum.FastMathFlag {
   400  	if len(olds) == 0 {
   401  		return nil
   402  	}
   403  	flags := make([]enum.FastMathFlag, len(olds))
   404  	for i, old := range olds {
   405  		flag := asmenum.FastMathFlagFromString(old.Text())
   406  		flags[i] = flag
   407  	}
   408  	return flags
   409  }
   410  
   411  // irFuncAttribute returns the IR function attribute corresponding to the given
   412  // AST function attribute.
   413  func (gen *generator) irFuncAttribute(old ast.FuncAttribute) ir.FuncAttribute {
   414  	switch old := old.(type) {
   415  	case *ast.AttrString:
   416  		return ir.AttrString(unquote(old.Text()))
   417  	case *ast.AttrPair:
   418  		return ir.AttrPair{
   419  			Key:   unquote(old.Key().Text()),
   420  			Value: unquote(old.Val().Text()),
   421  		}
   422  	case *ast.AttrGroupID:
   423  		id := attrGroupID(*old)
   424  		def, ok := gen.new.attrGroupDefs[id]
   425  		if !ok {
   426  			// Attribute group definition for ID not found.
   427  			//
   428  			// The input file should have contained this definition, but seeing as
   429  			// the LLVM test suite contains several LLVM IR files which omit the
   430  			// attribute group definitions, we will play nice and add an empty
   431  			// definition instead of panicking.
   432  			//
   433  			// This issue is tracked at: https://github.com/llir/llvm/issues/37
   434  			def = &ir.AttrGroupDef{ID: id}
   435  			gen.new.attrGroupDefs[id] = def
   436  		}
   437  		return def
   438  	// TODO: add support for Align.
   439  	//case *ast.Align:
   440  	//	return ir.Align(uintLit(old.N()))
   441  	case *ast.AlignPair:
   442  		return ir.Align(uintLit(old.N()))
   443  	case *ast.AlignStack:
   444  		return ir.AlignStack(uintLit(old.N()))
   445  	case *ast.AlignStackPair:
   446  		return ir.AlignStack(uintLit(old.N()))
   447  	case *ast.AllocSize:
   448  		elemSizeIndex := int(uintLit(old.ElemSizeIndex()))
   449  		if nElemsIndex, ok := old.NElemsIndex(); ok {
   450  			return ir.AllocSize{
   451  				ElemSizeIndex: elemSizeIndex,
   452  				NElemsIndex:   int(uintLit(nElemsIndex)),
   453  			}
   454  		}
   455  		return ir.AllocSize{
   456  			ElemSizeIndex: elemSizeIndex,
   457  			NElemsIndex:   -1,
   458  		}
   459  	case *ast.FuncAttr:
   460  		return asmenum.FuncAttrFromString(old.Text())
   461  	case *ast.Preallocated:
   462  		typ, err := gen.irType(old.Typ())
   463  		if err != nil {
   464  			panic(err.Error())
   465  		}
   466  		return ir.Preallocated{Typ: typ}
   467  	case *ast.VScaleRange:
   468  		min := int(uintLit(old.Min()))
   469  		if max, ok := old.Max(); ok {
   470  			return ir.VectorScaleRange{
   471  				Min: min,
   472  				Max: int(uintLit(max)),
   473  			}
   474  		}
   475  		return ir.VectorScaleRange{
   476  			Min: -1,  // NOTE: using -1 to denote omitted value.
   477  			Max: min, // NOTE: Min denotes Max if Max is not present.
   478  		}
   479  	default:
   480  		panic(fmt.Errorf("support for function attribute %T not yet implemented", old))
   481  	}
   482  }
   483  
   484  // irImmutable returns the immutable boolean (constant or global) corresponding
   485  // to the given AST immutable.
   486  func irImmutable(old ast.Immutable) bool {
   487  	text := old.Text()
   488  	switch text {
   489  	case "constant":
   490  		return true
   491  	case "global":
   492  		return false
   493  	default:
   494  		panic(fmt.Errorf("support for immutable %q not yet implemented", text))
   495  	}
   496  }
   497  
   498  // irIncoming returns the incoming value corresponding to the given AST incoming
   499  // value.
   500  func (fgen *funcGen) irIncoming(xType types.Type, oldX ast.Value, oldPred ast.LocalIdent) (*ir.Incoming, error) {
   501  	x, err := fgen.irValue(xType, oldX)
   502  	if err != nil {
   503  		return nil, errors.WithStack(err)
   504  	}
   505  	predIdent := localIdent(oldPred)
   506  	v, ok := fgen.locals[predIdent]
   507  	if !ok {
   508  		return nil, errors.Errorf("unable to locate local identifier %q", predIdent.Ident())
   509  	}
   510  	pred, ok := v.(*ir.Block)
   511  	if !ok {
   512  		return nil, errors.Errorf("invalid basic block type; expected *ir.Block, got %T", v)
   513  	}
   514  	return ir.NewIncoming(x, pred), nil
   515  }
   516  
   517  // irIndirectSymbol returns the IR indirect symbol corresponding to the given
   518  // AST indirect symbol.
   519  func (gen *generator) irIndirectSymbol(typ *types.PointerType, old ast.IndirectSymbol) (constant.Constant, error) {
   520  	switch old := old.(type) {
   521  	case *ast.TypeConst:
   522  		symbol, err := gen.irTypeConst(*old)
   523  		if err != nil {
   524  			return nil, errors.WithStack(err)
   525  		}
   526  		return symbol, nil
   527  	case *ast.BitCastExpr:
   528  		symbol, err := gen.irConstant(typ, old)
   529  		if err != nil {
   530  			return nil, errors.WithStack(err)
   531  		}
   532  		return symbol, nil
   533  	case *ast.GetElementPtrExpr:
   534  		symbol, err := gen.irConstant(typ, old)
   535  		if err != nil {
   536  			return nil, errors.WithStack(err)
   537  		}
   538  		return symbol, nil
   539  	case *ast.AddrSpaceCastExpr:
   540  		symbol, err := gen.irConstant(typ, old)
   541  		if err != nil {
   542  			return nil, errors.WithStack(err)
   543  		}
   544  		return symbol, nil
   545  	case *ast.IntToPtrExpr:
   546  		symbol, err := gen.irConstant(typ, old)
   547  		if err != nil {
   548  			return nil, errors.WithStack(err)
   549  		}
   550  		return symbol, nil
   551  	default:
   552  		panic(fmt.Errorf("support for indirect symbol %T not yet implemented", old))
   553  	}
   554  }
   555  
   556  // irInlineAsm translates the AST inline assembler expression into an equivalent
   557  // IR inline assembler expression.
   558  func irInlineAsm(typ types.Type, old *ast.InlineAsm) *ir.InlineAsm {
   559  	// Assembly instructions.
   560  	asm := stringLit(old.Asm())
   561  	// Constraints.
   562  	constraint := stringLit(old.Constraints())
   563  	v := ir.NewInlineAsm(typ, asm, constraint)
   564  	// (optional) Side effect.
   565  	_, v.SideEffect = old.SideEffect()
   566  	// (optional) Stack alignment.
   567  	_, v.AlignStack = old.AlignStackTok()
   568  	// (optional) Intel dialect.
   569  	_, v.IntelDialect = old.IntelDialect()
   570  	return v
   571  }
   572  
   573  // irOperandBundle returns the IR operand bundle corresponding to the given AST
   574  // operand bundle.
   575  func (fgen *funcGen) irOperandBundle(old ast.OperandBundle) (*ir.OperandBundle, error) {
   576  	// Tag.
   577  	tag := stringLit(old.Tag())
   578  	// Inputs.
   579  	var inputs []value.Value
   580  	for _, oldInput := range old.Inputs() {
   581  		input, err := fgen.irTypeValue(oldInput)
   582  		if err != nil {
   583  			return nil, errors.WithStack(err)
   584  		}
   585  		inputs = append(inputs, input)
   586  	}
   587  	return ir.NewOperandBundle(tag, inputs...), nil
   588  }
   589  
   590  // irOverflowFlags returns the IR overflow flags corresponding to the given AST
   591  // overflow flags.
   592  func irOverflowFlags(olds []ast.OverflowFlag) []enum.OverflowFlag {
   593  	if len(olds) == 0 {
   594  		return nil
   595  	}
   596  	flags := make([]enum.OverflowFlag, len(olds))
   597  	for i, old := range olds {
   598  		flag := asmenum.OverflowFlagFromString(old.Text())
   599  		flags[i] = flag
   600  	}
   601  	return flags
   602  }
   603  
   604  // irParamAttribute returns the IR parameter attribute corresponding to the given
   605  // AST parameter attribute.
   606  func (gen *generator) irParamAttribute(old ast.ParamAttribute) (ir.ParamAttribute, error) {
   607  	switch old := old.(type) {
   608  	case *ast.AttrString:
   609  		return ir.AttrString(unquote(old.Text())), nil
   610  	case *ast.AttrPair:
   611  		return ir.AttrPair{
   612  			Key:   unquote(old.Key().Text()),
   613  			Value: unquote(old.Val().Text()),
   614  		}, nil
   615  	case *ast.Align:
   616  		return ir.Align(uintLit(old.N())), nil
   617  	case *ast.AlignStack:
   618  		return ir.AlignStack(uintLit(old.N())), nil
   619  	case *ast.ByRefAttr:
   620  		typ, err := gen.irType(old.Typ())
   621  		if err != nil {
   622  			return nil, errors.WithStack(err)
   623  		}
   624  		return ir.ByRef{Typ: typ}, nil
   625  	case *ast.Byval:
   626  		if t, ok := old.Typ(); ok {
   627  			typ, err := gen.irType(t)
   628  			if err != nil {
   629  				return nil, errors.WithStack(err)
   630  			}
   631  			return ir.Byval{Typ: typ}, nil
   632  		}
   633  		return ir.Byval{}, nil
   634  	case *ast.Dereferenceable:
   635  		return ir.Dereferenceable{N: uintLit(old.N())}, nil
   636  	case *ast.DereferenceableOrNull:
   637  		return ir.Dereferenceable{
   638  			N:           uintLit(old.N()),
   639  			DerefOrNull: true,
   640  		}, nil
   641  	case *ast.ElementType:
   642  		typ, err := gen.irType(old.Typ())
   643  		if err != nil {
   644  			return nil, errors.WithStack(err)
   645  		}
   646  		return ir.ElementType{Typ: typ}, nil
   647  	case *ast.InAlloca:
   648  		typ, err := gen.irType(old.Typ())
   649  		if err != nil {
   650  			return nil, err
   651  		}
   652  		return ir.InAlloca{Typ: typ}, nil
   653  	case *ast.ParamAttr:
   654  		return asmenum.ParamAttrFromString(old.Text()), nil
   655  	case *ast.Preallocated:
   656  		typ, err := gen.irType(old.Typ())
   657  		if err != nil {
   658  			return nil, err
   659  		}
   660  		return ir.Preallocated{Typ: typ}, nil
   661  	case *ast.StructRetAttr:
   662  		typ, err := gen.irType(old.Typ())
   663  		if err != nil {
   664  			return nil, err
   665  		}
   666  		return ir.SRet{Typ: typ}, nil
   667  	default:
   668  		panic(fmt.Errorf("support for parameter attribute %T not yet implemented", old))
   669  	}
   670  }
   671  
   672  // irReturnAttribute returns the IR return attribute corresponding to the given
   673  // AST return attribute.
   674  func irReturnAttribute(old ast.ReturnAttribute) ir.ReturnAttribute {
   675  	switch old := old.(type) {
   676  	// TODO: add support for AttrString.
   677  	//case *ast.AttrString:
   678  	//	return ir.AttrString(unquote(old.Text()))
   679  	// TODO: add support for AttrPair.
   680  	//case *ast.AttrPair:
   681  	//	return ir.AttrPair{
   682  	//		Key:   unquote(old.Key().Text()),
   683  	//		Value: unquote(old.Val().Text()),
   684  	//	}
   685  	// TODO: re-enable
   686  	//case *ast.Align:
   687  	//	return ir.Align(uintLit(old.N()))
   688  	case *ast.Dereferenceable:
   689  		return ir.Dereferenceable{N: uintLit(old.N())}
   690  	case *ast.DereferenceableOrNull:
   691  		return ir.Dereferenceable{
   692  			N:           uintLit(old.N()),
   693  			DerefOrNull: true,
   694  		}
   695  	case *ast.ReturnAttr:
   696  		return asmenum.ReturnAttrFromString(old.Text())
   697  	default:
   698  		panic(fmt.Errorf("support for return attribute %T not yet implemented", old))
   699  	}
   700  }
   701  
   702  // irTLSModelFromThreadLocal returns the IR TLS model corresponding to the given
   703  // AST thread local storage.
   704  func irTLSModelFromThreadLocal(old ast.ThreadLocal) enum.TLSModel {
   705  	if n, ok := old.Model(); ok {
   706  		// e.g. thread_local(initialexec)
   707  		return asmenum.TLSModelFromString(n.Text())
   708  	}
   709  	// If no explicit model is given, the "general dynamic" model is used.
   710  	//    thread_local
   711  	return enum.TLSModelGeneric
   712  }
   713  
   714  // irUnwindTarget returns the IR unwind target corresponding to the given AST
   715  // unwind target.
   716  func (fgen *funcGen) irUnwindTarget(n ast.UnwindTarget) (*ir.Block, error) {
   717  	switch n := n.(type) {
   718  	case *ast.Label:
   719  		return fgen.irBlock(*n)
   720  	case *ast.UnwindToCaller:
   721  		// A nil unwind target basic block indicates "unwind to caller".
   722  		return nil, nil
   723  	default:
   724  		panic(fmt.Errorf("support for unwind target %T not yet implemented", n))
   725  	}
   726  }
   727  
   728  // irUseListOrder returns the IR use-list order corresponding to the given AST
   729  // use-list order.
   730  func (fgen *funcGen) irUseListOrder(old ast.UseListOrder) (*ir.UseListOrder, error) {
   731  	// Value.
   732  	val, err := fgen.irTypeValue(old.Val())
   733  	if err != nil {
   734  		return nil, errors.WithStack(err)
   735  	}
   736  	// Indices.
   737  	indices := uintSlice(old.Indices())
   738  	useListOrder := &ir.UseListOrder{
   739  		Value:   val,
   740  		Indices: indices,
   741  	}
   742  	return useListOrder, nil
   743  }
   744  
   745  // ### [ Helpers ] #############################################################
   746  
   747  // unquote returns the unquoted version of s if quoted, and the original string
   748  // otherwise.
   749  func unquote(s string) string {
   750  	if len(s) >= 2 && strings.HasPrefix(s, `"`) && strings.HasSuffix(s, `"`) {
   751  		return string(enc.Unquote(s))
   752  	}
   753  	return s
   754  }
   755  
   756  // text returns the text of the given node.
   757  func text(n ast.LlvmNode) string {
   758  	if n := n.LlvmNode(); n.IsValid() {
   759  		return n.Text()
   760  	}
   761  	return ""
   762  }
   763  
   764  // findBlock returns the basic block with the given local identifier in the
   765  // function.
   766  func findBlock(f *ir.Func, blockIdent ir.LocalIdent) (*ir.Block, error) {
   767  	for _, block := range f.Blocks {
   768  		if block.LocalIdent == blockIdent {
   769  			return block, nil
   770  		}
   771  	}
   772  	return nil, errors.Errorf("unable to locate basic block %q of function %q", blockIdent.Ident(), f.Ident())
   773  }