github.com/goplus/llgo@v0.8.3/cl/compile.go (about) 1 /* 2 * Copyright (c) 2024 The GoPlus Authors (goplus.org). All rights reserved. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 package cl 18 19 import ( 20 "fmt" 21 "go/ast" 22 "go/constant" 23 "go/token" 24 "go/types" 25 "log" 26 "os" 27 "sort" 28 "strings" 29 30 llssa "github.com/goplus/llgo/ssa" 31 "golang.org/x/tools/go/ssa" 32 ) 33 34 // ----------------------------------------------------------------------------- 35 36 type dbgFlags = int 37 38 const ( 39 DbgFlagInstruction dbgFlags = 1 << iota 40 DbgFlagGoSSA 41 42 DbgFlagAll = DbgFlagInstruction | DbgFlagGoSSA 43 ) 44 45 var ( 46 debugInstr bool 47 debugGoSSA bool 48 ) 49 50 // SetDebug sets debug flags. 51 func SetDebug(dbgFlags dbgFlags) { 52 debugInstr = (dbgFlags & DbgFlagInstruction) != 0 53 debugGoSSA = (dbgFlags & DbgFlagGoSSA) != 0 54 } 55 56 // ----------------------------------------------------------------------------- 57 58 const ( 59 fnNormal = iota 60 fnHasVArg 61 fnIgnore 62 ) 63 64 func (p *context) funcKind(vfn ssa.Value) int { 65 if fn, ok := vfn.(*ssa.Function); ok { 66 params := fn.Signature.Params() 67 n := params.Len() 68 if n == 0 { 69 if fn.Signature.Recv() == nil { 70 if fn.Name() == "init" && p.pkgNoInit(fn.Pkg.Pkg) { 71 return fnIgnore 72 } 73 } 74 } else { 75 last := params.At(n - 1) 76 if last.Name() == llssa.NameValist { 77 return fnHasVArg 78 } 79 } 80 } 81 return fnNormal 82 } 83 84 func (p *context) pkgNoInit(pkg *types.Package) bool { 85 p.ensureLoaded(pkg) 86 if i, ok := p.loaded[pkg]; ok { 87 return i.kind >= PkgNoInit 88 } 89 return false 90 } 91 92 func ignoreName(name string) bool { 93 /* TODO(xsw): confirm this is not needed more 94 if name == "unsafe.init" { 95 return true 96 } 97 */ 98 if strings.HasPrefix(name, "internal/") || strings.HasPrefix(name, "crypto/") || 99 strings.HasPrefix(name, "arena.") || strings.HasPrefix(name, "maps.") || 100 strings.HasPrefix(name, "time.") || strings.HasPrefix(name, "syscall.") || 101 strings.HasPrefix(name, "os.") || strings.HasPrefix(name, "plugin.") || 102 strings.HasPrefix(name, "reflect.") || strings.HasPrefix(name, "errors.") { 103 return true // TODO(xsw) 104 } 105 return inPkg(name, "runtime") || inPkg(name, "sync") 106 } 107 108 func inPkg(name, pkg string) bool { 109 if len(name) > len(pkg) && strings.HasPrefix(name, pkg) { 110 c := name[len(pkg)] 111 return c == '.' || c == '/' 112 } 113 return false 114 } 115 116 // ----------------------------------------------------------------------------- 117 118 type instrOrValue interface { 119 ssa.Instruction 120 ssa.Value 121 } 122 123 const ( 124 PkgNormal = iota 125 PkgLLGo 126 PkgPyModule // py.<module> 127 PkgNoInit // noinit: a package that don't need to be initialized 128 PkgDeclOnly // decl: a package that only have declarations 129 PkgLinkIR // link llvm ir (.ll) 130 PkgLinkExtern // link external object (.a/.so/.dll/.dylib/etc.) 131 // PkgLinkBitCode // link bitcode (.bc) 132 ) 133 134 type pkgInfo struct { 135 kind int 136 } 137 138 type context struct { 139 prog llssa.Program 140 pkg llssa.Package 141 fn llssa.Function 142 fset *token.FileSet 143 goProg *ssa.Program 144 goTyps *types.Package 145 goPkg *ssa.Package 146 pyMod string 147 link map[string]string // pkgPath.nameInPkg => linkname 148 loaded map[*types.Package]*pkgInfo // loaded packages 149 bvals map[ssa.Value]llssa.Expr // block values 150 vargs map[*ssa.Alloc][]llssa.Expr // varargs 151 inits []func() 152 phis []func() 153 } 154 155 func (p *context) inMain(instr ssa.Instruction) bool { 156 return instr.Parent().Name() == "main" 157 } 158 159 func (p *context) compileType(pkg llssa.Package, t *ssa.Type) { 160 tn := t.Object().(*types.TypeName) 161 if tn.IsAlias() { // don't need to compile alias type 162 return 163 } 164 tnName := tn.Name() 165 typ := tn.Type() 166 name := llssa.FullName(tn.Pkg(), tnName) 167 if ignoreName(name) { 168 return 169 } 170 if debugInstr { 171 log.Println("==> NewType", name, typ) 172 } 173 p.compileMethods(pkg, typ) 174 p.compileMethods(pkg, types.NewPointer(typ)) 175 } 176 177 func (p *context) compileMethods(pkg llssa.Package, typ types.Type) { 178 prog := p.goProg 179 mthds := prog.MethodSets.MethodSet(typ) 180 for i, n := 0, mthds.Len(); i < n; i++ { 181 mthd := mthds.At(i) 182 if ssaMthd := prog.MethodValue(mthd); ssaMthd != nil { 183 p.compileFuncDecl(pkg, ssaMthd) 184 } 185 } 186 } 187 188 // Global variable. 189 func (p *context) compileGlobal(pkg llssa.Package, gbl *ssa.Global) { 190 typ := gbl.Type() 191 name, vtype := p.varName(gbl.Pkg.Pkg, gbl) 192 if vtype == pyVar || ignoreName(name) || checkCgo(gbl.Name()) { 193 return 194 } 195 if debugInstr { 196 log.Println("==> NewVar", name, typ) 197 } 198 g := pkg.NewVar(name, typ, llssa.Background(vtype)) 199 if vtype == goVar { 200 g.Init(p.prog.Null(g.Type)) 201 } 202 } 203 204 func makeClosureCtx(pkg *types.Package, vars []*ssa.FreeVar) *types.Var { 205 n := len(vars) 206 flds := make([]*types.Var, n) 207 for i, v := range vars { 208 flds[i] = types.NewField(token.NoPos, pkg, v.Name(), v.Type(), false) 209 } 210 t := types.NewPointer(types.NewStruct(flds, nil)) 211 return types.NewParam(token.NoPos, pkg, "__llgo_ctx", t) 212 } 213 214 var ( 215 argvTy = types.NewPointer(types.NewPointer(types.Typ[types.Int8])) 216 ) 217 218 func (p *context) compileFuncDecl(pkg llssa.Package, f *ssa.Function) (llssa.Function, llssa.PyObjRef, int) { 219 pkgTypes, name, ftype := p.funcName(f, true) 220 if ftype != goFunc { 221 /* 222 if ftype == pyFunc { 223 // TODO(xsw): pyMod == "" 224 fnName := pysymPrefix + p.pyMod + "." + name 225 return nil, pkg.NewPyFunc(fnName, f.Signature, call), pyFunc 226 } 227 */ 228 return nil, nil, ignoredFunc 229 } 230 fn := pkg.FuncOf(name) 231 if fn != nil && fn.HasBody() { 232 return fn, nil, goFunc 233 } 234 235 var sig = f.Signature 236 var hasCtx = len(f.FreeVars) > 0 237 if hasCtx { 238 if debugInstr { 239 log.Println("==> NewClosure", name, "type:", sig) 240 } 241 ctx := makeClosureCtx(pkgTypes, f.FreeVars) 242 sig = llssa.FuncAddCtx(ctx, sig) 243 } else { 244 if debugInstr { 245 log.Println("==> NewFunc", name, "type:", sig.Recv(), sig, "ftype:", ftype) 246 } 247 } 248 if fn == nil { 249 if name == "main" { 250 argc := types.NewParam(token.NoPos, pkgTypes, "", types.Typ[types.Int32]) 251 argv := types.NewParam(token.NoPos, pkgTypes, "", argvTy) 252 params := types.NewTuple(argc, argv) 253 ret := types.NewParam(token.NoPos, pkgTypes, "", p.prog.CInt().RawType()) 254 results := types.NewTuple(ret) 255 sig = types.NewSignatureType(nil, nil, nil, params, results, false) 256 } 257 fn = pkg.NewFuncEx(name, sig, llssa.Background(ftype), hasCtx) 258 } 259 260 if nblk := len(f.Blocks); nblk > 0 { 261 fn.MakeBlocks(nblk) // to set fn.HasBody() = true 262 p.inits = append(p.inits, func() { 263 p.fn = fn 264 defer func() { 265 p.fn = nil 266 }() 267 p.phis = nil 268 if debugGoSSA { 269 f.WriteTo(os.Stderr) 270 } 271 if debugInstr { 272 log.Println("==> FuncBody", name) 273 } 274 b := fn.NewBuilder() 275 p.bvals = make(map[ssa.Value]llssa.Expr) 276 off := make([]int, len(f.Blocks)) 277 for i, block := range f.Blocks { 278 off[i] = p.compilePhis(b, block) 279 } 280 for i, block := range f.Blocks { 281 doMainInit := (i == 0 && name == "main") 282 doModInit := (i == 1 && f.Name() == "init" && sig.Recv() == nil) 283 p.compileBlock(b, block, off[i], doMainInit, doModInit) 284 } 285 for _, phi := range p.phis { 286 phi() 287 } 288 }) 289 } 290 return fn, nil, goFunc 291 } 292 293 // funcOf returns a function by name and set ftype = goFunc, cFunc, etc. 294 // or returns nil and set ftype = llgoCstr, llgoAlloca, llgoUnreachable, etc. 295 func (p *context) funcOf(fn *ssa.Function) (aFn llssa.Function, pyFn llssa.PyObjRef, ftype int) { 296 pkgTypes, name, ftype := p.funcName(fn, false) 297 switch ftype { 298 case pyFunc: 299 if kind, mod := pkgKindByScope(pkgTypes.Scope()); kind == PkgPyModule { 300 pkg := p.pkg 301 fnName := pysymPrefix + mod + "." + name 302 if pyFn = pkg.PyObjOf(fnName); pyFn == nil { 303 pyFn = pkg.PyNewFunc(fnName, fn.Signature, true) 304 return 305 } 306 } 307 ftype = ignoredFunc 308 case llgoInstr: 309 switch name { 310 case "cstr": 311 ftype = llgoCstr 312 case "advance": 313 ftype = llgoAdvance 314 case "index": 315 ftype = llgoIndex 316 case "alloca": 317 ftype = llgoAlloca 318 case "allocaCStr": 319 ftype = llgoAllocaCStr 320 case "stringData": 321 ftype = llgoStringData 322 case "pyList": 323 ftype = llgoPyList 324 case "unreachable": 325 ftype = llgoUnreachable 326 default: 327 panic("unknown llgo instruction: " + name) 328 } 329 default: 330 pkg := p.pkg 331 if aFn = pkg.FuncOf(name); aFn == nil { 332 if len(fn.FreeVars) > 0 { 333 return nil, nil, ignoredFunc 334 } 335 sig := fn.Signature 336 aFn = pkg.NewFuncEx(name, sig, llssa.Background(ftype), false) 337 } 338 } 339 return 340 } 341 342 func modOf(name string) string { 343 if pos := strings.LastIndexByte(name, '.'); pos > 0 { 344 return name[:pos] 345 } 346 return "" 347 } 348 349 func (p *context) compileBlock(b llssa.Builder, block *ssa.BasicBlock, n int, doMainInit, doModInit bool) llssa.BasicBlock { 350 var last int 351 var pyModInit bool 352 var prog = p.prog 353 var pkg = p.pkg 354 var instrs = block.Instrs[n:] 355 var ret = p.fn.Block(block.Index) 356 b.SetBlock(ret) 357 if doModInit { 358 if pyModInit = p.pyMod != ""; pyModInit { 359 last = len(instrs) - 1 360 instrs = instrs[:last] 361 } else { 362 // TODO(xsw): confirm pyMod don't need to call LoadPyModSyms 363 p.inits = append(p.inits, func() { 364 if objs := pkg.PyObjs(); len(objs) > 0 { 365 mods := make(map[string][]llssa.PyObjRef) 366 for name, obj := range objs { 367 modName := modOf(name) 368 mods[modName] = append(mods[modName], obj) 369 } 370 371 // sort by module name 372 modNames := make([]string, 0, len(mods)) 373 for modName := range mods { 374 modNames = append(modNames, modName) 375 } 376 sort.Strings(modNames) 377 378 b.SetBlockEx(ret, llssa.AfterInit) 379 for _, modName := range modNames { 380 objs := mods[modName] 381 b.PyLoadModSyms(modName, objs...) 382 } 383 } 384 }) 385 } 386 } else if doMainInit { 387 fn := p.fn 388 argc := pkg.NewVar("__llgo_argc", types.NewPointer(types.Typ[types.Int32]), llssa.InC) 389 argv := pkg.NewVar("__llgo_argv", types.NewPointer(argvTy), llssa.InC) 390 argc.Init(prog.Null(argc.Type)) 391 argv.Init(prog.Null(argv.Type)) 392 b.Store(argc.Expr, fn.Param(0)) 393 b.Store(argv.Expr, fn.Param(1)) 394 callRuntimeInit(b, pkg) 395 b.Call(pkg.FuncOf("main.init").Expr) 396 } 397 for _, instr := range instrs { 398 p.compileInstr(b, instr) 399 } 400 if pyModInit { 401 jump := block.Instrs[n+last].(*ssa.Jump) 402 jumpTo := p.jumpTo(jump) 403 modPath := p.pyMod 404 modName := pysymPrefix + modPath 405 modPtr := pkg.PyNewModVar(modName, true).Expr 406 mod := b.Load(modPtr) 407 cond := b.BinOp(token.NEQ, mod, prog.Null(mod.Type)) 408 newBlk := p.fn.MakeBlock() 409 b.If(cond, jumpTo, newBlk) 410 b.SetBlock(newBlk) 411 b.Store(modPtr, b.PyImportMod(modPath)) 412 b.Jump(jumpTo) 413 } 414 return ret 415 } 416 417 const ( 418 RuntimeInit = llssa.PkgRuntime + ".init" 419 ) 420 421 func callRuntimeInit(b llssa.Builder, pkg llssa.Package) { 422 fn := pkg.NewFunc(RuntimeInit, llssa.NoArgsNoRet, llssa.InC) // don't need to convert runtime.init 423 b.Call(fn.Expr) 424 } 425 426 func isAny(t types.Type) bool { 427 if t, ok := t.(*types.Interface); ok { 428 return t.Empty() 429 } 430 return false 431 } 432 433 func intVal(v ssa.Value) int64 { 434 if c, ok := v.(*ssa.Const); ok { 435 if iv, exact := constant.Int64Val(c.Value); exact { 436 return iv 437 } 438 } 439 panic("intVal: ssa.Value is not a const int") 440 } 441 442 func (p *context) isVArgs(vx ssa.Value) (ret []llssa.Expr, ok bool) { 443 if va, vok := vx.(*ssa.Alloc); vok { 444 ret, ok = p.vargs[va] // varargs: this is a varargs index 445 } 446 return 447 } 448 449 func (p *context) checkVArgs(v *ssa.Alloc, t *types.Pointer) bool { 450 if v.Comment == "varargs" { // this maybe a varargs allocation 451 if arr, ok := t.Elem().(*types.Array); ok { 452 if isAny(arr.Elem()) && isVargs(p, v) { 453 p.vargs[v] = make([]llssa.Expr, arr.Len()) 454 return true 455 } 456 } 457 } 458 return false 459 } 460 461 func isVargs(ctx *context, v *ssa.Alloc) bool { 462 refs := *v.Referrers() 463 n := len(refs) 464 lastref := refs[n-1] 465 if i, ok := lastref.(*ssa.Slice); ok { 466 if refs = *i.Referrers(); len(refs) == 1 { 467 if call, ok := refs[0].(*ssa.Call); ok { 468 return ctx.funcKind(call.Call.Value) == fnHasVArg 469 } 470 } 471 } 472 return false 473 } 474 475 // func cstr(string) *int8 476 func cstr(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) { 477 if len(args) == 1 { 478 if c, ok := args[0].(*ssa.Const); ok { 479 if v := c.Value; v.Kind() == constant.String { 480 sv := constant.StringVal(v) 481 return b.CStr(sv) 482 } 483 } 484 } 485 panic("cstr(<string-literal>): invalid arguments") 486 } 487 488 // func index(arr *T, idx int) T 489 func (p *context) index(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) { 490 return b.Load(p.advance(b, args)) 491 } 492 493 // func advance(ptr *T, offset int) *T 494 func (p *context) advance(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) { 495 if len(args) == 2 { 496 ptr := p.compileValue(b, args[0]) 497 offset := p.compileValue(b, args[1]) 498 return b.Advance(ptr, offset) 499 } 500 panic("advance(p ptr, offset int): invalid arguments") 501 } 502 503 // func alloca(size uintptr) unsafe.Pointer 504 func (p *context) alloca(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) { 505 if len(args) == 1 { 506 n := p.compileValue(b, args[0]) 507 return b.Alloca(n) 508 } 509 panic("alloca(size uintptr): invalid arguments") 510 } 511 512 // func allocaCStr(s string) *int8 513 func (p *context) allocaCStr(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) { 514 if len(args) == 1 { 515 s := p.compileValue(b, args[0]) 516 return b.AllocaCStr(s) 517 } 518 panic("allocaCStr(s string): invalid arguments") 519 } 520 521 // func stringData(s string) *int8 522 func (p *context) stringData(b llssa.Builder, args []ssa.Value) (ret llssa.Expr) { 523 if len(args) == 1 { 524 s := p.compileValue(b, args[0]) 525 return b.StringData(s) 526 } 527 panic("stringData(s string): invalid arguments") 528 } 529 530 func isPhi(i ssa.Instruction) bool { 531 _, ok := i.(*ssa.Phi) 532 return ok 533 } 534 535 func (p *context) compilePhis(b llssa.Builder, block *ssa.BasicBlock) int { 536 ret := p.fn.Block(block.Index) 537 b.SetBlockEx(ret, llssa.AtEnd) 538 if ninstr := len(block.Instrs); ninstr > 0 { 539 if isPhi(block.Instrs[0]) { 540 n := 1 541 for n < ninstr && isPhi(block.Instrs[n]) { 542 n++ 543 } 544 rets := make([]llssa.Expr, n) 545 for i := 0; i < n; i++ { 546 iv := block.Instrs[i].(*ssa.Phi) 547 rets[i] = p.compilePhi(b, iv) 548 } 549 for i := 0; i < n; i++ { 550 iv := block.Instrs[i].(*ssa.Phi) 551 p.bvals[iv] = rets[i].Do(b) 552 } 553 return n 554 } 555 } 556 return 0 557 } 558 559 func (p *context) compilePhi(b llssa.Builder, v *ssa.Phi) (ret llssa.Expr) { 560 phi := b.Phi(p.prog.Type(v.Type(), llssa.InGo)) 561 ret = phi.Expr 562 p.phis = append(p.phis, func() { 563 preds := v.Block().Preds 564 bblks := make([]llssa.BasicBlock, len(preds)) 565 for i, pred := range preds { 566 bblks[i] = p.fn.Block(pred.Index) 567 } 568 edges := v.Edges 569 phi.AddIncoming(b, bblks, func(i int) llssa.Expr { 570 return p.compileValue(b, edges[i]) 571 }) 572 }) 573 return 574 } 575 576 func (p *context) compileInstrOrValue(b llssa.Builder, iv instrOrValue, asValue bool) (ret llssa.Expr) { 577 if asValue { 578 if v, ok := p.bvals[iv]; ok { 579 return v 580 } 581 log.Panicln("unreachable:", iv) 582 } 583 switch v := iv.(type) { 584 case *ssa.Call: 585 cv := v.Call.Value 586 kind := p.funcKind(cv) 587 if kind == fnIgnore { 588 return 589 } 590 args := v.Call.Args 591 if debugGoSSA { 592 log.Println(">>> Call", cv, args) 593 } 594 switch cv := cv.(type) { 595 case *ssa.Builtin: 596 fn := cv.Name() 597 if fn == "ssa:wrapnilchk" { // TODO(xsw): check nil ptr 598 arg := args[0] 599 ret = p.compileValue(b, arg) 600 // log.Println("wrapnilchk:", ret.TypeOf()) 601 } else { 602 args := p.compileValues(b, args, kind) 603 ret = b.BuiltinCall(fn, args...) 604 } 605 case *ssa.Function: 606 aFn, pyFn, ftype := p.compileFunction(cv) 607 switch ftype { 608 case goFunc, cFunc: 609 args := p.compileValues(b, args, kind) 610 ret = b.Call(aFn.Expr, args...) 611 case pyFunc: 612 args := p.compileValues(b, args, kind) 613 ret = b.Call(pyFn.Expr, args...) 614 case llgoPyList: 615 args := p.compileValues(b, args, fnHasVArg) 616 ret = b.PyList(args...) 617 case llgoCstr: 618 ret = cstr(b, args) 619 case llgoAdvance: 620 ret = p.advance(b, args) 621 case llgoIndex: 622 ret = p.index(b, args) 623 case llgoAlloca: 624 ret = p.alloca(b, args) 625 case llgoAllocaCStr: 626 ret = p.allocaCStr(b, args) 627 case llgoStringData: 628 ret = p.stringData(b, args) 629 case llgoUnreachable: // func unreachable() 630 b.Unreachable() 631 default: 632 panic("todo") 633 } 634 default: 635 fn := p.compileValue(b, cv) 636 args := p.compileValues(b, args, kind) 637 ret = b.Call(fn, args...) 638 } 639 case *ssa.BinOp: 640 x := p.compileValue(b, v.X) 641 y := p.compileValue(b, v.Y) 642 ret = b.BinOp(v.Op, x, y) 643 case *ssa.UnOp: 644 x := p.compileValue(b, v.X) 645 ret = b.UnOp(v.Op, x) 646 case *ssa.ChangeType: 647 t := v.Type() 648 x := p.compileValue(b, v.X) 649 ret = b.ChangeType(p.prog.Type(t, llssa.InGo), x) 650 case *ssa.Convert: 651 t := v.Type() 652 x := p.compileValue(b, v.X) 653 ret = b.Convert(p.prog.Type(t, llssa.InGo), x) 654 case *ssa.FieldAddr: 655 x := p.compileValue(b, v.X) 656 ret = b.FieldAddr(x, v.Field) 657 case *ssa.Alloc: 658 t := v.Type().(*types.Pointer) 659 if p.checkVArgs(v, t) { // varargs: this maybe a varargs allocation 660 return 661 } 662 elem := p.prog.Type(t.Elem(), llssa.InGo) 663 ret = b.Alloc(elem, v.Heap) 664 case *ssa.IndexAddr: 665 vx := v.X 666 if _, ok := p.isVArgs(vx); ok { // varargs: this is a varargs index 667 return 668 } 669 x := p.compileValue(b, vx) 670 idx := p.compileValue(b, v.Index) 671 ret = b.IndexAddr(x, idx) 672 case *ssa.Index: 673 x := p.compileValue(b, v.X) 674 idx := p.compileValue(b, v.Index) 675 ret = b.Index(x, idx, func(e llssa.Expr) (ret llssa.Expr) { 676 if e == x { 677 if n, ok := v.X.(*ssa.UnOp); ok { 678 return p.compileValue(b, n.X) 679 } 680 } 681 panic(fmt.Errorf("todo: addr of %v", e)) 682 }) 683 case *ssa.Lookup: 684 x := p.compileValue(b, v.X) 685 idx := p.compileValue(b, v.Index) 686 ret = b.Lookup(x, idx, v.CommaOk) 687 case *ssa.Slice: 688 vx := v.X 689 if _, ok := p.isVArgs(vx); ok { // varargs: this is a varargs slice 690 return 691 } 692 var low, high, max llssa.Expr 693 x := p.compileValue(b, vx) 694 if v.Low != nil { 695 low = p.compileValue(b, v.Low) 696 } 697 if v.High != nil { 698 high = p.compileValue(b, v.High) 699 } 700 if v.Max != nil { 701 max = p.compileValue(b, v.Max) 702 } 703 ret = b.Slice(x, low, high, max) 704 case *ssa.MakeInterface: 705 if refs := *v.Referrers(); len(refs) == 1 { 706 if ref, ok := refs[0].(*ssa.Store); ok { 707 if va, ok := ref.Addr.(*ssa.IndexAddr); ok { 708 if _, ok = p.isVArgs(va.X); ok { // varargs: this is a varargs store 709 return 710 } 711 } 712 } 713 } 714 t := p.prog.Type(v.Type(), llssa.InGo) 715 x := p.compileValue(b, v.X) 716 ret = b.MakeInterface(t, x) 717 case *ssa.MakeSlice: 718 var nCap llssa.Expr 719 t := p.prog.Type(v.Type(), llssa.InGo) 720 nLen := p.compileValue(b, v.Len) 721 if v.Cap != nil { 722 nCap = p.compileValue(b, v.Cap) 723 } 724 ret = b.MakeSlice(t, nLen, nCap) 725 case *ssa.MakeMap: 726 var nReserve llssa.Expr 727 t := p.prog.Type(v.Type(), llssa.InGo) 728 if v.Reserve != nil { 729 nReserve = p.compileValue(b, v.Reserve) 730 } 731 ret = b.MakeMap(t, nReserve) 732 case *ssa.MakeClosure: 733 fn := p.compileValue(b, v.Fn) 734 bindings := p.compileValues(b, v.Bindings, 0) 735 ret = b.MakeClosure(fn, bindings) 736 case *ssa.TypeAssert: 737 x := p.compileValue(b, v.X) 738 t := p.prog.Type(v.AssertedType, llssa.InGo) 739 ret = b.TypeAssert(x, t, v.CommaOk) 740 case *ssa.Extract: 741 x := p.compileValue(b, v.Tuple) 742 ret = b.Extract(x, v.Index) 743 default: 744 panic(fmt.Sprintf("compileInstrAndValue: unknown instr - %T\n", iv)) 745 } 746 p.bvals[iv] = ret 747 return ret 748 } 749 750 func (p *context) jumpTo(v *ssa.Jump) llssa.BasicBlock { 751 fn := p.fn 752 succs := v.Block().Succs 753 return fn.Block(succs[0].Index) 754 } 755 756 func (p *context) compileInstr(b llssa.Builder, instr ssa.Instruction) { 757 if iv, ok := instr.(instrOrValue); ok { 758 p.compileInstrOrValue(b, iv, false) 759 return 760 } 761 switch v := instr.(type) { 762 case *ssa.Store: 763 va := v.Addr 764 if va, ok := va.(*ssa.IndexAddr); ok { 765 if args, ok := p.isVArgs(va.X); ok { // varargs: this is a varargs store 766 idx := intVal(va.Index) 767 val := v.Val 768 if vi, ok := val.(*ssa.MakeInterface); ok { 769 val = vi.X 770 } 771 args[idx] = p.compileValue(b, val) 772 return 773 } 774 } 775 ptr := p.compileValue(b, va) 776 val := p.compileValue(b, v.Val) 777 b.Store(ptr, val) 778 case *ssa.Jump: 779 jmpb := p.jumpTo(v) 780 b.Jump(jmpb) 781 case *ssa.Return: 782 var results []llssa.Expr 783 if n := len(v.Results); n > 0 { 784 results = make([]llssa.Expr, n) 785 for i, r := range v.Results { 786 results[i] = p.compileValue(b, r) 787 } 788 } 789 if p.inMain(instr) { 790 results = make([]llssa.Expr, 1) 791 results[0] = p.prog.IntVal(0, p.prog.CInt()) 792 } 793 b.Return(results...) 794 case *ssa.If: 795 fn := p.fn 796 cond := p.compileValue(b, v.Cond) 797 succs := v.Block().Succs 798 thenb := fn.Block(succs[0].Index) 799 elseb := fn.Block(succs[1].Index) 800 b.If(cond, thenb, elseb) 801 case *ssa.MapUpdate: 802 m := p.compileValue(b, v.Map) 803 key := p.compileValue(b, v.Key) 804 val := p.compileValue(b, v.Value) 805 b.MapUpdate(m, key, val) 806 case *ssa.Panic: 807 arg := p.compileValue(b, v.X).Do(b) 808 b.Panic(arg) 809 default: 810 panic(fmt.Sprintf("compileInstr: unknown instr - %T\n", instr)) 811 } 812 } 813 814 func (p *context) compileFunction(v *ssa.Function) (goFn llssa.Function, pyFn llssa.PyObjRef, kind int) { 815 // v.Pkg == nil: means auto generated function? 816 if v.Pkg == p.goPkg || v.Pkg == nil { 817 // function in this package 818 goFn, pyFn, kind = p.compileFuncDecl(p.pkg, v) 819 if kind != ignoredFunc { 820 return 821 } 822 } 823 return p.funcOf(v) 824 } 825 826 func (p *context) compileValue(b llssa.Builder, v ssa.Value) llssa.Expr { 827 if iv, ok := v.(instrOrValue); ok { 828 return p.compileInstrOrValue(b, iv, true) 829 } 830 switch v := v.(type) { 831 case *ssa.Parameter: 832 fn := v.Parent() 833 for idx, param := range fn.Params { 834 if param == v { 835 return p.fn.Param(idx) 836 } 837 } 838 case *ssa.Function: 839 aFn, pyFn, _ := p.compileFunction(v) 840 if aFn != nil { 841 return aFn.Expr 842 } 843 return pyFn.Expr 844 case *ssa.Global: 845 return p.varOf(b, v) 846 case *ssa.Const: 847 t := types.Default(v.Type()) 848 return b.Const(v.Value, p.prog.Type(t, llssa.InGo)) 849 case *ssa.FreeVar: 850 fn := v.Parent() 851 for idx, freeVar := range fn.FreeVars { 852 if freeVar == v { 853 return p.fn.FreeVar(b, idx) 854 } 855 } 856 } 857 panic(fmt.Sprintf("compileValue: unknown value - %T\n", v)) 858 } 859 860 func (p *context) compileVArg(ret []llssa.Expr, b llssa.Builder, v ssa.Value) []llssa.Expr { 861 _ = b 862 switch v := v.(type) { 863 case *ssa.Slice: // varargs: this is a varargs slice 864 if args, ok := p.isVArgs(v.X); ok { 865 return append(ret, args...) 866 } 867 case *ssa.Const: 868 if v.Value == nil { 869 return ret 870 } 871 } 872 panic(fmt.Sprintf("compileVArg: unknown value - %T\n", v)) 873 } 874 875 func (p *context) compileValues(b llssa.Builder, vals []ssa.Value, hasVArg int) []llssa.Expr { 876 n := len(vals) - hasVArg 877 ret := make([]llssa.Expr, n) 878 for i := 0; i < n; i++ { 879 ret[i] = p.compileValue(b, vals[i]).Do(b) 880 } 881 if hasVArg > 0 { 882 ret = p.compileVArg(ret, b, vals[n]) 883 } 884 return ret 885 } 886 887 // ----------------------------------------------------------------------------- 888 889 // NewPackage compiles a Go package to LLVM IR package. 890 func NewPackage(prog llssa.Program, pkg *ssa.Package, files []*ast.File) (ret llssa.Package, err error) { 891 type namedMember struct { 892 name string 893 val ssa.Member 894 } 895 896 members := make([]*namedMember, 0, len(pkg.Members)) 897 for name, v := range pkg.Members { 898 members = append(members, &namedMember{name, v}) 899 } 900 sort.Slice(members, func(i, j int) bool { 901 return members[i].name < members[j].name 902 }) 903 904 pkgProg := pkg.Prog 905 pkgTypes := pkg.Pkg 906 pkgName, pkgPath := pkgTypes.Name(), llssa.PathOf(pkgTypes) 907 if pkgPath == llssa.PkgRuntime { 908 prog.SetRuntime(pkgTypes) 909 } 910 ret = prog.NewPackage(pkgName, pkgPath) 911 912 ctx := &context{ 913 prog: prog, 914 pkg: ret, 915 fset: pkgProg.Fset, 916 goProg: pkgProg, 917 goTyps: pkgTypes, 918 goPkg: pkg, 919 link: make(map[string]string), 920 vargs: make(map[*ssa.Alloc][]llssa.Expr), 921 loaded: map[*types.Package]*pkgInfo{ 922 types.Unsafe: {kind: PkgDeclOnly}, // TODO(xsw): PkgNoInit or PkgDeclOnly? 923 }, 924 } 925 ctx.initPyModule() 926 ctx.initFiles(pkgPath, files) 927 for _, m := range members { 928 member := m.val 929 switch member := member.(type) { 930 case *ssa.Function: 931 if member.TypeParams() != nil || member.TypeArgs() != nil { 932 // TODO(xsw): don't compile generic functions 933 // Do not try to build generic (non-instantiated) functions. 934 continue 935 } 936 ctx.compileFuncDecl(ret, member) 937 case *ssa.Type: 938 ctx.compileType(ret, member) 939 case *ssa.Global: 940 ctx.compileGlobal(ret, member) 941 } 942 } 943 for len(ctx.inits) > 0 { 944 inits := ctx.inits 945 ctx.inits = nil 946 for _, ini := range inits { 947 ini() 948 } 949 } 950 return 951 } 952 953 // -----------------------------------------------------------------------------