github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/compiler/symbol.go (about)

     1  package compiler
     2  
     3  // This file manages symbols, that is, functions and globals. It reads their
     4  // pragmas, determines the link name, etc.
     5  
     6  import (
     7  	"fmt"
     8  	"go/ast"
     9  	"go/token"
    10  	"go/types"
    11  	"strconv"
    12  	"strings"
    13  
    14  	"github.com/tinygo-org/tinygo/compiler/llvmutil"
    15  	"github.com/tinygo-org/tinygo/loader"
    16  	"golang.org/x/tools/go/ssa"
    17  	"tinygo.org/x/go-llvm"
    18  )
    19  
    20  // functionInfo contains some information about a function or method. In
    21  // particular, it contains information obtained from pragmas.
    22  //
    23  // The linkName value contains a valid link name, even if //go:linkname is not
    24  // present.
    25  type functionInfo struct {
    26  	wasmModule string     // go:wasm-module
    27  	wasmName   string     // wasm-export-name or wasm-import-name in the IR
    28  	linkName   string     // go:linkname, go:export - the IR function name
    29  	section    string     // go:section - object file section name
    30  	exported   bool       // go:export, CGo
    31  	interrupt  bool       // go:interrupt
    32  	nobounds   bool       // go:nobounds
    33  	variadic   bool       // go:variadic (CGo only)
    34  	inline     inlineType // go:inline
    35  }
    36  
    37  type inlineType int
    38  
    39  // How much to inline.
    40  const (
    41  	// Default behavior. The compiler decides for itself whether any given
    42  	// function will be inlined. Whether any function is inlined depends on the
    43  	// optimization level.
    44  	inlineDefault inlineType = iota
    45  
    46  	// Inline hint, just like the C inline keyword (signalled using
    47  	// //go:inline). The compiler will be more likely to inline this function,
    48  	// but it is not a guarantee.
    49  	inlineHint
    50  
    51  	// Don't inline, just like the GCC noinline attribute. Signalled using
    52  	// //go:noinline.
    53  	inlineNone
    54  )
    55  
    56  // Values for the allockind attribute. Source:
    57  // https://github.com/llvm/llvm-project/blob/release/16.x/llvm/include/llvm/IR/Attributes.h#L49
    58  const (
    59  	allocKindAlloc = 1 << iota
    60  	allocKindRealloc
    61  	allocKindFree
    62  	allocKindUninitialized
    63  	allocKindZeroed
    64  	allocKindAligned
    65  )
    66  
    67  // getFunction returns the LLVM function for the given *ssa.Function, creating
    68  // it if needed. It can later be filled with compilerContext.createFunction().
    69  func (c *compilerContext) getFunction(fn *ssa.Function) (llvm.Type, llvm.Value) {
    70  	info := c.getFunctionInfo(fn)
    71  	llvmFn := c.mod.NamedFunction(info.linkName)
    72  	if !llvmFn.IsNil() {
    73  		return llvmFn.GlobalValueType(), llvmFn
    74  	}
    75  
    76  	var retType llvm.Type
    77  	if fn.Signature.Results() == nil {
    78  		retType = c.ctx.VoidType()
    79  	} else if fn.Signature.Results().Len() == 1 {
    80  		retType = c.getLLVMType(fn.Signature.Results().At(0).Type())
    81  	} else {
    82  		results := make([]llvm.Type, 0, fn.Signature.Results().Len())
    83  		for i := 0; i < fn.Signature.Results().Len(); i++ {
    84  			results = append(results, c.getLLVMType(fn.Signature.Results().At(i).Type()))
    85  		}
    86  		retType = c.ctx.StructType(results, false)
    87  	}
    88  
    89  	var paramInfos []paramInfo
    90  	for _, param := range getParams(fn.Signature) {
    91  		paramType := c.getLLVMType(param.Type())
    92  		paramFragmentInfos := c.expandFormalParamType(paramType, param.Name(), param.Type())
    93  		paramInfos = append(paramInfos, paramFragmentInfos...)
    94  	}
    95  
    96  	// Add an extra parameter as the function context. This context is used in
    97  	// closures and bound methods, but should be optimized away when not used.
    98  	if !info.exported {
    99  		paramInfos = append(paramInfos, paramInfo{llvmType: c.dataPtrType, name: "context", elemSize: 0})
   100  	}
   101  
   102  	var paramTypes []llvm.Type
   103  	for _, info := range paramInfos {
   104  		paramTypes = append(paramTypes, info.llvmType)
   105  	}
   106  
   107  	fnType := llvm.FunctionType(retType, paramTypes, info.variadic)
   108  	llvmFn = llvm.AddFunction(c.mod, info.linkName, fnType)
   109  	if strings.HasPrefix(c.Triple, "wasm") {
   110  		// C functions without prototypes like this:
   111  		//   void foo();
   112  		// are actually variadic functions. However, it appears that it has been
   113  		// decided in WebAssembly that such prototype-less functions are not
   114  		// allowed in WebAssembly.
   115  		// In C, this can only happen when there are zero parameters, hence this
   116  		// check here. For more information:
   117  		// https://reviews.llvm.org/D48443
   118  		// https://github.com/WebAssembly/tool-conventions/issues/16
   119  		if info.variadic && len(fn.Params) == 0 {
   120  			attr := c.ctx.CreateStringAttribute("no-prototype", "")
   121  			llvmFn.AddFunctionAttr(attr)
   122  		}
   123  	}
   124  	c.addStandardDeclaredAttributes(llvmFn)
   125  
   126  	dereferenceableOrNullKind := llvm.AttributeKindID("dereferenceable_or_null")
   127  	for i, info := range paramInfos {
   128  		if info.elemSize != 0 {
   129  			dereferenceableOrNull := c.ctx.CreateEnumAttribute(dereferenceableOrNullKind, info.elemSize)
   130  			llvmFn.AddAttributeAtIndex(i+1, dereferenceableOrNull)
   131  		}
   132  	}
   133  
   134  	// Set a number of function or parameter attributes, depending on the
   135  	// function. These functions are runtime functions that are known to have
   136  	// certain attributes that might not be inferred by the compiler.
   137  	switch info.linkName {
   138  	case "abort":
   139  		// On *nix systems, the "abort" functuion in libc is used to handle fatal panics.
   140  		// Mark it as noreturn so LLVM can optimize away code.
   141  		llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("noreturn"), 0))
   142  	case "runtime.alloc":
   143  		// Tell the optimizer that runtime.alloc is an allocator, meaning that it
   144  		// returns values that are never null and never alias to an existing value.
   145  		for _, attrName := range []string{"noalias", "nonnull"} {
   146  			llvmFn.AddAttributeAtIndex(0, c.ctx.CreateEnumAttribute(llvm.AttributeKindID(attrName), 0))
   147  		}
   148  		// Add attributes to signal to LLVM that this is an allocator function.
   149  		// This enables a number of optimizations.
   150  		llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("allockind"), allocKindAlloc|allocKindZeroed))
   151  		llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("alloc-family", "runtime.alloc"))
   152  		// Use a special value to indicate the first parameter:
   153  		// > allocsize has two integer arguments, but because they're both 32 bits, we can
   154  		// > pack them into one 64-bit value, at the cost of making said value
   155  		// > nonsensical.
   156  		// >
   157  		// > In order to do this, we need to reserve one value of the second (optional)
   158  		// > allocsize argument to signify "not present."
   159  		llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("allocsize"), 0x0000_0000_ffff_ffff))
   160  	case "runtime.sliceAppend":
   161  		// Appending a slice will only read the to-be-appended slice, it won't
   162  		// be modified.
   163  		llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
   164  		llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0))
   165  	case "runtime.sliceCopy":
   166  		// Copying a slice won't capture any of the parameters.
   167  		llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("writeonly"), 0))
   168  		llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
   169  		llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0))
   170  		llvmFn.AddAttributeAtIndex(2, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
   171  	case "runtime.trackPointer":
   172  		// This function is necessary for tracking pointers on the stack in a
   173  		// portable way (see gc_stack_portable.go). Indicate to the optimizer
   174  		// that the only thing we'll do is read the pointer.
   175  		llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nocapture"), 0))
   176  		llvmFn.AddAttributeAtIndex(1, c.ctx.CreateEnumAttribute(llvm.AttributeKindID("readonly"), 0))
   177  	case "__mulsi3", "__divmodsi4", "__udivmodsi4":
   178  		if strings.Split(c.Triple, "-")[0] == "avr" {
   179  			// These functions are compiler-rt/libgcc functions that are
   180  			// currently implemented in Go. Assembly versions should appear in
   181  			// LLVM 17 hopefully. Until then, they need to be made available to
   182  			// the linker and the best way to do that is llvm.compiler.used.
   183  			// I considered adding a pragma for this, but the LLVM language
   184  			// reference explicitly says that this feature should not be exposed
   185  			// to source languages:
   186  			// > This is a rare construct that should only be used in rare
   187  			// > circumstances, and should not be exposed to source languages.
   188  			llvmutil.AppendToGlobal(c.mod, "llvm.compiler.used", llvmFn)
   189  		}
   190  	}
   191  
   192  	// External/exported functions may not retain pointer values.
   193  	// https://golang.org/cmd/cgo/#hdr-Passing_pointers
   194  	if info.exported {
   195  		if c.archFamily() == "wasm32" && len(fn.Blocks) == 0 {
   196  			// We need to add the wasm-import-module and the wasm-import-name
   197  			// attributes.
   198  			if info.wasmModule != "" {
   199  				llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("wasm-import-module", info.wasmModule))
   200  			}
   201  
   202  			llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("wasm-import-name", info.wasmName))
   203  		}
   204  		nocaptureKind := llvm.AttributeKindID("nocapture")
   205  		nocapture := c.ctx.CreateEnumAttribute(nocaptureKind, 0)
   206  		for i, typ := range paramTypes {
   207  			if typ.TypeKind() == llvm.PointerTypeKind {
   208  				llvmFn.AddAttributeAtIndex(i+1, nocapture)
   209  			}
   210  		}
   211  	}
   212  
   213  	// Synthetic functions are functions that do not appear in the source code,
   214  	// they are artificially constructed. Usually they are wrapper functions
   215  	// that are not referenced anywhere except in a SSA call instruction so
   216  	// should be created right away.
   217  	// The exception is the package initializer, which does appear in the
   218  	// *ssa.Package members and so shouldn't be created here.
   219  	if fn.Synthetic != "" && fn.Synthetic != "package initializer" && fn.Synthetic != "generic function" {
   220  		irbuilder := c.ctx.NewBuilder()
   221  		b := newBuilder(c, irbuilder, fn)
   222  		b.createFunction()
   223  		irbuilder.Dispose()
   224  		llvmFn.SetLinkage(llvm.LinkOnceODRLinkage)
   225  		llvmFn.SetUnnamedAddr(true)
   226  	}
   227  
   228  	return fnType, llvmFn
   229  }
   230  
   231  // getFunctionInfo returns information about a function that is not directly
   232  // present in *ssa.Function, such as the link name and whether it should be
   233  // exported.
   234  func (c *compilerContext) getFunctionInfo(f *ssa.Function) functionInfo {
   235  	if info, ok := c.functionInfos[f]; ok {
   236  		return info
   237  	}
   238  	info := functionInfo{
   239  		// Pick the default linkName.
   240  		linkName: f.RelString(nil),
   241  	}
   242  	// Check for //go: pragmas, which may change the link name (among others).
   243  	c.parsePragmas(&info, f)
   244  	c.functionInfos[f] = info
   245  	return info
   246  }
   247  
   248  // parsePragmas is used by getFunctionInfo to parse function pragmas such as
   249  // //export or //go:noinline.
   250  func (c *compilerContext) parsePragmas(info *functionInfo, f *ssa.Function) {
   251  	if f.Syntax() == nil {
   252  		return
   253  	}
   254  	if decl, ok := f.Syntax().(*ast.FuncDecl); ok && decl.Doc != nil {
   255  		for _, comment := range decl.Doc.List {
   256  			text := comment.Text
   257  			if strings.HasPrefix(text, "//export ") {
   258  				// Rewrite '//export' to '//go:export' for compatibility with
   259  				// gc.
   260  				text = "//go:" + text[2:]
   261  			}
   262  			if !strings.HasPrefix(text, "//go:") {
   263  				continue
   264  			}
   265  			parts := strings.Fields(text)
   266  			switch parts[0] {
   267  			case "//go:export":
   268  				if len(parts) != 2 {
   269  					continue
   270  				}
   271  
   272  				info.linkName = parts[1]
   273  				info.wasmName = info.linkName
   274  				info.exported = true
   275  			case "//go:interrupt":
   276  				if hasUnsafeImport(f.Pkg.Pkg) {
   277  					info.interrupt = true
   278  				}
   279  			case "//go:wasm-module":
   280  				// Alternative comment for setting the import module.
   281  				// This is deprecated, use //go:wasmimport instead.
   282  				if len(parts) != 2 {
   283  					continue
   284  				}
   285  				info.wasmModule = parts[1]
   286  			case "//go:wasmimport":
   287  				// Import a WebAssembly function, for example a WASI function.
   288  				// Original proposal: https://github.com/golang/go/issues/38248
   289  				// Allow globally: https://github.com/golang/go/issues/59149
   290  				if len(parts) != 3 {
   291  					continue
   292  				}
   293  				c.checkWasmImport(f, comment.Text)
   294  				info.exported = true
   295  				info.wasmModule = parts[1]
   296  				info.wasmName = parts[2]
   297  			case "//go:inline":
   298  				info.inline = inlineHint
   299  			case "//go:noinline":
   300  				info.inline = inlineNone
   301  			case "//go:linkname":
   302  				if len(parts) != 3 || parts[1] != f.Name() {
   303  					continue
   304  				}
   305  				// Only enable go:linkname when the package imports "unsafe".
   306  				// This is a slightly looser requirement than what gc uses: gc
   307  				// requires the file to import "unsafe", not the package as a
   308  				// whole.
   309  				if hasUnsafeImport(f.Pkg.Pkg) {
   310  					info.linkName = parts[2]
   311  				}
   312  			case "//go:section":
   313  				// Only enable go:section when the package imports "unsafe".
   314  				// go:section also implies go:noinline since inlining could
   315  				// move the code to a different section than that requested.
   316  				if len(parts) == 2 && hasUnsafeImport(f.Pkg.Pkg) {
   317  					info.section = parts[1]
   318  					info.inline = inlineNone
   319  				}
   320  			case "//go:nobounds":
   321  				// Skip bounds checking in this function. Useful for some
   322  				// runtime functions.
   323  				// This is somewhat dangerous and thus only imported in packages
   324  				// that import unsafe.
   325  				if hasUnsafeImport(f.Pkg.Pkg) {
   326  					info.nobounds = true
   327  				}
   328  			case "//go:variadic":
   329  				// The //go:variadic pragma is emitted by the CGo preprocessing
   330  				// pass for C variadic functions. This includes both explicit
   331  				// (with ...) and implicit (no parameters in signature)
   332  				// functions.
   333  				if strings.HasPrefix(f.Name(), "C.") {
   334  					// This prefix cannot naturally be created, it must have
   335  					// been created as a result of CGo preprocessing.
   336  					info.variadic = true
   337  				}
   338  			}
   339  		}
   340  	}
   341  }
   342  
   343  // Check whether this function cannot be used in //go:wasmimport. It will add an
   344  // error if this is the case.
   345  //
   346  // The list of allowed types is based on this proposal:
   347  // https://github.com/golang/go/issues/59149
   348  func (c *compilerContext) checkWasmImport(f *ssa.Function, pragma string) {
   349  	if c.pkg.Path() == "runtime" || c.pkg.Path() == "syscall/js" {
   350  		// The runtime is a special case. Allow all kinds of parameters
   351  		// (importantly, including pointers).
   352  		return
   353  	}
   354  	if f.Blocks != nil {
   355  		// Defined functions cannot be exported.
   356  		c.addError(f.Pos(), fmt.Sprintf("can only use //go:wasmimport on declarations"))
   357  		return
   358  	}
   359  	if f.Signature.Results().Len() > 1 {
   360  		c.addError(f.Signature.Results().At(1).Pos(), fmt.Sprintf("%s: too many return values", pragma))
   361  	} else if f.Signature.Results().Len() == 1 {
   362  		result := f.Signature.Results().At(0)
   363  		if !isValidWasmType(result.Type(), true) {
   364  			c.addError(result.Pos(), fmt.Sprintf("%s: unsupported result type %s", pragma, result.Type().String()))
   365  		}
   366  	}
   367  	for _, param := range f.Params {
   368  		// Check whether the type is allowed.
   369  		// Only a very limited number of types can be mapped to WebAssembly.
   370  		if !isValidWasmType(param.Type(), false) {
   371  			c.addError(param.Pos(), fmt.Sprintf("%s: unsupported parameter type %s", pragma, param.Type().String()))
   372  		}
   373  	}
   374  }
   375  
   376  // Check whether the type maps directly to a WebAssembly type, according to:
   377  // https://github.com/golang/go/issues/59149
   378  func isValidWasmType(typ types.Type, isReturn bool) bool {
   379  	switch typ := typ.Underlying().(type) {
   380  	case *types.Basic:
   381  		switch typ.Kind() {
   382  		case types.Int32, types.Uint32, types.Int64, types.Uint64:
   383  			return true
   384  		case types.Float32, types.Float64:
   385  			return true
   386  		case types.UnsafePointer:
   387  			if !isReturn {
   388  				return true
   389  			}
   390  		}
   391  	}
   392  	return false
   393  }
   394  
   395  // getParams returns the function parameters, including the receiver at the
   396  // start. This is an alternative to the Params member of *ssa.Function, which is
   397  // not yet populated when the package has not yet been built.
   398  func getParams(sig *types.Signature) []*types.Var {
   399  	params := []*types.Var{}
   400  	if sig.Recv() != nil {
   401  		params = append(params, sig.Recv())
   402  	}
   403  	for i := 0; i < sig.Params().Len(); i++ {
   404  		params = append(params, sig.Params().At(i))
   405  	}
   406  	return params
   407  }
   408  
   409  // addStandardDeclaredAttributes adds attributes that are set for any function,
   410  // whether declared or defined.
   411  func (c *compilerContext) addStandardDeclaredAttributes(llvmFn llvm.Value) {
   412  	if c.SizeLevel >= 1 {
   413  		// Set the "optsize" attribute to make slightly smaller binaries at the
   414  		// cost of minimal performance loss (-Os in Clang).
   415  		kind := llvm.AttributeKindID("optsize")
   416  		attr := c.ctx.CreateEnumAttribute(kind, 0)
   417  		llvmFn.AddFunctionAttr(attr)
   418  	}
   419  	if c.SizeLevel >= 2 {
   420  		// Set the "minsize" attribute to reduce code size even further,
   421  		// regardless of performance loss (-Oz in Clang).
   422  		kind := llvm.AttributeKindID("minsize")
   423  		attr := c.ctx.CreateEnumAttribute(kind, 0)
   424  		llvmFn.AddFunctionAttr(attr)
   425  	}
   426  	if c.CPU != "" {
   427  		llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("target-cpu", c.CPU))
   428  	}
   429  	if c.Features != "" {
   430  		llvmFn.AddFunctionAttr(c.ctx.CreateStringAttribute("target-features", c.Features))
   431  	}
   432  }
   433  
   434  // addStandardDefinedAttributes adds the set of attributes that are added to
   435  // every function defined by TinyGo (even thunks/wrappers), possibly depending
   436  // on the architecture. It does not set attributes only set for declared
   437  // functions, use addStandardDeclaredAttributes for this.
   438  func (c *compilerContext) addStandardDefinedAttributes(llvmFn llvm.Value) {
   439  	// TinyGo does not currently raise exceptions, so set the 'nounwind' flag.
   440  	// This behavior matches Clang when compiling C source files.
   441  	// It reduces binary size on Linux a little bit on non-x86_64 targets by
   442  	// eliminating exception tables for these functions.
   443  	llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("nounwind"), 0))
   444  	if strings.Split(c.Triple, "-")[0] == "x86_64" {
   445  		// Required by the ABI.
   446  		// The uwtable has two possible values: sync (1) or async (2). We use
   447  		// sync because we currently don't use async unwind tables.
   448  		// For details, see: https://llvm.org/docs/LangRef.html#function-attributes
   449  		llvmFn.AddFunctionAttr(c.ctx.CreateEnumAttribute(llvm.AttributeKindID("uwtable"), 1))
   450  	}
   451  }
   452  
   453  // addStandardAttributes adds all attributes added to defined functions.
   454  func (c *compilerContext) addStandardAttributes(llvmFn llvm.Value) {
   455  	c.addStandardDeclaredAttributes(llvmFn)
   456  	c.addStandardDefinedAttributes(llvmFn)
   457  }
   458  
   459  // globalInfo contains some information about a specific global. By default,
   460  // linkName is equal to .RelString(nil) on a global and extern is false, but for
   461  // some symbols this is different (due to //go:extern for example).
   462  type globalInfo struct {
   463  	linkName string // go:extern
   464  	extern   bool   // go:extern
   465  	align    int    // go:align
   466  	section  string // go:section
   467  }
   468  
   469  // loadASTComments loads comments on globals from the AST, for use later in the
   470  // program. In particular, they are required for //go:extern pragmas on globals.
   471  func (c *compilerContext) loadASTComments(pkg *loader.Package) {
   472  	for _, file := range pkg.Files {
   473  		for _, decl := range file.Decls {
   474  			switch decl := decl.(type) {
   475  			case *ast.GenDecl:
   476  				switch decl.Tok {
   477  				case token.VAR:
   478  					if len(decl.Specs) != 1 {
   479  						continue
   480  					}
   481  					for _, spec := range decl.Specs {
   482  						switch spec := spec.(type) {
   483  						case *ast.ValueSpec: // decl.Tok == token.VAR
   484  							for _, name := range spec.Names {
   485  								id := pkg.Pkg.Path() + "." + name.Name
   486  								c.astComments[id] = decl.Doc
   487  							}
   488  						}
   489  					}
   490  				}
   491  			}
   492  		}
   493  	}
   494  }
   495  
   496  // getGlobal returns a LLVM IR global value for a Go SSA global. It is added to
   497  // the LLVM IR if it has not been added already.
   498  func (c *compilerContext) getGlobal(g *ssa.Global) llvm.Value {
   499  	info := c.getGlobalInfo(g)
   500  	llvmGlobal := c.mod.NamedGlobal(info.linkName)
   501  	if llvmGlobal.IsNil() {
   502  		typ := g.Type().(*types.Pointer).Elem()
   503  		llvmType := c.getLLVMType(typ)
   504  		llvmGlobal = llvm.AddGlobal(c.mod, llvmType, info.linkName)
   505  
   506  		// Set alignment from the //go:align comment.
   507  		alignment := c.targetData.ABITypeAlignment(llvmType)
   508  		if info.align > alignment {
   509  			alignment = info.align
   510  		}
   511  		if alignment <= 0 || alignment&(alignment-1) != 0 {
   512  			// Check for power-of-two (or 0).
   513  			// See: https://stackoverflow.com/a/108360
   514  			c.addError(g.Pos(), "global variable alignment must be a positive power of two")
   515  		} else {
   516  			// Set the alignment only when it is a power of two.
   517  			llvmGlobal.SetAlignment(alignment)
   518  		}
   519  
   520  		if c.Debug && !info.extern {
   521  			// Add debug info.
   522  			pos := c.program.Fset.Position(g.Pos())
   523  			diglobal := c.dibuilder.CreateGlobalVariableExpression(c.difiles[pos.Filename], llvm.DIGlobalVariableExpression{
   524  				Name:        g.RelString(nil),
   525  				LinkageName: info.linkName,
   526  				File:        c.getDIFile(pos.Filename),
   527  				Line:        pos.Line,
   528  				Type:        c.getDIType(typ),
   529  				LocalToUnit: false,
   530  				Expr:        c.dibuilder.CreateExpression(nil),
   531  				AlignInBits: uint32(alignment) * 8,
   532  			})
   533  			llvmGlobal.AddMetadata(0, diglobal)
   534  		}
   535  	}
   536  	return llvmGlobal
   537  }
   538  
   539  // getGlobalInfo returns some information about a specific global.
   540  func (c *compilerContext) getGlobalInfo(g *ssa.Global) globalInfo {
   541  	info := globalInfo{
   542  		// Pick the default linkName.
   543  		linkName: g.RelString(nil),
   544  	}
   545  	// Check for //go: pragmas, which may change the link name (among others).
   546  	doc := c.astComments[info.linkName]
   547  	if doc != nil {
   548  		info.parsePragmas(doc)
   549  	}
   550  	return info
   551  }
   552  
   553  // Parse //go: pragma comments from the source. In particular, it parses the
   554  // //go:extern pragma on globals.
   555  func (info *globalInfo) parsePragmas(doc *ast.CommentGroup) {
   556  	for _, comment := range doc.List {
   557  		if !strings.HasPrefix(comment.Text, "//go:") {
   558  			continue
   559  		}
   560  		parts := strings.Fields(comment.Text)
   561  		switch parts[0] {
   562  		case "//go:extern":
   563  			info.extern = true
   564  			if len(parts) == 2 {
   565  				info.linkName = parts[1]
   566  			}
   567  		case "//go:align":
   568  			align, err := strconv.Atoi(parts[1])
   569  			if err == nil {
   570  				info.align = align
   571  			}
   572  		case "//go:section":
   573  			if len(parts) == 2 {
   574  				info.section = parts[1]
   575  			}
   576  		}
   577  	}
   578  }
   579  
   580  // Get all methods of a type.
   581  func getAllMethods(prog *ssa.Program, typ types.Type) []*types.Selection {
   582  	ms := prog.MethodSets.MethodSet(typ)
   583  	methods := make([]*types.Selection, ms.Len())
   584  	for i := 0; i < ms.Len(); i++ {
   585  		methods[i] = ms.At(i)
   586  	}
   587  	return methods
   588  }
   589  
   590  // Return true if this package imports "unsafe", false otherwise.
   591  func hasUnsafeImport(pkg *types.Package) bool {
   592  	for _, imp := range pkg.Imports() {
   593  		if imp == types.Unsafe {
   594  			return true
   595  		}
   596  	}
   597  	return false
   598  }