github.com/tetratelabs/wazero@v1.7.3-0.20240513003603-48f702e154b5/internal/engine/wazevo/ssa/builder.go (about) 1 package ssa 2 3 import ( 4 "fmt" 5 "sort" 6 "strings" 7 8 "github.com/tetratelabs/wazero/internal/engine/wazevo/wazevoapi" 9 ) 10 11 // Builder is used to builds SSA consisting of Basic Blocks per function. 12 type Builder interface { 13 // Init must be called to reuse this builder for the next function. 14 Init(typ *Signature) 15 16 // Signature returns the Signature of the currently-compiled function. 17 Signature() *Signature 18 19 // BlockIDMax returns the maximum value of BasicBlocksID existing in the currently-compiled function. 20 BlockIDMax() BasicBlockID 21 22 // AllocateBasicBlock creates a basic block in SSA function. 23 AllocateBasicBlock() BasicBlock 24 25 // CurrentBlock returns the currently handled BasicBlock which is set by the latest call to SetCurrentBlock. 26 CurrentBlock() BasicBlock 27 28 // EntryBlock returns the entry BasicBlock of the currently-compiled function. 29 EntryBlock() BasicBlock 30 31 // SetCurrentBlock sets the instruction insertion target to the BasicBlock `b`. 32 SetCurrentBlock(b BasicBlock) 33 34 // DeclareVariable declares a Variable of the given Type. 35 DeclareVariable(Type) Variable 36 37 // DefineVariable defines a variable in the `block` with value. 38 // The defining instruction will be inserted into the `block`. 39 DefineVariable(variable Variable, value Value, block BasicBlock) 40 41 // DefineVariableInCurrentBB is the same as DefineVariable except the definition is 42 // inserted into the current BasicBlock. Alias to DefineVariable(x, y, CurrentBlock()). 43 DefineVariableInCurrentBB(variable Variable, value Value) 44 45 // AllocateInstruction returns a new Instruction. 46 AllocateInstruction() *Instruction 47 48 // InsertInstruction executes BasicBlock.InsertInstruction for the currently handled basic block. 49 InsertInstruction(raw *Instruction) 50 51 // allocateValue allocates an unused Value. 52 allocateValue(typ Type) Value 53 54 // MustFindValue searches the latest definition of the given Variable and returns the result. 55 MustFindValue(variable Variable) Value 56 57 // MustFindValueInBlk is the same as MustFindValue except it searches the latest definition from the given BasicBlock. 58 MustFindValueInBlk(variable Variable, blk BasicBlock) Value 59 60 // FindValueInLinearPath tries to find the latest definition of the given Variable in the linear path to the current BasicBlock. 61 // If it cannot find the definition, or it's not sealed yet, it returns ValueInvalid. 62 FindValueInLinearPath(variable Variable) Value 63 64 // Seal declares that we've known all the predecessors to this block and were added via AddPred. 65 // After calling this, AddPred will be forbidden. 66 Seal(blk BasicBlock) 67 68 // AnnotateValue is for debugging purpose. 69 AnnotateValue(value Value, annotation string) 70 71 // DeclareSignature appends the *Signature to be referenced by various instructions (e.g. OpcodeCall). 72 DeclareSignature(signature *Signature) 73 74 // Signatures returns the slice of declared Signatures. 75 Signatures() []*Signature 76 77 // ResolveSignature returns the Signature which corresponds to SignatureID. 78 ResolveSignature(id SignatureID) *Signature 79 80 // RunPasses runs various passes on the constructed SSA function. 81 RunPasses() 82 83 // Format returns the debugging string of the SSA function. 84 Format() string 85 86 // BlockIteratorBegin initializes the state to iterate over all the valid BasicBlock(s) compiled. 87 // Combined with BlockIteratorNext, we can use this like: 88 // 89 // for blk := builder.BlockIteratorBegin(); blk != nil; blk = builder.BlockIteratorNext() { 90 // // ... 91 // } 92 // 93 // The returned blocks are ordered in the order of AllocateBasicBlock being called. 94 BlockIteratorBegin() BasicBlock 95 96 // BlockIteratorNext advances the state for iteration initialized by BlockIteratorBegin. 97 // Returns nil if there's no unseen BasicBlock. 98 BlockIteratorNext() BasicBlock 99 100 // ValueRefCounts returns the map of ValueID to its reference count. 101 // The returned slice must not be modified. 102 ValueRefCounts() []int 103 104 // BlockIteratorReversePostOrderBegin is almost the same as BlockIteratorBegin except it returns the BasicBlock in the reverse post-order. 105 // This is available after RunPasses is run. 106 BlockIteratorReversePostOrderBegin() BasicBlock 107 108 // BlockIteratorReversePostOrderNext is almost the same as BlockIteratorPostOrderNext except it returns the BasicBlock in the reverse post-order. 109 // This is available after RunPasses is run. 110 BlockIteratorReversePostOrderNext() BasicBlock 111 112 // ReturnBlock returns the BasicBlock which is used to return from the function. 113 ReturnBlock() BasicBlock 114 115 // InsertUndefined inserts an undefined instruction at the current position. 116 InsertUndefined() 117 118 // SetCurrentSourceOffset sets the current source offset. The incoming instruction will be annotated with this offset. 119 SetCurrentSourceOffset(line SourceOffset) 120 121 // LoopNestingForestRoots returns the roots of the loop nesting forest. 122 LoopNestingForestRoots() []BasicBlock 123 124 // LowestCommonAncestor returns the lowest common ancestor in the dominator tree of the given BasicBlock(s). 125 LowestCommonAncestor(blk1, blk2 BasicBlock) BasicBlock 126 127 // Idom returns the immediate dominator of the given BasicBlock. 128 Idom(blk BasicBlock) BasicBlock 129 130 VarLengthPool() *wazevoapi.VarLengthPool[Value] 131 } 132 133 // NewBuilder returns a new Builder implementation. 134 func NewBuilder() Builder { 135 return &builder{ 136 instructionsPool: wazevoapi.NewPool[Instruction](resetInstruction), 137 basicBlocksPool: wazevoapi.NewPool[basicBlock](resetBasicBlock), 138 varLengthPool: wazevoapi.NewVarLengthPool[Value](), 139 valueAnnotations: make(map[ValueID]string), 140 signatures: make(map[SignatureID]*Signature), 141 blkVisited: make(map[*basicBlock]int), 142 valueIDAliases: make(map[ValueID]Value), 143 redundantParameterIndexToValue: make(map[int]Value), 144 returnBlk: &basicBlock{id: basicBlockIDReturnBlock}, 145 } 146 } 147 148 // builder implements Builder interface. 149 type builder struct { 150 basicBlocksPool wazevoapi.Pool[basicBlock] 151 instructionsPool wazevoapi.Pool[Instruction] 152 varLengthPool wazevoapi.VarLengthPool[Value] 153 signatures map[SignatureID]*Signature 154 currentSignature *Signature 155 156 // reversePostOrderedBasicBlocks are the BasicBlock(s) ordered in the reverse post-order after passCalculateImmediateDominators. 157 reversePostOrderedBasicBlocks []*basicBlock 158 currentBB *basicBlock 159 returnBlk *basicBlock 160 161 // variables track the types for Variable with the index regarded Variable. 162 variables []Type 163 // nextValueID is used by builder.AllocateValue. 164 nextValueID ValueID 165 // nextVariable is used by builder.AllocateVariable. 166 nextVariable Variable 167 168 valueIDAliases map[ValueID]Value 169 valueAnnotations map[ValueID]string 170 171 // valueRefCounts is used to lower the SSA in backend, and will be calculated 172 // by the last SSA-level optimization pass. 173 valueRefCounts []int 174 175 // dominators stores the immediate dominator of each BasicBlock. 176 // The index is blockID of the BasicBlock. 177 dominators []*basicBlock 178 sparseTree dominatorSparseTree 179 180 // loopNestingForestRoots are the roots of the loop nesting forest. 181 loopNestingForestRoots []BasicBlock 182 183 // The followings are used for optimization passes/deterministic compilation. 184 instStack []*Instruction 185 blkVisited map[*basicBlock]int 186 valueIDToInstruction []*Instruction 187 blkStack []*basicBlock 188 blkStack2 []*basicBlock 189 ints []int 190 redundantParameterIndexToValue map[int]Value 191 192 // blockIterCur is used to implement blockIteratorBegin and blockIteratorNext. 193 blockIterCur int 194 195 // donePreBlockLayoutPasses is true if all the passes before LayoutBlocks are called. 196 donePreBlockLayoutPasses bool 197 // doneBlockLayout is true if LayoutBlocks is called. 198 doneBlockLayout bool 199 // donePostBlockLayoutPasses is true if all the passes after LayoutBlocks are called. 200 donePostBlockLayoutPasses bool 201 202 currentSourceOffset SourceOffset 203 } 204 205 func (b *builder) VarLengthPool() *wazevoapi.VarLengthPool[Value] { 206 return &b.varLengthPool 207 } 208 209 // ReturnBlock implements Builder.ReturnBlock. 210 func (b *builder) ReturnBlock() BasicBlock { 211 return b.returnBlk 212 } 213 214 // Init implements Builder.Reset. 215 func (b *builder) Init(s *Signature) { 216 b.nextVariable = 0 217 b.currentSignature = s 218 resetBasicBlock(b.returnBlk) 219 b.instructionsPool.Reset() 220 b.basicBlocksPool.Reset() 221 b.varLengthPool.Reset() 222 b.donePreBlockLayoutPasses = false 223 b.doneBlockLayout = false 224 b.donePostBlockLayoutPasses = false 225 for _, sig := range b.signatures { 226 sig.used = false 227 } 228 229 b.ints = b.ints[:0] 230 b.blkStack = b.blkStack[:0] 231 b.blkStack2 = b.blkStack2[:0] 232 b.dominators = b.dominators[:0] 233 b.loopNestingForestRoots = b.loopNestingForestRoots[:0] 234 235 for i := 0; i < b.basicBlocksPool.Allocated(); i++ { 236 blk := b.basicBlocksPool.View(i) 237 delete(b.blkVisited, blk) 238 } 239 b.basicBlocksPool.Reset() 240 241 for v := ValueID(0); v < b.nextValueID; v++ { 242 delete(b.valueAnnotations, v) 243 delete(b.valueIDAliases, v) 244 b.valueRefCounts[v] = 0 245 b.valueIDToInstruction[v] = nil 246 } 247 b.nextValueID = 0 248 b.reversePostOrderedBasicBlocks = b.reversePostOrderedBasicBlocks[:0] 249 b.doneBlockLayout = false 250 for i := range b.valueRefCounts { 251 b.valueRefCounts[i] = 0 252 } 253 254 b.currentSourceOffset = sourceOffsetUnknown 255 } 256 257 // Signature implements Builder.Signature. 258 func (b *builder) Signature() *Signature { 259 return b.currentSignature 260 } 261 262 // AnnotateValue implements Builder.AnnotateValue. 263 func (b *builder) AnnotateValue(value Value, a string) { 264 b.valueAnnotations[value.ID()] = a 265 } 266 267 // AllocateInstruction implements Builder.AllocateInstruction. 268 func (b *builder) AllocateInstruction() *Instruction { 269 instr := b.instructionsPool.Allocate() 270 instr.id = b.instructionsPool.Allocated() 271 return instr 272 } 273 274 // DeclareSignature implements Builder.AnnotateValue. 275 func (b *builder) DeclareSignature(s *Signature) { 276 b.signatures[s.ID] = s 277 s.used = false 278 } 279 280 // Signatures implements Builder.Signatures. 281 func (b *builder) Signatures() (ret []*Signature) { 282 for _, sig := range b.signatures { 283 ret = append(ret, sig) 284 } 285 sort.Slice(ret, func(i, j int) bool { 286 return ret[i].ID < ret[j].ID 287 }) 288 return 289 } 290 291 // SetCurrentSourceOffset implements Builder.SetCurrentSourceOffset. 292 func (b *builder) SetCurrentSourceOffset(l SourceOffset) { 293 b.currentSourceOffset = l 294 } 295 296 func (b *builder) usedSignatures() (ret []*Signature) { 297 for _, sig := range b.signatures { 298 if sig.used { 299 ret = append(ret, sig) 300 } 301 } 302 sort.Slice(ret, func(i, j int) bool { 303 return ret[i].ID < ret[j].ID 304 }) 305 return 306 } 307 308 // ResolveSignature implements Builder.ResolveSignature. 309 func (b *builder) ResolveSignature(id SignatureID) *Signature { 310 return b.signatures[id] 311 } 312 313 // AllocateBasicBlock implements Builder.AllocateBasicBlock. 314 func (b *builder) AllocateBasicBlock() BasicBlock { 315 return b.allocateBasicBlock() 316 } 317 318 // allocateBasicBlock allocates a new basicBlock. 319 func (b *builder) allocateBasicBlock() *basicBlock { 320 id := BasicBlockID(b.basicBlocksPool.Allocated()) 321 blk := b.basicBlocksPool.Allocate() 322 blk.id = id 323 return blk 324 } 325 326 // Idom implements Builder.Idom. 327 func (b *builder) Idom(blk BasicBlock) BasicBlock { 328 return b.dominators[blk.ID()] 329 } 330 331 // InsertInstruction implements Builder.InsertInstruction. 332 func (b *builder) InsertInstruction(instr *Instruction) { 333 b.currentBB.InsertInstruction(instr) 334 335 if l := b.currentSourceOffset; l.Valid() { 336 // Emit the source offset info only when the instruction has side effect because 337 // these are the only instructions that are accessed by stack unwinding. 338 // This reduces the significant amount of the offset info in the binary. 339 if instr.sideEffect() != sideEffectNone { 340 instr.annotateSourceOffset(l) 341 } 342 } 343 344 resultTypesFn := instructionReturnTypes[instr.opcode] 345 if resultTypesFn == nil { 346 panic("TODO: " + instr.Format(b)) 347 } 348 349 t1, ts := resultTypesFn(b, instr) 350 if t1.invalid() { 351 return 352 } 353 354 r1 := b.allocateValue(t1) 355 instr.rValue = r1 356 357 tsl := len(ts) 358 if tsl == 0 { 359 return 360 } 361 362 rValues := b.varLengthPool.Allocate(tsl) 363 for i := 0; i < tsl; i++ { 364 rValues = rValues.Append(&b.varLengthPool, b.allocateValue(ts[i])) 365 } 366 instr.rValues = rValues 367 } 368 369 // DefineVariable implements Builder.DefineVariable. 370 func (b *builder) DefineVariable(variable Variable, value Value, block BasicBlock) { 371 if b.variables[variable].invalid() { 372 panic("BUG: trying to define variable " + variable.String() + " but is not declared yet") 373 } 374 375 if b.variables[variable] != value.Type() { 376 panic(fmt.Sprintf("BUG: inconsistent type for variable %d: expected %s but got %s", variable, b.variables[variable], value.Type())) 377 } 378 bb := block.(*basicBlock) 379 bb.lastDefinitions[variable] = value 380 } 381 382 // DefineVariableInCurrentBB implements Builder.DefineVariableInCurrentBB. 383 func (b *builder) DefineVariableInCurrentBB(variable Variable, value Value) { 384 b.DefineVariable(variable, value, b.currentBB) 385 } 386 387 // SetCurrentBlock implements Builder.SetCurrentBlock. 388 func (b *builder) SetCurrentBlock(bb BasicBlock) { 389 b.currentBB = bb.(*basicBlock) 390 } 391 392 // CurrentBlock implements Builder.CurrentBlock. 393 func (b *builder) CurrentBlock() BasicBlock { 394 return b.currentBB 395 } 396 397 // EntryBlock implements Builder.EntryBlock. 398 func (b *builder) EntryBlock() BasicBlock { 399 return b.entryBlk() 400 } 401 402 // DeclareVariable implements Builder.DeclareVariable. 403 func (b *builder) DeclareVariable(typ Type) Variable { 404 v := b.allocateVariable() 405 iv := int(v) 406 if l := len(b.variables); l <= iv { 407 b.variables = append(b.variables, make([]Type, 2*(l+1))...) 408 } 409 b.variables[v] = typ 410 return v 411 } 412 413 // allocateVariable allocates a new variable. 414 func (b *builder) allocateVariable() (ret Variable) { 415 ret = b.nextVariable 416 b.nextVariable++ 417 return 418 } 419 420 // allocateValue implements Builder.AllocateValue. 421 func (b *builder) allocateValue(typ Type) (v Value) { 422 v = Value(b.nextValueID) 423 v = v.setType(typ) 424 b.nextValueID++ 425 return 426 } 427 428 // FindValueInLinearPath implements Builder.FindValueInLinearPath. 429 func (b *builder) FindValueInLinearPath(variable Variable) Value { 430 return b.findValueInLinearPath(variable, b.currentBB) 431 } 432 433 func (b *builder) findValueInLinearPath(variable Variable, blk *basicBlock) Value { 434 if val, ok := blk.lastDefinitions[variable]; ok { 435 return val 436 } else if !blk.sealed { 437 return ValueInvalid 438 } 439 440 if pred := blk.singlePred; pred != nil { 441 // If this block is sealed and have only one predecessor, 442 // we can use the value in that block without ambiguity on definition. 443 return b.findValueInLinearPath(variable, pred) 444 } 445 if len(blk.preds) == 1 { 446 panic("BUG") 447 } 448 return ValueInvalid 449 } 450 451 func (b *builder) MustFindValueInBlk(variable Variable, blk BasicBlock) Value { 452 typ := b.definedVariableType(variable) 453 return b.findValue(typ, variable, blk.(*basicBlock)) 454 } 455 456 // MustFindValue implements Builder.MustFindValue. 457 func (b *builder) MustFindValue(variable Variable) Value { 458 typ := b.definedVariableType(variable) 459 return b.findValue(typ, variable, b.currentBB) 460 } 461 462 // findValue recursively tries to find the latest definition of a `variable`. The algorithm is described in 463 // the section 2 of the paper https://link.springer.com/content/pdf/10.1007/978-3-642-37051-9_6.pdf. 464 // 465 // TODO: reimplement this in iterative, not recursive, to avoid stack overflow. 466 func (b *builder) findValue(typ Type, variable Variable, blk *basicBlock) Value { 467 if val, ok := blk.lastDefinitions[variable]; ok { 468 // The value is already defined in this block! 469 return val 470 } else if !blk.sealed { // Incomplete CFG as in the paper. 471 // If this is not sealed, that means it might have additional unknown predecessor later on. 472 // So we temporarily define the placeholder value here (not add as a parameter yet!), 473 // and record it as unknown. 474 // The unknown values are resolved when we call seal this block via BasicBlock.Seal(). 475 value := b.allocateValue(typ) 476 if wazevoapi.SSALoggingEnabled { 477 fmt.Printf("adding unknown value placeholder for %s at %d\n", variable, blk.id) 478 } 479 blk.lastDefinitions[variable] = value 480 blk.unknownValues = append(blk.unknownValues, unknownValue{ 481 variable: variable, 482 value: value, 483 }) 484 return value 485 } 486 487 if pred := blk.singlePred; pred != nil { 488 // If this block is sealed and have only one predecessor, 489 // we can use the value in that block without ambiguity on definition. 490 return b.findValue(typ, variable, pred) 491 } else if len(blk.preds) == 0 { 492 panic("BUG: value is not defined for " + variable.String()) 493 } 494 495 // If this block has multiple predecessors, we have to gather the definitions, 496 // and treat them as an argument to this block. 497 // 498 // The first thing is to define a new parameter to this block which may or may not be redundant, but 499 // later we eliminate trivial params in an optimization pass. This must be done before finding the 500 // definitions in the predecessors so that we can break the cycle. 501 paramValue := blk.AddParam(b, typ) 502 b.DefineVariable(variable, paramValue, blk) 503 504 // After the new param is added, we have to manipulate the original branching instructions 505 // in predecessors so that they would pass the definition of `variable` as the argument to 506 // the newly added PHI. 507 for i := range blk.preds { 508 pred := &blk.preds[i] 509 value := b.findValue(typ, variable, pred.blk) 510 pred.branch.addArgumentBranchInst(b, value) 511 } 512 return paramValue 513 } 514 515 // Seal implements Builder.Seal. 516 func (b *builder) Seal(raw BasicBlock) { 517 blk := raw.(*basicBlock) 518 if len(blk.preds) == 1 { 519 blk.singlePred = blk.preds[0].blk 520 } 521 blk.sealed = true 522 523 for _, v := range blk.unknownValues { 524 variable, phiValue := v.variable, v.value 525 typ := b.definedVariableType(variable) 526 blk.addParamOn(typ, phiValue) 527 for i := range blk.preds { 528 pred := &blk.preds[i] 529 predValue := b.findValue(typ, variable, pred.blk) 530 if !predValue.Valid() { 531 panic("BUG: value is not defined anywhere in the predecessors in the CFG") 532 } 533 pred.branch.addArgumentBranchInst(b, predValue) 534 } 535 } 536 } 537 538 // definedVariableType returns the type of the given variable. If the variable is not defined yet, it panics. 539 func (b *builder) definedVariableType(variable Variable) Type { 540 typ := b.variables[variable] 541 if typ.invalid() { 542 panic(fmt.Sprintf("%s is not defined yet", variable)) 543 } 544 return typ 545 } 546 547 // Format implements Builder.Format. 548 func (b *builder) Format() string { 549 str := strings.Builder{} 550 usedSigs := b.usedSignatures() 551 if len(usedSigs) > 0 { 552 str.WriteByte('\n') 553 str.WriteString("signatures:\n") 554 for _, sig := range usedSigs { 555 str.WriteByte('\t') 556 str.WriteString(sig.String()) 557 str.WriteByte('\n') 558 } 559 } 560 561 var iterBegin, iterNext func() *basicBlock 562 if b.doneBlockLayout { 563 iterBegin, iterNext = b.blockIteratorReversePostOrderBegin, b.blockIteratorReversePostOrderNext 564 } else { 565 iterBegin, iterNext = b.blockIteratorBegin, b.blockIteratorNext 566 } 567 for bb := iterBegin(); bb != nil; bb = iterNext() { 568 str.WriteByte('\n') 569 str.WriteString(bb.FormatHeader(b)) 570 str.WriteByte('\n') 571 572 for cur := bb.Root(); cur != nil; cur = cur.Next() { 573 str.WriteByte('\t') 574 str.WriteString(cur.Format(b)) 575 str.WriteByte('\n') 576 } 577 } 578 return str.String() 579 } 580 581 // BlockIteratorNext implements Builder.BlockIteratorNext. 582 func (b *builder) BlockIteratorNext() BasicBlock { 583 if blk := b.blockIteratorNext(); blk == nil { 584 return nil // BasicBlock((*basicBlock)(nil)) != BasicBlock(nil) 585 } else { 586 return blk 587 } 588 } 589 590 // BlockIteratorNext implements Builder.BlockIteratorNext. 591 func (b *builder) blockIteratorNext() *basicBlock { 592 index := b.blockIterCur 593 for { 594 if index == b.basicBlocksPool.Allocated() { 595 return nil 596 } 597 ret := b.basicBlocksPool.View(index) 598 index++ 599 if !ret.invalid { 600 b.blockIterCur = index 601 return ret 602 } 603 } 604 } 605 606 // BlockIteratorBegin implements Builder.BlockIteratorBegin. 607 func (b *builder) BlockIteratorBegin() BasicBlock { 608 return b.blockIteratorBegin() 609 } 610 611 // BlockIteratorBegin implements Builder.BlockIteratorBegin. 612 func (b *builder) blockIteratorBegin() *basicBlock { 613 b.blockIterCur = 0 614 return b.blockIteratorNext() 615 } 616 617 // BlockIteratorReversePostOrderBegin implements Builder.BlockIteratorReversePostOrderBegin. 618 func (b *builder) BlockIteratorReversePostOrderBegin() BasicBlock { 619 return b.blockIteratorReversePostOrderBegin() 620 } 621 622 // BlockIteratorBegin implements Builder.BlockIteratorBegin. 623 func (b *builder) blockIteratorReversePostOrderBegin() *basicBlock { 624 b.blockIterCur = 0 625 return b.blockIteratorReversePostOrderNext() 626 } 627 628 // BlockIteratorReversePostOrderNext implements Builder.BlockIteratorReversePostOrderNext. 629 func (b *builder) BlockIteratorReversePostOrderNext() BasicBlock { 630 if blk := b.blockIteratorReversePostOrderNext(); blk == nil { 631 return nil // BasicBlock((*basicBlock)(nil)) != BasicBlock(nil) 632 } else { 633 return blk 634 } 635 } 636 637 // BlockIteratorNext implements Builder.BlockIteratorNext. 638 func (b *builder) blockIteratorReversePostOrderNext() *basicBlock { 639 if b.blockIterCur >= len(b.reversePostOrderedBasicBlocks) { 640 return nil 641 } else { 642 ret := b.reversePostOrderedBasicBlocks[b.blockIterCur] 643 b.blockIterCur++ 644 return ret 645 } 646 } 647 648 // ValueRefCounts implements Builder.ValueRefCounts. 649 func (b *builder) ValueRefCounts() []int { 650 return b.valueRefCounts 651 } 652 653 // alias records the alias of the given values. The alias(es) will be 654 // eliminated in the optimization pass via resolveArgumentAlias. 655 func (b *builder) alias(dst, src Value) { 656 b.valueIDAliases[dst.ID()] = src 657 } 658 659 // resolveArgumentAlias resolves the alias of the arguments of the given instruction. 660 func (b *builder) resolveArgumentAlias(instr *Instruction) { 661 if instr.v.Valid() { 662 instr.v = b.resolveAlias(instr.v) 663 } 664 665 if instr.v2.Valid() { 666 instr.v2 = b.resolveAlias(instr.v2) 667 } 668 669 if instr.v3.Valid() { 670 instr.v3 = b.resolveAlias(instr.v3) 671 } 672 673 view := instr.vs.View() 674 for i, v := range view { 675 view[i] = b.resolveAlias(v) 676 } 677 } 678 679 // resolveAlias resolves the alias of the given value. 680 func (b *builder) resolveAlias(v Value) Value { 681 // Some aliases are chained, so we need to resolve them recursively. 682 for { 683 if src, ok := b.valueIDAliases[v.ID()]; ok { 684 v = src 685 } else { 686 break 687 } 688 } 689 return v 690 } 691 692 // entryBlk returns the entry block of the function. 693 func (b *builder) entryBlk() *basicBlock { 694 return b.basicBlocksPool.View(0) 695 } 696 697 // isDominatedBy returns true if the given block `n` is dominated by the given block `d`. 698 // Before calling this, the builder must pass by passCalculateImmediateDominators. 699 func (b *builder) isDominatedBy(n *basicBlock, d *basicBlock) bool { 700 if len(b.dominators) == 0 { 701 panic("BUG: passCalculateImmediateDominators must be called before calling isDominatedBy") 702 } 703 ent := b.entryBlk() 704 doms := b.dominators 705 for n != d && n != ent { 706 n = doms[n.id] 707 } 708 return n == d 709 } 710 711 // BlockIDMax implements Builder.BlockIDMax. 712 func (b *builder) BlockIDMax() BasicBlockID { 713 return BasicBlockID(b.basicBlocksPool.Allocated()) 714 } 715 716 // InsertUndefined implements Builder.InsertUndefined. 717 func (b *builder) InsertUndefined() { 718 instr := b.AllocateInstruction() 719 instr.opcode = OpcodeUndefined 720 b.InsertInstruction(instr) 721 } 722 723 // LoopNestingForestRoots implements Builder.LoopNestingForestRoots. 724 func (b *builder) LoopNestingForestRoots() []BasicBlock { 725 return b.loopNestingForestRoots 726 } 727 728 // LowestCommonAncestor implements Builder.LowestCommonAncestor. 729 func (b *builder) LowestCommonAncestor(blk1, blk2 BasicBlock) BasicBlock { 730 return b.sparseTree.findLCA(blk1.ID(), blk2.ID()) 731 }