Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 1 | //===- ssa.go - IR generation from go/ssa ---------------------------------===// |
| 2 | // |
| 3 | // The LLVM Compiler Infrastructure |
| 4 | // |
| 5 | // This file is distributed under the University of Illinois Open Source |
| 6 | // License. See LICENSE.TXT for details. |
| 7 | // |
| 8 | //===----------------------------------------------------------------------===// |
| 9 | // |
| 10 | // This file implements the top-level LLVM IR generation from go/ssa form. |
| 11 | // |
| 12 | //===----------------------------------------------------------------------===// |
| 13 | |
| 14 | package irgen |
| 15 | |
| 16 | import ( |
| 17 | "fmt" |
| 18 | "go/ast" |
| 19 | "go/token" |
| 20 | "os" |
| 21 | "sort" |
| 22 | |
| 23 | "llvm.org/llgo/ssaopt" |
| 24 | "llvm.org/llgo/third_party/go.tools/go/ssa" |
| 25 | "llvm.org/llgo/third_party/go.tools/go/ssa/ssautil" |
| 26 | "llvm.org/llgo/third_party/go.tools/go/types" |
| 27 | "llvm.org/llvm/bindings/go/llvm" |
| 28 | ) |
| 29 | |
| 30 | // A globalInit is used to temporarily store a global's initializer until |
| 31 | // we are ready to build it. |
| 32 | type globalInit struct { |
| 33 | val llvm.Value |
| 34 | elems []globalInit |
| 35 | } |
| 36 | |
| 37 | func (gi *globalInit) update(typ llvm.Type, indices []uint32, val llvm.Value) { |
| 38 | if len(indices) == 0 { |
| 39 | gi.val = val |
| 40 | return |
| 41 | } |
| 42 | |
| 43 | if gi.val.C != nil { |
| 44 | gi.val = llvm.ConstInsertValue(gi.val, val, indices) |
| 45 | } |
| 46 | |
| 47 | tk := typ.TypeKind() |
| 48 | |
| 49 | if len(gi.elems) == 0 { |
| 50 | switch tk { |
| 51 | case llvm.StructTypeKind: |
| 52 | gi.elems = make([]globalInit, typ.StructElementTypesCount()) |
| 53 | case llvm.ArrayTypeKind: |
| 54 | gi.elems = make([]globalInit, typ.ArrayLength()) |
| 55 | default: |
| 56 | panic("unexpected type") |
| 57 | } |
| 58 | } |
| 59 | |
| 60 | var eltyp llvm.Type |
| 61 | switch tk { |
| 62 | case llvm.StructTypeKind: |
| 63 | eltyp = typ.StructElementTypes()[indices[0]] |
| 64 | case llvm.ArrayTypeKind: |
| 65 | eltyp = typ.ElementType() |
| 66 | default: |
| 67 | panic("unexpected type") |
| 68 | } |
| 69 | |
| 70 | gi.elems[indices[0]].update(eltyp, indices[1:], val) |
| 71 | } |
| 72 | |
| 73 | func (gi *globalInit) build(typ llvm.Type) llvm.Value { |
| 74 | if gi.val.C != nil { |
| 75 | return gi.val |
| 76 | } |
| 77 | if len(gi.elems) == 0 { |
| 78 | return llvm.ConstNull(typ) |
| 79 | } |
| 80 | |
| 81 | switch typ.TypeKind() { |
| 82 | case llvm.StructTypeKind: |
| 83 | eltypes := typ.StructElementTypes() |
| 84 | elems := make([]llvm.Value, len(eltypes)) |
| 85 | for i, eltyp := range eltypes { |
| 86 | elems[i] = gi.elems[i].build(eltyp) |
| 87 | } |
| 88 | return llvm.ConstStruct(elems, false) |
| 89 | case llvm.ArrayTypeKind: |
| 90 | eltyp := typ.ElementType() |
| 91 | elems := make([]llvm.Value, len(gi.elems)) |
| 92 | for i := range gi.elems { |
| 93 | elems[i] = gi.elems[i].build(eltyp) |
| 94 | } |
| 95 | return llvm.ConstArray(eltyp, elems) |
| 96 | default: |
| 97 | panic("unexpected type") |
| 98 | } |
| 99 | } |
| 100 | |
| 101 | type unit struct { |
| 102 | *compiler |
| 103 | pkg *ssa.Package |
| 104 | globals map[ssa.Value]llvm.Value |
| 105 | globalInits map[llvm.Value]*globalInit |
| 106 | |
| 107 | // funcDescriptors maps *ssa.Functions to function descriptors, |
| 108 | // the first-class representation of functions. |
| 109 | funcDescriptors map[*ssa.Function]llvm.Value |
| 110 | |
| 111 | // undefinedFuncs contains functions that have been resolved |
| 112 | // (declared) but not defined. |
| 113 | undefinedFuncs map[*ssa.Function]bool |
| 114 | |
| 115 | gcRoots []llvm.Value |
| 116 | } |
| 117 | |
| 118 | func newUnit(c *compiler, pkg *ssa.Package) *unit { |
| 119 | u := &unit{ |
| 120 | compiler: c, |
| 121 | pkg: pkg, |
| 122 | globals: make(map[ssa.Value]llvm.Value), |
| 123 | globalInits: make(map[llvm.Value]*globalInit), |
| 124 | funcDescriptors: make(map[*ssa.Function]llvm.Value), |
| 125 | undefinedFuncs: make(map[*ssa.Function]bool), |
| 126 | } |
| 127 | return u |
| 128 | } |
| 129 | |
| 130 | type byMemberName []ssa.Member |
| 131 | |
| 132 | func (ms byMemberName) Len() int { return len(ms) } |
| 133 | func (ms byMemberName) Swap(i, j int) { |
| 134 | ms[i], ms[j] = ms[j], ms[i] |
| 135 | } |
| 136 | func (ms byMemberName) Less(i, j int) bool { |
| 137 | return ms[i].Name() < ms[j].Name() |
| 138 | } |
| 139 | |
| 140 | type byFunctionString []*ssa.Function |
| 141 | |
| 142 | func (fns byFunctionString) Len() int { return len(fns) } |
| 143 | func (fns byFunctionString) Swap(i, j int) { |
| 144 | fns[i], fns[j] = fns[j], fns[i] |
| 145 | } |
| 146 | func (fns byFunctionString) Less(i, j int) bool { |
| 147 | return fns[i].String() < fns[j].String() |
| 148 | } |
| 149 | |
| 150 | // Emit functions in order of their fully qualified names. This is so that a |
| 151 | // bootstrap build can be verified by comparing the stage2 and stage3 binaries. |
| 152 | func (u *unit) defineFunctionsInOrder(functions map[*ssa.Function]bool) { |
| 153 | fns := []*ssa.Function{} |
| 154 | for f, _ := range functions { |
| 155 | fns = append(fns, f) |
| 156 | } |
| 157 | sort.Sort(byFunctionString(fns)) |
| 158 | for _, f := range fns { |
| 159 | u.defineFunction(f) |
| 160 | } |
| 161 | } |
| 162 | |
| 163 | // translatePackage translates an *ssa.Package into an LLVM module, and returns |
| 164 | // the translation unit information. |
| 165 | func (u *unit) translatePackage(pkg *ssa.Package) { |
| 166 | ms := make([]ssa.Member, len(pkg.Members)) |
| 167 | i := 0 |
| 168 | for _, m := range pkg.Members { |
| 169 | ms[i] = m |
| 170 | i++ |
| 171 | } |
| 172 | |
| 173 | sort.Sort(byMemberName(ms)) |
| 174 | |
| 175 | // Initialize global storage and type descriptors for this package. |
| 176 | // We must create globals regardless of whether they're referenced, |
| 177 | // hence the duplication in frame.value. |
| 178 | for _, m := range ms { |
| 179 | switch v := m.(type) { |
| 180 | case *ssa.Global: |
| 181 | elemtyp := deref(v.Type()) |
| 182 | llelemtyp := u.llvmtypes.ToLLVM(elemtyp) |
| 183 | vname := u.types.mc.mangleGlobalName(v) |
| 184 | global := llvm.AddGlobal(u.module.Module, llelemtyp, vname) |
| 185 | if !v.Object().Exported() { |
| 186 | global.SetLinkage(llvm.InternalLinkage) |
| 187 | } |
| 188 | u.addGlobal(global, elemtyp) |
| 189 | global = llvm.ConstBitCast(global, u.llvmtypes.ToLLVM(v.Type())) |
| 190 | u.globals[v] = global |
| 191 | case *ssa.Type: |
| 192 | u.types.getTypeDescriptorPointer(v.Type()) |
| 193 | } |
| 194 | } |
| 195 | |
| 196 | // Define functions. |
| 197 | u.defineFunctionsInOrder(ssautil.AllFunctions(pkg.Prog)) |
| 198 | |
| 199 | // Emit initializers for type descriptors, which may trigger |
| 200 | // the resolution of additional functions. |
| 201 | u.types.emitTypeDescInitializers() |
| 202 | |
| 203 | // Define remaining functions that were resolved during |
| 204 | // runtime type mapping, but not defined. |
| 205 | u.defineFunctionsInOrder(u.undefinedFuncs) |
| 206 | |
| 207 | // Set initializers for globals. |
| 208 | for global, init := range u.globalInits { |
| 209 | initval := init.build(global.Type().ElementType()) |
| 210 | global.SetInitializer(initval) |
| 211 | } |
| 212 | } |
| 213 | |
| 214 | func (u *unit) addGlobal(global llvm.Value, ty types.Type) { |
| 215 | u.globalInits[global] = new(globalInit) |
| 216 | |
| 217 | if hasPointers(ty) { |
| 218 | global = llvm.ConstBitCast(global, llvm.PointerType(llvm.Int8Type(), 0)) |
| 219 | size := llvm.ConstInt(u.types.inttype, uint64(u.types.Sizeof(ty)), false) |
| 220 | root := llvm.ConstStruct([]llvm.Value{global, size}, false) |
| 221 | u.gcRoots = append(u.gcRoots, root) |
| 222 | } |
| 223 | } |
| 224 | |
| 225 | // ResolveMethod implements MethodResolver.ResolveMethod. |
| 226 | func (u *unit) ResolveMethod(s *types.Selection) *govalue { |
| 227 | m := u.pkg.Prog.Method(s) |
| 228 | llfn := u.resolveFunctionGlobal(m) |
| 229 | llfn = llvm.ConstBitCast(llfn, llvm.PointerType(llvm.Int8Type(), 0)) |
| 230 | return newValue(llfn, m.Signature) |
| 231 | } |
| 232 | |
| 233 | // resolveFunctionDescriptorGlobal returns a reference to the LLVM global |
| 234 | // storing the function's descriptor. |
| 235 | func (u *unit) resolveFunctionDescriptorGlobal(f *ssa.Function) llvm.Value { |
| 236 | llfd, ok := u.funcDescriptors[f] |
| 237 | if !ok { |
| 238 | name := u.types.mc.mangleFunctionName(f) + "$descriptor" |
| 239 | llfd = llvm.AddGlobal(u.module.Module, llvm.PointerType(llvm.Int8Type(), 0), name) |
| 240 | llfd.SetGlobalConstant(true) |
| 241 | u.funcDescriptors[f] = llfd |
| 242 | } |
| 243 | return llfd |
| 244 | } |
| 245 | |
| 246 | // resolveFunctionDescriptor returns a function's |
| 247 | // first-class value representation. |
| 248 | func (u *unit) resolveFunctionDescriptor(f *ssa.Function) *govalue { |
| 249 | llfd := u.resolveFunctionDescriptorGlobal(f) |
| 250 | llfd = llvm.ConstBitCast(llfd, llvm.PointerType(llvm.Int8Type(), 0)) |
| 251 | return newValue(llfd, f.Signature) |
| 252 | } |
| 253 | |
| 254 | // resolveFunctionGlobal returns an llvm.Value for a function global. |
| 255 | func (u *unit) resolveFunctionGlobal(f *ssa.Function) llvm.Value { |
| 256 | if v, ok := u.globals[f]; ok { |
| 257 | return v |
| 258 | } |
| 259 | name := u.types.mc.mangleFunctionName(f) |
| 260 | // It's possible that the function already exists in the module; |
| 261 | // for example, if it's a runtime intrinsic that the compiler |
| 262 | // has already referenced. |
| 263 | llvmFunction := u.module.Module.NamedFunction(name) |
| 264 | if llvmFunction.IsNil() { |
| 265 | fti := u.llvmtypes.getSignatureInfo(f.Signature) |
| 266 | llvmFunction = fti.declare(u.module.Module, name) |
| 267 | u.undefinedFuncs[f] = true |
| 268 | } |
| 269 | u.globals[f] = llvmFunction |
| 270 | return llvmFunction |
| 271 | } |
| 272 | |
| 273 | func (u *unit) getFunctionLinkage(f *ssa.Function) llvm.Linkage { |
| 274 | switch { |
| 275 | case f.Pkg == nil: |
| 276 | // Synthetic functions outside packages may appear in multiple packages. |
| 277 | return llvm.LinkOnceODRLinkage |
| 278 | |
| 279 | case f.Parent() != nil: |
| 280 | // Anonymous. |
| 281 | return llvm.InternalLinkage |
| 282 | |
| 283 | case f.Signature.Recv() == nil && !ast.IsExported(f.Name()) && |
| 284 | !(f.Name() == "main" && f.Pkg.Object.Path() == "main") && |
| 285 | f.Name() != "init": |
| 286 | // Unexported methods may be referenced as part of an interface method |
| 287 | // table in another package. TODO(pcc): detect when this cannot happen. |
| 288 | return llvm.InternalLinkage |
| 289 | |
| 290 | default: |
| 291 | return llvm.ExternalLinkage |
| 292 | } |
| 293 | } |
| 294 | |
| 295 | func (u *unit) defineFunction(f *ssa.Function) { |
| 296 | // Only define functions from this package, or synthetic |
| 297 | // wrappers (which do not have a package). |
| 298 | if f.Pkg != nil && f.Pkg != u.pkg { |
| 299 | return |
| 300 | } |
| 301 | |
| 302 | llfn := u.resolveFunctionGlobal(f) |
| 303 | linkage := u.getFunctionLinkage(f) |
| 304 | |
| 305 | isMethod := f.Signature.Recv() != nil |
| 306 | |
| 307 | // Methods cannot be referred to via a descriptor. |
| 308 | if !isMethod { |
| 309 | llfd := u.resolveFunctionDescriptorGlobal(f) |
| 310 | llfd.SetInitializer(llvm.ConstBitCast(llfn, llvm.PointerType(llvm.Int8Type(), 0))) |
| 311 | llfd.SetLinkage(linkage) |
| 312 | } |
| 313 | |
| 314 | // We only need to emit a descriptor for functions without bodies. |
| 315 | if len(f.Blocks) == 0 { |
| 316 | return |
| 317 | } |
| 318 | |
| 319 | ssaopt.LowerAllocsToStack(f) |
| 320 | |
| 321 | if u.DumpSSA { |
| 322 | f.WriteTo(os.Stderr) |
| 323 | } |
| 324 | |
| 325 | fr := newFrame(u, llfn) |
| 326 | defer fr.dispose() |
| 327 | fr.addCommonFunctionAttrs(fr.function) |
| 328 | fr.function.SetLinkage(linkage) |
| 329 | |
| 330 | fr.logf("Define function: %s", f.String()) |
| 331 | fti := u.llvmtypes.getSignatureInfo(f.Signature) |
| 332 | delete(u.undefinedFuncs, f) |
| 333 | fr.retInf = fti.retInf |
| 334 | |
| 335 | // Push the compile unit and function onto the debug context. |
| 336 | if u.GenerateDebug { |
| 337 | u.debug.PushFunction(fr.function, f.Signature, f.Pos()) |
| 338 | defer u.debug.PopFunction() |
| 339 | u.debug.SetLocation(fr.builder, f.Pos()) |
| 340 | } |
| 341 | |
| 342 | // If a function calls recover, we create a separate function to |
| 343 | // hold the real function, and this function calls __go_can_recover |
| 344 | // and bridges to it. |
| 345 | if callsRecover(f) { |
| 346 | fr = fr.bridgeRecoverFunc(fr.function, fti) |
| 347 | } |
| 348 | |
| 349 | fr.blocks = make([]llvm.BasicBlock, len(f.Blocks)) |
| 350 | fr.lastBlocks = make([]llvm.BasicBlock, len(f.Blocks)) |
| 351 | for i, block := range f.Blocks { |
| 352 | fr.blocks[i] = llvm.AddBasicBlock(fr.function, fmt.Sprintf(".%d.%s", i, block.Comment)) |
| 353 | } |
| 354 | fr.builder.SetInsertPointAtEnd(fr.blocks[0]) |
| 355 | |
| 356 | prologueBlock := llvm.InsertBasicBlock(fr.blocks[0], "prologue") |
| 357 | fr.builder.SetInsertPointAtEnd(prologueBlock) |
| 358 | |
| 359 | // Map parameter positions to indices. We use this |
| 360 | // when processing locals to map back to parameters |
| 361 | // when generating debug metadata. |
| 362 | paramPos := make(map[token.Pos]int) |
| 363 | for i, param := range f.Params { |
| 364 | paramPos[param.Pos()] = i |
| 365 | llparam := fti.argInfos[i].decode(llvm.GlobalContext(), fr.builder, fr.builder) |
| 366 | if isMethod && i == 0 { |
| 367 | if _, ok := param.Type().Underlying().(*types.Pointer); !ok { |
| 368 | llparam = fr.builder.CreateBitCast(llparam, llvm.PointerType(fr.types.ToLLVM(param.Type()), 0), "") |
| 369 | llparam = fr.builder.CreateLoad(llparam, "") |
| 370 | } |
| 371 | } |
| 372 | fr.env[param] = newValue(llparam, param.Type()) |
| 373 | } |
| 374 | |
| 375 | // Load closure, extract free vars. |
| 376 | if len(f.FreeVars) > 0 { |
| 377 | for _, fv := range f.FreeVars { |
| 378 | fr.env[fv] = newValue(llvm.ConstNull(u.llvmtypes.ToLLVM(fv.Type())), fv.Type()) |
| 379 | } |
| 380 | elemTypes := make([]llvm.Type, len(f.FreeVars)+1) |
| 381 | elemTypes[0] = llvm.PointerType(llvm.Int8Type(), 0) // function pointer |
| 382 | for i, fv := range f.FreeVars { |
| 383 | elemTypes[i+1] = u.llvmtypes.ToLLVM(fv.Type()) |
| 384 | } |
| 385 | structType := llvm.StructType(elemTypes, false) |
| 386 | closure := fr.runtime.getClosure.call(fr)[0] |
| 387 | closure = fr.builder.CreateBitCast(closure, llvm.PointerType(structType, 0), "") |
| 388 | for i, fv := range f.FreeVars { |
| 389 | ptr := fr.builder.CreateStructGEP(closure, i+1, "") |
| 390 | ptr = fr.builder.CreateLoad(ptr, "") |
| 391 | fr.env[fv] = newValue(ptr, fv.Type()) |
| 392 | } |
| 393 | } |
| 394 | |
| 395 | // Allocate stack space for locals in the prologue block. |
| 396 | for _, local := range f.Locals { |
| 397 | typ := fr.llvmtypes.ToLLVM(deref(local.Type())) |
| 398 | alloca := fr.builder.CreateAlloca(typ, local.Comment) |
| 399 | fr.memsetZero(alloca, llvm.SizeOf(typ)) |
| 400 | bcalloca := fr.builder.CreateBitCast(alloca, llvm.PointerType(llvm.Int8Type(), 0), "") |
| 401 | value := newValue(bcalloca, local.Type()) |
| 402 | fr.env[local] = value |
| 403 | if fr.GenerateDebug { |
| 404 | paramIndex, ok := paramPos[local.Pos()] |
| 405 | if !ok { |
| 406 | paramIndex = -1 |
| 407 | } |
| 408 | fr.debug.Declare(fr.builder, local, alloca, paramIndex) |
| 409 | } |
| 410 | } |
| 411 | |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 412 | // If the function contains any defers, we must first create |
| 413 | // an unwind block. We can short-circuit the check for defers with |
| 414 | // f.Recover != nil. |
| 415 | if f.Recover != nil || hasDefer(f) { |
| 416 | fr.unwindBlock = llvm.AddBasicBlock(fr.function, "") |
| 417 | fr.frameptr = fr.builder.CreateAlloca(llvm.Int8Type(), "") |
| 418 | } |
| 419 | |
Peter Collingbourne | d34d92f | 2014-12-31 00:25:39 +0000 | [diff] [blame] | 420 | // Keep track of the block into which we need to insert the call |
| 421 | // to __go_register_gc_roots. This needs to be inserted after the |
| 422 | // init guard check under the llgo ABI. |
| 423 | var registerGcBlock llvm.BasicBlock |
| 424 | |
| 425 | // If this is the "init" function, emit the init guard check and |
| 426 | // enable init-specific optimizations. |
| 427 | if !isMethod && f.Name() == "init" { |
| 428 | registerGcBlock = fr.emitInitPrologue() |
| 429 | fr.isInit = true |
| 430 | } |
| 431 | |
| 432 | fr.builder.CreateBr(fr.blocks[0]) |
| 433 | fr.allocaBuilder.SetInsertPointBefore(prologueBlock.FirstInstruction()) |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 434 | |
| 435 | for _, block := range f.DomPreorder() { |
| 436 | fr.translateBlock(block, fr.blocks[block.Index]) |
| 437 | } |
| 438 | |
| 439 | fr.fixupPhis() |
| 440 | |
| 441 | if !fr.unwindBlock.IsNil() { |
| 442 | fr.setupUnwindBlock(f.Recover, f.Signature.Results()) |
| 443 | } |
| 444 | |
| 445 | // The init function needs to register the GC roots first. We do this |
| 446 | // after generating code for it because allocations may have caused |
| 447 | // additional GC roots to be created. |
| 448 | if fr.isInit { |
Peter Collingbourne | d34d92f | 2014-12-31 00:25:39 +0000 | [diff] [blame] | 449 | fr.builder.SetInsertPointBefore(registerGcBlock.FirstInstruction()) |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 450 | fr.registerGcRoots() |
| 451 | } |
| 452 | } |
| 453 | |
| 454 | type pendingPhi struct { |
| 455 | ssa *ssa.Phi |
| 456 | llvm llvm.Value |
| 457 | } |
| 458 | |
| 459 | type frame struct { |
| 460 | *unit |
| 461 | function llvm.Value |
| 462 | builder, allocaBuilder llvm.Builder |
| 463 | retInf retInfo |
| 464 | blocks []llvm.BasicBlock |
| 465 | lastBlocks []llvm.BasicBlock |
| 466 | runtimeErrorBlocks [gccgoRuntimeErrorCount]llvm.BasicBlock |
| 467 | unwindBlock llvm.BasicBlock |
| 468 | frameptr llvm.Value |
| 469 | env map[ssa.Value]*govalue |
| 470 | ptr map[ssa.Value]llvm.Value |
| 471 | tuples map[ssa.Value][]*govalue |
| 472 | phis []pendingPhi |
| 473 | canRecover llvm.Value |
| 474 | isInit bool |
| 475 | } |
| 476 | |
| 477 | func newFrame(u *unit, fn llvm.Value) *frame { |
| 478 | return &frame{ |
| 479 | unit: u, |
| 480 | function: fn, |
| 481 | builder: llvm.GlobalContext().NewBuilder(), |
| 482 | allocaBuilder: llvm.GlobalContext().NewBuilder(), |
| 483 | env: make(map[ssa.Value]*govalue), |
| 484 | ptr: make(map[ssa.Value]llvm.Value), |
| 485 | tuples: make(map[ssa.Value][]*govalue), |
| 486 | } |
| 487 | } |
| 488 | |
| 489 | func (fr *frame) dispose() { |
| 490 | fr.builder.Dispose() |
| 491 | fr.allocaBuilder.Dispose() |
| 492 | } |
| 493 | |
Peter Collingbourne | d34d92f | 2014-12-31 00:25:39 +0000 | [diff] [blame] | 494 | // emitInitPrologue emits the init-specific function prologue (guard check and |
| 495 | // initialization of dependent packages under the llgo native ABI), and returns |
| 496 | // the basic block into which the GC registration call should be emitted. |
| 497 | func (fr *frame) emitInitPrologue() llvm.BasicBlock { |
| 498 | if fr.GccgoABI { |
| 499 | return fr.builder.GetInsertBlock() |
| 500 | } |
| 501 | |
| 502 | initGuard := llvm.AddGlobal(fr.module.Module, llvm.Int1Type(), "init$guard") |
| 503 | initGuard.SetLinkage(llvm.InternalLinkage) |
| 504 | initGuard.SetInitializer(llvm.ConstNull(llvm.Int1Type())) |
| 505 | |
| 506 | returnBlock := llvm.AddBasicBlock(fr.function, "") |
| 507 | initBlock := llvm.AddBasicBlock(fr.function, "") |
| 508 | |
| 509 | initGuardVal := fr.builder.CreateLoad(initGuard, "") |
| 510 | fr.builder.CreateCondBr(initGuardVal, returnBlock, initBlock) |
| 511 | |
| 512 | fr.builder.SetInsertPointAtEnd(returnBlock) |
| 513 | fr.builder.CreateRetVoid() |
| 514 | |
| 515 | fr.builder.SetInsertPointAtEnd(initBlock) |
| 516 | fr.builder.CreateStore(llvm.ConstInt(llvm.Int1Type(), 1, false), initGuard) |
| 517 | ftyp := llvm.FunctionType(llvm.VoidType(), nil, false) |
| 518 | for _, pkg := range fr.pkg.Object.Imports() { |
| 519 | initname := ManglePackagePath(pkg.Path()) + "..import" |
| 520 | initfn := fr.module.Module.NamedFunction(initname) |
| 521 | if initfn.IsNil() { |
| 522 | initfn = llvm.AddFunction(fr.module.Module, initname, ftyp) |
| 523 | } |
| 524 | fr.builder.CreateCall(initfn, nil, "") |
| 525 | } |
| 526 | |
| 527 | return initBlock |
| 528 | } |
| 529 | |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 530 | // bridgeRecoverFunc creates a function that may call recover(), and creates |
| 531 | // a call to it from the current frame. The created function will be called |
| 532 | // with a boolean parameter that indicates whether it may call recover(). |
| 533 | // |
| 534 | // The created function will have the same name as the current frame's function |
| 535 | // with "$recover" appended, having the same return types and parameters with |
| 536 | // an additional boolean parameter appended. |
| 537 | // |
| 538 | // A new frame will be returned for the newly created function. |
| 539 | func (fr *frame) bridgeRecoverFunc(llfn llvm.Value, fti functionTypeInfo) *frame { |
| 540 | // The bridging function must not be inlined, or the return address |
| 541 | // may not correspond to the source function. |
| 542 | llfn.AddFunctionAttr(llvm.NoInlineAttribute) |
| 543 | |
| 544 | // Call __go_can_recover, passing in the function's return address. |
| 545 | entry := llvm.AddBasicBlock(llfn, "entry") |
| 546 | fr.builder.SetInsertPointAtEnd(entry) |
| 547 | canRecover := fr.runtime.canRecover.call(fr, fr.returnAddress(0))[0] |
| 548 | returnType := fti.functionType.ReturnType() |
| 549 | argTypes := fti.functionType.ParamTypes() |
| 550 | argTypes = append(argTypes, canRecover.Type()) |
| 551 | |
| 552 | // Create and call the $recover function. |
| 553 | ftiRecover := fti |
| 554 | ftiRecover.functionType = llvm.FunctionType(returnType, argTypes, false) |
| 555 | llfnRecover := ftiRecover.declare(fr.module.Module, llfn.Name()+"$recover") |
| 556 | fr.addCommonFunctionAttrs(llfnRecover) |
| 557 | llfnRecover.SetLinkage(llvm.InternalLinkage) |
| 558 | args := make([]llvm.Value, len(argTypes)-1, len(argTypes)) |
| 559 | for i := range args { |
| 560 | args[i] = llfn.Param(i) |
| 561 | } |
| 562 | args = append(args, canRecover) |
| 563 | result := fr.builder.CreateCall(llfnRecover, args, "") |
| 564 | if returnType.TypeKind() == llvm.VoidTypeKind { |
| 565 | fr.builder.CreateRetVoid() |
| 566 | } else { |
| 567 | fr.builder.CreateRet(result) |
| 568 | } |
| 569 | |
| 570 | // The $recover function must condition calls to __go_recover on |
| 571 | // the result of __go_can_recover passed in as an argument. |
| 572 | fr = newFrame(fr.unit, llfnRecover) |
| 573 | fr.retInf = ftiRecover.retInf |
| 574 | fr.canRecover = fr.function.Param(len(argTypes) - 1) |
| 575 | return fr |
| 576 | } |
| 577 | |
| 578 | func (fr *frame) registerGcRoots() { |
| 579 | if len(fr.gcRoots) != 0 { |
| 580 | rootty := fr.gcRoots[0].Type() |
| 581 | roots := append(fr.gcRoots, llvm.ConstNull(rootty)) |
| 582 | rootsarr := llvm.ConstArray(rootty, roots) |
| 583 | rootsstruct := llvm.ConstStruct([]llvm.Value{llvm.ConstNull(llvm.PointerType(llvm.Int8Type(), 0)), rootsarr}, false) |
| 584 | |
| 585 | rootsglobal := llvm.AddGlobal(fr.module.Module, rootsstruct.Type(), "") |
| 586 | rootsglobal.SetInitializer(rootsstruct) |
| 587 | rootsglobal.SetLinkage(llvm.InternalLinkage) |
| 588 | fr.runtime.registerGcRoots.callOnly(fr, llvm.ConstBitCast(rootsglobal, llvm.PointerType(llvm.Int8Type(), 0))) |
| 589 | } |
| 590 | } |
| 591 | |
| 592 | func (fr *frame) fixupPhis() { |
| 593 | for _, phi := range fr.phis { |
| 594 | values := make([]llvm.Value, len(phi.ssa.Edges)) |
| 595 | blocks := make([]llvm.BasicBlock, len(phi.ssa.Edges)) |
| 596 | block := phi.ssa.Block() |
| 597 | for i, edge := range phi.ssa.Edges { |
| 598 | values[i] = fr.llvmvalue(edge) |
| 599 | blocks[i] = fr.lastBlock(block.Preds[i]) |
| 600 | } |
| 601 | phi.llvm.AddIncoming(values, blocks) |
| 602 | } |
| 603 | } |
| 604 | |
| 605 | func (fr *frame) createLandingPad(cleanup bool) llvm.Value { |
| 606 | lp := fr.builder.CreateLandingPad(fr.runtime.gccgoExceptionType, fr.runtime.gccgoPersonality, 0, "") |
| 607 | if cleanup { |
| 608 | lp.SetCleanup(true) |
| 609 | } else { |
| 610 | lp.AddClause(llvm.ConstNull(llvm.PointerType(llvm.Int8Type(), 0))) |
| 611 | } |
| 612 | return lp |
| 613 | } |
| 614 | |
| 615 | // Runs defers. If a defer panics, check for recovers in later defers. |
| 616 | func (fr *frame) runDefers() { |
| 617 | loopbb := llvm.AddBasicBlock(fr.function, "") |
| 618 | fr.builder.CreateBr(loopbb) |
| 619 | |
| 620 | retrylpad := llvm.AddBasicBlock(fr.function, "") |
| 621 | fr.builder.SetInsertPointAtEnd(retrylpad) |
| 622 | fr.createLandingPad(false) |
| 623 | fr.runtime.checkDefer.callOnly(fr, fr.frameptr) |
| 624 | fr.builder.CreateBr(loopbb) |
| 625 | |
| 626 | fr.builder.SetInsertPointAtEnd(loopbb) |
| 627 | fr.runtime.undefer.invoke(fr, retrylpad, fr.frameptr) |
| 628 | } |
| 629 | |
| 630 | func (fr *frame) setupUnwindBlock(rec *ssa.BasicBlock, results *types.Tuple) { |
| 631 | recoverbb := llvm.AddBasicBlock(fr.function, "") |
| 632 | if rec != nil { |
| 633 | fr.translateBlock(rec, recoverbb) |
| 634 | } else if results.Len() == 0 || results.At(0).Anonymous() { |
| 635 | // TODO(pcc): Remove this code after https://codereview.appspot.com/87210044/ lands |
| 636 | fr.builder.SetInsertPointAtEnd(recoverbb) |
| 637 | values := make([]llvm.Value, results.Len()) |
| 638 | for i := range values { |
| 639 | values[i] = llvm.ConstNull(fr.llvmtypes.ToLLVM(results.At(i).Type())) |
| 640 | } |
| 641 | fr.retInf.encode(llvm.GlobalContext(), fr.allocaBuilder, fr.builder, values) |
| 642 | } else { |
| 643 | fr.builder.SetInsertPointAtEnd(recoverbb) |
| 644 | fr.builder.CreateUnreachable() |
| 645 | } |
| 646 | |
| 647 | checkunwindbb := llvm.AddBasicBlock(fr.function, "") |
| 648 | fr.builder.SetInsertPointAtEnd(checkunwindbb) |
| 649 | exc := fr.createLandingPad(true) |
| 650 | fr.runDefers() |
| 651 | |
| 652 | frame := fr.builder.CreateLoad(fr.frameptr, "") |
| 653 | shouldresume := fr.builder.CreateIsNull(frame, "") |
| 654 | |
| 655 | resumebb := llvm.AddBasicBlock(fr.function, "") |
| 656 | fr.builder.CreateCondBr(shouldresume, resumebb, recoverbb) |
| 657 | |
| 658 | fr.builder.SetInsertPointAtEnd(resumebb) |
| 659 | fr.builder.CreateResume(exc) |
| 660 | |
| 661 | fr.builder.SetInsertPointAtEnd(fr.unwindBlock) |
| 662 | fr.createLandingPad(false) |
| 663 | fr.runtime.checkDefer.invoke(fr, checkunwindbb, fr.frameptr) |
| 664 | fr.runDefers() |
| 665 | fr.builder.CreateBr(recoverbb) |
| 666 | } |
| 667 | |
| 668 | func (fr *frame) translateBlock(b *ssa.BasicBlock, llb llvm.BasicBlock) { |
| 669 | fr.builder.SetInsertPointAtEnd(llb) |
| 670 | for _, instr := range b.Instrs { |
| 671 | fr.instruction(instr) |
| 672 | } |
| 673 | fr.lastBlocks[b.Index] = fr.builder.GetInsertBlock() |
| 674 | } |
| 675 | |
| 676 | func (fr *frame) block(b *ssa.BasicBlock) llvm.BasicBlock { |
| 677 | return fr.blocks[b.Index] |
| 678 | } |
| 679 | |
| 680 | func (fr *frame) lastBlock(b *ssa.BasicBlock) llvm.BasicBlock { |
| 681 | return fr.lastBlocks[b.Index] |
| 682 | } |
| 683 | |
| 684 | func (fr *frame) value(v ssa.Value) (result *govalue) { |
| 685 | switch v := v.(type) { |
| 686 | case nil: |
| 687 | return nil |
| 688 | case *ssa.Function: |
| 689 | return fr.resolveFunctionDescriptor(v) |
| 690 | case *ssa.Const: |
| 691 | return fr.newValueFromConst(v.Value, v.Type()) |
| 692 | case *ssa.Global: |
| 693 | if g, ok := fr.globals[v]; ok { |
| 694 | return newValue(g, v.Type()) |
| 695 | } |
| 696 | // Create an external global. Globals for this package are defined |
| 697 | // on entry to translatePackage, and have initialisers. |
| 698 | llelemtyp := fr.llvmtypes.ToLLVM(deref(v.Type())) |
| 699 | vname := fr.types.mc.mangleGlobalName(v) |
| 700 | llglobal := llvm.AddGlobal(fr.module.Module, llelemtyp, vname) |
| 701 | llglobal = llvm.ConstBitCast(llglobal, fr.llvmtypes.ToLLVM(v.Type())) |
| 702 | fr.globals[v] = llglobal |
| 703 | return newValue(llglobal, v.Type()) |
| 704 | } |
| 705 | if value, ok := fr.env[v]; ok { |
| 706 | return value |
| 707 | } |
| 708 | |
Peter Collingbourne | 1f89ffd | 2014-12-17 09:45:05 +0000 | [diff] [blame] | 709 | panic(fmt.Errorf("Instruction %q not visited yet", v.Name())) |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 710 | } |
| 711 | |
| 712 | func (fr *frame) llvmvalue(v ssa.Value) llvm.Value { |
| 713 | if gv := fr.value(v); gv != nil { |
| 714 | return gv.value |
| 715 | } else { |
| 716 | return llvm.Value{nil} |
| 717 | } |
| 718 | } |
| 719 | |
| 720 | func (fr *frame) isNonNull(v ssa.Value) bool { |
| 721 | switch v.(type) { |
| 722 | case |
| 723 | // Globals have a fixed (non-nil) address. |
| 724 | *ssa.Global, |
| 725 | // The language does not specify what happens if an allocation fails. |
| 726 | *ssa.Alloc, |
| 727 | // These have already been nil checked. |
| 728 | *ssa.FieldAddr, *ssa.IndexAddr: |
| 729 | return true |
| 730 | default: |
| 731 | return false |
| 732 | } |
| 733 | } |
| 734 | |
| 735 | func (fr *frame) nilCheck(v ssa.Value, llptr llvm.Value) { |
| 736 | if !fr.isNonNull(v) { |
| 737 | ptrnull := fr.builder.CreateIsNull(llptr, "") |
| 738 | fr.condBrRuntimeError(ptrnull, gccgoRuntimeErrorNIL_DEREFERENCE) |
| 739 | } |
| 740 | } |
| 741 | |
Peter Collingbourne | 1f89ffd | 2014-12-17 09:45:05 +0000 | [diff] [blame] | 742 | func (fr *frame) canAvoidElementLoad(ptr ssa.Value) bool { |
| 743 | for _, ref := range *ptr.Referrers() { |
| 744 | switch ref := ref.(type) { |
| 745 | case *ssa.Field: |
| 746 | case *ssa.Index: |
| 747 | if ref.X != ptr { |
| 748 | return false |
| 749 | } |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 750 | // ok |
| 751 | default: |
| 752 | return false |
| 753 | } |
| 754 | } |
| 755 | |
| 756 | return true |
| 757 | } |
| 758 | |
| 759 | // If this value is sufficiently large, look through referrers to see if we can |
| 760 | // avoid a load. |
| 761 | func (fr *frame) canAvoidLoad(instr *ssa.UnOp, op llvm.Value) bool { |
Peter Collingbourne | 1f89ffd | 2014-12-17 09:45:05 +0000 | [diff] [blame] | 762 | if fr.types.Sizeof(instr.Type()) < 2*fr.types.Sizeof(types.Typ[types.Int]) { |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 763 | // Don't bother with small values. |
| 764 | return false |
| 765 | } |
| 766 | |
| 767 | // Keep track of whether our pointer may escape. We conservatively assume |
| 768 | // that MakeInterfaces will escape. |
| 769 | esc := false |
| 770 | |
| 771 | // We only know how to avoid loads if they are used to create an interface |
| 772 | // or read an element of the structure. If we see any other referrer, abort. |
| 773 | for _, ref := range *instr.Referrers() { |
Peter Collingbourne | 1f89ffd | 2014-12-17 09:45:05 +0000 | [diff] [blame] | 774 | switch ref := ref.(type) { |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 775 | case *ssa.MakeInterface: |
| 776 | esc = true |
Peter Collingbourne | 1f89ffd | 2014-12-17 09:45:05 +0000 | [diff] [blame] | 777 | case *ssa.Field: |
| 778 | case *ssa.Index: |
| 779 | if ref.X != instr { |
| 780 | // This should never happen, as indices are always of type int |
| 781 | // and we don't bother with values smaller than 2*sizeof(int). |
| 782 | panic("impossible") |
| 783 | } |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 784 | // ok |
| 785 | default: |
| 786 | return false |
| 787 | } |
| 788 | } |
| 789 | |
| 790 | var opcopy llvm.Value |
| 791 | if esc { |
| 792 | opcopy = fr.createTypeMalloc(instr.Type()) |
| 793 | } else { |
| 794 | opcopy = fr.allocaBuilder.CreateAlloca(fr.types.ToLLVM(instr.Type()), "") |
| 795 | } |
| 796 | fr.memcpy(opcopy, op, llvm.ConstInt(fr.types.inttype, uint64(fr.types.Sizeof(instr.Type())), false)) |
| 797 | |
| 798 | fr.ptr[instr] = opcopy |
| 799 | return true |
| 800 | } |
| 801 | |
| 802 | // Return true iff we think it might be beneficial to turn this alloc instruction |
| 803 | // into a statically allocated global. |
| 804 | // Precondition: we are compiling the init function. |
| 805 | func (fr *frame) shouldStaticallyAllocate(alloc *ssa.Alloc) bool { |
| 806 | // First, see if the allocated type is an array or struct, and if so determine |
| 807 | // the number of elements in the type. If the type is anything else, we |
| 808 | // statically allocate unconditionally. |
| 809 | var numElems int64 |
| 810 | switch ty := deref(alloc.Type()).Underlying().(type) { |
| 811 | case *types.Array: |
| 812 | numElems = ty.Len() |
| 813 | case *types.Struct: |
| 814 | numElems = int64(ty.NumFields()) |
| 815 | default: |
| 816 | return true |
| 817 | } |
| 818 | |
| 819 | // We treat the number of referrers to the alloc instruction as a rough |
| 820 | // proxy for the number of elements initialized. If the data structure |
| 821 | // is densely initialized (> 1/4 elements initialized), enable the |
| 822 | // optimization. |
| 823 | return int64(len(*alloc.Referrers()))*4 > numElems |
| 824 | } |
| 825 | |
| 826 | // If val is a constant and addr refers to a global variable which is defined in |
| 827 | // this module or an element thereof, simulate the effect of storing val at addr |
| 828 | // in the global variable's initializer and return true, otherwise return false. |
| 829 | // Precondition: we are compiling the init function. |
| 830 | func (fr *frame) maybeStoreInInitializer(val, addr llvm.Value) bool { |
| 831 | if val.IsAConstant().IsNil() { |
| 832 | return false |
| 833 | } |
| 834 | |
| 835 | if !addr.IsAConstantExpr().IsNil() && addr.OperandsCount() >= 2 && |
| 836 | // TODO(pcc): Explicitly check that this is a constant GEP. |
| 837 | // I don't think there are any other kinds of constantexpr which |
| 838 | // satisfy the conditions we test for here, so this is probably safe. |
| 839 | !addr.Operand(0).IsAGlobalVariable().IsNil() && |
| 840 | addr.Operand(1).IsNull() { |
| 841 | gv := addr.Operand(0) |
| 842 | globalInit, ok := fr.globalInits[gv] |
| 843 | if !ok { |
| 844 | return false |
| 845 | } |
| 846 | indices := make([]uint32, addr.OperandsCount()-2) |
| 847 | for i := range indices { |
| 848 | op := addr.Operand(i + 2) |
| 849 | if op.IsAConstantInt().IsNil() { |
| 850 | return false |
| 851 | } |
| 852 | indices[i] = uint32(op.ZExtValue()) |
| 853 | } |
| 854 | globalInit.update(gv.Type().ElementType(), indices, val) |
| 855 | return true |
| 856 | } else if !addr.IsAGlobalVariable().IsNil() { |
| 857 | if globalInit, ok := fr.globalInits[addr]; ok { |
| 858 | globalInit.update(addr.Type().ElementType(), nil, val) |
| 859 | return true |
| 860 | } |
| 861 | return false |
| 862 | } else { |
| 863 | return false |
| 864 | } |
| 865 | } |
| 866 | |
| 867 | func (fr *frame) instruction(instr ssa.Instruction) { |
| 868 | fr.logf("[%T] %v @ %s\n", instr, instr, fr.pkg.Prog.Fset.Position(instr.Pos())) |
| 869 | if fr.GenerateDebug { |
| 870 | fr.debug.SetLocation(fr.builder, instr.Pos()) |
| 871 | } |
| 872 | |
| 873 | switch instr := instr.(type) { |
| 874 | case *ssa.Alloc: |
| 875 | typ := deref(instr.Type()) |
| 876 | llvmtyp := fr.llvmtypes.ToLLVM(typ) |
| 877 | var value llvm.Value |
| 878 | if !instr.Heap { |
| 879 | value = fr.env[instr].value |
| 880 | fr.memsetZero(value, llvm.SizeOf(llvmtyp)) |
| 881 | } else if fr.isInit && fr.shouldStaticallyAllocate(instr) { |
| 882 | // If this is the init function and we think it may be beneficial, |
| 883 | // allocate memory statically in the object file rather than on the |
| 884 | // heap. This allows us to optimize constant stores into such |
| 885 | // variables as static initializations. |
| 886 | global := llvm.AddGlobal(fr.module.Module, llvmtyp, "") |
| 887 | global.SetLinkage(llvm.InternalLinkage) |
| 888 | fr.addGlobal(global, typ) |
| 889 | ptr := llvm.ConstBitCast(global, llvm.PointerType(llvm.Int8Type(), 0)) |
| 890 | fr.env[instr] = newValue(ptr, instr.Type()) |
| 891 | } else { |
| 892 | value = fr.createTypeMalloc(typ) |
| 893 | value.SetName(instr.Comment) |
| 894 | value = fr.builder.CreateBitCast(value, llvm.PointerType(llvm.Int8Type(), 0), "") |
| 895 | fr.env[instr] = newValue(value, instr.Type()) |
| 896 | } |
| 897 | |
| 898 | case *ssa.BinOp: |
| 899 | lhs, rhs := fr.value(instr.X), fr.value(instr.Y) |
| 900 | fr.env[instr] = fr.binaryOp(lhs, instr.Op, rhs) |
| 901 | |
| 902 | case *ssa.Call: |
| 903 | tuple := fr.callInstruction(instr) |
| 904 | if len(tuple) == 1 { |
| 905 | fr.env[instr] = tuple[0] |
| 906 | } else { |
| 907 | fr.tuples[instr] = tuple |
| 908 | } |
| 909 | |
| 910 | case *ssa.ChangeInterface: |
| 911 | x := fr.value(instr.X) |
| 912 | // The source type must be a non-empty interface, |
| 913 | // as ChangeInterface cannot fail (E2I may fail). |
| 914 | if instr.Type().Underlying().(*types.Interface).NumMethods() > 0 { |
| 915 | x = fr.changeInterface(x, instr.Type(), false) |
| 916 | } else { |
| 917 | x = fr.convertI2E(x) |
| 918 | } |
| 919 | fr.env[instr] = x |
| 920 | |
| 921 | case *ssa.ChangeType: |
| 922 | value := fr.llvmvalue(instr.X) |
| 923 | if _, ok := instr.Type().Underlying().(*types.Pointer); ok { |
| 924 | value = fr.builder.CreateBitCast(value, fr.llvmtypes.ToLLVM(instr.Type()), "") |
| 925 | } |
| 926 | fr.env[instr] = newValue(value, instr.Type()) |
| 927 | |
| 928 | case *ssa.Convert: |
| 929 | v := fr.value(instr.X) |
| 930 | fr.env[instr] = fr.convert(v, instr.Type()) |
| 931 | |
| 932 | case *ssa.Defer: |
| 933 | fn, arg := fr.createThunk(instr) |
| 934 | fr.runtime.Defer.call(fr, fr.frameptr, fn, arg) |
| 935 | |
| 936 | case *ssa.Extract: |
| 937 | var elem llvm.Value |
| 938 | if t, ok := fr.tuples[instr.Tuple]; ok { |
| 939 | elem = t[instr.Index].value |
| 940 | } else { |
| 941 | tuple := fr.llvmvalue(instr.Tuple) |
| 942 | elem = fr.builder.CreateExtractValue(tuple, instr.Index, instr.Name()) |
| 943 | } |
| 944 | elemtyp := instr.Type() |
| 945 | fr.env[instr] = newValue(elem, elemtyp) |
| 946 | |
| 947 | case *ssa.Field: |
| 948 | fieldtyp := instr.Type() |
| 949 | if p, ok := fr.ptr[instr.X]; ok { |
| 950 | field := fr.builder.CreateStructGEP(p, instr.Field, instr.Name()) |
Peter Collingbourne | 1f89ffd | 2014-12-17 09:45:05 +0000 | [diff] [blame] | 951 | if fr.canAvoidElementLoad(instr) { |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 952 | fr.ptr[instr] = field |
| 953 | } else { |
| 954 | fr.env[instr] = newValue(fr.builder.CreateLoad(field, ""), fieldtyp) |
| 955 | } |
| 956 | } else { |
| 957 | value := fr.llvmvalue(instr.X) |
| 958 | field := fr.builder.CreateExtractValue(value, instr.Field, instr.Name()) |
| 959 | fr.env[instr] = newValue(field, fieldtyp) |
| 960 | } |
| 961 | |
| 962 | case *ssa.FieldAddr: |
| 963 | ptr := fr.llvmvalue(instr.X) |
| 964 | fr.nilCheck(instr.X, ptr) |
| 965 | xtyp := instr.X.Type().Underlying().(*types.Pointer).Elem() |
| 966 | ptrtyp := llvm.PointerType(fr.llvmtypes.ToLLVM(xtyp), 0) |
| 967 | ptr = fr.builder.CreateBitCast(ptr, ptrtyp, "") |
| 968 | fieldptr := fr.builder.CreateStructGEP(ptr, instr.Field, instr.Name()) |
| 969 | fieldptr = fr.builder.CreateBitCast(fieldptr, llvm.PointerType(llvm.Int8Type(), 0), "") |
| 970 | fieldptrtyp := instr.Type() |
| 971 | fr.env[instr] = newValue(fieldptr, fieldptrtyp) |
| 972 | |
| 973 | case *ssa.Go: |
| 974 | fn, arg := fr.createThunk(instr) |
| 975 | fr.runtime.Go.call(fr, fn, arg) |
| 976 | |
| 977 | case *ssa.If: |
| 978 | cond := fr.llvmvalue(instr.Cond) |
| 979 | block := instr.Block() |
| 980 | trueBlock := fr.block(block.Succs[0]) |
| 981 | falseBlock := fr.block(block.Succs[1]) |
| 982 | cond = fr.builder.CreateTrunc(cond, llvm.Int1Type(), "") |
| 983 | fr.builder.CreateCondBr(cond, trueBlock, falseBlock) |
| 984 | |
| 985 | case *ssa.Index: |
| 986 | var arrayptr llvm.Value |
| 987 | |
| 988 | if ptr, ok := fr.ptr[instr.X]; ok { |
| 989 | arrayptr = ptr |
| 990 | } else { |
| 991 | array := fr.llvmvalue(instr.X) |
| 992 | arrayptr = fr.allocaBuilder.CreateAlloca(array.Type(), "") |
| 993 | |
| 994 | fr.builder.CreateStore(array, arrayptr) |
| 995 | } |
| 996 | index := fr.llvmvalue(instr.Index) |
| 997 | |
| 998 | arraytyp := instr.X.Type().Underlying().(*types.Array) |
| 999 | arraylen := llvm.ConstInt(fr.llvmtypes.inttype, uint64(arraytyp.Len()), false) |
| 1000 | |
| 1001 | // The index may not have been promoted to int (for example, if it |
| 1002 | // came from a composite literal). |
| 1003 | index = fr.createZExtOrTrunc(index, fr.types.inttype, "") |
| 1004 | |
| 1005 | // Bounds checking: 0 <= index < len |
| 1006 | zero := llvm.ConstNull(fr.types.inttype) |
| 1007 | i0 := fr.builder.CreateICmp(llvm.IntSLT, index, zero, "") |
| 1008 | li := fr.builder.CreateICmp(llvm.IntSLE, arraylen, index, "") |
| 1009 | |
| 1010 | cond := fr.builder.CreateOr(i0, li, "") |
| 1011 | |
| 1012 | fr.condBrRuntimeError(cond, gccgoRuntimeErrorARRAY_INDEX_OUT_OF_BOUNDS) |
| 1013 | |
| 1014 | addr := fr.builder.CreateGEP(arrayptr, []llvm.Value{zero, index}, "") |
Peter Collingbourne | 1f89ffd | 2014-12-17 09:45:05 +0000 | [diff] [blame] | 1015 | if fr.canAvoidElementLoad(instr) { |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 1016 | fr.ptr[instr] = addr |
| 1017 | } else { |
| 1018 | fr.env[instr] = newValue(fr.builder.CreateLoad(addr, ""), instr.Type()) |
| 1019 | } |
| 1020 | |
| 1021 | case *ssa.IndexAddr: |
| 1022 | x := fr.llvmvalue(instr.X) |
| 1023 | index := fr.llvmvalue(instr.Index) |
| 1024 | var arrayptr, arraylen llvm.Value |
| 1025 | var elemtyp types.Type |
| 1026 | var errcode uint64 |
| 1027 | switch typ := instr.X.Type().Underlying().(type) { |
| 1028 | case *types.Slice: |
| 1029 | elemtyp = typ.Elem() |
| 1030 | arrayptr = fr.builder.CreateExtractValue(x, 0, "") |
| 1031 | arraylen = fr.builder.CreateExtractValue(x, 1, "") |
| 1032 | errcode = gccgoRuntimeErrorSLICE_INDEX_OUT_OF_BOUNDS |
| 1033 | case *types.Pointer: // *array |
| 1034 | arraytyp := typ.Elem().Underlying().(*types.Array) |
| 1035 | elemtyp = arraytyp.Elem() |
| 1036 | fr.nilCheck(instr.X, x) |
| 1037 | arrayptr = x |
| 1038 | arraylen = llvm.ConstInt(fr.llvmtypes.inttype, uint64(arraytyp.Len()), false) |
| 1039 | errcode = gccgoRuntimeErrorARRAY_INDEX_OUT_OF_BOUNDS |
| 1040 | } |
| 1041 | |
| 1042 | // The index may not have been promoted to int (for example, if it |
| 1043 | // came from a composite literal). |
| 1044 | index = fr.createZExtOrTrunc(index, fr.types.inttype, "") |
| 1045 | |
| 1046 | // Bounds checking: 0 <= index < len |
| 1047 | zero := llvm.ConstNull(fr.types.inttype) |
| 1048 | i0 := fr.builder.CreateICmp(llvm.IntSLT, index, zero, "") |
| 1049 | li := fr.builder.CreateICmp(llvm.IntSLE, arraylen, index, "") |
| 1050 | |
| 1051 | cond := fr.builder.CreateOr(i0, li, "") |
| 1052 | |
| 1053 | fr.condBrRuntimeError(cond, errcode) |
| 1054 | |
| 1055 | ptrtyp := llvm.PointerType(fr.llvmtypes.ToLLVM(elemtyp), 0) |
| 1056 | arrayptr = fr.builder.CreateBitCast(arrayptr, ptrtyp, "") |
| 1057 | addr := fr.builder.CreateGEP(arrayptr, []llvm.Value{index}, "") |
| 1058 | addr = fr.builder.CreateBitCast(addr, llvm.PointerType(llvm.Int8Type(), 0), "") |
| 1059 | fr.env[instr] = newValue(addr, types.NewPointer(elemtyp)) |
| 1060 | |
| 1061 | case *ssa.Jump: |
| 1062 | succ := instr.Block().Succs[0] |
| 1063 | fr.builder.CreateBr(fr.block(succ)) |
| 1064 | |
| 1065 | case *ssa.Lookup: |
| 1066 | x := fr.value(instr.X) |
| 1067 | index := fr.value(instr.Index) |
| 1068 | if isString(x.Type().Underlying()) { |
| 1069 | fr.env[instr] = fr.stringIndex(x, index) |
| 1070 | } else { |
| 1071 | v, ok := fr.mapLookup(x, index) |
| 1072 | if instr.CommaOk { |
| 1073 | fr.tuples[instr] = []*govalue{v, ok} |
| 1074 | } else { |
| 1075 | fr.env[instr] = v |
| 1076 | } |
| 1077 | } |
| 1078 | |
| 1079 | case *ssa.MakeChan: |
| 1080 | fr.env[instr] = fr.makeChan(instr.Type(), fr.value(instr.Size)) |
| 1081 | |
| 1082 | case *ssa.MakeClosure: |
| 1083 | llfn := fr.resolveFunctionGlobal(instr.Fn.(*ssa.Function)) |
| 1084 | llfn = llvm.ConstBitCast(llfn, llvm.PointerType(llvm.Int8Type(), 0)) |
| 1085 | fn := newValue(llfn, instr.Fn.(*ssa.Function).Signature) |
| 1086 | bindings := make([]*govalue, len(instr.Bindings)) |
| 1087 | for i, binding := range instr.Bindings { |
| 1088 | bindings[i] = fr.value(binding) |
| 1089 | } |
| 1090 | fr.env[instr] = fr.makeClosure(fn, bindings) |
| 1091 | |
| 1092 | case *ssa.MakeInterface: |
| 1093 | // fr.ptr[instr.X] will be set if a pointer load was elided by canAvoidLoad |
| 1094 | if ptr, ok := fr.ptr[instr.X]; ok { |
| 1095 | fr.env[instr] = fr.makeInterfaceFromPointer(ptr, instr.X.Type(), instr.Type()) |
| 1096 | } else { |
| 1097 | receiver := fr.llvmvalue(instr.X) |
| 1098 | fr.env[instr] = fr.makeInterface(receiver, instr.X.Type(), instr.Type()) |
| 1099 | } |
| 1100 | |
| 1101 | case *ssa.MakeMap: |
| 1102 | fr.env[instr] = fr.makeMap(instr.Type(), fr.value(instr.Reserve)) |
| 1103 | |
| 1104 | case *ssa.MakeSlice: |
| 1105 | length := fr.value(instr.Len) |
| 1106 | capacity := fr.value(instr.Cap) |
| 1107 | fr.env[instr] = fr.makeSlice(instr.Type(), length, capacity) |
| 1108 | |
| 1109 | case *ssa.MapUpdate: |
| 1110 | m := fr.value(instr.Map) |
| 1111 | k := fr.value(instr.Key) |
| 1112 | v := fr.value(instr.Value) |
| 1113 | fr.mapUpdate(m, k, v) |
| 1114 | |
| 1115 | case *ssa.Next: |
| 1116 | iter := fr.tuples[instr.Iter] |
| 1117 | if instr.IsString { |
| 1118 | fr.tuples[instr] = fr.stringIterNext(iter) |
| 1119 | } else { |
| 1120 | fr.tuples[instr] = fr.mapIterNext(iter) |
| 1121 | } |
| 1122 | |
| 1123 | case *ssa.Panic: |
| 1124 | arg := fr.value(instr.X) |
Peter Collingbourne | b6edff9 | 2014-12-28 22:39:01 +0000 | [diff] [blame] | 1125 | fr.callPanic(arg, true) |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 1126 | |
| 1127 | case *ssa.Phi: |
| 1128 | typ := instr.Type() |
| 1129 | phi := fr.builder.CreatePHI(fr.llvmtypes.ToLLVM(typ), instr.Comment) |
| 1130 | fr.env[instr] = newValue(phi, typ) |
| 1131 | fr.phis = append(fr.phis, pendingPhi{instr, phi}) |
| 1132 | |
| 1133 | case *ssa.Range: |
| 1134 | x := fr.value(instr.X) |
| 1135 | switch x.Type().Underlying().(type) { |
| 1136 | case *types.Map: |
| 1137 | fr.tuples[instr] = fr.mapIterInit(x) |
| 1138 | case *types.Basic: // string |
| 1139 | fr.tuples[instr] = fr.stringIterInit(x) |
| 1140 | default: |
| 1141 | panic(fmt.Sprintf("unhandled range for type %T", x.Type())) |
| 1142 | } |
| 1143 | |
| 1144 | case *ssa.Return: |
| 1145 | vals := make([]llvm.Value, len(instr.Results)) |
| 1146 | for i, res := range instr.Results { |
| 1147 | vals[i] = fr.llvmvalue(res) |
| 1148 | } |
| 1149 | fr.retInf.encode(llvm.GlobalContext(), fr.allocaBuilder, fr.builder, vals) |
| 1150 | |
| 1151 | case *ssa.RunDefers: |
| 1152 | fr.runDefers() |
| 1153 | |
| 1154 | case *ssa.Select: |
| 1155 | states := make([]selectState, len(instr.States)) |
| 1156 | for i, state := range instr.States { |
| 1157 | states[i] = selectState{ |
| 1158 | Dir: state.Dir, |
| 1159 | Chan: fr.value(state.Chan), |
| 1160 | Send: fr.value(state.Send), |
| 1161 | } |
| 1162 | } |
| 1163 | index, recvOk, recvElems := fr.chanSelect(states, instr.Blocking) |
| 1164 | tuple := append([]*govalue{index, recvOk}, recvElems...) |
| 1165 | fr.tuples[instr] = tuple |
| 1166 | |
| 1167 | case *ssa.Send: |
| 1168 | fr.chanSend(fr.value(instr.Chan), fr.value(instr.X)) |
| 1169 | |
| 1170 | case *ssa.Slice: |
| 1171 | x := fr.llvmvalue(instr.X) |
| 1172 | low := fr.llvmvalue(instr.Low) |
| 1173 | high := fr.llvmvalue(instr.High) |
| 1174 | max := fr.llvmvalue(instr.Max) |
| 1175 | slice := fr.slice(x, instr.X.Type(), low, high, max) |
| 1176 | fr.env[instr] = newValue(slice, instr.Type()) |
| 1177 | |
| 1178 | case *ssa.Store: |
| 1179 | addr := fr.llvmvalue(instr.Addr) |
| 1180 | value := fr.llvmvalue(instr.Val) |
| 1181 | addr = fr.builder.CreateBitCast(addr, llvm.PointerType(value.Type(), 0), "") |
| 1182 | // If this is the init function, see if we can simulate the effect |
| 1183 | // of the store in a global's initializer, in which case we can avoid |
| 1184 | // generating code for it. |
| 1185 | if !fr.isInit || !fr.maybeStoreInInitializer(value, addr) { |
| 1186 | fr.nilCheck(instr.Addr, addr) |
| 1187 | fr.builder.CreateStore(value, addr) |
| 1188 | } |
| 1189 | |
| 1190 | case *ssa.TypeAssert: |
| 1191 | x := fr.value(instr.X) |
| 1192 | if instr.CommaOk { |
| 1193 | v, ok := fr.interfaceTypeCheck(x, instr.AssertedType) |
| 1194 | fr.tuples[instr] = []*govalue{v, ok} |
| 1195 | } else { |
| 1196 | fr.env[instr] = fr.interfaceTypeAssert(x, instr.AssertedType) |
| 1197 | } |
| 1198 | |
| 1199 | case *ssa.UnOp: |
| 1200 | operand := fr.value(instr.X) |
| 1201 | switch instr.Op { |
| 1202 | case token.ARROW: |
| 1203 | x, ok := fr.chanRecv(operand, instr.CommaOk) |
| 1204 | if instr.CommaOk { |
| 1205 | fr.tuples[instr] = []*govalue{x, ok} |
| 1206 | } else { |
| 1207 | fr.env[instr] = x |
| 1208 | } |
| 1209 | case token.MUL: |
| 1210 | fr.nilCheck(instr.X, operand.value) |
| 1211 | if !fr.canAvoidLoad(instr, operand.value) { |
| 1212 | // The bitcast is necessary to handle recursive pointer loads. |
| 1213 | llptr := fr.builder.CreateBitCast(operand.value, llvm.PointerType(fr.llvmtypes.ToLLVM(instr.Type()), 0), "") |
| 1214 | fr.env[instr] = newValue(fr.builder.CreateLoad(llptr, ""), instr.Type()) |
| 1215 | } |
| 1216 | default: |
| 1217 | fr.env[instr] = fr.unaryOp(operand, instr.Op) |
| 1218 | } |
| 1219 | |
| 1220 | default: |
| 1221 | panic(fmt.Sprintf("unhandled: %v", instr)) |
| 1222 | } |
| 1223 | } |
| 1224 | |
| 1225 | func (fr *frame) callBuiltin(typ types.Type, builtin *ssa.Builtin, args []ssa.Value) []*govalue { |
| 1226 | switch builtin.Name() { |
| 1227 | case "print", "println": |
| 1228 | llargs := make([]*govalue, len(args)) |
| 1229 | for i, arg := range args { |
| 1230 | llargs[i] = fr.value(arg) |
| 1231 | } |
| 1232 | fr.printValues(builtin.Name() == "println", llargs...) |
| 1233 | return nil |
| 1234 | |
| 1235 | case "panic": |
Peter Collingbourne | b6edff9 | 2014-12-28 22:39:01 +0000 | [diff] [blame] | 1236 | fr.callPanic(fr.value(args[0]), false) |
Peter Collingbourne | ad9841e | 2014-11-27 00:06:42 +0000 | [diff] [blame] | 1237 | return nil |
| 1238 | |
| 1239 | case "recover": |
| 1240 | return []*govalue{fr.callRecover(false)} |
| 1241 | |
| 1242 | case "append": |
| 1243 | return []*govalue{fr.callAppend(fr.value(args[0]), fr.value(args[1]))} |
| 1244 | |
| 1245 | case "close": |
| 1246 | fr.chanClose(fr.value(args[0])) |
| 1247 | return nil |
| 1248 | |
| 1249 | case "cap": |
| 1250 | return []*govalue{fr.callCap(fr.value(args[0]))} |
| 1251 | |
| 1252 | case "len": |
| 1253 | return []*govalue{fr.callLen(fr.value(args[0]))} |
| 1254 | |
| 1255 | case "copy": |
| 1256 | return []*govalue{fr.callCopy(fr.value(args[0]), fr.value(args[1]))} |
| 1257 | |
| 1258 | case "delete": |
| 1259 | fr.mapDelete(fr.value(args[0]), fr.value(args[1])) |
| 1260 | return nil |
| 1261 | |
| 1262 | case "real": |
| 1263 | return []*govalue{fr.extractRealValue(fr.value(args[0]))} |
| 1264 | |
| 1265 | case "imag": |
| 1266 | return []*govalue{fr.extractImagValue(fr.value(args[0]))} |
| 1267 | |
| 1268 | case "complex": |
| 1269 | r := fr.llvmvalue(args[0]) |
| 1270 | i := fr.llvmvalue(args[1]) |
| 1271 | cmplx := llvm.Undef(fr.llvmtypes.ToLLVM(typ)) |
| 1272 | cmplx = fr.builder.CreateInsertValue(cmplx, r, 0, "") |
| 1273 | cmplx = fr.builder.CreateInsertValue(cmplx, i, 1, "") |
| 1274 | return []*govalue{newValue(cmplx, typ)} |
| 1275 | |
| 1276 | case "ssa:wrapnilchk": |
| 1277 | ptr := fr.value(args[0]) |
| 1278 | fr.nilCheck(args[0], ptr.value) |
| 1279 | return []*govalue{ptr} |
| 1280 | |
| 1281 | default: |
| 1282 | panic("unimplemented: " + builtin.Name()) |
| 1283 | } |
| 1284 | } |
| 1285 | |
| 1286 | // callInstruction translates function call instructions. |
| 1287 | func (fr *frame) callInstruction(instr ssa.CallInstruction) []*govalue { |
| 1288 | call := instr.Common() |
| 1289 | if builtin, ok := call.Value.(*ssa.Builtin); ok { |
| 1290 | var typ types.Type |
| 1291 | if v := instr.Value(); v != nil { |
| 1292 | typ = v.Type() |
| 1293 | } |
| 1294 | return fr.callBuiltin(typ, builtin, call.Args) |
| 1295 | } |
| 1296 | |
| 1297 | args := make([]*govalue, len(call.Args)) |
| 1298 | for i, arg := range call.Args { |
| 1299 | args[i] = fr.value(arg) |
| 1300 | } |
| 1301 | |
| 1302 | var fn *govalue |
| 1303 | if call.IsInvoke() { |
| 1304 | var recv *govalue |
| 1305 | fn, recv = fr.interfaceMethod(fr.llvmvalue(call.Value), call.Value.Type(), call.Method) |
| 1306 | args = append([]*govalue{recv}, args...) |
| 1307 | } else { |
| 1308 | if ssafn, ok := call.Value.(*ssa.Function); ok { |
| 1309 | llfn := fr.resolveFunctionGlobal(ssafn) |
| 1310 | llfn = llvm.ConstBitCast(llfn, llvm.PointerType(llvm.Int8Type(), 0)) |
| 1311 | fn = newValue(llfn, ssafn.Type()) |
| 1312 | } else { |
| 1313 | // First-class function values are stored as *{*fnptr}, so |
| 1314 | // we must extract the function pointer. We must also |
| 1315 | // call __go_set_closure, in case the function is a closure. |
| 1316 | fn = fr.value(call.Value) |
| 1317 | fr.runtime.setClosure.call(fr, fn.value) |
| 1318 | fnptr := fr.builder.CreateBitCast(fn.value, llvm.PointerType(fn.value.Type(), 0), "") |
| 1319 | fnptr = fr.builder.CreateLoad(fnptr, "") |
| 1320 | fn = newValue(fnptr, fn.Type()) |
| 1321 | } |
| 1322 | if recv := call.Signature().Recv(); recv != nil { |
| 1323 | if _, ok := recv.Type().Underlying().(*types.Pointer); !ok { |
| 1324 | recvalloca := fr.allocaBuilder.CreateAlloca(args[0].value.Type(), "") |
| 1325 | fr.builder.CreateStore(args[0].value, recvalloca) |
| 1326 | args[0] = newValue(recvalloca, types.NewPointer(args[0].Type())) |
| 1327 | } |
| 1328 | } |
| 1329 | } |
| 1330 | return fr.createCall(fn, args) |
| 1331 | } |
| 1332 | |
| 1333 | func hasDefer(f *ssa.Function) bool { |
| 1334 | for _, b := range f.Blocks { |
| 1335 | for _, instr := range b.Instrs { |
| 1336 | if _, ok := instr.(*ssa.Defer); ok { |
| 1337 | return true |
| 1338 | } |
| 1339 | } |
| 1340 | } |
| 1341 | return false |
| 1342 | } |
| 1343 | |
| 1344 | func callsRecover(f *ssa.Function) bool { |
| 1345 | for _, b := range f.Blocks { |
| 1346 | for _, instr := range b.Instrs { |
| 1347 | if instr, ok := instr.(ssa.CallInstruction); ok { |
| 1348 | b, ok := instr.Common().Value.(*ssa.Builtin) |
| 1349 | if ok && b.Name() == "recover" { |
| 1350 | return true |
| 1351 | } |
| 1352 | } |
| 1353 | } |
| 1354 | } |
| 1355 | return false |
| 1356 | } |