github.com/tinygo-org/tinygo@v0.31.3-0.20240404173401-90b0bf646c27/compiler/compiler.go (about) 1 package compiler 2 3 import ( 4 "debug/dwarf" 5 "errors" 6 "fmt" 7 "go/ast" 8 "go/constant" 9 "go/token" 10 "go/types" 11 "math/bits" 12 "path" 13 "path/filepath" 14 "sort" 15 "strconv" 16 "strings" 17 18 "github.com/tinygo-org/tinygo/compiler/llvmutil" 19 "github.com/tinygo-org/tinygo/loader" 20 "golang.org/x/tools/go/ssa" 21 "golang.org/x/tools/go/types/typeutil" 22 "tinygo.org/x/go-llvm" 23 ) 24 25 func init() { 26 llvm.InitializeAllTargets() 27 llvm.InitializeAllTargetMCs() 28 llvm.InitializeAllTargetInfos() 29 llvm.InitializeAllAsmParsers() 30 llvm.InitializeAllAsmPrinters() 31 } 32 33 // Config is the configuration for the compiler. Most settings should be copied 34 // directly from compileopts.Config, it recreated here to decouple the compiler 35 // package a bit and because it makes caching easier. 36 // 37 // This struct can be used for caching: if one of the flags here changes the 38 // code must be recompiled. 39 type Config struct { 40 // Target and output information. 41 Triple string 42 CPU string 43 Features string 44 ABI string 45 GOOS string 46 GOARCH string 47 CodeModel string 48 RelocationModel string 49 SizeLevel int 50 TinyGoVersion string // for llvm.ident 51 52 // Various compiler options that determine how code is generated. 53 Scheduler string 54 AutomaticStackSize bool 55 DefaultStackSize uint64 56 MaxStackAlloc uint64 57 NeedsStackObjects bool 58 Debug bool // Whether to emit debug information in the LLVM module. 59 PanicStrategy string 60 } 61 62 // compilerContext contains function-independent data that should still be 63 // available while compiling every function. It is not strictly read-only, but 64 // must not contain function-dependent data such as an IR builder. 65 type compilerContext struct { 66 *Config 67 DumpSSA bool 68 mod llvm.Module 69 ctx llvm.Context 70 builder llvm.Builder // only used for constant operations 71 dibuilder *llvm.DIBuilder 72 cu llvm.Metadata 73 difiles map[string]llvm.Metadata 74 ditypes map[types.Type]llvm.Metadata 75 llvmTypes typeutil.Map 76 interfaceTypes typeutil.Map 77 machine llvm.TargetMachine 78 targetData llvm.TargetData 79 intType llvm.Type 80 dataPtrType llvm.Type // pointer in address space 0 81 funcPtrType llvm.Type // pointer in function address space (1 for AVR, 0 elsewhere) 82 funcPtrAddrSpace int 83 uintptrType llvm.Type 84 program *ssa.Program 85 diagnostics []error 86 functionInfos map[*ssa.Function]functionInfo 87 astComments map[string]*ast.CommentGroup 88 embedGlobals map[string][]*loader.EmbedFile 89 pkg *types.Package 90 packageDir string // directory for this package 91 runtimePkg *types.Package 92 } 93 94 // newCompilerContext returns a new compiler context ready for use, most 95 // importantly with a newly created LLVM context and module. 96 func newCompilerContext(moduleName string, machine llvm.TargetMachine, config *Config, dumpSSA bool) *compilerContext { 97 c := &compilerContext{ 98 Config: config, 99 DumpSSA: dumpSSA, 100 difiles: make(map[string]llvm.Metadata), 101 ditypes: make(map[types.Type]llvm.Metadata), 102 machine: machine, 103 targetData: machine.CreateTargetData(), 104 functionInfos: map[*ssa.Function]functionInfo{}, 105 astComments: map[string]*ast.CommentGroup{}, 106 } 107 108 c.ctx = llvm.NewContext() 109 c.builder = c.ctx.NewBuilder() 110 c.mod = c.ctx.NewModule(moduleName) 111 c.mod.SetTarget(config.Triple) 112 c.mod.SetDataLayout(c.targetData.String()) 113 if c.Debug { 114 c.dibuilder = llvm.NewDIBuilder(c.mod) 115 } 116 117 c.uintptrType = c.ctx.IntType(c.targetData.PointerSize() * 8) 118 if c.targetData.PointerSize() <= 4 { 119 // 8, 16, 32 bits targets 120 c.intType = c.ctx.Int32Type() 121 } else if c.targetData.PointerSize() == 8 { 122 // 64 bits target 123 c.intType = c.ctx.Int64Type() 124 } else { 125 panic("unknown pointer size") 126 } 127 c.dataPtrType = llvm.PointerType(c.ctx.Int8Type(), 0) 128 129 dummyFuncType := llvm.FunctionType(c.ctx.VoidType(), nil, false) 130 dummyFunc := llvm.AddFunction(c.mod, "tinygo.dummy", dummyFuncType) 131 c.funcPtrAddrSpace = dummyFunc.Type().PointerAddressSpace() 132 c.funcPtrType = dummyFunc.Type() 133 dummyFunc.EraseFromParentAsFunction() 134 135 return c 136 } 137 138 // Dispose everything related to the context, _except_ for the IR module (and 139 // the associated context). 140 func (c *compilerContext) dispose() { 141 c.builder.Dispose() 142 } 143 144 // builder contains all information relevant to build a single function. 145 type builder struct { 146 *compilerContext 147 llvm.Builder 148 fn *ssa.Function 149 llvmFnType llvm.Type 150 llvmFn llvm.Value 151 info functionInfo 152 locals map[ssa.Value]llvm.Value // local variables 153 blockEntries map[*ssa.BasicBlock]llvm.BasicBlock // a *ssa.BasicBlock may be split up 154 blockExits map[*ssa.BasicBlock]llvm.BasicBlock // these are the exit blocks 155 currentBlock *ssa.BasicBlock 156 phis []phiNode 157 deferPtr llvm.Value 158 deferFrame llvm.Value 159 stackChainAlloca llvm.Value 160 landingpad llvm.BasicBlock 161 difunc llvm.Metadata 162 dilocals map[*types.Var]llvm.Metadata 163 initInlinedAt llvm.Metadata // fake inlinedAt position 164 initPseudoFuncs map[string]llvm.Metadata // fake "inlined" functions for proper init debug locations 165 allDeferFuncs []interface{} 166 deferFuncs map[*ssa.Function]int 167 deferInvokeFuncs map[string]int 168 deferClosureFuncs map[*ssa.Function]int 169 deferExprFuncs map[ssa.Value]int 170 selectRecvBuf map[*ssa.Select]llvm.Value 171 deferBuiltinFuncs map[ssa.Value]deferBuiltin 172 runDefersBlock []llvm.BasicBlock 173 afterDefersBlock []llvm.BasicBlock 174 } 175 176 func newBuilder(c *compilerContext, irbuilder llvm.Builder, f *ssa.Function) *builder { 177 fnType, fn := c.getFunction(f) 178 return &builder{ 179 compilerContext: c, 180 Builder: irbuilder, 181 fn: f, 182 llvmFnType: fnType, 183 llvmFn: fn, 184 info: c.getFunctionInfo(f), 185 locals: make(map[ssa.Value]llvm.Value), 186 dilocals: make(map[*types.Var]llvm.Metadata), 187 blockEntries: make(map[*ssa.BasicBlock]llvm.BasicBlock), 188 blockExits: make(map[*ssa.BasicBlock]llvm.BasicBlock), 189 } 190 } 191 192 type deferBuiltin struct { 193 callName string 194 pos token.Pos 195 argTypes []types.Type 196 callback int 197 } 198 199 type phiNode struct { 200 ssa *ssa.Phi 201 llvm llvm.Value 202 } 203 204 // NewTargetMachine returns a new llvm.TargetMachine based on the passed-in 205 // configuration. It is used by the compiler and is needed for machine code 206 // emission. 207 func NewTargetMachine(config *Config) (llvm.TargetMachine, error) { 208 target, err := llvm.GetTargetFromTriple(config.Triple) 209 if err != nil { 210 return llvm.TargetMachine{}, err 211 } 212 213 var codeModel llvm.CodeModel 214 var relocationModel llvm.RelocMode 215 216 switch config.CodeModel { 217 case "default": 218 codeModel = llvm.CodeModelDefault 219 case "tiny": 220 codeModel = llvm.CodeModelTiny 221 case "small": 222 codeModel = llvm.CodeModelSmall 223 case "kernel": 224 codeModel = llvm.CodeModelKernel 225 case "medium": 226 codeModel = llvm.CodeModelMedium 227 case "large": 228 codeModel = llvm.CodeModelLarge 229 } 230 231 switch config.RelocationModel { 232 case "static": 233 relocationModel = llvm.RelocStatic 234 case "pic": 235 relocationModel = llvm.RelocPIC 236 case "dynamicnopic": 237 relocationModel = llvm.RelocDynamicNoPic 238 } 239 240 machine := target.CreateTargetMachine(config.Triple, config.CPU, config.Features, llvm.CodeGenLevelDefault, relocationModel, codeModel) 241 return machine, nil 242 } 243 244 // Sizes returns a types.Sizes appropriate for the given target machine. It 245 // includes the correct int size and aligment as is necessary for the Go 246 // typechecker. 247 func Sizes(machine llvm.TargetMachine) types.Sizes { 248 targetData := machine.CreateTargetData() 249 defer targetData.Dispose() 250 251 var intWidth int 252 if targetData.PointerSize() <= 4 { 253 // 8, 16, 32 bits targets 254 intWidth = 32 255 } else if targetData.PointerSize() == 8 { 256 // 64 bits target 257 intWidth = 64 258 } else { 259 panic("unknown pointer size") 260 } 261 262 // Construct a complex128 type because that's likely the type with the 263 // biggest alignment on most/all ABIs. 264 ctx := llvm.NewContext() 265 defer ctx.Dispose() 266 complex128Type := ctx.StructType([]llvm.Type{ctx.DoubleType(), ctx.DoubleType()}, false) 267 return &stdSizes{ 268 IntSize: int64(intWidth / 8), 269 PtrSize: int64(targetData.PointerSize()), 270 MaxAlign: int64(targetData.ABITypeAlignment(complex128Type)), 271 } 272 } 273 274 // CompilePackage compiles a single package to a LLVM module. 275 func CompilePackage(moduleName string, pkg *loader.Package, ssaPkg *ssa.Package, machine llvm.TargetMachine, config *Config, dumpSSA bool) (llvm.Module, []error) { 276 c := newCompilerContext(moduleName, machine, config, dumpSSA) 277 defer c.dispose() 278 c.packageDir = pkg.OriginalDir() 279 c.embedGlobals = pkg.EmbedGlobals 280 c.pkg = pkg.Pkg 281 c.runtimePkg = ssaPkg.Prog.ImportedPackage("runtime").Pkg 282 c.program = ssaPkg.Prog 283 284 // Convert AST to SSA. 285 ssaPkg.Build() 286 287 // Initialize debug information. 288 if c.Debug { 289 c.cu = c.dibuilder.CreateCompileUnit(llvm.DICompileUnit{ 290 Language: 0xb, // DW_LANG_C99 (0xc, off-by-one?) 291 File: "<unknown>", 292 Dir: "", 293 Producer: "TinyGo", 294 Optimized: true, 295 }) 296 } 297 298 // Load comments such as //go:extern on globals. 299 c.loadASTComments(pkg) 300 301 // Predeclare the runtime.alloc function, which is used by the wordpack 302 // functionality. 303 c.getFunction(c.program.ImportedPackage("runtime").Members["alloc"].(*ssa.Function)) 304 if c.NeedsStackObjects { 305 // Predeclare trackPointer, which is used everywhere we use runtime.alloc. 306 c.getFunction(c.program.ImportedPackage("runtime").Members["trackPointer"].(*ssa.Function)) 307 } 308 309 // Compile all functions, methods, and global variables in this package. 310 irbuilder := c.ctx.NewBuilder() 311 defer irbuilder.Dispose() 312 c.createPackage(irbuilder, ssaPkg) 313 314 // see: https://reviews.llvm.org/D18355 315 if c.Debug { 316 c.mod.AddNamedMetadataOperand("llvm.module.flags", 317 c.ctx.MDNode([]llvm.Metadata{ 318 llvm.ConstInt(c.ctx.Int32Type(), 2, false).ConstantAsMetadata(), // Warning on mismatch 319 c.ctx.MDString("Debug Info Version"), 320 llvm.ConstInt(c.ctx.Int32Type(), 3, false).ConstantAsMetadata(), // DWARF version 321 }), 322 ) 323 c.mod.AddNamedMetadataOperand("llvm.module.flags", 324 c.ctx.MDNode([]llvm.Metadata{ 325 llvm.ConstInt(c.ctx.Int32Type(), 7, false).ConstantAsMetadata(), // Max on mismatch 326 c.ctx.MDString("Dwarf Version"), 327 llvm.ConstInt(c.ctx.Int32Type(), 4, false).ConstantAsMetadata(), 328 }), 329 ) 330 if c.TinyGoVersion != "" { 331 // It is necessary to set llvm.ident, otherwise debugging on MacOS 332 // won't work. 333 c.mod.AddNamedMetadataOperand("llvm.ident", 334 c.ctx.MDNode(([]llvm.Metadata{ 335 c.ctx.MDString("TinyGo version " + c.TinyGoVersion), 336 }))) 337 } 338 c.dibuilder.Finalize() 339 c.dibuilder.Destroy() 340 } 341 342 // Add the "target-abi" flag, which is necessary on RISC-V otherwise it will 343 // pick one that doesn't match the -mabi Clang flag. 344 if c.ABI != "" { 345 c.mod.AddNamedMetadataOperand("llvm.module.flags", 346 c.ctx.MDNode([]llvm.Metadata{ 347 llvm.ConstInt(c.ctx.Int32Type(), 1, false).ConstantAsMetadata(), // Error on mismatch 348 c.ctx.MDString("target-abi"), 349 c.ctx.MDString(c.ABI), 350 }), 351 ) 352 } 353 354 return c.mod, c.diagnostics 355 } 356 357 func (c *compilerContext) getRuntimeType(name string) types.Type { 358 return c.runtimePkg.Scope().Lookup(name).(*types.TypeName).Type() 359 } 360 361 // getLLVMRuntimeType obtains a named type from the runtime package and returns 362 // it as a LLVM type, creating it if necessary. It is a shorthand for 363 // getLLVMType(getRuntimeType(name)). 364 func (c *compilerContext) getLLVMRuntimeType(name string) llvm.Type { 365 return c.getLLVMType(c.getRuntimeType(name)) 366 } 367 368 // getLLVMType returns a LLVM type for a Go type. It doesn't recreate already 369 // created types. This is somewhat important for performance, but especially 370 // important for named struct types (which should only be created once). 371 func (c *compilerContext) getLLVMType(goType types.Type) llvm.Type { 372 // Try to load the LLVM type from the cache. 373 // Note: *types.Named isn't unique when working with generics. 374 // See https://github.com/golang/go/issues/53914 375 // This is the reason for using typeutil.Map to lookup LLVM types for Go types. 376 ival := c.llvmTypes.At(goType) 377 if ival != nil { 378 return ival.(llvm.Type) 379 } 380 // Not already created, so adding this type to the cache. 381 llvmType := c.makeLLVMType(goType) 382 c.llvmTypes.Set(goType, llvmType) 383 return llvmType 384 } 385 386 // makeLLVMType creates a LLVM type for a Go type. Don't call this, use 387 // getLLVMType instead. 388 func (c *compilerContext) makeLLVMType(goType types.Type) llvm.Type { 389 switch typ := goType.(type) { 390 case *types.Array: 391 elemType := c.getLLVMType(typ.Elem()) 392 return llvm.ArrayType(elemType, int(typ.Len())) 393 case *types.Basic: 394 switch typ.Kind() { 395 case types.Bool, types.UntypedBool: 396 return c.ctx.Int1Type() 397 case types.Int8, types.Uint8: 398 return c.ctx.Int8Type() 399 case types.Int16, types.Uint16: 400 return c.ctx.Int16Type() 401 case types.Int32, types.Uint32: 402 return c.ctx.Int32Type() 403 case types.Int, types.Uint: 404 return c.intType 405 case types.Int64, types.Uint64: 406 return c.ctx.Int64Type() 407 case types.Float32: 408 return c.ctx.FloatType() 409 case types.Float64: 410 return c.ctx.DoubleType() 411 case types.Complex64: 412 return c.ctx.StructType([]llvm.Type{c.ctx.FloatType(), c.ctx.FloatType()}, false) 413 case types.Complex128: 414 return c.ctx.StructType([]llvm.Type{c.ctx.DoubleType(), c.ctx.DoubleType()}, false) 415 case types.String, types.UntypedString: 416 return c.getLLVMRuntimeType("_string") 417 case types.Uintptr: 418 return c.uintptrType 419 case types.UnsafePointer: 420 return c.dataPtrType 421 default: 422 panic("unknown basic type: " + typ.String()) 423 } 424 case *types.Chan, *types.Map, *types.Pointer: 425 return c.dataPtrType // all pointers are the same 426 case *types.Interface: 427 return c.getLLVMRuntimeType("_interface") 428 case *types.Named: 429 if st, ok := typ.Underlying().(*types.Struct); ok { 430 // Structs are a special case. While other named types are ignored 431 // in LLVM IR, named structs are implemented as named structs in 432 // LLVM. This is because it is otherwise impossible to create 433 // self-referencing types such as linked lists. 434 llvmName := typ.String() 435 llvmType := c.ctx.StructCreateNamed(llvmName) 436 c.llvmTypes.Set(goType, llvmType) // avoid infinite recursion 437 underlying := c.getLLVMType(st) 438 llvmType.StructSetBody(underlying.StructElementTypes(), false) 439 return llvmType 440 } 441 return c.getLLVMType(typ.Underlying()) 442 case *types.Signature: // function value 443 return c.getFuncType(typ) 444 case *types.Slice: 445 members := []llvm.Type{ 446 c.dataPtrType, 447 c.uintptrType, // len 448 c.uintptrType, // cap 449 } 450 return c.ctx.StructType(members, false) 451 case *types.Struct: 452 members := make([]llvm.Type, typ.NumFields()) 453 for i := 0; i < typ.NumFields(); i++ { 454 members[i] = c.getLLVMType(typ.Field(i).Type()) 455 } 456 return c.ctx.StructType(members, false) 457 case *types.TypeParam: 458 return c.getLLVMType(typ.Underlying()) 459 case *types.Tuple: 460 members := make([]llvm.Type, typ.Len()) 461 for i := 0; i < typ.Len(); i++ { 462 members[i] = c.getLLVMType(typ.At(i).Type()) 463 } 464 return c.ctx.StructType(members, false) 465 default: 466 panic("unknown type: " + goType.String()) 467 } 468 } 469 470 // Is this a pointer type of some sort? Can be unsafe.Pointer or any *T pointer. 471 func isPointer(typ types.Type) bool { 472 if _, ok := typ.(*types.Pointer); ok { 473 return true 474 } else if typ, ok := typ.(*types.Basic); ok && typ.Kind() == types.UnsafePointer { 475 return true 476 } else { 477 return false 478 } 479 } 480 481 // Get the DWARF type for this Go type. 482 func (c *compilerContext) getDIType(typ types.Type) llvm.Metadata { 483 if md, ok := c.ditypes[typ]; ok { 484 return md 485 } 486 md := c.createDIType(typ) 487 c.ditypes[typ] = md 488 return md 489 } 490 491 // createDIType creates a new DWARF type. Don't call this function directly, 492 // call getDIType instead. 493 func (c *compilerContext) createDIType(typ types.Type) llvm.Metadata { 494 llvmType := c.getLLVMType(typ) 495 sizeInBytes := c.targetData.TypeAllocSize(llvmType) 496 switch typ := typ.(type) { 497 case *types.Array: 498 return c.dibuilder.CreateArrayType(llvm.DIArrayType{ 499 SizeInBits: sizeInBytes * 8, 500 AlignInBits: uint32(c.targetData.ABITypeAlignment(llvmType)) * 8, 501 ElementType: c.getDIType(typ.Elem()), 502 Subscripts: []llvm.DISubrange{ 503 { 504 Lo: 0, 505 Count: typ.Len(), 506 }, 507 }, 508 }) 509 case *types.Basic: 510 var encoding llvm.DwarfTypeEncoding 511 if typ.Info()&types.IsBoolean != 0 { 512 encoding = llvm.DW_ATE_boolean 513 } else if typ.Info()&types.IsFloat != 0 { 514 encoding = llvm.DW_ATE_float 515 } else if typ.Info()&types.IsComplex != 0 { 516 encoding = llvm.DW_ATE_complex_float 517 } else if typ.Info()&types.IsUnsigned != 0 { 518 encoding = llvm.DW_ATE_unsigned 519 } else if typ.Info()&types.IsInteger != 0 { 520 encoding = llvm.DW_ATE_signed 521 } else if typ.Kind() == types.UnsafePointer { 522 return c.dibuilder.CreatePointerType(llvm.DIPointerType{ 523 Name: "unsafe.Pointer", 524 SizeInBits: c.targetData.TypeAllocSize(llvmType) * 8, 525 AlignInBits: uint32(c.targetData.ABITypeAlignment(llvmType)) * 8, 526 AddressSpace: 0, 527 }) 528 } else if typ.Info()&types.IsString != 0 { 529 return c.dibuilder.CreateStructType(llvm.Metadata{}, llvm.DIStructType{ 530 Name: "string", 531 SizeInBits: sizeInBytes * 8, 532 AlignInBits: uint32(c.targetData.ABITypeAlignment(llvmType)) * 8, 533 Elements: []llvm.Metadata{ 534 c.dibuilder.CreateMemberType(llvm.Metadata{}, llvm.DIMemberType{ 535 Name: "ptr", 536 SizeInBits: c.targetData.TypeAllocSize(c.dataPtrType) * 8, 537 AlignInBits: uint32(c.targetData.ABITypeAlignment(c.dataPtrType)) * 8, 538 OffsetInBits: 0, 539 Type: c.getDIType(types.NewPointer(types.Typ[types.Byte])), 540 }), 541 c.dibuilder.CreateMemberType(llvm.Metadata{}, llvm.DIMemberType{ 542 Name: "len", 543 SizeInBits: c.targetData.TypeAllocSize(c.uintptrType) * 8, 544 AlignInBits: uint32(c.targetData.ABITypeAlignment(c.uintptrType)) * 8, 545 OffsetInBits: c.targetData.ElementOffset(llvmType, 1) * 8, 546 Type: c.getDIType(types.Typ[types.Uintptr]), 547 }), 548 }, 549 }) 550 } else { 551 panic("unknown basic type") 552 } 553 return c.dibuilder.CreateBasicType(llvm.DIBasicType{ 554 Name: typ.String(), 555 SizeInBits: sizeInBytes * 8, 556 Encoding: encoding, 557 }) 558 case *types.Chan: 559 return c.getDIType(types.NewPointer(c.program.ImportedPackage("runtime").Members["channel"].(*ssa.Type).Type())) 560 case *types.Interface: 561 return c.getDIType(c.program.ImportedPackage("runtime").Members["_interface"].(*ssa.Type).Type()) 562 case *types.Map: 563 return c.getDIType(types.NewPointer(c.program.ImportedPackage("runtime").Members["hashmap"].(*ssa.Type).Type())) 564 case *types.Named: 565 // Placeholder metadata node, to be replaced afterwards. 566 temporaryMDNode := c.dibuilder.CreateReplaceableCompositeType(llvm.Metadata{}, llvm.DIReplaceableCompositeType{ 567 Tag: dwarf.TagTypedef, 568 SizeInBits: sizeInBytes * 8, 569 AlignInBits: uint32(c.targetData.ABITypeAlignment(llvmType)) * 8, 570 }) 571 c.ditypes[typ] = temporaryMDNode 572 md := c.dibuilder.CreateTypedef(llvm.DITypedef{ 573 Type: c.getDIType(typ.Underlying()), 574 Name: typ.String(), 575 }) 576 temporaryMDNode.ReplaceAllUsesWith(md) 577 return md 578 case *types.Pointer: 579 return c.dibuilder.CreatePointerType(llvm.DIPointerType{ 580 Pointee: c.getDIType(typ.Elem()), 581 SizeInBits: c.targetData.TypeAllocSize(llvmType) * 8, 582 AlignInBits: uint32(c.targetData.ABITypeAlignment(llvmType)) * 8, 583 AddressSpace: 0, 584 }) 585 case *types.Signature: 586 // actually a closure 587 fields := llvmType.StructElementTypes() 588 return c.dibuilder.CreateStructType(llvm.Metadata{}, llvm.DIStructType{ 589 SizeInBits: sizeInBytes * 8, 590 AlignInBits: uint32(c.targetData.ABITypeAlignment(llvmType)) * 8, 591 Elements: []llvm.Metadata{ 592 c.dibuilder.CreateMemberType(llvm.Metadata{}, llvm.DIMemberType{ 593 Name: "context", 594 SizeInBits: c.targetData.TypeAllocSize(fields[1]) * 8, 595 AlignInBits: uint32(c.targetData.ABITypeAlignment(fields[1])) * 8, 596 OffsetInBits: 0, 597 Type: c.getDIType(types.Typ[types.UnsafePointer]), 598 }), 599 c.dibuilder.CreateMemberType(llvm.Metadata{}, llvm.DIMemberType{ 600 Name: "fn", 601 SizeInBits: c.targetData.TypeAllocSize(fields[0]) * 8, 602 AlignInBits: uint32(c.targetData.ABITypeAlignment(fields[0])) * 8, 603 OffsetInBits: c.targetData.ElementOffset(llvmType, 1) * 8, 604 Type: c.getDIType(types.Typ[types.UnsafePointer]), 605 }), 606 }, 607 }) 608 case *types.Slice: 609 fields := llvmType.StructElementTypes() 610 return c.dibuilder.CreateStructType(llvm.Metadata{}, llvm.DIStructType{ 611 Name: typ.String(), 612 SizeInBits: sizeInBytes * 8, 613 AlignInBits: uint32(c.targetData.ABITypeAlignment(llvmType)) * 8, 614 Elements: []llvm.Metadata{ 615 c.dibuilder.CreateMemberType(llvm.Metadata{}, llvm.DIMemberType{ 616 Name: "ptr", 617 SizeInBits: c.targetData.TypeAllocSize(fields[0]) * 8, 618 AlignInBits: uint32(c.targetData.ABITypeAlignment(fields[0])) * 8, 619 OffsetInBits: 0, 620 Type: c.getDIType(types.NewPointer(typ.Elem())), 621 }), 622 c.dibuilder.CreateMemberType(llvm.Metadata{}, llvm.DIMemberType{ 623 Name: "len", 624 SizeInBits: c.targetData.TypeAllocSize(c.uintptrType) * 8, 625 AlignInBits: uint32(c.targetData.ABITypeAlignment(c.uintptrType)) * 8, 626 OffsetInBits: c.targetData.ElementOffset(llvmType, 1) * 8, 627 Type: c.getDIType(types.Typ[types.Uintptr]), 628 }), 629 c.dibuilder.CreateMemberType(llvm.Metadata{}, llvm.DIMemberType{ 630 Name: "cap", 631 SizeInBits: c.targetData.TypeAllocSize(c.uintptrType) * 8, 632 AlignInBits: uint32(c.targetData.ABITypeAlignment(c.uintptrType)) * 8, 633 OffsetInBits: c.targetData.ElementOffset(llvmType, 2) * 8, 634 Type: c.getDIType(types.Typ[types.Uintptr]), 635 }), 636 }, 637 }) 638 case *types.Struct: 639 elements := make([]llvm.Metadata, typ.NumFields()) 640 for i := range elements { 641 field := typ.Field(i) 642 fieldType := field.Type() 643 llvmField := c.getLLVMType(fieldType) 644 elements[i] = c.dibuilder.CreateMemberType(llvm.Metadata{}, llvm.DIMemberType{ 645 Name: field.Name(), 646 SizeInBits: c.targetData.TypeAllocSize(llvmField) * 8, 647 AlignInBits: uint32(c.targetData.ABITypeAlignment(llvmField)) * 8, 648 OffsetInBits: c.targetData.ElementOffset(llvmType, i) * 8, 649 Type: c.getDIType(fieldType), 650 }) 651 } 652 md := c.dibuilder.CreateStructType(llvm.Metadata{}, llvm.DIStructType{ 653 SizeInBits: sizeInBytes * 8, 654 AlignInBits: uint32(c.targetData.ABITypeAlignment(llvmType)) * 8, 655 Elements: elements, 656 }) 657 return md 658 case *types.TypeParam: 659 return c.getDIType(typ.Underlying()) 660 default: 661 panic("unknown type while generating DWARF debug type: " + typ.String()) 662 } 663 } 664 665 // setDebugLocation sets the current debug location for the builder. 666 func (b *builder) setDebugLocation(pos token.Pos) { 667 if pos == token.NoPos { 668 // No debug information available for this instruction. 669 b.SetCurrentDebugLocation(0, 0, b.difunc, llvm.Metadata{}) 670 return 671 } 672 673 position := b.program.Fset.Position(pos) 674 if b.fn.Synthetic == "package initializer" { 675 // Package initializers are treated specially, because while individual 676 // Go SSA instructions have file/line/col information, the parent 677 // function does not. LLVM doesn't store filename information per 678 // instruction, only per function. We work around this difference by 679 // creating a fake DIFunction for each Go file and say that the 680 // instruction really came from that (fake) function but was inlined in 681 // the package initializer function. 682 position := b.program.Fset.Position(pos) 683 name := filepath.Base(position.Filename) 684 difunc, ok := b.initPseudoFuncs[name] 685 if !ok { 686 diFuncType := b.dibuilder.CreateSubroutineType(llvm.DISubroutineType{ 687 File: b.getDIFile(position.Filename), 688 }) 689 difunc = b.dibuilder.CreateFunction(b.getDIFile(position.Filename), llvm.DIFunction{ 690 Name: b.fn.RelString(nil) + "#" + name, 691 File: b.getDIFile(position.Filename), 692 Line: 0, 693 Type: diFuncType, 694 LocalToUnit: true, 695 IsDefinition: true, 696 ScopeLine: 0, 697 Flags: llvm.FlagPrototyped, 698 Optimized: true, 699 }) 700 b.initPseudoFuncs[name] = difunc 701 } 702 b.SetCurrentDebugLocation(uint(position.Line), uint(position.Column), difunc, b.initInlinedAt) 703 return 704 } 705 706 // Regular debug information. 707 b.SetCurrentDebugLocation(uint(position.Line), uint(position.Column), b.difunc, llvm.Metadata{}) 708 } 709 710 // getLocalVariable returns a debug info entry for a local variable, which may 711 // either be a parameter or a regular variable. It will create a new metadata 712 // entry if there isn't one for the variable yet. 713 func (b *builder) getLocalVariable(variable *types.Var) llvm.Metadata { 714 if dilocal, ok := b.dilocals[variable]; ok { 715 // DILocalVariable was already created, return it directly. 716 return dilocal 717 } 718 719 pos := b.program.Fset.Position(variable.Pos()) 720 721 // Check whether this is a function parameter. 722 for i, param := range b.fn.Params { 723 if param.Object().(*types.Var) == variable { 724 // Yes it is, create it as a function parameter. 725 dilocal := b.dibuilder.CreateParameterVariable(b.difunc, llvm.DIParameterVariable{ 726 Name: param.Name(), 727 File: b.getDIFile(pos.Filename), 728 Line: pos.Line, 729 Type: b.getDIType(param.Type()), 730 AlwaysPreserve: true, 731 ArgNo: i + 1, 732 }) 733 b.dilocals[variable] = dilocal 734 return dilocal 735 } 736 } 737 738 // No, it's not a parameter. Create a regular (auto) variable. 739 dilocal := b.dibuilder.CreateAutoVariable(b.difunc, llvm.DIAutoVariable{ 740 Name: variable.Name(), 741 File: b.getDIFile(pos.Filename), 742 Line: pos.Line, 743 Type: b.getDIType(variable.Type()), 744 AlwaysPreserve: true, 745 }) 746 b.dilocals[variable] = dilocal 747 return dilocal 748 } 749 750 // attachDebugInfo adds debug info to a function declaration. It returns the 751 // DISubprogram metadata node. 752 func (c *compilerContext) attachDebugInfo(f *ssa.Function) llvm.Metadata { 753 pos := c.program.Fset.Position(f.Syntax().Pos()) 754 _, fn := c.getFunction(f) 755 return c.attachDebugInfoRaw(f, fn, "", pos.Filename, pos.Line) 756 } 757 758 // attachDebugInfo adds debug info to a function declaration. It returns the 759 // DISubprogram metadata node. This method allows some more control over how 760 // debug info is added to the function. 761 func (c *compilerContext) attachDebugInfoRaw(f *ssa.Function, llvmFn llvm.Value, suffix, filename string, line int) llvm.Metadata { 762 // Debug info for this function. 763 params := getParams(f.Signature) 764 diparams := make([]llvm.Metadata, 0, len(params)) 765 for _, param := range params { 766 diparams = append(diparams, c.getDIType(param.Type())) 767 } 768 diFuncType := c.dibuilder.CreateSubroutineType(llvm.DISubroutineType{ 769 File: c.getDIFile(filename), 770 Parameters: diparams, 771 Flags: 0, // ? 772 }) 773 difunc := c.dibuilder.CreateFunction(c.getDIFile(filename), llvm.DIFunction{ 774 Name: f.RelString(nil) + suffix, 775 LinkageName: c.getFunctionInfo(f).linkName + suffix, 776 File: c.getDIFile(filename), 777 Line: line, 778 Type: diFuncType, 779 LocalToUnit: true, 780 IsDefinition: true, 781 ScopeLine: 0, 782 Flags: llvm.FlagPrototyped, 783 Optimized: true, 784 }) 785 llvmFn.SetSubprogram(difunc) 786 return difunc 787 } 788 789 // getDIFile returns a DIFile metadata node for the given filename. It tries to 790 // use one that was already created, otherwise it falls back to creating a new 791 // one. 792 func (c *compilerContext) getDIFile(filename string) llvm.Metadata { 793 if _, ok := c.difiles[filename]; !ok { 794 dir, file := filepath.Split(filename) 795 if dir != "" { 796 dir = dir[:len(dir)-1] 797 } 798 c.difiles[filename] = c.dibuilder.CreateFile(file, dir) 799 } 800 return c.difiles[filename] 801 } 802 803 // createPackage builds the LLVM IR for all types, methods, and global variables 804 // in the given package. 805 func (c *compilerContext) createPackage(irbuilder llvm.Builder, pkg *ssa.Package) { 806 // Sort by position, so that the order of the functions in the IR matches 807 // the order of functions in the source file. This is useful for testing, 808 // for example. 809 var members []string 810 for name := range pkg.Members { 811 members = append(members, name) 812 } 813 sort.Slice(members, func(i, j int) bool { 814 iPos := pkg.Members[members[i]].Pos() 815 jPos := pkg.Members[members[j]].Pos() 816 if i == j { 817 // Cannot sort by pos, so do it by name. 818 return members[i] < members[j] 819 } 820 return iPos < jPos 821 }) 822 823 // Define all functions. 824 for _, name := range members { 825 member := pkg.Members[name] 826 switch member := member.(type) { 827 case *ssa.Function: 828 if member.TypeParams() != nil { 829 // Do not try to build generic (non-instantiated) functions. 830 continue 831 } 832 // Create the function definition. 833 b := newBuilder(c, irbuilder, member) 834 if _, ok := mathToLLVMMapping[member.RelString(nil)]; ok { 835 // The body of this function (if there is one) is ignored and 836 // replaced with a LLVM intrinsic call. 837 b.defineMathOp() 838 continue 839 } 840 if ok := b.defineMathBitsIntrinsic(); ok { 841 // Like a math intrinsic, the body of this function was replaced 842 // with a LLVM intrinsic. 843 continue 844 } 845 if member.Blocks == nil { 846 // Try to define this as an intrinsic function. 847 b.defineIntrinsicFunction() 848 // It might not be an intrinsic function but simply an external 849 // function (defined via //go:linkname). Leave it undefined in 850 // that case. 851 continue 852 } 853 b.createFunction() 854 case *ssa.Type: 855 if types.IsInterface(member.Type()) { 856 // Interfaces don't have concrete methods. 857 continue 858 } 859 860 // Named type. We should make sure all methods are created. 861 // This includes both functions with pointer receivers and those 862 // without. 863 methods := getAllMethods(pkg.Prog, member.Type()) 864 methods = append(methods, getAllMethods(pkg.Prog, types.NewPointer(member.Type()))...) 865 for _, method := range methods { 866 // Parse this method. 867 fn := pkg.Prog.MethodValue(method) 868 if fn == nil { 869 continue // probably a generic method 870 } 871 if member.Type().String() != member.String() { 872 // This is a member on a type alias. Do not build such a 873 // function. 874 continue 875 } 876 if fn.Blocks == nil { 877 continue // external function 878 } 879 if fn.Synthetic != "" && fn.Synthetic != "package initializer" { 880 // This function is a kind of wrapper function (created by 881 // the ssa package, not appearing in the source code) that 882 // is created by the getFunction method as needed. 883 // Therefore, don't build it here to avoid "function 884 // redeclared" errors. 885 continue 886 } 887 // Create the function definition. 888 b := newBuilder(c, irbuilder, fn) 889 b.createFunction() 890 } 891 case *ssa.Global: 892 // Global variable. 893 info := c.getGlobalInfo(member) 894 global := c.getGlobal(member) 895 if files, ok := c.embedGlobals[member.Name()]; ok { 896 c.createEmbedGlobal(member, global, files) 897 } else if !info.extern { 898 global.SetInitializer(llvm.ConstNull(global.GlobalValueType())) 899 global.SetVisibility(llvm.HiddenVisibility) 900 if info.section != "" { 901 global.SetSection(info.section) 902 } 903 } 904 } 905 } 906 907 // Add forwarding functions for functions that would otherwise be 908 // implemented in assembly. 909 for _, name := range members { 910 member := pkg.Members[name] 911 switch member := member.(type) { 912 case *ssa.Function: 913 if member.Blocks != nil { 914 continue // external function 915 } 916 info := c.getFunctionInfo(member) 917 if aliasName, ok := stdlibAliases[info.linkName]; ok { 918 alias := c.mod.NamedFunction(aliasName) 919 if alias.IsNil() { 920 // Shouldn't happen, but perhaps best to just ignore. 921 // The error will be a link error, if there is an error. 922 continue 923 } 924 b := newBuilder(c, irbuilder, member) 925 b.createAlias(alias) 926 } 927 } 928 } 929 } 930 931 // createEmbedGlobal creates an initializer for a //go:embed global variable. 932 func (c *compilerContext) createEmbedGlobal(member *ssa.Global, global llvm.Value, files []*loader.EmbedFile) { 933 switch typ := member.Type().(*types.Pointer).Elem().Underlying().(type) { 934 case *types.Basic: 935 // String type. 936 if typ.Kind() != types.String { 937 // This is checked at the AST level, so should be unreachable. 938 panic("expected a string type") 939 } 940 if len(files) != 1 { 941 c.addError(member.Pos(), fmt.Sprintf("//go:embed for a string should be given exactly one file, got %d", len(files))) 942 return 943 } 944 strObj := c.getEmbedFileString(files[0]) 945 global.SetInitializer(strObj) 946 global.SetVisibility(llvm.HiddenVisibility) 947 948 case *types.Slice: 949 if typ.Elem().Underlying().(*types.Basic).Kind() != types.Byte { 950 // This is checked at the AST level, so should be unreachable. 951 panic("expected a byte slice") 952 } 953 if len(files) != 1 { 954 c.addError(member.Pos(), fmt.Sprintf("//go:embed for a string should be given exactly one file, got %d", len(files))) 955 return 956 } 957 file := files[0] 958 bufferValue := c.ctx.ConstString(string(file.Data), false) 959 bufferGlobal := llvm.AddGlobal(c.mod, bufferValue.Type(), c.pkg.Path()+"$embedslice") 960 bufferGlobal.SetInitializer(bufferValue) 961 bufferGlobal.SetLinkage(llvm.InternalLinkage) 962 bufferGlobal.SetAlignment(1) 963 slicePtr := llvm.ConstInBoundsGEP(bufferValue.Type(), bufferGlobal, []llvm.Value{ 964 llvm.ConstInt(c.uintptrType, 0, false), 965 llvm.ConstInt(c.uintptrType, 0, false), 966 }) 967 sliceLen := llvm.ConstInt(c.uintptrType, file.Size, false) 968 sliceObj := c.ctx.ConstStruct([]llvm.Value{slicePtr, sliceLen, sliceLen}, false) 969 global.SetInitializer(sliceObj) 970 global.SetVisibility(llvm.HiddenVisibility) 971 972 if c.Debug { 973 // Add debug info to the slice backing array. 974 position := c.program.Fset.Position(member.Pos()) 975 diglobal := c.dibuilder.CreateGlobalVariableExpression(llvm.Metadata{}, llvm.DIGlobalVariableExpression{ 976 File: c.getDIFile(position.Filename), 977 Line: position.Line, 978 Type: c.getDIType(types.NewArray(types.Typ[types.Byte], int64(len(file.Data)))), 979 LocalToUnit: true, 980 Expr: c.dibuilder.CreateExpression(nil), 981 }) 982 bufferGlobal.AddMetadata(0, diglobal) 983 } 984 985 case *types.Struct: 986 // Assume this is an embed.FS struct: 987 // https://cs.opensource.google/go/go/+/refs/tags/go1.18.2:src/embed/embed.go;l=148 988 // It looks like this: 989 // type FS struct { 990 // files *file 991 // } 992 993 // Make a slice of the files, as they will appear in the binary. They 994 // are sorted in a special way to allow for binary searches, see 995 // src/embed/embed.go for details. 996 dirset := map[string]struct{}{} 997 var allFiles []*loader.EmbedFile 998 for _, file := range files { 999 allFiles = append(allFiles, file) 1000 dirname := file.Name 1001 for { 1002 dirname, _ = path.Split(path.Clean(dirname)) 1003 if dirname == "" { 1004 break 1005 } 1006 if _, ok := dirset[dirname]; ok { 1007 break 1008 } 1009 dirset[dirname] = struct{}{} 1010 allFiles = append(allFiles, &loader.EmbedFile{ 1011 Name: dirname, 1012 }) 1013 } 1014 } 1015 sort.Slice(allFiles, func(i, j int) bool { 1016 dir1, name1 := path.Split(path.Clean(allFiles[i].Name)) 1017 dir2, name2 := path.Split(path.Clean(allFiles[j].Name)) 1018 if dir1 != dir2 { 1019 return dir1 < dir2 1020 } 1021 return name1 < name2 1022 }) 1023 1024 // Make the backing array for the []files slice. This is a LLVM global. 1025 embedFileStructType := typ.Field(0).Type().(*types.Pointer).Elem().(*types.Slice).Elem() 1026 llvmEmbedFileStructType := c.getLLVMType(embedFileStructType) 1027 var fileStructs []llvm.Value 1028 for _, file := range allFiles { 1029 fileStruct := llvm.ConstNull(llvmEmbedFileStructType) 1030 name := c.createConst(ssa.NewConst(constant.MakeString(file.Name), types.Typ[types.String]), getPos(member)) 1031 fileStruct = c.builder.CreateInsertValue(fileStruct, name, 0, "") // "name" field 1032 if file.Hash != "" { 1033 data := c.getEmbedFileString(file) 1034 fileStruct = c.builder.CreateInsertValue(fileStruct, data, 1, "") // "data" field 1035 } 1036 fileStructs = append(fileStructs, fileStruct) 1037 } 1038 sliceDataInitializer := llvm.ConstArray(llvmEmbedFileStructType, fileStructs) 1039 sliceDataGlobal := llvm.AddGlobal(c.mod, sliceDataInitializer.Type(), c.pkg.Path()+"$embedfsfiles") 1040 sliceDataGlobal.SetInitializer(sliceDataInitializer) 1041 sliceDataGlobal.SetLinkage(llvm.InternalLinkage) 1042 sliceDataGlobal.SetGlobalConstant(true) 1043 sliceDataGlobal.SetUnnamedAddr(true) 1044 sliceDataGlobal.SetAlignment(c.targetData.ABITypeAlignment(sliceDataInitializer.Type())) 1045 if c.Debug { 1046 // Add debug information for code size attribution (among others). 1047 position := c.program.Fset.Position(member.Pos()) 1048 diglobal := c.dibuilder.CreateGlobalVariableExpression(llvm.Metadata{}, llvm.DIGlobalVariableExpression{ 1049 File: c.getDIFile(position.Filename), 1050 Line: position.Line, 1051 Type: c.getDIType(types.NewArray(embedFileStructType, int64(len(allFiles)))), 1052 LocalToUnit: true, 1053 Expr: c.dibuilder.CreateExpression(nil), 1054 }) 1055 sliceDataGlobal.AddMetadata(0, diglobal) 1056 } 1057 1058 // Create the slice object itself. 1059 // Because embed.FS refers to it as *[]embed.file instead of a plain 1060 // []embed.file, we have to store this as a global. 1061 slicePtr := llvm.ConstInBoundsGEP(sliceDataInitializer.Type(), sliceDataGlobal, []llvm.Value{ 1062 llvm.ConstInt(c.uintptrType, 0, false), 1063 llvm.ConstInt(c.uintptrType, 0, false), 1064 }) 1065 sliceLen := llvm.ConstInt(c.uintptrType, uint64(len(fileStructs)), false) 1066 sliceInitializer := c.ctx.ConstStruct([]llvm.Value{slicePtr, sliceLen, sliceLen}, false) 1067 sliceGlobal := llvm.AddGlobal(c.mod, sliceInitializer.Type(), c.pkg.Path()+"$embedfsslice") 1068 sliceGlobal.SetInitializer(sliceInitializer) 1069 sliceGlobal.SetLinkage(llvm.InternalLinkage) 1070 sliceGlobal.SetGlobalConstant(true) 1071 sliceGlobal.SetUnnamedAddr(true) 1072 sliceGlobal.SetAlignment(c.targetData.ABITypeAlignment(sliceInitializer.Type())) 1073 if c.Debug { 1074 position := c.program.Fset.Position(member.Pos()) 1075 diglobal := c.dibuilder.CreateGlobalVariableExpression(llvm.Metadata{}, llvm.DIGlobalVariableExpression{ 1076 File: c.getDIFile(position.Filename), 1077 Line: position.Line, 1078 Type: c.getDIType(types.NewSlice(embedFileStructType)), 1079 LocalToUnit: true, 1080 Expr: c.dibuilder.CreateExpression(nil), 1081 }) 1082 sliceGlobal.AddMetadata(0, diglobal) 1083 } 1084 1085 // Define the embed.FS struct. It has only one field: the files (as a 1086 // *[]embed.file). 1087 globalInitializer := llvm.ConstNull(c.getLLVMType(member.Type().(*types.Pointer).Elem())) 1088 globalInitializer = c.builder.CreateInsertValue(globalInitializer, sliceGlobal, 0, "") 1089 global.SetInitializer(globalInitializer) 1090 global.SetVisibility(llvm.HiddenVisibility) 1091 global.SetAlignment(c.targetData.ABITypeAlignment(globalInitializer.Type())) 1092 } 1093 } 1094 1095 // getEmbedFileString returns the (constant) string object with the contents of 1096 // the given file. This is a llvm.Value of a regular Go string. 1097 func (c *compilerContext) getEmbedFileString(file *loader.EmbedFile) llvm.Value { 1098 dataGlobalName := "embed/file_" + file.Hash 1099 dataGlobal := c.mod.NamedGlobal(dataGlobalName) 1100 dataGlobalType := llvm.ArrayType(c.ctx.Int8Type(), int(file.Size)) 1101 if dataGlobal.IsNil() { 1102 dataGlobal = llvm.AddGlobal(c.mod, dataGlobalType, dataGlobalName) 1103 } 1104 strPtr := llvm.ConstInBoundsGEP(dataGlobalType, dataGlobal, []llvm.Value{ 1105 llvm.ConstInt(c.uintptrType, 0, false), 1106 llvm.ConstInt(c.uintptrType, 0, false), 1107 }) 1108 strLen := llvm.ConstInt(c.uintptrType, file.Size, false) 1109 return llvm.ConstNamedStruct(c.getLLVMRuntimeType("_string"), []llvm.Value{strPtr, strLen}) 1110 } 1111 1112 // Start defining a function so that it can be filled with instructions: load 1113 // parameters, create basic blocks, and set up debug information. 1114 // This is separated out from createFunction() so that it is also usable to 1115 // define compiler intrinsics like the atomic operations in sync/atomic. 1116 func (b *builder) createFunctionStart(intrinsic bool) { 1117 if b.DumpSSA { 1118 fmt.Printf("\nfunc %s:\n", b.fn) 1119 } 1120 if !b.llvmFn.IsDeclaration() { 1121 errValue := b.llvmFn.Name() + " redeclared in this program" 1122 fnPos := getPosition(b.llvmFn) 1123 if fnPos.IsValid() { 1124 errValue += "\n\tprevious declaration at " + fnPos.String() 1125 } 1126 b.addError(b.fn.Pos(), errValue) 1127 return 1128 } 1129 1130 b.addStandardDefinedAttributes(b.llvmFn) 1131 if !b.info.exported { 1132 // Do not set visibility for local linkage (internal or private). 1133 // Otherwise a "local linkage requires default visibility" 1134 // assertion error in llvm-project/llvm/include/llvm/IR/GlobalValue.h:236 1135 // is thrown. 1136 if b.llvmFn.Linkage() != llvm.InternalLinkage && 1137 b.llvmFn.Linkage() != llvm.PrivateLinkage { 1138 b.llvmFn.SetVisibility(llvm.HiddenVisibility) 1139 } 1140 b.llvmFn.SetUnnamedAddr(true) 1141 } 1142 if b.info.section != "" { 1143 b.llvmFn.SetSection(b.info.section) 1144 } 1145 if b.info.exported && strings.HasPrefix(b.Triple, "wasm") { 1146 // Set the exported name. This is necessary for WebAssembly because 1147 // otherwise the function is not exported. 1148 functionAttr := b.ctx.CreateStringAttribute("wasm-export-name", b.info.linkName) 1149 b.llvmFn.AddFunctionAttr(functionAttr) 1150 // Unlike most targets, exported functions are actually visible in 1151 // WebAssembly (even if it's not called from within the WebAssembly 1152 // module). But LTO generally optimizes such functions away. Therefore, 1153 // exported functions must be explicitly marked as used. 1154 llvmutil.AppendToGlobal(b.mod, "llvm.used", b.llvmFn) 1155 } 1156 1157 // Some functions have a pragma controlling the inlining level. 1158 switch b.info.inline { 1159 case inlineHint: 1160 // Add LLVM inline hint to functions with //go:inline pragma. 1161 inline := b.ctx.CreateEnumAttribute(llvm.AttributeKindID("inlinehint"), 0) 1162 b.llvmFn.AddFunctionAttr(inline) 1163 case inlineNone: 1164 // Add LLVM attribute to always avoid inlining this function. 1165 noinline := b.ctx.CreateEnumAttribute(llvm.AttributeKindID("noinline"), 0) 1166 b.llvmFn.AddFunctionAttr(noinline) 1167 } 1168 1169 if b.info.interrupt { 1170 // Mark this function as an interrupt. 1171 // This is necessary on MCUs that don't push caller saved registers when 1172 // entering an interrupt, such as on AVR. 1173 if strings.HasPrefix(b.Triple, "avr") { 1174 b.llvmFn.AddFunctionAttr(b.ctx.CreateStringAttribute("signal", "")) 1175 } else { 1176 b.addError(b.fn.Pos(), "//go:interrupt not supported on this architecture") 1177 } 1178 } 1179 1180 // Add debug info, if needed. 1181 if b.Debug { 1182 if b.fn.Synthetic == "package initializer" { 1183 // Package initializer functions have no debug info. Create some 1184 // fake debug info to at least have *something*. 1185 b.difunc = b.attachDebugInfoRaw(b.fn, b.llvmFn, "", b.packageDir, 0) 1186 } else if b.fn.Syntax() != nil { 1187 // Create debug info file if needed. 1188 b.difunc = b.attachDebugInfo(b.fn) 1189 } 1190 b.setDebugLocation(b.fn.Pos()) 1191 } 1192 1193 // Pre-create all basic blocks in the function. 1194 var entryBlock llvm.BasicBlock 1195 if intrinsic { 1196 // This function isn't defined in Go SSA. It is probably a compiler 1197 // intrinsic (like an atomic operation). Create the entry block 1198 // manually. 1199 entryBlock = b.ctx.AddBasicBlock(b.llvmFn, "entry") 1200 } else { 1201 for _, block := range b.fn.DomPreorder() { 1202 llvmBlock := b.ctx.AddBasicBlock(b.llvmFn, block.Comment) 1203 b.blockEntries[block] = llvmBlock 1204 b.blockExits[block] = llvmBlock 1205 } 1206 // Normal functions have an entry block. 1207 entryBlock = b.blockEntries[b.fn.Blocks[0]] 1208 } 1209 b.SetInsertPointAtEnd(entryBlock) 1210 1211 if b.fn.Synthetic == "package initializer" { 1212 b.initPseudoFuncs = make(map[string]llvm.Metadata) 1213 1214 // Create a fake 'inlined at' metadata node. 1215 // See setDebugLocation for details. 1216 alloca := b.CreateAlloca(b.uintptrType, "") 1217 b.initInlinedAt = alloca.InstructionDebugLoc() 1218 alloca.EraseFromParentAsInstruction() 1219 } 1220 1221 // Load function parameters 1222 llvmParamIndex := 0 1223 for _, param := range b.fn.Params { 1224 llvmType := b.getLLVMType(param.Type()) 1225 fields := make([]llvm.Value, 0, 1) 1226 for _, info := range b.expandFormalParamType(llvmType, param.Name(), param.Type()) { 1227 param := b.llvmFn.Param(llvmParamIndex) 1228 param.SetName(info.name) 1229 fields = append(fields, param) 1230 llvmParamIndex++ 1231 } 1232 b.locals[param] = b.collapseFormalParam(llvmType, fields) 1233 1234 // Add debug information to this parameter (if available) 1235 if b.Debug && b.fn.Syntax() != nil { 1236 dbgParam := b.getLocalVariable(param.Object().(*types.Var)) 1237 loc := b.GetCurrentDebugLocation() 1238 if len(fields) == 1 { 1239 expr := b.dibuilder.CreateExpression(nil) 1240 b.dibuilder.InsertValueAtEnd(fields[0], dbgParam, expr, loc, entryBlock) 1241 } else { 1242 fieldOffsets := b.expandFormalParamOffsets(llvmType) 1243 for i, field := range fields { 1244 expr := b.dibuilder.CreateExpression([]uint64{ 1245 0x1000, // DW_OP_LLVM_fragment 1246 fieldOffsets[i] * 8, // offset in bits 1247 b.targetData.TypeAllocSize(field.Type()) * 8, // size in bits 1248 }) 1249 b.dibuilder.InsertValueAtEnd(field, dbgParam, expr, loc, entryBlock) 1250 } 1251 } 1252 } 1253 } 1254 1255 // Load free variables from the context. This is a closure (or bound 1256 // method). 1257 var context llvm.Value 1258 if !b.info.exported { 1259 context = b.llvmFn.LastParam() 1260 context.SetName("context") 1261 } 1262 if len(b.fn.FreeVars) != 0 { 1263 // Get a list of all variable types in the context. 1264 freeVarTypes := make([]llvm.Type, len(b.fn.FreeVars)) 1265 for i, freeVar := range b.fn.FreeVars { 1266 freeVarTypes[i] = b.getLLVMType(freeVar.Type()) 1267 } 1268 1269 // Load each free variable from the context pointer. 1270 // A free variable is always a pointer when this is a closure, but it 1271 // can be another type when it is a wrapper for a bound method (these 1272 // wrappers are generated by the ssa package). 1273 for i, val := range b.emitPointerUnpack(context, freeVarTypes) { 1274 b.locals[b.fn.FreeVars[i]] = val 1275 } 1276 } 1277 1278 if b.fn.Recover != nil { 1279 // This function has deferred function calls. Set some things up for 1280 // them. 1281 b.deferInitFunc() 1282 } 1283 1284 if b.NeedsStackObjects { 1285 // Create a dummy alloca that will be used in runtime.trackPointer. 1286 // It is necessary to pass a dummy alloca to runtime.trackPointer 1287 // because runtime.trackPointer is replaced by an alloca store. 1288 b.stackChainAlloca = b.CreateAlloca(b.ctx.Int8Type(), "stackalloc") 1289 } 1290 } 1291 1292 // createFunction builds the LLVM IR implementation for this function. The 1293 // function must not yet be defined, otherwise this function will create a 1294 // diagnostic. 1295 func (b *builder) createFunction() { 1296 b.createFunctionStart(false) 1297 1298 // Fill blocks with instructions. 1299 for _, block := range b.fn.DomPreorder() { 1300 if b.DumpSSA { 1301 fmt.Printf("%d: %s:\n", block.Index, block.Comment) 1302 } 1303 b.SetInsertPointAtEnd(b.blockEntries[block]) 1304 b.currentBlock = block 1305 for _, instr := range block.Instrs { 1306 if instr, ok := instr.(*ssa.DebugRef); ok { 1307 if !b.Debug { 1308 continue 1309 } 1310 object := instr.Object() 1311 variable, ok := object.(*types.Var) 1312 if !ok { 1313 // Not a local variable. 1314 continue 1315 } 1316 if instr.IsAddr { 1317 // TODO, this may happen for *ssa.Alloc and *ssa.FieldAddr 1318 // for example. 1319 continue 1320 } 1321 dbgVar := b.getLocalVariable(variable) 1322 pos := b.program.Fset.Position(instr.Pos()) 1323 b.dibuilder.InsertValueAtEnd(b.getValue(instr.X, getPos(instr)), dbgVar, b.dibuilder.CreateExpression(nil), llvm.DebugLoc{ 1324 Line: uint(pos.Line), 1325 Col: uint(pos.Column), 1326 Scope: b.difunc, 1327 }, b.GetInsertBlock()) 1328 continue 1329 } 1330 if b.DumpSSA { 1331 if val, ok := instr.(ssa.Value); ok && val.Name() != "" { 1332 fmt.Printf("\t%s = %s\n", val.Name(), val.String()) 1333 } else { 1334 fmt.Printf("\t%s\n", instr.String()) 1335 } 1336 } 1337 b.createInstruction(instr) 1338 } 1339 if b.fn.Name() == "init" && len(block.Instrs) == 0 { 1340 b.CreateRetVoid() 1341 } 1342 } 1343 1344 // The rundefers instruction needs to be created after all defer 1345 // instructions have been created. Otherwise it won't handle all defer 1346 // cases. 1347 for i, bb := range b.runDefersBlock { 1348 b.SetInsertPointAtEnd(bb) 1349 b.createRunDefers() 1350 b.CreateBr(b.afterDefersBlock[i]) 1351 } 1352 1353 if b.hasDeferFrame() { 1354 // Create the landing pad block, where execution continues after a 1355 // panic. 1356 b.createLandingPad() 1357 } 1358 1359 // Resolve phi nodes 1360 for _, phi := range b.phis { 1361 block := phi.ssa.Block() 1362 for i, edge := range phi.ssa.Edges { 1363 llvmVal := b.getValue(edge, getPos(phi.ssa)) 1364 llvmBlock := b.blockExits[block.Preds[i]] 1365 phi.llvm.AddIncoming([]llvm.Value{llvmVal}, []llvm.BasicBlock{llvmBlock}) 1366 } 1367 } 1368 1369 if b.NeedsStackObjects { 1370 // Track phi nodes. 1371 for _, phi := range b.phis { 1372 insertPoint := llvm.NextInstruction(phi.llvm) 1373 for !insertPoint.IsAPHINode().IsNil() { 1374 insertPoint = llvm.NextInstruction(insertPoint) 1375 } 1376 b.SetInsertPointBefore(insertPoint) 1377 b.trackValue(phi.llvm) 1378 } 1379 } 1380 1381 // Create anonymous functions (closures etc.). 1382 for _, sub := range b.fn.AnonFuncs { 1383 b := newBuilder(b.compilerContext, b.Builder, sub) 1384 b.llvmFn.SetLinkage(llvm.InternalLinkage) 1385 b.createFunction() 1386 } 1387 } 1388 1389 // posser is an interface that's implemented by both ssa.Value and 1390 // ssa.Instruction. It is implemented by everything that has a Pos() method, 1391 // which is all that getPos() needs. 1392 type posser interface { 1393 Pos() token.Pos 1394 } 1395 1396 // getPos returns position information for a ssa.Value or ssa.Instruction. 1397 // 1398 // Not all instructions have position information, especially when they're 1399 // implicit (such as implicit casts or implicit returns at the end of a 1400 // function). In these cases, it makes sense to try a bit harder to guess what 1401 // the position really should be. 1402 func getPos(val posser) token.Pos { 1403 pos := val.Pos() 1404 if pos != token.NoPos { 1405 // Easy: position is known. 1406 return pos 1407 } 1408 1409 // No position information is known. 1410 switch val := val.(type) { 1411 case *ssa.MakeInterface: 1412 return getPos(val.X) 1413 case *ssa.MakeClosure: 1414 return val.Fn.(*ssa.Function).Pos() 1415 case *ssa.Return: 1416 syntax := val.Parent().Syntax() 1417 if syntax != nil { 1418 // non-synthetic 1419 return syntax.End() 1420 } 1421 return token.NoPos 1422 case *ssa.FieldAddr: 1423 return getPos(val.X) 1424 case *ssa.IndexAddr: 1425 return getPos(val.X) 1426 case *ssa.Slice: 1427 return getPos(val.X) 1428 case *ssa.Store: 1429 return getPos(val.Addr) 1430 case *ssa.Extract: 1431 return getPos(val.Tuple) 1432 default: 1433 // This is reachable, for example with *ssa.Const, *ssa.If, and 1434 // *ssa.Jump. They might be implemented in some way in the future. 1435 return token.NoPos 1436 } 1437 } 1438 1439 // createInstruction builds the LLVM IR equivalent instructions for the 1440 // particular Go SSA instruction. 1441 func (b *builder) createInstruction(instr ssa.Instruction) { 1442 if b.Debug { 1443 b.setDebugLocation(getPos(instr)) 1444 } 1445 1446 switch instr := instr.(type) { 1447 case ssa.Value: 1448 if value, err := b.createExpr(instr); err != nil { 1449 // This expression could not be parsed. Add the error to the list 1450 // of diagnostics and continue with an undef value. 1451 // The resulting IR will be incorrect (but valid). However, 1452 // compilation can proceed which is useful because there may be 1453 // more compilation errors which can then all be shown together to 1454 // the user. 1455 b.diagnostics = append(b.diagnostics, err) 1456 b.locals[instr] = llvm.Undef(b.getLLVMType(instr.Type())) 1457 } else { 1458 b.locals[instr] = value 1459 if len(*instr.Referrers()) != 0 && b.NeedsStackObjects { 1460 b.trackExpr(instr, value) 1461 } 1462 } 1463 case *ssa.DebugRef: 1464 // ignore 1465 case *ssa.Defer: 1466 b.createDefer(instr) 1467 case *ssa.Go: 1468 // Start a new goroutine. 1469 b.createGo(instr) 1470 case *ssa.If: 1471 cond := b.getValue(instr.Cond, getPos(instr)) 1472 block := instr.Block() 1473 blockThen := b.blockEntries[block.Succs[0]] 1474 blockElse := b.blockEntries[block.Succs[1]] 1475 b.CreateCondBr(cond, blockThen, blockElse) 1476 case *ssa.Jump: 1477 blockJump := b.blockEntries[instr.Block().Succs[0]] 1478 b.CreateBr(blockJump) 1479 case *ssa.MapUpdate: 1480 m := b.getValue(instr.Map, getPos(instr)) 1481 key := b.getValue(instr.Key, getPos(instr)) 1482 value := b.getValue(instr.Value, getPos(instr)) 1483 mapType := instr.Map.Type().Underlying().(*types.Map) 1484 b.createMapUpdate(mapType.Key(), m, key, value, instr.Pos()) 1485 case *ssa.Panic: 1486 value := b.getValue(instr.X, getPos(instr)) 1487 b.createRuntimeInvoke("_panic", []llvm.Value{value}, "") 1488 b.CreateUnreachable() 1489 case *ssa.Return: 1490 if b.hasDeferFrame() { 1491 b.createRuntimeCall("destroyDeferFrame", []llvm.Value{b.deferFrame}, "") 1492 } 1493 if len(instr.Results) == 0 { 1494 b.CreateRetVoid() 1495 } else if len(instr.Results) == 1 { 1496 b.CreateRet(b.getValue(instr.Results[0], getPos(instr))) 1497 } else { 1498 // Multiple return values. Put them all in a struct. 1499 retVal := llvm.ConstNull(b.llvmFn.GlobalValueType().ReturnType()) 1500 for i, result := range instr.Results { 1501 val := b.getValue(result, getPos(instr)) 1502 retVal = b.CreateInsertValue(retVal, val, i, "") 1503 } 1504 b.CreateRet(retVal) 1505 } 1506 case *ssa.RunDefers: 1507 // Note where we're going to put the rundefers block 1508 run := b.insertBasicBlock("rundefers.block") 1509 b.CreateBr(run) 1510 b.runDefersBlock = append(b.runDefersBlock, run) 1511 1512 after := b.insertBasicBlock("rundefers.after") 1513 b.SetInsertPointAtEnd(after) 1514 b.afterDefersBlock = append(b.afterDefersBlock, after) 1515 case *ssa.Send: 1516 b.createChanSend(instr) 1517 case *ssa.Store: 1518 llvmAddr := b.getValue(instr.Addr, getPos(instr)) 1519 llvmVal := b.getValue(instr.Val, getPos(instr)) 1520 b.createNilCheck(instr.Addr, llvmAddr, "store") 1521 if b.targetData.TypeAllocSize(llvmVal.Type()) == 0 { 1522 // nothing to store 1523 return 1524 } 1525 b.CreateStore(llvmVal, llvmAddr) 1526 default: 1527 b.addError(instr.Pos(), "unknown instruction: "+instr.String()) 1528 } 1529 } 1530 1531 // createBuiltin lowers a builtin Go function (append, close, delete, etc.) to 1532 // LLVM IR. It uses runtime calls for some builtins. 1533 func (b *builder) createBuiltin(argTypes []types.Type, argValues []llvm.Value, callName string, pos token.Pos) (llvm.Value, error) { 1534 switch callName { 1535 case "append": 1536 src := argValues[0] 1537 elems := argValues[1] 1538 srcBuf := b.CreateExtractValue(src, 0, "append.srcBuf") 1539 srcLen := b.CreateExtractValue(src, 1, "append.srcLen") 1540 srcCap := b.CreateExtractValue(src, 2, "append.srcCap") 1541 elemsBuf := b.CreateExtractValue(elems, 0, "append.elemsBuf") 1542 elemsLen := b.CreateExtractValue(elems, 1, "append.elemsLen") 1543 elemType := b.getLLVMType(argTypes[0].Underlying().(*types.Slice).Elem()) 1544 elemSize := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(elemType), false) 1545 result := b.createRuntimeCall("sliceAppend", []llvm.Value{srcBuf, elemsBuf, srcLen, srcCap, elemsLen, elemSize}, "append.new") 1546 newPtr := b.CreateExtractValue(result, 0, "append.newPtr") 1547 newLen := b.CreateExtractValue(result, 1, "append.newLen") 1548 newCap := b.CreateExtractValue(result, 2, "append.newCap") 1549 newSlice := llvm.Undef(src.Type()) 1550 newSlice = b.CreateInsertValue(newSlice, newPtr, 0, "") 1551 newSlice = b.CreateInsertValue(newSlice, newLen, 1, "") 1552 newSlice = b.CreateInsertValue(newSlice, newCap, 2, "") 1553 return newSlice, nil 1554 case "cap": 1555 value := argValues[0] 1556 var llvmCap llvm.Value 1557 switch argTypes[0].Underlying().(type) { 1558 case *types.Chan: 1559 llvmCap = b.createRuntimeCall("chanCap", []llvm.Value{value}, "cap") 1560 case *types.Slice: 1561 llvmCap = b.CreateExtractValue(value, 2, "cap") 1562 default: 1563 return llvm.Value{}, b.makeError(pos, "todo: cap: unknown type") 1564 } 1565 if b.targetData.TypeAllocSize(llvmCap.Type()) < b.targetData.TypeAllocSize(b.intType) { 1566 llvmCap = b.CreateZExt(llvmCap, b.intType, "len.int") 1567 } 1568 return llvmCap, nil 1569 case "close": 1570 b.createChanClose(argValues[0]) 1571 return llvm.Value{}, nil 1572 case "complex": 1573 r := argValues[0] 1574 i := argValues[1] 1575 t := argTypes[0].Underlying().(*types.Basic) 1576 var cplx llvm.Value 1577 switch t.Kind() { 1578 case types.Float32: 1579 cplx = llvm.Undef(b.ctx.StructType([]llvm.Type{b.ctx.FloatType(), b.ctx.FloatType()}, false)) 1580 case types.Float64: 1581 cplx = llvm.Undef(b.ctx.StructType([]llvm.Type{b.ctx.DoubleType(), b.ctx.DoubleType()}, false)) 1582 default: 1583 return llvm.Value{}, b.makeError(pos, "unsupported type in complex builtin: "+t.String()) 1584 } 1585 cplx = b.CreateInsertValue(cplx, r, 0, "") 1586 cplx = b.CreateInsertValue(cplx, i, 1, "") 1587 return cplx, nil 1588 case "clear": 1589 value := argValues[0] 1590 switch typ := argTypes[0].Underlying().(type) { 1591 case *types.Slice: 1592 elementType := b.getLLVMType(typ.Elem()) 1593 elementSize := b.targetData.TypeAllocSize(elementType) 1594 elementAlign := b.targetData.ABITypeAlignment(elementType) 1595 1596 // The pointer to the data to be cleared. 1597 llvmBuf := b.CreateExtractValue(value, 0, "buf") 1598 1599 // The length (in bytes) to be cleared. 1600 llvmLen := b.CreateExtractValue(value, 1, "len") 1601 llvmLen = b.CreateMul(llvmLen, llvm.ConstInt(llvmLen.Type(), elementSize, false), "") 1602 1603 // Do the clear operation using the LLVM memset builtin. 1604 // This is also correct for nil slices: in those cases, len will be 1605 // 0 which means the memset call is a no-op (according to the LLVM 1606 // LangRef). 1607 memset := b.getMemsetFunc() 1608 call := b.createCall(memset.GlobalValueType(), memset, []llvm.Value{ 1609 llvmBuf, // dest 1610 llvm.ConstInt(b.ctx.Int8Type(), 0, false), // val 1611 llvmLen, // len 1612 llvm.ConstInt(b.ctx.Int1Type(), 0, false), // isVolatile 1613 }, "") 1614 call.AddCallSiteAttribute(1, b.ctx.CreateEnumAttribute(llvm.AttributeKindID("align"), uint64(elementAlign))) 1615 1616 return llvm.Value{}, nil 1617 case *types.Map: 1618 m := argValues[0] 1619 b.createMapClear(m) 1620 return llvm.Value{}, nil 1621 default: 1622 return llvm.Value{}, b.makeError(pos, "unsupported type in clear builtin: "+typ.String()) 1623 } 1624 case "copy": 1625 dst := argValues[0] 1626 src := argValues[1] 1627 dstLen := b.CreateExtractValue(dst, 1, "copy.dstLen") 1628 srcLen := b.CreateExtractValue(src, 1, "copy.srcLen") 1629 dstBuf := b.CreateExtractValue(dst, 0, "copy.dstArray") 1630 srcBuf := b.CreateExtractValue(src, 0, "copy.srcArray") 1631 elemType := b.getLLVMType(argTypes[0].Underlying().(*types.Slice).Elem()) 1632 elemSize := llvm.ConstInt(b.uintptrType, b.targetData.TypeAllocSize(elemType), false) 1633 return b.createRuntimeCall("sliceCopy", []llvm.Value{dstBuf, srcBuf, dstLen, srcLen, elemSize}, "copy.n"), nil 1634 case "delete": 1635 m := argValues[0] 1636 key := argValues[1] 1637 return llvm.Value{}, b.createMapDelete(argTypes[1], m, key, pos) 1638 case "imag": 1639 cplx := argValues[0] 1640 return b.CreateExtractValue(cplx, 1, "imag"), nil 1641 case "len": 1642 value := argValues[0] 1643 var llvmLen llvm.Value 1644 switch argTypes[0].Underlying().(type) { 1645 case *types.Basic, *types.Slice: 1646 // string or slice 1647 llvmLen = b.CreateExtractValue(value, 1, "len") 1648 case *types.Chan: 1649 llvmLen = b.createRuntimeCall("chanLen", []llvm.Value{value}, "len") 1650 case *types.Map: 1651 llvmLen = b.createRuntimeCall("hashmapLen", []llvm.Value{value}, "len") 1652 default: 1653 return llvm.Value{}, b.makeError(pos, "todo: len: unknown type") 1654 } 1655 if b.targetData.TypeAllocSize(llvmLen.Type()) < b.targetData.TypeAllocSize(b.intType) { 1656 llvmLen = b.CreateZExt(llvmLen, b.intType, "len.int") 1657 } 1658 return llvmLen, nil 1659 case "min", "max": 1660 // min and max builtins, added in Go 1.21. 1661 // We can simply reuse the existing binop comparison code, which has all 1662 // the edge cases figured out already. 1663 tok := token.LSS 1664 if callName == "max" { 1665 tok = token.GTR 1666 } 1667 result := argValues[0] 1668 typ := argTypes[0] 1669 for _, arg := range argValues[1:] { 1670 cmp, err := b.createBinOp(tok, typ, typ, result, arg, pos) 1671 if err != nil { 1672 return result, err 1673 } 1674 result = b.CreateSelect(cmp, result, arg, "") 1675 } 1676 return result, nil 1677 case "print", "println": 1678 for i, value := range argValues { 1679 if i >= 1 && callName == "println" { 1680 b.createRuntimeCall("printspace", nil, "") 1681 } 1682 typ := argTypes[i].Underlying() 1683 switch typ := typ.(type) { 1684 case *types.Basic: 1685 switch typ.Kind() { 1686 case types.String, types.UntypedString: 1687 b.createRuntimeCall("printstring", []llvm.Value{value}, "") 1688 case types.Uintptr: 1689 b.createRuntimeCall("printptr", []llvm.Value{value}, "") 1690 case types.UnsafePointer: 1691 ptrValue := b.CreatePtrToInt(value, b.uintptrType, "") 1692 b.createRuntimeCall("printptr", []llvm.Value{ptrValue}, "") 1693 default: 1694 // runtime.print{int,uint}{8,16,32,64} 1695 if typ.Info()&types.IsInteger != 0 { 1696 name := "print" 1697 if typ.Info()&types.IsUnsigned != 0 { 1698 name += "uint" 1699 } else { 1700 name += "int" 1701 } 1702 name += strconv.FormatUint(b.targetData.TypeAllocSize(value.Type())*8, 10) 1703 b.createRuntimeCall(name, []llvm.Value{value}, "") 1704 } else if typ.Kind() == types.Bool { 1705 b.createRuntimeCall("printbool", []llvm.Value{value}, "") 1706 } else if typ.Kind() == types.Float32 { 1707 b.createRuntimeCall("printfloat32", []llvm.Value{value}, "") 1708 } else if typ.Kind() == types.Float64 { 1709 b.createRuntimeCall("printfloat64", []llvm.Value{value}, "") 1710 } else if typ.Kind() == types.Complex64 { 1711 b.createRuntimeCall("printcomplex64", []llvm.Value{value}, "") 1712 } else if typ.Kind() == types.Complex128 { 1713 b.createRuntimeCall("printcomplex128", []llvm.Value{value}, "") 1714 } else { 1715 return llvm.Value{}, b.makeError(pos, "unknown basic arg type: "+typ.String()) 1716 } 1717 } 1718 case *types.Interface: 1719 b.createRuntimeCall("printitf", []llvm.Value{value}, "") 1720 case *types.Map: 1721 b.createRuntimeCall("printmap", []llvm.Value{value}, "") 1722 case *types.Pointer: 1723 ptrValue := b.CreatePtrToInt(value, b.uintptrType, "") 1724 b.createRuntimeCall("printptr", []llvm.Value{ptrValue}, "") 1725 case *types.Slice: 1726 bufptr := b.CreateExtractValue(value, 0, "") 1727 buflen := b.CreateExtractValue(value, 1, "") 1728 bufcap := b.CreateExtractValue(value, 2, "") 1729 ptrValue := b.CreatePtrToInt(bufptr, b.uintptrType, "") 1730 b.createRuntimeCall("printslice", []llvm.Value{ptrValue, buflen, bufcap}, "") 1731 default: 1732 return llvm.Value{}, b.makeError(pos, "unknown arg type: "+typ.String()) 1733 } 1734 } 1735 if callName == "println" { 1736 b.createRuntimeCall("printnl", nil, "") 1737 } 1738 return llvm.Value{}, nil // print() or println() returns void 1739 case "real": 1740 cplx := argValues[0] 1741 return b.CreateExtractValue(cplx, 0, "real"), nil 1742 case "recover": 1743 useParentFrame := uint64(0) 1744 if b.hasDeferFrame() { 1745 // recover() should return the panic value of the parent function, 1746 // not of the current function. 1747 useParentFrame = 1 1748 } 1749 return b.createRuntimeCall("_recover", []llvm.Value{llvm.ConstInt(b.ctx.Int1Type(), useParentFrame, false)}, ""), nil 1750 case "ssa:wrapnilchk": 1751 // TODO: do an actual nil check? 1752 return argValues[0], nil 1753 1754 // Builtins from the unsafe package. 1755 case "Add": // unsafe.Add 1756 // This is basically just a GEP operation. 1757 // Note: the pointer is always of type *i8. 1758 ptr := argValues[0] 1759 len := argValues[1] 1760 return b.CreateGEP(b.ctx.Int8Type(), ptr, []llvm.Value{len}, ""), nil 1761 case "Alignof": // unsafe.Alignof 1762 align := b.targetData.ABITypeAlignment(argValues[0].Type()) 1763 return llvm.ConstInt(b.uintptrType, uint64(align), false), nil 1764 case "Offsetof": // unsafe.Offsetof 1765 // This builtin is a bit harder to implement and may need a bit of 1766 // refactoring to work (it may be easier to implement if we have access 1767 // to the underlying Go SSA instruction). It is also rarely used: it 1768 // only applies in generic code and unsafe.Offsetof isn't very commonly 1769 // used anyway. 1770 // In other words, postpone it to some other day. 1771 return llvm.Value{}, b.makeError(pos, "todo: unsafe.Offsetof") 1772 case "Sizeof": // unsafe.Sizeof 1773 size := b.targetData.TypeAllocSize(argValues[0].Type()) 1774 return llvm.ConstInt(b.uintptrType, size, false), nil 1775 case "Slice", "String": // unsafe.Slice, unsafe.String 1776 // This creates a slice or string from a pointer and a length. 1777 // Note that the exception mentioned in the documentation (if the 1778 // pointer and length are nil, the slice is also nil) is trivially 1779 // already the case. 1780 ptr := argValues[0] 1781 len := argValues[1] 1782 var elementType llvm.Type 1783 if callName == "Slice" { 1784 elementType = b.getLLVMType(argTypes[0].Underlying().(*types.Pointer).Elem()) 1785 } else { 1786 elementType = b.ctx.Int8Type() 1787 } 1788 b.createUnsafeSliceStringCheck("unsafe."+callName, ptr, len, elementType, argTypes[1].Underlying().(*types.Basic)) 1789 if len.Type().IntTypeWidth() < b.uintptrType.IntTypeWidth() { 1790 // Too small, zero-extend len. 1791 len = b.CreateZExt(len, b.uintptrType, "") 1792 } else if len.Type().IntTypeWidth() > b.uintptrType.IntTypeWidth() { 1793 // Too big, truncate len. 1794 len = b.CreateTrunc(len, b.uintptrType, "") 1795 } 1796 if callName == "Slice" { 1797 slice := llvm.Undef(b.ctx.StructType([]llvm.Type{ 1798 ptr.Type(), 1799 b.uintptrType, 1800 b.uintptrType, 1801 }, false)) 1802 slice = b.CreateInsertValue(slice, ptr, 0, "") 1803 slice = b.CreateInsertValue(slice, len, 1, "") 1804 slice = b.CreateInsertValue(slice, len, 2, "") 1805 return slice, nil 1806 } else { 1807 str := llvm.Undef(b.getLLVMRuntimeType("_string")) 1808 str = b.CreateInsertValue(str, argValues[0], 0, "") 1809 str = b.CreateInsertValue(str, len, 1, "") 1810 return str, nil 1811 } 1812 case "SliceData", "StringData": // unsafe.SliceData, unsafe.StringData 1813 return b.CreateExtractValue(argValues[0], 0, "slice.data"), nil 1814 default: 1815 return llvm.Value{}, b.makeError(pos, "todo: builtin: "+callName) 1816 } 1817 } 1818 1819 // createFunctionCall lowers a Go SSA call instruction (to a simple function, 1820 // closure, function pointer, builtin, method, etc.) to LLVM IR, usually a call 1821 // instruction. 1822 // 1823 // This is also where compiler intrinsics are implemented. 1824 func (b *builder) createFunctionCall(instr *ssa.CallCommon) (llvm.Value, error) { 1825 var params []llvm.Value 1826 for _, param := range instr.Args { 1827 params = append(params, b.getValue(param, getPos(instr))) 1828 } 1829 1830 // Try to call the function directly for trivially static calls. 1831 var callee, context llvm.Value 1832 var calleeType llvm.Type 1833 exported := false 1834 if fn := instr.StaticCallee(); fn != nil { 1835 // Direct function call, either to a named or anonymous (directly 1836 // applied) function call. If it is anonymous, it may be a closure. 1837 name := fn.RelString(nil) 1838 switch { 1839 case name == "device.Asm" || name == "device/arm.Asm" || name == "device/arm64.Asm" || name == "device/avr.Asm" || name == "device/riscv.Asm": 1840 return b.createInlineAsm(instr.Args) 1841 case name == "device.AsmFull" || name == "device/arm.AsmFull" || name == "device/arm64.AsmFull" || name == "device/avr.AsmFull" || name == "device/riscv.AsmFull": 1842 return b.createInlineAsmFull(instr) 1843 case strings.HasPrefix(name, "device/arm.SVCall"): 1844 return b.emitSVCall(instr.Args, getPos(instr)) 1845 case strings.HasPrefix(name, "device/arm64.SVCall"): 1846 return b.emitSV64Call(instr.Args, getPos(instr)) 1847 case strings.HasPrefix(name, "(device/riscv.CSR)."): 1848 return b.emitCSROperation(instr) 1849 case strings.HasPrefix(name, "syscall.Syscall") || strings.HasPrefix(name, "syscall.RawSyscall"): 1850 return b.createSyscall(instr) 1851 case strings.HasPrefix(name, "syscall.rawSyscallNoError"): 1852 return b.createRawSyscallNoError(instr) 1853 case name == "runtime.supportsRecover": 1854 supportsRecover := uint64(0) 1855 if b.supportsRecover() { 1856 supportsRecover = 1 1857 } 1858 return llvm.ConstInt(b.ctx.Int1Type(), supportsRecover, false), nil 1859 case name == "runtime.panicStrategy": 1860 // These constants are defined in src/runtime/panic.go. 1861 panicStrategy := map[string]uint64{ 1862 "print": 1, // panicStrategyPrint 1863 "trap": 2, // panicStrategyTrap 1864 }[b.Config.PanicStrategy] 1865 return llvm.ConstInt(b.ctx.Int8Type(), panicStrategy, false), nil 1866 case name == "runtime/interrupt.New": 1867 return b.createInterruptGlobal(instr) 1868 } 1869 1870 calleeType, callee = b.getFunction(fn) 1871 info := b.getFunctionInfo(fn) 1872 if callee.IsNil() { 1873 return llvm.Value{}, b.makeError(instr.Pos(), "undefined function: "+info.linkName) 1874 } 1875 switch value := instr.Value.(type) { 1876 case *ssa.Function: 1877 // Regular function call. No context is necessary. 1878 context = llvm.Undef(b.dataPtrType) 1879 if info.variadic && len(fn.Params) == 0 { 1880 // This matches Clang, see: https://godbolt.org/z/Gqv49xKMq 1881 // Eventually we might be able to eliminate this special case 1882 // entirely. For details, see: 1883 // https://discourse.llvm.org/t/rfc-enabling-wstrict-prototypes-by-default-in-c/60521 1884 calleeType = llvm.FunctionType(callee.GlobalValueType().ReturnType(), nil, false) 1885 } 1886 case *ssa.MakeClosure: 1887 // A call on a func value, but the callee is trivial to find. For 1888 // example: immediately applied functions. 1889 funcValue := b.getValue(value, getPos(value)) 1890 context = b.extractFuncContext(funcValue) 1891 default: 1892 panic("StaticCallee returned an unexpected value") 1893 } 1894 exported = info.exported 1895 } else if call, ok := instr.Value.(*ssa.Builtin); ok { 1896 // Builtin function (append, close, delete, etc.).) 1897 var argTypes []types.Type 1898 for _, arg := range instr.Args { 1899 argTypes = append(argTypes, arg.Type()) 1900 } 1901 return b.createBuiltin(argTypes, params, call.Name(), instr.Pos()) 1902 } else if instr.IsInvoke() { 1903 // Interface method call (aka invoke call). 1904 itf := b.getValue(instr.Value, getPos(instr)) // interface value (runtime._interface) 1905 typecode := b.CreateExtractValue(itf, 0, "invoke.func.typecode") 1906 value := b.CreateExtractValue(itf, 1, "invoke.func.value") // receiver 1907 // Prefix the params with receiver value and suffix with typecode. 1908 params = append([]llvm.Value{value}, params...) 1909 params = append(params, typecode) 1910 callee = b.getInvokeFunction(instr) 1911 calleeType = callee.GlobalValueType() 1912 context = llvm.Undef(b.dataPtrType) 1913 } else { 1914 // Function pointer. 1915 value := b.getValue(instr.Value, getPos(instr)) 1916 // This is a func value, which cannot be called directly. We have to 1917 // extract the function pointer and context first from the func value. 1918 callee, context = b.decodeFuncValue(value) 1919 calleeType = b.getLLVMFunctionType(instr.Value.Type().Underlying().(*types.Signature)) 1920 b.createNilCheck(instr.Value, callee, "fpcall") 1921 } 1922 1923 if !exported { 1924 // This function takes a context parameter. 1925 // Add it to the end of the parameter list. 1926 params = append(params, context) 1927 } 1928 1929 return b.createInvoke(calleeType, callee, params, ""), nil 1930 } 1931 1932 // getValue returns the LLVM value of a constant, function value, global, or 1933 // already processed SSA expression. 1934 func (b *builder) getValue(expr ssa.Value, pos token.Pos) llvm.Value { 1935 switch expr := expr.(type) { 1936 case *ssa.Const: 1937 if pos == token.NoPos { 1938 // If the position isn't known, at least try to find in which file 1939 // it is defined. 1940 file := b.program.Fset.File(b.fn.Pos()) 1941 if file != nil { 1942 pos = file.Pos(0) 1943 } 1944 } 1945 return b.createConst(expr, pos) 1946 case *ssa.Function: 1947 if b.getFunctionInfo(expr).exported { 1948 b.addError(expr.Pos(), "cannot use an exported function as value: "+expr.String()) 1949 return llvm.Undef(b.getLLVMType(expr.Type())) 1950 } 1951 _, fn := b.getFunction(expr) 1952 return b.createFuncValue(fn, llvm.Undef(b.dataPtrType), expr.Signature) 1953 case *ssa.Global: 1954 value := b.getGlobal(expr) 1955 if value.IsNil() { 1956 b.addError(expr.Pos(), "global not found: "+expr.RelString(nil)) 1957 return llvm.Undef(b.getLLVMType(expr.Type())) 1958 } 1959 return value 1960 default: 1961 // other (local) SSA value 1962 if value, ok := b.locals[expr]; ok { 1963 return value 1964 } else { 1965 // indicates a compiler bug 1966 panic("local has not been parsed: " + expr.String()) 1967 } 1968 } 1969 } 1970 1971 // maxSliceSize determines the maximum size a slice of the given element type 1972 // can be. 1973 func (c *compilerContext) maxSliceSize(elementType llvm.Type) uint64 { 1974 // Calculate ^uintptr(0), which is the max value that fits in uintptr. 1975 maxPointerValue := llvm.ConstNot(llvm.ConstInt(c.uintptrType, 0, false)).ZExtValue() 1976 // Calculate (^uint(0))/2, which is the max value that fits in an int. 1977 maxIntegerValue := llvm.ConstNot(llvm.ConstInt(c.intType, 0, false)).ZExtValue() / 2 1978 1979 // Determine the maximum allowed size for a slice. The biggest possible 1980 // pointer (starting from 0) would be maxPointerValue*sizeof(elementType) so 1981 // divide by the element type to get the real maximum size. 1982 elementSize := c.targetData.TypeAllocSize(elementType) 1983 if elementSize == 0 { 1984 elementSize = 1 1985 } 1986 maxSize := maxPointerValue / elementSize 1987 1988 // len(slice) is an int. Make sure the length remains small enough to fit in 1989 // an int. 1990 if maxSize > maxIntegerValue { 1991 maxSize = maxIntegerValue 1992 } 1993 1994 return maxSize 1995 } 1996 1997 // createExpr translates a Go SSA expression to LLVM IR. This can be zero, one, 1998 // or multiple LLVM IR instructions and/or runtime calls. 1999 func (b *builder) createExpr(expr ssa.Value) (llvm.Value, error) { 2000 if _, ok := b.locals[expr]; ok { 2001 // sanity check 2002 panic("instruction has already been created: " + expr.String()) 2003 } 2004 2005 switch expr := expr.(type) { 2006 case *ssa.Alloc: 2007 typ := b.getLLVMType(expr.Type().Underlying().(*types.Pointer).Elem()) 2008 size := b.targetData.TypeAllocSize(typ) 2009 // Move all "large" allocations to the heap. 2010 if expr.Heap || size > b.MaxStackAlloc { 2011 // Calculate ^uintptr(0) 2012 maxSize := llvm.ConstNot(llvm.ConstInt(b.uintptrType, 0, false)).ZExtValue() 2013 if size > maxSize { 2014 // Size would be truncated if truncated to uintptr. 2015 return llvm.Value{}, b.makeError(expr.Pos(), fmt.Sprintf("value is too big (%v bytes)", size)) 2016 } 2017 sizeValue := llvm.ConstInt(b.uintptrType, size, false) 2018 layoutValue := b.createObjectLayout(typ, expr.Pos()) 2019 buf := b.createRuntimeCall("alloc", []llvm.Value{sizeValue, layoutValue}, expr.Comment) 2020 return buf, nil 2021 } else { 2022 buf := llvmutil.CreateEntryBlockAlloca(b.Builder, typ, expr.Comment) 2023 if b.targetData.TypeAllocSize(typ) != 0 { 2024 b.CreateStore(llvm.ConstNull(typ), buf) // zero-initialize var 2025 } 2026 return buf, nil 2027 } 2028 case *ssa.BinOp: 2029 x := b.getValue(expr.X, getPos(expr)) 2030 y := b.getValue(expr.Y, getPos(expr)) 2031 return b.createBinOp(expr.Op, expr.X.Type(), expr.Y.Type(), x, y, expr.Pos()) 2032 case *ssa.Call: 2033 return b.createFunctionCall(expr.Common()) 2034 case *ssa.ChangeInterface: 2035 // Do not change between interface types: always use the underlying 2036 // (concrete) type in the type number of the interface. Every method 2037 // call on an interface will do a lookup which method to call. 2038 // This is different from how the official Go compiler works, because of 2039 // heap allocation and because it's easier to implement, see: 2040 // https://research.swtch.com/interfaces 2041 return b.getValue(expr.X, getPos(expr)), nil 2042 case *ssa.ChangeType: 2043 // This instruction changes the type, but the underlying value remains 2044 // the same. This is often a no-op, but sometimes we have to change the 2045 // LLVM type as well. 2046 x := b.getValue(expr.X, getPos(expr)) 2047 llvmType := b.getLLVMType(expr.Type()) 2048 if x.Type() == llvmType { 2049 // Different Go type but same LLVM type (for example, named int). 2050 // This is the common case. 2051 return x, nil 2052 } 2053 // Figure out what kind of type we need to cast. 2054 switch llvmType.TypeKind() { 2055 case llvm.StructTypeKind: 2056 // Unfortunately, we can't just bitcast structs. We have to 2057 // actually create a new struct of the correct type and insert the 2058 // values from the previous struct in there. 2059 value := llvm.Undef(llvmType) 2060 for i := 0; i < llvmType.StructElementTypesCount(); i++ { 2061 field := b.CreateExtractValue(x, i, "changetype.field") 2062 value = b.CreateInsertValue(value, field, i, "changetype.struct") 2063 } 2064 return value, nil 2065 default: 2066 return llvm.Value{}, errors.New("todo: unknown ChangeType type: " + expr.X.Type().String()) 2067 } 2068 case *ssa.Const: 2069 panic("const is not an expression") 2070 case *ssa.Convert: 2071 x := b.getValue(expr.X, getPos(expr)) 2072 return b.createConvert(expr.X.Type(), expr.Type(), x, expr.Pos()) 2073 case *ssa.Extract: 2074 if _, ok := expr.Tuple.(*ssa.Select); ok { 2075 return b.getChanSelectResult(expr), nil 2076 } 2077 value := b.getValue(expr.Tuple, getPos(expr)) 2078 return b.CreateExtractValue(value, expr.Index, ""), nil 2079 case *ssa.Field: 2080 value := b.getValue(expr.X, getPos(expr)) 2081 result := b.CreateExtractValue(value, expr.Field, "") 2082 return result, nil 2083 case *ssa.FieldAddr: 2084 val := b.getValue(expr.X, getPos(expr)) 2085 // Check for nil pointer before calculating the address, from the spec: 2086 // > For an operand x of type T, the address operation &x generates a 2087 // > pointer of type *T to x. [...] If the evaluation of x would cause a 2088 // > run-time panic, then the evaluation of &x does too. 2089 b.createNilCheck(expr.X, val, "gep") 2090 // Do a GEP on the pointer to get the field address. 2091 indices := []llvm.Value{ 2092 llvm.ConstInt(b.ctx.Int32Type(), 0, false), 2093 llvm.ConstInt(b.ctx.Int32Type(), uint64(expr.Field), false), 2094 } 2095 elementType := b.getLLVMType(expr.X.Type().Underlying().(*types.Pointer).Elem()) 2096 return b.CreateInBoundsGEP(elementType, val, indices, ""), nil 2097 case *ssa.Function: 2098 panic("function is not an expression") 2099 case *ssa.Global: 2100 panic("global is not an expression") 2101 case *ssa.Index: 2102 collection := b.getValue(expr.X, getPos(expr)) 2103 index := b.getValue(expr.Index, getPos(expr)) 2104 2105 switch xType := expr.X.Type().Underlying().(type) { 2106 case *types.Basic: // extract byte from string 2107 // Value type must be a string, which is a basic type. 2108 if xType.Info()&types.IsString == 0 { 2109 panic("lookup on non-string?") 2110 } 2111 2112 // Sometimes, the index can be e.g. an uint8 or int8, and we have to 2113 // correctly extend that type for two reasons: 2114 // 1. The lookup bounds check expects an index of at least uintptr 2115 // size. 2116 // 2. getelementptr has signed operands, and therefore s[uint8(x)] 2117 // can be lowered as s[int8(x)]. That would be a bug. 2118 index = b.extendInteger(index, expr.Index.Type(), b.uintptrType) 2119 2120 // Bounds check. 2121 length := b.CreateExtractValue(collection, 1, "len") 2122 b.createLookupBoundsCheck(length, index) 2123 2124 // Lookup byte 2125 buf := b.CreateExtractValue(collection, 0, "") 2126 bufElemType := b.ctx.Int8Type() 2127 bufPtr := b.CreateInBoundsGEP(bufElemType, buf, []llvm.Value{index}, "") 2128 return b.CreateLoad(bufElemType, bufPtr, ""), nil 2129 case *types.Array: // extract element from array 2130 // Extend index to at least uintptr size, because getelementptr 2131 // assumes index is a signed integer. 2132 index = b.extendInteger(index, expr.Index.Type(), b.uintptrType) 2133 2134 // Check bounds. 2135 arrayLen := llvm.ConstInt(b.uintptrType, uint64(xType.Len()), false) 2136 b.createLookupBoundsCheck(arrayLen, index) 2137 2138 // Can't load directly from array (as index is non-constant), so 2139 // have to do it using an alloca+gep+load. 2140 arrayType := collection.Type() 2141 alloca, allocaSize := b.createTemporaryAlloca(arrayType, "index.alloca") 2142 b.CreateStore(collection, alloca) 2143 zero := llvm.ConstInt(b.ctx.Int32Type(), 0, false) 2144 ptr := b.CreateInBoundsGEP(arrayType, alloca, []llvm.Value{zero, index}, "index.gep") 2145 result := b.CreateLoad(arrayType.ElementType(), ptr, "index.load") 2146 b.emitLifetimeEnd(alloca, allocaSize) 2147 return result, nil 2148 default: 2149 panic("unknown *ssa.Index type") 2150 } 2151 case *ssa.IndexAddr: 2152 val := b.getValue(expr.X, getPos(expr)) 2153 index := b.getValue(expr.Index, getPos(expr)) 2154 2155 // Get buffer pointer and length 2156 var bufptr, buflen llvm.Value 2157 var bufType llvm.Type 2158 switch ptrTyp := expr.X.Type().Underlying().(type) { 2159 case *types.Pointer: 2160 typ := ptrTyp.Elem().Underlying() 2161 switch typ := typ.(type) { 2162 case *types.Array: 2163 bufptr = val 2164 buflen = llvm.ConstInt(b.uintptrType, uint64(typ.Len()), false) 2165 bufType = b.getLLVMType(typ) 2166 // Check for nil pointer before calculating the address, from 2167 // the spec: 2168 // > For an operand x of type T, the address operation &x 2169 // > generates a pointer of type *T to x. [...] If the 2170 // > evaluation of x would cause a run-time panic, then the 2171 // > evaluation of &x does too. 2172 b.createNilCheck(expr.X, bufptr, "gep") 2173 default: 2174 return llvm.Value{}, b.makeError(expr.Pos(), "todo: indexaddr: "+typ.String()) 2175 } 2176 case *types.Slice: 2177 bufptr = b.CreateExtractValue(val, 0, "indexaddr.ptr") 2178 buflen = b.CreateExtractValue(val, 1, "indexaddr.len") 2179 bufType = b.getLLVMType(ptrTyp.Elem()) 2180 default: 2181 return llvm.Value{}, b.makeError(expr.Pos(), "todo: indexaddr: "+ptrTyp.String()) 2182 } 2183 2184 // Make sure index is at least the size of uintptr becuase getelementptr 2185 // assumes index is a signed integer. 2186 index = b.extendInteger(index, expr.Index.Type(), b.uintptrType) 2187 2188 // Bounds check. 2189 b.createLookupBoundsCheck(buflen, index) 2190 2191 switch expr.X.Type().Underlying().(type) { 2192 case *types.Pointer: 2193 indices := []llvm.Value{ 2194 llvm.ConstInt(b.ctx.Int32Type(), 0, false), 2195 index, 2196 } 2197 return b.CreateInBoundsGEP(bufType, bufptr, indices, ""), nil 2198 case *types.Slice: 2199 return b.CreateInBoundsGEP(bufType, bufptr, []llvm.Value{index}, ""), nil 2200 default: 2201 panic("unreachable") 2202 } 2203 case *ssa.Lookup: // map lookup 2204 value := b.getValue(expr.X, getPos(expr)) 2205 index := b.getValue(expr.Index, getPos(expr)) 2206 valueType := expr.Type() 2207 if expr.CommaOk { 2208 valueType = valueType.(*types.Tuple).At(0).Type() 2209 } 2210 return b.createMapLookup(expr.X.Type().Underlying().(*types.Map).Key(), valueType, value, index, expr.CommaOk, expr.Pos()) 2211 case *ssa.MakeChan: 2212 return b.createMakeChan(expr), nil 2213 case *ssa.MakeClosure: 2214 return b.parseMakeClosure(expr) 2215 case *ssa.MakeInterface: 2216 val := b.getValue(expr.X, getPos(expr)) 2217 return b.createMakeInterface(val, expr.X.Type(), expr.Pos()), nil 2218 case *ssa.MakeMap: 2219 return b.createMakeMap(expr) 2220 case *ssa.MakeSlice: 2221 sliceLen := b.getValue(expr.Len, getPos(expr)) 2222 sliceCap := b.getValue(expr.Cap, getPos(expr)) 2223 sliceType := expr.Type().Underlying().(*types.Slice) 2224 llvmElemType := b.getLLVMType(sliceType.Elem()) 2225 elemSize := b.targetData.TypeAllocSize(llvmElemType) 2226 elemSizeValue := llvm.ConstInt(b.uintptrType, elemSize, false) 2227 2228 maxSize := b.maxSliceSize(llvmElemType) 2229 if elemSize > maxSize { 2230 // This seems to be checked by the typechecker already, but let's 2231 // check it again just to be sure. 2232 return llvm.Value{}, b.makeError(expr.Pos(), fmt.Sprintf("slice element type is too big (%v bytes)", elemSize)) 2233 } 2234 2235 // Bounds checking. 2236 lenType := expr.Len.Type().Underlying().(*types.Basic) 2237 capType := expr.Cap.Type().Underlying().(*types.Basic) 2238 maxSizeValue := llvm.ConstInt(b.uintptrType, maxSize, false) 2239 b.createSliceBoundsCheck(maxSizeValue, sliceLen, sliceCap, sliceCap, lenType, capType, capType) 2240 2241 // Allocate the backing array. 2242 sliceCapCast, err := b.createConvert(expr.Cap.Type(), types.Typ[types.Uintptr], sliceCap, expr.Pos()) 2243 if err != nil { 2244 return llvm.Value{}, err 2245 } 2246 sliceSize := b.CreateBinOp(llvm.Mul, elemSizeValue, sliceCapCast, "makeslice.cap") 2247 layoutValue := b.createObjectLayout(llvmElemType, expr.Pos()) 2248 slicePtr := b.createRuntimeCall("alloc", []llvm.Value{sliceSize, layoutValue}, "makeslice.buf") 2249 2250 // Extend or truncate if necessary. This is safe as we've already done 2251 // the bounds check. 2252 sliceLen, err = b.createConvert(expr.Len.Type(), types.Typ[types.Uintptr], sliceLen, expr.Pos()) 2253 if err != nil { 2254 return llvm.Value{}, err 2255 } 2256 sliceCap, err = b.createConvert(expr.Cap.Type(), types.Typ[types.Uintptr], sliceCap, expr.Pos()) 2257 if err != nil { 2258 return llvm.Value{}, err 2259 } 2260 2261 // Create the slice. 2262 slice := b.ctx.ConstStruct([]llvm.Value{ 2263 llvm.Undef(slicePtr.Type()), 2264 llvm.Undef(b.uintptrType), 2265 llvm.Undef(b.uintptrType), 2266 }, false) 2267 slice = b.CreateInsertValue(slice, slicePtr, 0, "") 2268 slice = b.CreateInsertValue(slice, sliceLen, 1, "") 2269 slice = b.CreateInsertValue(slice, sliceCap, 2, "") 2270 return slice, nil 2271 case *ssa.Next: 2272 rangeVal := expr.Iter.(*ssa.Range).X 2273 llvmRangeVal := b.getValue(rangeVal, getPos(expr)) 2274 it := b.getValue(expr.Iter, getPos(expr)) 2275 if expr.IsString { 2276 return b.createRuntimeCall("stringNext", []llvm.Value{llvmRangeVal, it}, "range.next"), nil 2277 } else { // map 2278 return b.createMapIteratorNext(rangeVal, llvmRangeVal, it), nil 2279 } 2280 case *ssa.Phi: 2281 phi := b.CreatePHI(b.getLLVMType(expr.Type()), "") 2282 b.phis = append(b.phis, phiNode{expr, phi}) 2283 return phi, nil 2284 case *ssa.Range: 2285 var iteratorType llvm.Type 2286 switch typ := expr.X.Type().Underlying().(type) { 2287 case *types.Basic: // string 2288 iteratorType = b.getLLVMRuntimeType("stringIterator") 2289 case *types.Map: 2290 iteratorType = b.getLLVMRuntimeType("hashmapIterator") 2291 default: 2292 panic("unknown type in range: " + typ.String()) 2293 } 2294 it, _ := b.createTemporaryAlloca(iteratorType, "range.it") 2295 b.CreateStore(llvm.ConstNull(iteratorType), it) 2296 return it, nil 2297 case *ssa.Select: 2298 return b.createSelect(expr), nil 2299 case *ssa.Slice: 2300 value := b.getValue(expr.X, getPos(expr)) 2301 2302 var lowType, highType, maxType *types.Basic 2303 var low, high, max llvm.Value 2304 2305 if expr.Low != nil { 2306 lowType = expr.Low.Type().Underlying().(*types.Basic) 2307 low = b.getValue(expr.Low, getPos(expr)) 2308 low = b.extendInteger(low, lowType, b.uintptrType) 2309 } else { 2310 lowType = types.Typ[types.Uintptr] 2311 low = llvm.ConstInt(b.uintptrType, 0, false) 2312 } 2313 2314 if expr.High != nil { 2315 highType = expr.High.Type().Underlying().(*types.Basic) 2316 high = b.getValue(expr.High, getPos(expr)) 2317 high = b.extendInteger(high, highType, b.uintptrType) 2318 } else { 2319 highType = types.Typ[types.Uintptr] 2320 } 2321 2322 if expr.Max != nil { 2323 maxType = expr.Max.Type().Underlying().(*types.Basic) 2324 max = b.getValue(expr.Max, getPos(expr)) 2325 max = b.extendInteger(max, maxType, b.uintptrType) 2326 } else { 2327 maxType = types.Typ[types.Uintptr] 2328 } 2329 2330 switch typ := expr.X.Type().Underlying().(type) { 2331 case *types.Pointer: // pointer to array 2332 // slice an array 2333 arrayType := typ.Elem().Underlying().(*types.Array) 2334 length := arrayType.Len() 2335 llvmLen := llvm.ConstInt(b.uintptrType, uint64(length), false) 2336 if high.IsNil() { 2337 high = llvmLen 2338 } 2339 if max.IsNil() { 2340 max = llvmLen 2341 } 2342 indices := []llvm.Value{ 2343 llvm.ConstInt(b.ctx.Int32Type(), 0, false), 2344 low, 2345 } 2346 2347 b.createNilCheck(expr.X, value, "slice") 2348 b.createSliceBoundsCheck(llvmLen, low, high, max, lowType, highType, maxType) 2349 2350 // Truncate ints bigger than uintptr. This is after the bounds 2351 // check so it's safe. 2352 if b.targetData.TypeAllocSize(low.Type()) > b.targetData.TypeAllocSize(b.uintptrType) { 2353 low = b.CreateTrunc(low, b.uintptrType, "") 2354 } 2355 if b.targetData.TypeAllocSize(high.Type()) > b.targetData.TypeAllocSize(b.uintptrType) { 2356 high = b.CreateTrunc(high, b.uintptrType, "") 2357 } 2358 if b.targetData.TypeAllocSize(max.Type()) > b.targetData.TypeAllocSize(b.uintptrType) { 2359 max = b.CreateTrunc(max, b.uintptrType, "") 2360 } 2361 2362 sliceLen := b.CreateSub(high, low, "slice.len") 2363 slicePtr := b.CreateInBoundsGEP(b.getLLVMType(arrayType), value, indices, "slice.ptr") 2364 sliceCap := b.CreateSub(max, low, "slice.cap") 2365 2366 slice := b.ctx.ConstStruct([]llvm.Value{ 2367 llvm.Undef(slicePtr.Type()), 2368 llvm.Undef(b.uintptrType), 2369 llvm.Undef(b.uintptrType), 2370 }, false) 2371 slice = b.CreateInsertValue(slice, slicePtr, 0, "") 2372 slice = b.CreateInsertValue(slice, sliceLen, 1, "") 2373 slice = b.CreateInsertValue(slice, sliceCap, 2, "") 2374 return slice, nil 2375 2376 case *types.Slice: 2377 // slice a slice 2378 oldPtr := b.CreateExtractValue(value, 0, "") 2379 oldLen := b.CreateExtractValue(value, 1, "") 2380 oldCap := b.CreateExtractValue(value, 2, "") 2381 if high.IsNil() { 2382 high = oldLen 2383 } 2384 if max.IsNil() { 2385 max = oldCap 2386 } 2387 2388 b.createSliceBoundsCheck(oldCap, low, high, max, lowType, highType, maxType) 2389 2390 // Truncate ints bigger than uintptr. This is after the bounds 2391 // check so it's safe. 2392 if b.targetData.TypeAllocSize(low.Type()) > b.targetData.TypeAllocSize(b.uintptrType) { 2393 low = b.CreateTrunc(low, b.uintptrType, "") 2394 } 2395 if b.targetData.TypeAllocSize(high.Type()) > b.targetData.TypeAllocSize(b.uintptrType) { 2396 high = b.CreateTrunc(high, b.uintptrType, "") 2397 } 2398 if b.targetData.TypeAllocSize(max.Type()) > b.targetData.TypeAllocSize(b.uintptrType) { 2399 max = b.CreateTrunc(max, b.uintptrType, "") 2400 } 2401 2402 ptrElemType := b.getLLVMType(typ.Elem()) 2403 newPtr := b.CreateInBoundsGEP(ptrElemType, oldPtr, []llvm.Value{low}, "") 2404 newLen := b.CreateSub(high, low, "") 2405 newCap := b.CreateSub(max, low, "") 2406 slice := b.ctx.ConstStruct([]llvm.Value{ 2407 llvm.Undef(newPtr.Type()), 2408 llvm.Undef(b.uintptrType), 2409 llvm.Undef(b.uintptrType), 2410 }, false) 2411 slice = b.CreateInsertValue(slice, newPtr, 0, "") 2412 slice = b.CreateInsertValue(slice, newLen, 1, "") 2413 slice = b.CreateInsertValue(slice, newCap, 2, "") 2414 return slice, nil 2415 2416 case *types.Basic: 2417 if typ.Info()&types.IsString == 0 { 2418 return llvm.Value{}, b.makeError(expr.Pos(), "unknown slice type: "+typ.String()) 2419 } 2420 // slice a string 2421 if expr.Max != nil { 2422 // This might as well be a panic, as the frontend should have 2423 // handled this already. 2424 return llvm.Value{}, b.makeError(expr.Pos(), "slicing a string with a max parameter is not allowed by the spec") 2425 } 2426 oldPtr := b.CreateExtractValue(value, 0, "") 2427 oldLen := b.CreateExtractValue(value, 1, "") 2428 if high.IsNil() { 2429 high = oldLen 2430 } 2431 2432 b.createSliceBoundsCheck(oldLen, low, high, high, lowType, highType, maxType) 2433 2434 // Truncate ints bigger than uintptr. This is after the bounds 2435 // check so it's safe. 2436 if b.targetData.TypeAllocSize(low.Type()) > b.targetData.TypeAllocSize(b.uintptrType) { 2437 low = b.CreateTrunc(low, b.uintptrType, "") 2438 } 2439 if b.targetData.TypeAllocSize(high.Type()) > b.targetData.TypeAllocSize(b.uintptrType) { 2440 high = b.CreateTrunc(high, b.uintptrType, "") 2441 } 2442 2443 newPtr := b.CreateInBoundsGEP(b.ctx.Int8Type(), oldPtr, []llvm.Value{low}, "") 2444 newLen := b.CreateSub(high, low, "") 2445 str := llvm.Undef(b.getLLVMRuntimeType("_string")) 2446 str = b.CreateInsertValue(str, newPtr, 0, "") 2447 str = b.CreateInsertValue(str, newLen, 1, "") 2448 return str, nil 2449 2450 default: 2451 return llvm.Value{}, b.makeError(expr.Pos(), "unknown slice type: "+typ.String()) 2452 } 2453 case *ssa.SliceToArrayPointer: 2454 // Conversion from a slice to an array pointer, as the name clearly 2455 // says. This requires a runtime check to make sure the slice is at 2456 // least as big as the array. 2457 slice := b.getValue(expr.X, getPos(expr)) 2458 sliceLen := b.CreateExtractValue(slice, 1, "") 2459 arrayLen := expr.Type().Underlying().(*types.Pointer).Elem().Underlying().(*types.Array).Len() 2460 b.createSliceToArrayPointerCheck(sliceLen, arrayLen) 2461 ptr := b.CreateExtractValue(slice, 0, "") 2462 return ptr, nil 2463 case *ssa.TypeAssert: 2464 return b.createTypeAssert(expr), nil 2465 case *ssa.UnOp: 2466 return b.createUnOp(expr) 2467 default: 2468 return llvm.Value{}, b.makeError(expr.Pos(), "todo: unknown expression: "+expr.String()) 2469 } 2470 } 2471 2472 // createBinOp creates a LLVM binary operation (add, sub, mul, etc) for a Go 2473 // binary operation. This is almost a direct mapping, but there are some subtle 2474 // differences such as the requirement in LLVM IR that both sides must have the 2475 // same type, even for bitshifts. Also, signedness in Go is encoded in the type 2476 // and is encoded in the operation in LLVM IR: this is important for some 2477 // operations such as divide. 2478 func (b *builder) createBinOp(op token.Token, typ, ytyp types.Type, x, y llvm.Value, pos token.Pos) (llvm.Value, error) { 2479 switch typ := typ.Underlying().(type) { 2480 case *types.Basic: 2481 if typ.Info()&types.IsInteger != 0 { 2482 // Operations on integers 2483 signed := typ.Info()&types.IsUnsigned == 0 2484 switch op { 2485 case token.ADD: // + 2486 return b.CreateAdd(x, y, ""), nil 2487 case token.SUB: // - 2488 return b.CreateSub(x, y, ""), nil 2489 case token.MUL: // * 2490 return b.CreateMul(x, y, ""), nil 2491 case token.QUO, token.REM: // /, % 2492 // Check for a divide by zero. If y is zero, the Go 2493 // specification says that a runtime error must be triggered. 2494 b.createDivideByZeroCheck(y) 2495 2496 if signed { 2497 // Deal with signed division overflow. 2498 // The LLVM LangRef says: 2499 // 2500 // Overflow also leads to undefined behavior; this is a 2501 // rare case, but can occur, for example, by doing a 2502 // 32-bit division of -2147483648 by -1. 2503 // 2504 // The Go specification however says this about division: 2505 // 2506 // The one exception to this rule is that if the dividend 2507 // x is the most negative value for the int type of x, the 2508 // quotient q = x / -1 is equal to x (and r = 0) due to 2509 // two's-complement integer overflow. 2510 // 2511 // In other words, in the special case that the lowest 2512 // possible signed integer is divided by -1, the result of 2513 // the division is the same as x (the dividend). 2514 // This is implemented by checking for this condition and 2515 // changing y to 1 if it occurs, for example for 32-bit 2516 // ints: 2517 // 2518 // if x == -2147483648 && y == -1 { 2519 // y = 1 2520 // } 2521 // 2522 // Dividing x by 1 obviously returns x, therefore satisfying 2523 // the Go specification without a branch. 2524 llvmType := x.Type() 2525 minusOne := llvm.ConstSub(llvm.ConstInt(llvmType, 0, false), llvm.ConstInt(llvmType, 1, false)) 2526 lowestInteger := llvm.ConstInt(x.Type(), 1<<(llvmType.IntTypeWidth()-1), false) 2527 yIsMinusOne := b.CreateICmp(llvm.IntEQ, y, minusOne, "") 2528 xIsLowestInteger := b.CreateICmp(llvm.IntEQ, x, lowestInteger, "") 2529 hasOverflow := b.CreateAnd(yIsMinusOne, xIsLowestInteger, "") 2530 y = b.CreateSelect(hasOverflow, llvm.ConstInt(llvmType, 1, true), y, "") 2531 2532 if op == token.QUO { 2533 return b.CreateSDiv(x, y, ""), nil 2534 } else { 2535 return b.CreateSRem(x, y, ""), nil 2536 } 2537 } else { 2538 if op == token.QUO { 2539 return b.CreateUDiv(x, y, ""), nil 2540 } else { 2541 return b.CreateURem(x, y, ""), nil 2542 } 2543 } 2544 case token.AND: // & 2545 return b.CreateAnd(x, y, ""), nil 2546 case token.OR: // | 2547 return b.CreateOr(x, y, ""), nil 2548 case token.XOR: // ^ 2549 return b.CreateXor(x, y, ""), nil 2550 case token.SHL, token.SHR: 2551 if ytyp.Underlying().(*types.Basic).Info()&types.IsUnsigned == 0 { 2552 // Ensure that y is not negative. 2553 b.createNegativeShiftCheck(y) 2554 } 2555 2556 sizeX := b.targetData.TypeAllocSize(x.Type()) 2557 sizeY := b.targetData.TypeAllocSize(y.Type()) 2558 2559 // Check if the shift is bigger than the bit-width of the shifted value. 2560 // This is UB in LLVM, so it needs to be handled seperately. 2561 // The Go spec indirectly defines the result as 0. 2562 // Negative shifts are handled earlier, so we can treat y as unsigned. 2563 overshifted := b.CreateICmp(llvm.IntUGE, y, llvm.ConstInt(y.Type(), 8*sizeX, false), "shift.overflow") 2564 2565 // Adjust the size of y to match x. 2566 switch { 2567 case sizeX > sizeY: 2568 y = b.CreateZExt(y, x.Type(), "") 2569 case sizeX < sizeY: 2570 // If it gets truncated, overshifted will be true and it will not matter. 2571 y = b.CreateTrunc(y, x.Type(), "") 2572 } 2573 2574 // Create a shift operation. 2575 var val llvm.Value 2576 switch op { 2577 case token.SHL: // << 2578 val = b.CreateShl(x, y, "") 2579 case token.SHR: // >> 2580 if signed { 2581 // Arithmetic right shifts work differently, since shifting a negative number right yields -1. 2582 // Cap the shift input rather than selecting the output. 2583 y = b.CreateSelect(overshifted, llvm.ConstInt(y.Type(), 8*sizeX-1, false), y, "shift.offset") 2584 return b.CreateAShr(x, y, ""), nil 2585 } else { 2586 val = b.CreateLShr(x, y, "") 2587 } 2588 default: 2589 panic("unreachable") 2590 } 2591 2592 // Select between the shift result and zero depending on whether there was an overshift. 2593 return b.CreateSelect(overshifted, llvm.ConstInt(val.Type(), 0, false), val, "shift.result"), nil 2594 case token.EQL: // == 2595 return b.CreateICmp(llvm.IntEQ, x, y, ""), nil 2596 case token.NEQ: // != 2597 return b.CreateICmp(llvm.IntNE, x, y, ""), nil 2598 case token.AND_NOT: // &^ 2599 // Go specific. Calculate "and not" with x & (~y) 2600 inv := b.CreateNot(y, "") // ~y 2601 return b.CreateAnd(x, inv, ""), nil 2602 case token.LSS: // < 2603 if signed { 2604 return b.CreateICmp(llvm.IntSLT, x, y, ""), nil 2605 } else { 2606 return b.CreateICmp(llvm.IntULT, x, y, ""), nil 2607 } 2608 case token.LEQ: // <= 2609 if signed { 2610 return b.CreateICmp(llvm.IntSLE, x, y, ""), nil 2611 } else { 2612 return b.CreateICmp(llvm.IntULE, x, y, ""), nil 2613 } 2614 case token.GTR: // > 2615 if signed { 2616 return b.CreateICmp(llvm.IntSGT, x, y, ""), nil 2617 } else { 2618 return b.CreateICmp(llvm.IntUGT, x, y, ""), nil 2619 } 2620 case token.GEQ: // >= 2621 if signed { 2622 return b.CreateICmp(llvm.IntSGE, x, y, ""), nil 2623 } else { 2624 return b.CreateICmp(llvm.IntUGE, x, y, ""), nil 2625 } 2626 default: 2627 panic("binop on integer: " + op.String()) 2628 } 2629 } else if typ.Info()&types.IsFloat != 0 { 2630 // Operations on floats 2631 switch op { 2632 case token.ADD: // + 2633 return b.CreateFAdd(x, y, ""), nil 2634 case token.SUB: // - 2635 return b.CreateFSub(x, y, ""), nil 2636 case token.MUL: // * 2637 return b.CreateFMul(x, y, ""), nil 2638 case token.QUO: // / 2639 return b.CreateFDiv(x, y, ""), nil 2640 case token.EQL: // == 2641 return b.CreateFCmp(llvm.FloatOEQ, x, y, ""), nil 2642 case token.NEQ: // != 2643 return b.CreateFCmp(llvm.FloatUNE, x, y, ""), nil 2644 case token.LSS: // < 2645 return b.CreateFCmp(llvm.FloatOLT, x, y, ""), nil 2646 case token.LEQ: // <= 2647 return b.CreateFCmp(llvm.FloatOLE, x, y, ""), nil 2648 case token.GTR: // > 2649 return b.CreateFCmp(llvm.FloatOGT, x, y, ""), nil 2650 case token.GEQ: // >= 2651 return b.CreateFCmp(llvm.FloatOGE, x, y, ""), nil 2652 default: 2653 panic("binop on float: " + op.String()) 2654 } 2655 } else if typ.Info()&types.IsComplex != 0 { 2656 r1 := b.CreateExtractValue(x, 0, "r1") 2657 r2 := b.CreateExtractValue(y, 0, "r2") 2658 i1 := b.CreateExtractValue(x, 1, "i1") 2659 i2 := b.CreateExtractValue(y, 1, "i2") 2660 switch op { 2661 case token.EQL: // == 2662 req := b.CreateFCmp(llvm.FloatOEQ, r1, r2, "") 2663 ieq := b.CreateFCmp(llvm.FloatOEQ, i1, i2, "") 2664 return b.CreateAnd(req, ieq, ""), nil 2665 case token.NEQ: // != 2666 req := b.CreateFCmp(llvm.FloatOEQ, r1, r2, "") 2667 ieq := b.CreateFCmp(llvm.FloatOEQ, i1, i2, "") 2668 neq := b.CreateAnd(req, ieq, "") 2669 return b.CreateNot(neq, ""), nil 2670 case token.ADD, token.SUB: 2671 var r, i llvm.Value 2672 switch op { 2673 case token.ADD: 2674 r = b.CreateFAdd(r1, r2, "") 2675 i = b.CreateFAdd(i1, i2, "") 2676 case token.SUB: 2677 r = b.CreateFSub(r1, r2, "") 2678 i = b.CreateFSub(i1, i2, "") 2679 default: 2680 panic("unreachable") 2681 } 2682 cplx := llvm.Undef(b.ctx.StructType([]llvm.Type{r.Type(), i.Type()}, false)) 2683 cplx = b.CreateInsertValue(cplx, r, 0, "") 2684 cplx = b.CreateInsertValue(cplx, i, 1, "") 2685 return cplx, nil 2686 case token.MUL: 2687 // Complex multiplication follows the current implementation in 2688 // the Go compiler, with the difference that complex64 2689 // components are not first scaled up to float64 for increased 2690 // precision. 2691 // https://github.com/golang/go/blob/170b8b4b12be50eeccbcdadb8523fb4fc670ca72/src/cmd/compile/internal/gc/ssa.go#L2089-L2127 2692 // The implementation is as follows: 2693 // r := real(a) * real(b) - imag(a) * imag(b) 2694 // i := real(a) * imag(b) + imag(a) * real(b) 2695 // Note: this does NOT follow the C11 specification (annex G): 2696 // http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1548.pdf#page=549 2697 // See https://github.com/golang/go/issues/29846 for a related 2698 // discussion. 2699 r := b.CreateFSub(b.CreateFMul(r1, r2, ""), b.CreateFMul(i1, i2, ""), "") 2700 i := b.CreateFAdd(b.CreateFMul(r1, i2, ""), b.CreateFMul(i1, r2, ""), "") 2701 cplx := llvm.Undef(b.ctx.StructType([]llvm.Type{r.Type(), i.Type()}, false)) 2702 cplx = b.CreateInsertValue(cplx, r, 0, "") 2703 cplx = b.CreateInsertValue(cplx, i, 1, "") 2704 return cplx, nil 2705 case token.QUO: 2706 // Complex division. 2707 // Do this in a library call because it's too difficult to do 2708 // inline. 2709 switch r1.Type().TypeKind() { 2710 case llvm.FloatTypeKind: 2711 return b.createRuntimeCall("complex64div", []llvm.Value{x, y}, ""), nil 2712 case llvm.DoubleTypeKind: 2713 return b.createRuntimeCall("complex128div", []llvm.Value{x, y}, ""), nil 2714 default: 2715 panic("unexpected complex type") 2716 } 2717 default: 2718 panic("binop on complex: " + op.String()) 2719 } 2720 } else if typ.Info()&types.IsBoolean != 0 { 2721 // Operations on booleans 2722 switch op { 2723 case token.EQL: // == 2724 return b.CreateICmp(llvm.IntEQ, x, y, ""), nil 2725 case token.NEQ: // != 2726 return b.CreateICmp(llvm.IntNE, x, y, ""), nil 2727 default: 2728 panic("binop on bool: " + op.String()) 2729 } 2730 } else if typ.Kind() == types.UnsafePointer { 2731 // Operations on pointers 2732 switch op { 2733 case token.EQL: // == 2734 return b.CreateICmp(llvm.IntEQ, x, y, ""), nil 2735 case token.NEQ: // != 2736 return b.CreateICmp(llvm.IntNE, x, y, ""), nil 2737 default: 2738 panic("binop on pointer: " + op.String()) 2739 } 2740 } else if typ.Info()&types.IsString != 0 { 2741 // Operations on strings 2742 switch op { 2743 case token.ADD: // + 2744 return b.createRuntimeCall("stringConcat", []llvm.Value{x, y}, ""), nil 2745 case token.EQL: // == 2746 return b.createRuntimeCall("stringEqual", []llvm.Value{x, y}, ""), nil 2747 case token.NEQ: // != 2748 result := b.createRuntimeCall("stringEqual", []llvm.Value{x, y}, "") 2749 return b.CreateNot(result, ""), nil 2750 case token.LSS: // x < y 2751 return b.createRuntimeCall("stringLess", []llvm.Value{x, y}, ""), nil 2752 case token.LEQ: // x <= y becomes NOT (y < x) 2753 result := b.createRuntimeCall("stringLess", []llvm.Value{y, x}, "") 2754 return b.CreateNot(result, ""), nil 2755 case token.GTR: // x > y becomes y < x 2756 return b.createRuntimeCall("stringLess", []llvm.Value{y, x}, ""), nil 2757 case token.GEQ: // x >= y becomes NOT (x < y) 2758 result := b.createRuntimeCall("stringLess", []llvm.Value{x, y}, "") 2759 return b.CreateNot(result, ""), nil 2760 default: 2761 panic("binop on string: " + op.String()) 2762 } 2763 } else { 2764 return llvm.Value{}, b.makeError(pos, "todo: unknown basic type in binop: "+typ.String()) 2765 } 2766 case *types.Signature: 2767 // Get raw scalars from the function value and compare those. 2768 // Function values may be implemented in multiple ways, but they all 2769 // have some way of getting a scalar value identifying the function. 2770 // This is safe: function pointers are generally not comparable 2771 // against each other, only against nil. So one of these has to be nil. 2772 x = b.extractFuncScalar(x) 2773 y = b.extractFuncScalar(y) 2774 switch op { 2775 case token.EQL: // == 2776 return b.CreateICmp(llvm.IntEQ, x, y, ""), nil 2777 case token.NEQ: // != 2778 return b.CreateICmp(llvm.IntNE, x, y, ""), nil 2779 default: 2780 return llvm.Value{}, b.makeError(pos, "binop on signature: "+op.String()) 2781 } 2782 case *types.Interface: 2783 switch op { 2784 case token.EQL, token.NEQ: // ==, != 2785 nilInterface := llvm.ConstNull(x.Type()) 2786 var result llvm.Value 2787 if x == nilInterface || y == nilInterface { 2788 // An interface value is compared against nil. 2789 // This is a very common case and is easy to optimize: simply 2790 // compare the typecodes (of which one is nil). 2791 typecodeX := b.CreateExtractValue(x, 0, "") 2792 typecodeY := b.CreateExtractValue(y, 0, "") 2793 result = b.CreateICmp(llvm.IntEQ, typecodeX, typecodeY, "") 2794 } else { 2795 // Fall back to a full interface comparison. 2796 result = b.createRuntimeCall("interfaceEqual", []llvm.Value{x, y}, "") 2797 } 2798 if op == token.NEQ { 2799 result = b.CreateNot(result, "") 2800 } 2801 return result, nil 2802 default: 2803 return llvm.Value{}, b.makeError(pos, "binop on interface: "+op.String()) 2804 } 2805 case *types.Chan, *types.Map, *types.Pointer: 2806 // Maps are in general not comparable, but can be compared against nil 2807 // (which is a nil pointer). This means they can be trivially compared 2808 // by treating them as a pointer. 2809 // Channels behave as pointers in that they are equal as long as they 2810 // are created with the same call to make or if both are nil. 2811 switch op { 2812 case token.EQL: // == 2813 return b.CreateICmp(llvm.IntEQ, x, y, ""), nil 2814 case token.NEQ: // != 2815 return b.CreateICmp(llvm.IntNE, x, y, ""), nil 2816 default: 2817 return llvm.Value{}, b.makeError(pos, "todo: binop on pointer: "+op.String()) 2818 } 2819 case *types.Slice: 2820 // Slices are in general not comparable, but can be compared against 2821 // nil. Assume at least one of them is nil to make the code easier. 2822 xPtr := b.CreateExtractValue(x, 0, "") 2823 yPtr := b.CreateExtractValue(y, 0, "") 2824 switch op { 2825 case token.EQL: // == 2826 return b.CreateICmp(llvm.IntEQ, xPtr, yPtr, ""), nil 2827 case token.NEQ: // != 2828 return b.CreateICmp(llvm.IntNE, xPtr, yPtr, ""), nil 2829 default: 2830 return llvm.Value{}, b.makeError(pos, "todo: binop on slice: "+op.String()) 2831 } 2832 case *types.Array: 2833 // Compare each array element and combine the result. From the spec: 2834 // Array values are comparable if values of the array element type 2835 // are comparable. Two array values are equal if their corresponding 2836 // elements are equal. 2837 result := llvm.ConstInt(b.ctx.Int1Type(), 1, true) 2838 for i := 0; i < int(typ.Len()); i++ { 2839 xField := b.CreateExtractValue(x, i, "") 2840 yField := b.CreateExtractValue(y, i, "") 2841 fieldEqual, err := b.createBinOp(token.EQL, typ.Elem(), typ.Elem(), xField, yField, pos) 2842 if err != nil { 2843 return llvm.Value{}, err 2844 } 2845 result = b.CreateAnd(result, fieldEqual, "") 2846 } 2847 switch op { 2848 case token.EQL: // == 2849 return result, nil 2850 case token.NEQ: // != 2851 return b.CreateNot(result, ""), nil 2852 default: 2853 return llvm.Value{}, b.makeError(pos, "unknown: binop on struct: "+op.String()) 2854 } 2855 case *types.Struct: 2856 // Compare each struct field and combine the result. From the spec: 2857 // Struct values are comparable if all their fields are comparable. 2858 // Two struct values are equal if their corresponding non-blank 2859 // fields are equal. 2860 result := llvm.ConstInt(b.ctx.Int1Type(), 1, true) 2861 for i := 0; i < typ.NumFields(); i++ { 2862 if typ.Field(i).Name() == "_" { 2863 // skip blank fields 2864 continue 2865 } 2866 fieldType := typ.Field(i).Type() 2867 xField := b.CreateExtractValue(x, i, "") 2868 yField := b.CreateExtractValue(y, i, "") 2869 fieldEqual, err := b.createBinOp(token.EQL, fieldType, fieldType, xField, yField, pos) 2870 if err != nil { 2871 return llvm.Value{}, err 2872 } 2873 result = b.CreateAnd(result, fieldEqual, "") 2874 } 2875 switch op { 2876 case token.EQL: // == 2877 return result, nil 2878 case token.NEQ: // != 2879 return b.CreateNot(result, ""), nil 2880 default: 2881 return llvm.Value{}, b.makeError(pos, "unknown: binop on struct: "+op.String()) 2882 } 2883 default: 2884 return llvm.Value{}, b.makeError(pos, "todo: binop type: "+typ.String()) 2885 } 2886 } 2887 2888 // createConst creates a LLVM constant value from a Go constant. 2889 func (c *compilerContext) createConst(expr *ssa.Const, pos token.Pos) llvm.Value { 2890 switch typ := expr.Type().Underlying().(type) { 2891 case *types.Basic: 2892 llvmType := c.getLLVMType(typ) 2893 if typ.Info()&types.IsBoolean != 0 { 2894 n := uint64(0) 2895 if constant.BoolVal(expr.Value) { 2896 n = 1 2897 } 2898 return llvm.ConstInt(llvmType, n, false) 2899 } else if typ.Info()&types.IsString != 0 { 2900 str := constant.StringVal(expr.Value) 2901 strLen := llvm.ConstInt(c.uintptrType, uint64(len(str)), false) 2902 var strPtr llvm.Value 2903 if str != "" { 2904 objname := c.pkg.Path() + "$string" 2905 globalType := llvm.ArrayType(c.ctx.Int8Type(), len(str)) 2906 global := llvm.AddGlobal(c.mod, globalType, objname) 2907 global.SetInitializer(c.ctx.ConstString(str, false)) 2908 global.SetLinkage(llvm.InternalLinkage) 2909 global.SetGlobalConstant(true) 2910 global.SetUnnamedAddr(true) 2911 global.SetAlignment(1) 2912 if c.Debug { 2913 // Unfortunately, expr.Pos() is always token.NoPos. 2914 position := c.program.Fset.Position(pos) 2915 diglobal := c.dibuilder.CreateGlobalVariableExpression(llvm.Metadata{}, llvm.DIGlobalVariableExpression{ 2916 File: c.getDIFile(position.Filename), 2917 Line: position.Line, 2918 Type: c.getDIType(types.NewArray(types.Typ[types.Byte], int64(len(str)))), 2919 LocalToUnit: true, 2920 Expr: c.dibuilder.CreateExpression(nil), 2921 }) 2922 global.AddMetadata(0, diglobal) 2923 } 2924 zero := llvm.ConstInt(c.ctx.Int32Type(), 0, false) 2925 strPtr = llvm.ConstInBoundsGEP(globalType, global, []llvm.Value{zero, zero}) 2926 } else { 2927 strPtr = llvm.ConstNull(c.dataPtrType) 2928 } 2929 strObj := llvm.ConstNamedStruct(c.getLLVMRuntimeType("_string"), []llvm.Value{strPtr, strLen}) 2930 return strObj 2931 } else if typ.Kind() == types.UnsafePointer { 2932 if !expr.IsNil() { 2933 value, _ := constant.Uint64Val(constant.ToInt(expr.Value)) 2934 return llvm.ConstIntToPtr(llvm.ConstInt(c.uintptrType, value, false), c.dataPtrType) 2935 } 2936 return llvm.ConstNull(c.dataPtrType) 2937 } else if typ.Info()&types.IsUnsigned != 0 { 2938 n, _ := constant.Uint64Val(constant.ToInt(expr.Value)) 2939 return llvm.ConstInt(llvmType, n, false) 2940 } else if typ.Info()&types.IsInteger != 0 { // signed 2941 n, _ := constant.Int64Val(constant.ToInt(expr.Value)) 2942 return llvm.ConstInt(llvmType, uint64(n), true) 2943 } else if typ.Info()&types.IsFloat != 0 { 2944 n, _ := constant.Float64Val(expr.Value) 2945 return llvm.ConstFloat(llvmType, n) 2946 } else if typ.Kind() == types.Complex64 { 2947 r := c.createConst(ssa.NewConst(constant.Real(expr.Value), types.Typ[types.Float32]), pos) 2948 i := c.createConst(ssa.NewConst(constant.Imag(expr.Value), types.Typ[types.Float32]), pos) 2949 cplx := llvm.Undef(c.ctx.StructType([]llvm.Type{c.ctx.FloatType(), c.ctx.FloatType()}, false)) 2950 cplx = c.builder.CreateInsertValue(cplx, r, 0, "") 2951 cplx = c.builder.CreateInsertValue(cplx, i, 1, "") 2952 return cplx 2953 } else if typ.Kind() == types.Complex128 { 2954 r := c.createConst(ssa.NewConst(constant.Real(expr.Value), types.Typ[types.Float64]), pos) 2955 i := c.createConst(ssa.NewConst(constant.Imag(expr.Value), types.Typ[types.Float64]), pos) 2956 cplx := llvm.Undef(c.ctx.StructType([]llvm.Type{c.ctx.DoubleType(), c.ctx.DoubleType()}, false)) 2957 cplx = c.builder.CreateInsertValue(cplx, r, 0, "") 2958 cplx = c.builder.CreateInsertValue(cplx, i, 1, "") 2959 return cplx 2960 } else { 2961 panic("unknown constant of basic type: " + expr.String()) 2962 } 2963 case *types.Chan: 2964 if expr.Value != nil { 2965 panic("expected nil chan constant") 2966 } 2967 return llvm.ConstNull(c.getLLVMType(expr.Type())) 2968 case *types.Signature: 2969 if expr.Value != nil { 2970 panic("expected nil signature constant") 2971 } 2972 return llvm.ConstNull(c.getLLVMType(expr.Type())) 2973 case *types.Interface: 2974 if expr.Value != nil { 2975 panic("expected nil interface constant") 2976 } 2977 // Create a generic nil interface with no dynamic type (typecode=0). 2978 fields := []llvm.Value{ 2979 llvm.ConstInt(c.uintptrType, 0, false), 2980 llvm.ConstPointerNull(c.dataPtrType), 2981 } 2982 return llvm.ConstNamedStruct(c.getLLVMRuntimeType("_interface"), fields) 2983 case *types.Pointer: 2984 if expr.Value != nil { 2985 panic("expected nil pointer constant") 2986 } 2987 return llvm.ConstPointerNull(c.getLLVMType(typ)) 2988 case *types.Array: 2989 if expr.Value != nil { 2990 panic("expected nil array constant") 2991 } 2992 return llvm.ConstNull(c.getLLVMType(expr.Type())) 2993 case *types.Slice: 2994 if expr.Value != nil { 2995 panic("expected nil slice constant") 2996 } 2997 llvmPtr := llvm.ConstPointerNull(c.dataPtrType) 2998 llvmLen := llvm.ConstInt(c.uintptrType, 0, false) 2999 slice := c.ctx.ConstStruct([]llvm.Value{ 3000 llvmPtr, // backing array 3001 llvmLen, // len 3002 llvmLen, // cap 3003 }, false) 3004 return slice 3005 case *types.Struct: 3006 if expr.Value != nil { 3007 panic("expected nil struct constant") 3008 } 3009 return llvm.ConstNull(c.getLLVMType(expr.Type())) 3010 case *types.Map: 3011 if !expr.IsNil() { 3012 // I believe this is not allowed by the Go spec. 3013 panic("non-nil map constant") 3014 } 3015 llvmType := c.getLLVMType(typ) 3016 return llvm.ConstNull(llvmType) 3017 default: 3018 panic("unknown constant: " + expr.String()) 3019 } 3020 } 3021 3022 // createConvert creates a Go type conversion instruction. 3023 func (b *builder) createConvert(typeFrom, typeTo types.Type, value llvm.Value, pos token.Pos) (llvm.Value, error) { 3024 llvmTypeFrom := value.Type() 3025 llvmTypeTo := b.getLLVMType(typeTo) 3026 3027 // Conversion between unsafe.Pointer and uintptr. 3028 isPtrFrom := isPointer(typeFrom.Underlying()) 3029 isPtrTo := isPointer(typeTo.Underlying()) 3030 if isPtrFrom && !isPtrTo { 3031 return b.CreatePtrToInt(value, llvmTypeTo, ""), nil 3032 } else if !isPtrFrom && isPtrTo { 3033 return b.CreateIntToPtr(value, llvmTypeTo, ""), nil 3034 } 3035 3036 // Conversion between pointers and unsafe.Pointer. 3037 if isPtrFrom && isPtrTo { 3038 return value, nil 3039 } 3040 3041 switch typeTo := typeTo.Underlying().(type) { 3042 case *types.Basic: 3043 sizeFrom := b.targetData.TypeAllocSize(llvmTypeFrom) 3044 3045 if typeTo.Info()&types.IsString != 0 { 3046 switch typeFrom := typeFrom.Underlying().(type) { 3047 case *types.Basic: 3048 // Assume a Unicode code point, as that is the only possible 3049 // value here. 3050 // Cast to an i32 value as expected by 3051 // runtime.stringFromUnicode. 3052 if sizeFrom > 4 { 3053 value = b.CreateTrunc(value, b.ctx.Int32Type(), "") 3054 } else if sizeFrom < 4 && typeTo.Info()&types.IsUnsigned != 0 { 3055 value = b.CreateZExt(value, b.ctx.Int32Type(), "") 3056 } else if sizeFrom < 4 { 3057 value = b.CreateSExt(value, b.ctx.Int32Type(), "") 3058 } 3059 return b.createRuntimeCall("stringFromUnicode", []llvm.Value{value}, ""), nil 3060 case *types.Slice: 3061 switch typeFrom.Elem().(*types.Basic).Kind() { 3062 case types.Byte: 3063 return b.createRuntimeCall("stringFromBytes", []llvm.Value{value}, ""), nil 3064 case types.Rune: 3065 return b.createRuntimeCall("stringFromRunes", []llvm.Value{value}, ""), nil 3066 default: 3067 return llvm.Value{}, b.makeError(pos, "todo: convert to string: "+typeFrom.String()) 3068 } 3069 default: 3070 return llvm.Value{}, b.makeError(pos, "todo: convert to string: "+typeFrom.String()) 3071 } 3072 } 3073 3074 typeFrom := typeFrom.Underlying().(*types.Basic) 3075 sizeTo := b.targetData.TypeAllocSize(llvmTypeTo) 3076 3077 if typeFrom.Info()&types.IsInteger != 0 && typeTo.Info()&types.IsInteger != 0 { 3078 // Conversion between two integers. 3079 if sizeFrom > sizeTo { 3080 return b.CreateTrunc(value, llvmTypeTo, ""), nil 3081 } else if typeFrom.Info()&types.IsUnsigned != 0 { // if unsigned 3082 return b.CreateZExt(value, llvmTypeTo, ""), nil 3083 } else { // if signed 3084 return b.CreateSExt(value, llvmTypeTo, ""), nil 3085 } 3086 } 3087 3088 if typeFrom.Info()&types.IsFloat != 0 && typeTo.Info()&types.IsFloat != 0 { 3089 // Conversion between two floats. 3090 if sizeFrom > sizeTo { 3091 return b.CreateFPTrunc(value, llvmTypeTo, ""), nil 3092 } else if sizeFrom < sizeTo { 3093 return b.CreateFPExt(value, llvmTypeTo, ""), nil 3094 } else { 3095 return value, nil 3096 } 3097 } 3098 3099 if typeFrom.Info()&types.IsFloat != 0 && typeTo.Info()&types.IsInteger != 0 { 3100 // Conversion from float to int. 3101 // Passing an out-of-bounds float to LLVM would cause UB, so that UB is trapped by select instructions. 3102 // The Go specification says that this should be implementation-defined behavior. 3103 // This implements saturating behavior, except that NaN is mapped to the minimum value. 3104 var significandBits int 3105 switch typeFrom.Kind() { 3106 case types.Float32: 3107 significandBits = 23 3108 case types.Float64: 3109 significandBits = 52 3110 } 3111 if typeTo.Info()&types.IsUnsigned != 0 { // if unsigned 3112 // Select the maximum value for this unsigned integer type. 3113 max := ^(^uint64(0) << uint(llvmTypeTo.IntTypeWidth())) 3114 maxFloat := float64(max) 3115 if bits.Len64(max) > significandBits { 3116 // Round the max down to fit within the significand. 3117 maxFloat = float64(max & (^uint64(0) << uint(bits.Len64(max)-significandBits))) 3118 } 3119 3120 // Check if the value is in-bounds (0 <= value <= max). 3121 positive := b.CreateFCmp(llvm.FloatOLE, llvm.ConstNull(llvmTypeFrom), value, "positive") 3122 withinMax := b.CreateFCmp(llvm.FloatOLE, value, llvm.ConstFloat(llvmTypeFrom, maxFloat), "withinmax") 3123 inBounds := b.CreateAnd(positive, withinMax, "inbounds") 3124 3125 // Assuming that the value is out-of-bounds, select a saturated value. 3126 saturated := b.CreateSelect(positive, 3127 llvm.ConstInt(llvmTypeTo, max, false), // value > max 3128 llvm.ConstNull(llvmTypeTo), // value < 0 (or NaN) 3129 "saturated", 3130 ) 3131 3132 // Do a normal conversion. 3133 normal := b.CreateFPToUI(value, llvmTypeTo, "normal") 3134 3135 return b.CreateSelect(inBounds, normal, saturated, ""), nil 3136 } else { // if signed 3137 // Select the minimum value for this signed integer type. 3138 min := uint64(1) << uint(llvmTypeTo.IntTypeWidth()-1) 3139 minFloat := -float64(min) 3140 3141 // Select the maximum value for this signed integer type. 3142 max := ^(^uint64(0) << uint(llvmTypeTo.IntTypeWidth()-1)) 3143 maxFloat := float64(max) 3144 if bits.Len64(max) > significandBits { 3145 // Round the max down to fit within the significand. 3146 maxFloat = float64(max & (^uint64(0) << uint(bits.Len64(max)-significandBits))) 3147 } 3148 3149 // Check if the value is in-bounds (min <= value <= max). 3150 aboveMin := b.CreateFCmp(llvm.FloatOLE, llvm.ConstFloat(llvmTypeFrom, minFloat), value, "abovemin") 3151 belowMax := b.CreateFCmp(llvm.FloatOLE, value, llvm.ConstFloat(llvmTypeFrom, maxFloat), "belowmax") 3152 inBounds := b.CreateAnd(aboveMin, belowMax, "inbounds") 3153 3154 // Assuming that the value is out-of-bounds, select a saturated value. 3155 saturated := b.CreateSelect(aboveMin, 3156 llvm.ConstInt(llvmTypeTo, max, false), // value > max 3157 llvm.ConstInt(llvmTypeTo, min, false), // value < min 3158 "saturated", 3159 ) 3160 3161 // Map NaN to 0. 3162 saturated = b.CreateSelect(b.CreateFCmp(llvm.FloatUNO, value, value, "isnan"), 3163 llvm.ConstNull(llvmTypeTo), 3164 saturated, 3165 "remapped", 3166 ) 3167 3168 // Do a normal conversion. 3169 normal := b.CreateFPToSI(value, llvmTypeTo, "normal") 3170 3171 return b.CreateSelect(inBounds, normal, saturated, ""), nil 3172 } 3173 } 3174 3175 if typeFrom.Info()&types.IsInteger != 0 && typeTo.Info()&types.IsFloat != 0 { 3176 // Conversion from int to float. 3177 if typeFrom.Info()&types.IsUnsigned != 0 { // if unsigned 3178 return b.CreateUIToFP(value, llvmTypeTo, ""), nil 3179 } else { // if signed 3180 return b.CreateSIToFP(value, llvmTypeTo, ""), nil 3181 } 3182 } 3183 3184 if typeFrom.Kind() == types.Complex128 && typeTo.Kind() == types.Complex64 { 3185 // Conversion from complex128 to complex64. 3186 r := b.CreateExtractValue(value, 0, "real.f64") 3187 i := b.CreateExtractValue(value, 1, "imag.f64") 3188 r = b.CreateFPTrunc(r, b.ctx.FloatType(), "real.f32") 3189 i = b.CreateFPTrunc(i, b.ctx.FloatType(), "imag.f32") 3190 cplx := llvm.Undef(b.ctx.StructType([]llvm.Type{b.ctx.FloatType(), b.ctx.FloatType()}, false)) 3191 cplx = b.CreateInsertValue(cplx, r, 0, "") 3192 cplx = b.CreateInsertValue(cplx, i, 1, "") 3193 return cplx, nil 3194 } 3195 3196 if typeFrom.Kind() == types.Complex64 && typeTo.Kind() == types.Complex128 { 3197 // Conversion from complex64 to complex128. 3198 r := b.CreateExtractValue(value, 0, "real.f32") 3199 i := b.CreateExtractValue(value, 1, "imag.f32") 3200 r = b.CreateFPExt(r, b.ctx.DoubleType(), "real.f64") 3201 i = b.CreateFPExt(i, b.ctx.DoubleType(), "imag.f64") 3202 cplx := llvm.Undef(b.ctx.StructType([]llvm.Type{b.ctx.DoubleType(), b.ctx.DoubleType()}, false)) 3203 cplx = b.CreateInsertValue(cplx, r, 0, "") 3204 cplx = b.CreateInsertValue(cplx, i, 1, "") 3205 return cplx, nil 3206 } 3207 3208 return llvm.Value{}, b.makeError(pos, "todo: convert: basic non-integer type: "+typeFrom.String()+" -> "+typeTo.String()) 3209 3210 case *types.Slice: 3211 if basic, ok := typeFrom.Underlying().(*types.Basic); !ok || basic.Info()&types.IsString == 0 { 3212 panic("can only convert from a string to a slice") 3213 } 3214 3215 elemType := typeTo.Elem().Underlying().(*types.Basic) // must be byte or rune 3216 switch elemType.Kind() { 3217 case types.Byte: 3218 return b.createRuntimeCall("stringToBytes", []llvm.Value{value}, ""), nil 3219 case types.Rune: 3220 return b.createRuntimeCall("stringToRunes", []llvm.Value{value}, ""), nil 3221 default: 3222 panic("unexpected type in string to slice conversion") 3223 } 3224 3225 default: 3226 return llvm.Value{}, b.makeError(pos, "todo: convert "+typeTo.String()+" <- "+typeFrom.String()) 3227 } 3228 } 3229 3230 // createUnOp creates LLVM IR for a given Go unary operation. 3231 // Most unary operators are pretty simple, such as the not and minus operator 3232 // which can all be directly lowered to IR. However, there is also the channel 3233 // receive operator which is handled in the runtime directly. 3234 func (b *builder) createUnOp(unop *ssa.UnOp) (llvm.Value, error) { 3235 x := b.getValue(unop.X, getPos(unop)) 3236 switch unop.Op { 3237 case token.NOT: // !x 3238 return b.CreateNot(x, ""), nil 3239 case token.SUB: // -x 3240 if typ, ok := unop.X.Type().Underlying().(*types.Basic); ok { 3241 if typ.Info()&types.IsInteger != 0 { 3242 return b.CreateSub(llvm.ConstInt(x.Type(), 0, false), x, ""), nil 3243 } else if typ.Info()&types.IsFloat != 0 { 3244 return b.CreateFNeg(x, ""), nil 3245 } else if typ.Info()&types.IsComplex != 0 { 3246 // Negate both components of the complex number. 3247 r := b.CreateExtractValue(x, 0, "r") 3248 i := b.CreateExtractValue(x, 1, "i") 3249 r = b.CreateFNeg(r, "") 3250 i = b.CreateFNeg(i, "") 3251 cplx := llvm.Undef(x.Type()) 3252 cplx = b.CreateInsertValue(cplx, r, 0, "") 3253 cplx = b.CreateInsertValue(cplx, i, 1, "") 3254 return cplx, nil 3255 } else { 3256 return llvm.Value{}, b.makeError(unop.Pos(), "todo: unknown basic type for negate: "+typ.String()) 3257 } 3258 } else { 3259 return llvm.Value{}, b.makeError(unop.Pos(), "todo: unknown type for negate: "+unop.X.Type().Underlying().String()) 3260 } 3261 case token.MUL: // *x, dereference pointer 3262 valueType := b.getLLVMType(unop.X.Type().Underlying().(*types.Pointer).Elem()) 3263 if b.targetData.TypeAllocSize(valueType) == 0 { 3264 // zero-length data 3265 return llvm.ConstNull(valueType), nil 3266 } else if strings.HasSuffix(unop.X.String(), "$funcaddr") { 3267 // CGo function pointer. The cgo part has rewritten CGo function 3268 // pointers as stub global variables of the form: 3269 // var C.add unsafe.Pointer 3270 // Instead of a load from the global, create a bitcast of the 3271 // function pointer itself. 3272 name := strings.TrimSuffix(unop.X.(*ssa.Global).Name(), "$funcaddr") 3273 pkg := b.fn.Pkg 3274 if pkg == nil { 3275 pkg = b.fn.Origin().Pkg 3276 } 3277 _, fn := b.getFunction(pkg.Members[name].(*ssa.Function)) 3278 if fn.IsNil() { 3279 return llvm.Value{}, b.makeError(unop.Pos(), "cgo function not found: "+name) 3280 } 3281 return fn, nil 3282 } else { 3283 b.createNilCheck(unop.X, x, "deref") 3284 load := b.CreateLoad(valueType, x, "") 3285 return load, nil 3286 } 3287 case token.XOR: // ^x, toggle all bits in integer 3288 return b.CreateXor(x, llvm.ConstInt(x.Type(), ^uint64(0), false), ""), nil 3289 case token.ARROW: // <-x, receive from channel 3290 return b.createChanRecv(unop), nil 3291 default: 3292 return llvm.Value{}, b.makeError(unop.Pos(), "todo: unknown unop") 3293 } 3294 }