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

     1  package asm
     2  
     3  import (
     4  	"fmt"
     5  
     6  	"github.com/llir/ll/ast"
     7  	asmenum "github.com/llir/llvm/asm/enum"
     8  	"github.com/llir/llvm/internal/enc"
     9  	"github.com/llir/llvm/internal/gep"
    10  	"github.com/llir/llvm/ir"
    11  	"github.com/llir/llvm/ir/constant"
    12  	"github.com/llir/llvm/ir/types"
    13  	"github.com/pkg/errors"
    14  )
    15  
    16  // === [ Create and index IR ] =================================================
    17  
    18  // createGlobalEntities indexes global identifiers and creates scaffolding IR
    19  // global declarations and definitions, indirect symbol definitions (aliases and
    20  // indirect functions), and function declarations and definitions (without
    21  // bodies but with types) of the given module.
    22  //
    23  // post-condition: gen.new.globals maps from global identifier (without '@'
    24  // prefix) to corresponding skeleton IR value.
    25  func (gen *generator) createGlobalEntities() error {
    26  	// 4a1. Index global identifiers and create scaffolding IR global
    27  	//      declarations and definitions, indirect symbol definitions (aliases
    28  	//      and indirect functions), and function declarations and definitions
    29  	//      (without bodies but with types).
    30  	for ident, old := range gen.old.globals {
    31  		new, err := gen.newGlobalEntity(ident, old)
    32  		if err != nil {
    33  			return errors.WithStack(err)
    34  		}
    35  		gen.new.globals[ident] = new
    36  	}
    37  	return nil
    38  }
    39  
    40  // newGlobalEntity returns a new scaffolding IR value (without body but with
    41  // type) based on the given AST global declaration or definition, indirect
    42  // symbol definitions (aliases and indirect functions), or function declaration
    43  // or definition.
    44  func (gen *generator) newGlobalEntity(ident ir.GlobalIdent, old ast.LlvmNode) (constant.Constant, error) {
    45  	switch old := old.(type) {
    46  	case *ast.GlobalDecl:
    47  		oldAddrSpace, _ := old.AddrSpace()
    48  		return gen.newGlobal(ident, old.ContentType(), oldAddrSpace)
    49  	case *ast.IndirectSymbolDef:
    50  		return gen.newIndirectSymbol(ident, old)
    51  	case *ast.FuncDecl:
    52  		return gen.newFunc(ident, old.Header())
    53  	case *ast.FuncDef:
    54  		return gen.newFunc(ident, old.Header())
    55  	default:
    56  		panic(fmt.Errorf("support for global variable, indirect symbol or function %T not yet implemented", old))
    57  	}
    58  }
    59  
    60  // newGlobal returns a new IR global variable declaration or definition (without
    61  // body but with type) based on the given AST content type and optional address
    62  // space.
    63  func (gen *generator) newGlobal(ident ir.GlobalIdent, oldContentType ast.Type, oldAddrSpace ast.AddrSpace) (*ir.Global, error) {
    64  	// Content type.
    65  	contentType, err := gen.irType(oldContentType)
    66  	if err != nil {
    67  		return nil, errors.WithStack(err)
    68  	}
    69  	typ := types.NewPointer(contentType)
    70  	// (optional) Address space.
    71  	var addrSpace types.AddrSpace
    72  	if oldAddrSpace.IsValid() {
    73  		addrSpace = irAddrSpace(oldAddrSpace)
    74  		typ.AddrSpace = addrSpace
    75  	}
    76  	return &ir.Global{GlobalIdent: ident, ContentType: contentType, Typ: typ, AddrSpace: addrSpace}, nil
    77  }
    78  
    79  // newIndirectSymbol returns a new IR indirect symbol definition (without body
    80  // but with type) based on the given AST indirect symbol.
    81  func (gen *generator) newIndirectSymbol(ident ir.GlobalIdent, old *ast.IndirectSymbolDef) (constant.Constant, error) {
    82  	// Content type.
    83  	contentType, err := gen.irType(old.ContentType())
    84  	if err != nil {
    85  		return nil, errors.WithStack(err)
    86  	}
    87  	typ := types.NewPointer(contentType)
    88  	// Infer address space of pointer type from indirect symbol as no explicit
    89  	// type/value pair is given for the indirect symbol when aliasee is a
    90  	// constant expression.
    91  	var symbolType types.Type
    92  	switch oldSymbol := old.IndirectSymbol().(type) {
    93  	case *ast.AddrSpaceCastExpr:
    94  		to, err := gen.irType(oldSymbol.To())
    95  		if err != nil {
    96  			return nil, errors.WithStack(err)
    97  		}
    98  		symbolType = to
    99  	case *ast.BitCastExpr:
   100  		to, err := gen.irType(oldSymbol.To())
   101  		if err != nil {
   102  			return nil, errors.WithStack(err)
   103  		}
   104  		symbolType = to
   105  	case *ast.GetElementPtrExpr:
   106  		symType, err := gen.gepExprType(oldSymbol)
   107  		if err != nil {
   108  			return nil, errors.WithStack(err)
   109  		}
   110  		symbolType = symType
   111  	case *ast.IntToPtrExpr:
   112  		to, err := gen.irType(oldSymbol.To())
   113  		if err != nil {
   114  			return nil, errors.WithStack(err)
   115  		}
   116  		symbolType = to
   117  	case *ast.TypeConst:
   118  		symType, err := gen.irType(oldSymbol.Typ())
   119  		if err != nil {
   120  			return nil, errors.WithStack(err)
   121  		}
   122  		symbolType = symType
   123  	default:
   124  		panic(fmt.Errorf("support for indirect symbol type %T not yet implemented", oldSymbol))
   125  	}
   126  	switch symbolType := symbolType.(type) {
   127  	case *types.PointerType:
   128  		typ.AddrSpace = symbolType.AddrSpace
   129  	default:
   130  		panic(fmt.Errorf("support for indirect symbol type %T not yet implemented", symbolType))
   131  	}
   132  	// Indirect symbol kind.
   133  	kind := old.IndirectSymbolKind().Text()
   134  	switch kind {
   135  	case "alias":
   136  		return &ir.Alias{GlobalIdent: ident, Typ: typ}, nil
   137  	case "ifunc":
   138  		return &ir.IFunc{GlobalIdent: ident, Typ: typ}, nil
   139  	default:
   140  		panic(fmt.Errorf("support for indirect symbol kind %q not yet implemented", kind))
   141  	}
   142  }
   143  
   144  // newFunc returns a new IR function declaration or definition (without body but
   145  // with type) based on the given AST function header.
   146  func (gen *generator) newFunc(ident ir.GlobalIdent, hdr ast.FuncHeader) (*ir.Func, error) {
   147  	// Function signature.
   148  	sig, err := gen.irSigFromHeader(hdr)
   149  	if err != nil {
   150  		return nil, errors.WithStack(err)
   151  	}
   152  	typ := types.NewPointer(sig)
   153  	// (optional) Address space.
   154  	var addrSpace types.AddrSpace
   155  	if n, ok := hdr.AddrSpace(); ok {
   156  		addrSpace = irAddrSpace(n)
   157  		typ.AddrSpace = addrSpace
   158  	}
   159  	return &ir.Func{GlobalIdent: ident, Sig: sig, Typ: typ, AddrSpace: addrSpace, Parent: gen.m}, nil
   160  }
   161  
   162  // ### [ Helper functions ] ####################################################
   163  
   164  // irSigFromHeader translates the AST function signature to an equivalent IR
   165  // function type.
   166  func (gen *generator) irSigFromHeader(old ast.FuncHeader) (*types.FuncType, error) {
   167  	// Return type.
   168  	sig := &types.FuncType{}
   169  	retType, err := gen.irType(old.RetType())
   170  	if err != nil {
   171  		return nil, errors.WithStack(err)
   172  	}
   173  	sig.RetType = retType
   174  	// Function parameters.
   175  	ps := old.Params()
   176  	if oldParams := ps.Params(); len(oldParams) > 0 {
   177  		sig.Params = make([]types.Type, len(oldParams))
   178  		for i, oldParam := range oldParams {
   179  			param, err := gen.irType(oldParam.Typ())
   180  			if err != nil {
   181  				return nil, errors.WithStack(err)
   182  			}
   183  			sig.Params[i] = param
   184  		}
   185  	}
   186  	// Variadic.
   187  	_, sig.Variadic = ps.Variadic()
   188  	return sig, nil
   189  }
   190  
   191  // === [ Translate AST to IR ] =================================================
   192  
   193  // translateGlobalEntities translate AST global declarations and definitions,
   194  // indirect symbol definitions, and function declarations and definitions to IR.
   195  func (gen *generator) translateGlobalEntities() error {
   196  	// TODO: make concurrent and benchmark difference in walltime.
   197  
   198  	// 4b1. Translate AST global declarations and definitions, indirect symbol
   199  	//      definitions, and function declarations and definitions to IR.
   200  	for ident, old := range gen.old.globals {
   201  		v, ok := gen.new.globals[ident]
   202  		if !ok {
   203  			panic(fmt.Errorf("unable to locate global identifier %q", ident.Ident()))
   204  		}
   205  		switch old := old.(type) {
   206  		case *ast.GlobalDecl:
   207  			new, ok := v.(*ir.Global)
   208  			if !ok {
   209  				panic(fmt.Errorf("invalid global declaration type; expected *ir.Global, got %T", v))
   210  			}
   211  			if err := gen.irGlobal(new, old); err != nil {
   212  				return errors.WithStack(err)
   213  			}
   214  		case *ast.IndirectSymbolDef:
   215  			kind := old.IndirectSymbolKind().Text()
   216  			switch kind {
   217  			case "alias":
   218  				new, ok := v.(*ir.Alias)
   219  				if !ok {
   220  					panic(fmt.Errorf("invalid alias definition type; expected *ir.Alias, got %T", v))
   221  				}
   222  				if err := gen.irAlias(new, old); err != nil {
   223  					return errors.WithStack(err)
   224  				}
   225  			case "ifunc":
   226  				new, ok := v.(*ir.IFunc)
   227  				if !ok {
   228  					panic(fmt.Errorf("invalid IFunc definition type; expected *ir.IFunc, got %T", v))
   229  				}
   230  				if err := gen.irIFunc(new, old); err != nil {
   231  					return errors.WithStack(err)
   232  				}
   233  			default:
   234  				panic(fmt.Errorf("support for indirect symbol kind %q not yet implemented", kind))
   235  			}
   236  		case *ast.FuncDecl:
   237  			new, ok := v.(*ir.Func)
   238  			if !ok {
   239  				panic(fmt.Errorf("invalid function declaration type; expected *ir.Func, got %T", v))
   240  			}
   241  			if err := gen.irFuncDecl(new, old); err != nil {
   242  				return errors.WithStack(err)
   243  			}
   244  		case *ast.FuncDef:
   245  			new, ok := v.(*ir.Func)
   246  			if !ok {
   247  				panic(fmt.Errorf("invalid function definition type; expected *ir.Func, got %T", v))
   248  			}
   249  			if err := gen.irFuncDef(new, old); err != nil {
   250  				return errors.WithStack(err)
   251  			}
   252  		default:
   253  			panic(fmt.Errorf("support for global variable, indirect symbol or function %T not yet implemented", old))
   254  		}
   255  	}
   256  	return nil
   257  }
   258  
   259  // --- [ Global declarations ] -------------------------------------------------
   260  
   261  // irGlobal translates the AST global declaration into an equivalent IR
   262  // global declaration.
   263  func (gen *generator) irGlobal(new *ir.Global, old *ast.GlobalDecl) error {
   264  	// (optional) Linkage.
   265  	if n, ok := old.Linkage(); ok {
   266  		new.Linkage = asmenum.LinkageFromString(n.LlvmNode().Text())
   267  	}
   268  	// (optional) Preemption.
   269  	if n, ok := old.Preemption(); ok {
   270  		new.Preemption = asmenum.PreemptionFromString(n.Text())
   271  	}
   272  	// (optional) Visibility.
   273  	if n, ok := old.Visibility(); ok {
   274  		new.Visibility = asmenum.VisibilityFromString(n.Text())
   275  	}
   276  	// (optional) DLL storage class.
   277  	if n, ok := old.DLLStorageClass(); ok {
   278  		new.DLLStorageClass = asmenum.DLLStorageClassFromString(n.Text())
   279  	}
   280  	// (optional) Thread local storage model.
   281  	if n, ok := old.ThreadLocal(); ok {
   282  		new.TLSModel = irTLSModelFromThreadLocal(n)
   283  	}
   284  	// (optional) Unnamed address.
   285  	if n, ok := old.UnnamedAddr(); ok {
   286  		new.UnnamedAddr = asmenum.UnnamedAddrFromString(n.Text())
   287  	}
   288  	// (optional) Address space: handled in newGlobalEntity.
   289  	// (optional) Externally initialized.
   290  	_, new.ExternallyInitialized = old.ExternallyInitialized()
   291  	// Immutability of global variable (constant or global).
   292  	new.Immutable = irImmutable(old.Immutable())
   293  	// Content type: handled in newGlobalEntity.
   294  	// Initial value (only used in global variable definitions).
   295  	if n, ok := old.Init(); ok {
   296  		init, err := gen.irConstant(new.ContentType, n)
   297  		if err != nil {
   298  			return errors.WithStack(err)
   299  		}
   300  		new.Init = init
   301  	}
   302  	for _, globalField := range old.GlobalFields() {
   303  		switch globalField := globalField.(type) {
   304  		// (optional) Section name.
   305  		case *ast.Section:
   306  			new.Section = stringLit(globalField.Name())
   307  		// (optional) Partition name.
   308  		case *ast.Partition:
   309  			new.Partition = stringLit(globalField.Name())
   310  		// (optional) Comdat.
   311  		case *ast.Comdat:
   312  			// When comdat name is omitted, the global name is used as an implicit
   313  			// comdat name.
   314  			name := new.Name()
   315  			if n, ok := globalField.Name(); ok {
   316  				name = comdatName(n)
   317  			}
   318  			def, ok := gen.new.comdatDefs[name]
   319  			if !ok {
   320  				return errors.Errorf("unable to locate comdat identifier %q used in global declaration of %q", enc.ComdatName(name), new.Ident())
   321  			}
   322  			new.Comdat = def
   323  		// (optional) Alignment.
   324  		case *ast.Align:
   325  			new.Align = irAlign(*globalField)
   326  		}
   327  	}
   328  	// (optional) Metadata.
   329  	md, err := gen.irMetadataAttachments(old.Metadata())
   330  	if err != nil {
   331  		return errors.WithStack(err)
   332  	}
   333  	new.Metadata = md
   334  	// (optional) Function attributes.
   335  	if oldFuncAttrs := old.FuncAttrs(); len(oldFuncAttrs) > 0 {
   336  		new.FuncAttrs = make([]ir.FuncAttribute, len(oldFuncAttrs))
   337  		for i, oldFuncAttr := range oldFuncAttrs {
   338  			funcAttr := gen.irFuncAttribute(oldFuncAttr)
   339  			new.FuncAttrs[i] = funcAttr
   340  		}
   341  	}
   342  	return nil
   343  }
   344  
   345  // --- [ Alias definitions ] ---------------------------------------------------
   346  
   347  // irAlias translates the AST indirect symbol definition (alias) into an
   348  // equivalent IR alias definition.
   349  func (gen *generator) irAlias(new *ir.Alias, old *ast.IndirectSymbolDef) error {
   350  	// (optional) Linkage.
   351  	if n, ok := old.Linkage(); ok {
   352  		new.Linkage = asmenum.LinkageFromString(n.Text())
   353  	}
   354  	if n, ok := old.ExternLinkage(); ok {
   355  		new.Linkage = asmenum.LinkageFromString(n.Text())
   356  	}
   357  	// (optional) Preemption.
   358  	if n, ok := old.Preemption(); ok {
   359  		new.Preemption = asmenum.PreemptionFromString(n.Text())
   360  	}
   361  	// (optional) Visibility.
   362  	if n, ok := old.Visibility(); ok {
   363  		new.Visibility = asmenum.VisibilityFromString(n.Text())
   364  	}
   365  	// (optional) DLL storage class.
   366  	if n, ok := old.DLLStorageClass(); ok {
   367  		new.DLLStorageClass = asmenum.DLLStorageClassFromString(n.Text())
   368  	}
   369  	// (optional) Thread local storage model.
   370  	if n, ok := old.ThreadLocal(); ok {
   371  		new.TLSModel = irTLSModelFromThreadLocal(n)
   372  	}
   373  	// (optional) Unnamed address.
   374  	if n, ok := old.UnnamedAddr(); ok {
   375  		new.UnnamedAddr = asmenum.UnnamedAddrFromString(n.Text())
   376  	}
   377  	// Content type: handled in newGlobalEntity.
   378  	// Aliasee.
   379  	aliasee, err := gen.irIndirectSymbol(new.Typ, old.IndirectSymbol())
   380  	if err != nil {
   381  		return errors.WithStack(err)
   382  	}
   383  	new.Aliasee = aliasee
   384  	// (optional) Partition name.
   385  	for _, partition := range old.Partitions() {
   386  		new.Partition = stringLit(partition.Name())
   387  	}
   388  	return nil
   389  }
   390  
   391  // --- [ IFunc definitions ] ---------------------------------------------------
   392  
   393  // irIFunc translates the AST indirect symbol definition (IFunc) into an
   394  // equivalent IR indirect function definition.
   395  func (gen *generator) irIFunc(new *ir.IFunc, old *ast.IndirectSymbolDef) error {
   396  	// (optional) Linkage.
   397  	if n, ok := old.Linkage(); ok {
   398  		new.Linkage = asmenum.LinkageFromString(n.Text())
   399  	}
   400  	if n, ok := old.ExternLinkage(); ok {
   401  		new.Linkage = asmenum.LinkageFromString(n.Text())
   402  	}
   403  	// (optional) Preemption.
   404  	if n, ok := old.Preemption(); ok {
   405  		new.Preemption = asmenum.PreemptionFromString(n.Text())
   406  	}
   407  	// (optional) Visibility.
   408  	if n, ok := old.Visibility(); ok {
   409  		new.Visibility = asmenum.VisibilityFromString(n.Text())
   410  	}
   411  	// (optional) DLL storage class.
   412  	if n, ok := old.DLLStorageClass(); ok {
   413  		new.DLLStorageClass = asmenum.DLLStorageClassFromString(n.Text())
   414  	}
   415  	// (optional) Thread local storage model.
   416  	if n, ok := old.ThreadLocal(); ok {
   417  		new.TLSModel = irTLSModelFromThreadLocal(n)
   418  	}
   419  	// (optional) Unnamed address.
   420  	if n, ok := old.UnnamedAddr(); ok {
   421  		new.UnnamedAddr = asmenum.UnnamedAddrFromString(n.Text())
   422  	}
   423  	// Content type: handled in newGlobalEntity.
   424  	// Resolver.
   425  	resolver, err := gen.irIndirectSymbol(new.Typ, old.IndirectSymbol())
   426  	if err != nil {
   427  		return errors.WithStack(err)
   428  	}
   429  	new.Resolver = resolver
   430  	// (optional) Partition name.
   431  	for _, partition := range old.Partitions() {
   432  		new.Partition = stringLit(partition.Name())
   433  	}
   434  	return nil
   435  }
   436  
   437  // --- [ Function declarations ] -----------------------------------------------
   438  
   439  // irFuncDecl translates the AST function declaration into an equivalent IR
   440  // function declaration.
   441  func (gen *generator) irFuncDecl(new *ir.Func, old *ast.FuncDecl) error {
   442  	// (optional) Metadata.
   443  	md, err := gen.irMetadataAttachments(old.Metadata())
   444  	if err != nil {
   445  		return errors.WithStack(err)
   446  	}
   447  	new.Metadata = md
   448  	// Function header.
   449  	return gen.irFuncHeader(new, old.Header())
   450  }
   451  
   452  // --- [ Function definitions ] ------------------------------------------------
   453  
   454  // irFuncDef translates the AST function definition into an equivalent IR
   455  // function definition.
   456  func (gen *generator) irFuncDef(new *ir.Func, old *ast.FuncDef) error {
   457  	// Function header.
   458  	if err := gen.irFuncHeader(new, old.Header()); err != nil {
   459  		return errors.WithStack(err)
   460  	}
   461  	// (optional) Metadata.
   462  	md, err := gen.irMetadataAttachments(old.Metadata())
   463  	if err != nil {
   464  		return errors.WithStack(err)
   465  	}
   466  	new.Metadata = md
   467  	// Basic blocks.
   468  	fgen := newFuncGen(gen, new)
   469  	oldBody := old.Body()
   470  	if err := fgen.resolveLocals(oldBody); err != nil {
   471  		return errors.WithStack(err)
   472  	}
   473  	// (optional) Use list orders.
   474  	if oldUseListOrders := oldBody.UseListOrders(); len(oldUseListOrders) > 0 {
   475  		new.UseListOrders = make([]*ir.UseListOrder, len(oldUseListOrders))
   476  		for i, oldUseListOrder := range oldUseListOrders {
   477  			useListOrder, err := fgen.irUseListOrder(oldUseListOrder)
   478  			if err != nil {
   479  				return errors.WithStack(err)
   480  			}
   481  			new.UseListOrders[i] = useListOrder
   482  		}
   483  	}
   484  	return nil
   485  }
   486  
   487  // ~~~ [ Function headers ] ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
   488  
   489  // irFuncHeader translates the AST function header into an equivalent IR
   490  // function.
   491  func (gen *generator) irFuncHeader(new *ir.Func, old ast.FuncHeader) error {
   492  	// (optional) Linkage.
   493  	if n, ok := old.Linkage(); ok {
   494  		new.Linkage = asmenum.LinkageFromString(n.Text())
   495  	}
   496  	if n, ok := old.ExternLinkage(); ok {
   497  		new.Linkage = asmenum.LinkageFromString(n.Text())
   498  	}
   499  	// (optional) Preemption.
   500  	if n, ok := old.Preemption(); ok {
   501  		new.Preemption = asmenum.PreemptionFromString(n.Text())
   502  	}
   503  	// (optional) Visibility.
   504  	if n, ok := old.Visibility(); ok {
   505  		new.Visibility = asmenum.VisibilityFromString(n.Text())
   506  	}
   507  	// (optional) DLL storage class.
   508  	if n, ok := old.DLLStorageClass(); ok {
   509  		new.DLLStorageClass = asmenum.DLLStorageClassFromString(n.Text())
   510  	}
   511  	// (optional) Calling convention.
   512  	if n, ok := old.CallingConv(); ok {
   513  		new.CallingConv = irCallingConv(n)
   514  	}
   515  	// (optional) Return attributes.
   516  	if oldReturnAttrs := old.ReturnAttrs(); len(oldReturnAttrs) > 0 {
   517  		new.ReturnAttrs = make([]ir.ReturnAttribute, len(oldReturnAttrs))
   518  		for i, oldRetAttr := range oldReturnAttrs {
   519  			retAttr := irReturnAttribute(oldRetAttr)
   520  			new.ReturnAttrs[i] = retAttr
   521  		}
   522  	}
   523  	// Return type: handled in newGlobalEntity.
   524  	// Function parameters.
   525  	ps := old.Params()
   526  	if oldParams := ps.Params(); len(oldParams) > 0 {
   527  		new.Params = make([]*ir.Param, len(oldParams))
   528  		for i, oldParam := range oldParams {
   529  			// Type.
   530  			typ, err := gen.irType(oldParam.Typ())
   531  			if err != nil {
   532  				return errors.WithStack(err)
   533  			}
   534  			// Name.
   535  			param := ir.NewParam("", typ)
   536  			if n, ok := oldParam.Name(); ok {
   537  				ident := localIdent(n)
   538  				param.LocalIdent = ident
   539  			}
   540  			// (optional) Parameter attributes.
   541  			if oldParamAttrs := oldParam.Attrs(); len(oldParamAttrs) > 0 {
   542  				param.Attrs = make([]ir.ParamAttribute, len(oldParamAttrs))
   543  				for j, oldParamAttr := range oldParamAttrs {
   544  					paramAttr, err := gen.irParamAttribute(oldParamAttr)
   545  					if err != nil {
   546  						return errors.WithStack(err)
   547  					}
   548  					param.Attrs[j] = paramAttr
   549  				}
   550  			}
   551  			new.Params[i] = param
   552  		}
   553  	}
   554  	// (optional) Unnamed address.
   555  	if n, ok := old.UnnamedAddr(); ok {
   556  		new.UnnamedAddr = asmenum.UnnamedAddrFromString(n.Text())
   557  	}
   558  	// (optional) Address space: handled in newGlobalEntity.
   559  	for _, funcHdrField := range old.FuncHdrFields() {
   560  		switch funcHdrField := funcHdrField.(type) {
   561  		// (optional) Function attributes.
   562  		case ast.FuncAttribute:
   563  			funcAttr := gen.irFuncAttribute(funcHdrField)
   564  			new.FuncAttrs = append(new.FuncAttrs, funcAttr)
   565  		// (optional) Alignment.
   566  		case *ast.Align:
   567  			new.Align = irAlign(*funcHdrField)
   568  		// (optional) Section name.
   569  		case *ast.Section:
   570  			new.Section = stringLit(funcHdrField.Name())
   571  		// (optional) Partition name.
   572  		case *ast.Partition:
   573  			new.Partition = stringLit(funcHdrField.Name())
   574  		// (optional) Comdat.
   575  		case *ast.Comdat:
   576  			// When comdat name is omitted, the function name is used as an implicit
   577  			// comdat name.
   578  			name := new.Name()
   579  			if n, ok := funcHdrField.Name(); ok {
   580  				name = comdatName(n)
   581  			}
   582  			def, ok := gen.new.comdatDefs[name]
   583  			if !ok {
   584  				return errors.Errorf("unable to locate comdat identifier %q used in function header of %q", enc.ComdatName(name), new.Ident())
   585  			}
   586  			new.Comdat = def
   587  		// (optional) Garbage collection.
   588  		case *ast.GCNode:
   589  			new.GC = stringLit(funcHdrField.Name())
   590  		// (optional) Prefix.
   591  		case *ast.Prefix:
   592  			prefix, err := gen.irTypeConst(funcHdrField.TypeConst())
   593  			if err != nil {
   594  				return errors.WithStack(err)
   595  			}
   596  			new.Prefix = prefix
   597  		// (optional) Prologue.
   598  		case *ast.Prologue:
   599  			prologue, err := gen.irTypeConst(funcHdrField.TypeConst())
   600  			if err != nil {
   601  				return errors.WithStack(err)
   602  			}
   603  			new.Prologue = prologue
   604  		// (optional) Prefix.
   605  		case *ast.Personality:
   606  			personality, err := gen.irTypeConst(funcHdrField.TypeConst())
   607  			if err != nil {
   608  				return errors.WithStack(err)
   609  			}
   610  			new.Personality = personality
   611  		}
   612  	}
   613  	return nil
   614  }
   615  
   616  // ### [ Helper functions ] ####################################################
   617  
   618  // gepExprType computes the result type of a getelementptr constant expression.
   619  //
   620  //    getelementptr ElemType, Src, Indices
   621  //
   622  // Notably, gepExprType returns the type of the gep expression without resolving
   623  // the underlying src value. As such gepExprType may be invoked before
   624  // completing global identifier resolution. This is needed to correctly resolve
   625  // the optional address space of indirect symbols (i.e. aliases and ifuncs).
   626  func (gen *generator) gepExprType(old *ast.GetElementPtrExpr) (types.Type, error) {
   627  	elemType, err := gen.irType(old.ElemType())
   628  	if err != nil {
   629  		return nil, errors.WithStack(err)
   630  	}
   631  	src, err := gen.irType(old.Src().Typ())
   632  	if err != nil {
   633  		return nil, errors.WithStack(err)
   634  	}
   635  	var idxs []gep.Index
   636  	for _, index := range old.Indices() {
   637  		indexVal := index.Index().Val()
   638  		idx := gen.getIndex(indexVal)
   639  		idxs = append(idxs, idx)
   640  	}
   641  	return gep.ResultType(elemType, src, idxs), nil
   642  }