github.com/aykevl/tinygo@v0.5.0/compiler/llvm.go (about) 1 package compiler 2 3 import ( 4 "tinygo.org/x/go-llvm" 5 ) 6 7 // This file contains helper functions for LLVM that are not exposed in the Go 8 // bindings. 9 10 // Return a list of values (actually, instructions) where this value is used as 11 // an operand. 12 func getUses(value llvm.Value) []llvm.Value { 13 if value.IsNil() { 14 return nil 15 } 16 var uses []llvm.Value 17 use := value.FirstUse() 18 for !use.IsNil() { 19 uses = append(uses, use.User()) 20 use = use.NextUse() 21 } 22 return uses 23 } 24 25 // splitBasicBlock splits a LLVM basic block into two parts. All instructions 26 // after afterInst are moved into a new basic block (created right after the 27 // current one) with the given name. 28 func (c *Compiler) splitBasicBlock(afterInst llvm.Value, insertAfter llvm.BasicBlock, name string) llvm.BasicBlock { 29 oldBlock := afterInst.InstructionParent() 30 newBlock := c.ctx.InsertBasicBlock(insertAfter, name) 31 var nextInstructions []llvm.Value // values to move 32 33 // Collect to-be-moved instructions. 34 inst := afterInst 35 for { 36 inst = llvm.NextInstruction(inst) 37 if inst.IsNil() { 38 break 39 } 40 nextInstructions = append(nextInstructions, inst) 41 } 42 43 // Move instructions. 44 c.builder.SetInsertPointAtEnd(newBlock) 45 for _, inst := range nextInstructions { 46 inst.RemoveFromParentAsInstruction() 47 c.builder.Insert(inst) 48 } 49 50 // Find PHI nodes to update. 51 var phiNodes []llvm.Value // PHI nodes to update 52 for bb := insertAfter.Parent().FirstBasicBlock(); !bb.IsNil(); bb = llvm.NextBasicBlock(bb) { 53 for inst := bb.FirstInstruction(); !inst.IsNil(); inst = llvm.NextInstruction(inst) { 54 if inst.IsAPHINode().IsNil() { 55 continue 56 } 57 needsUpdate := false 58 incomingCount := inst.IncomingCount() 59 for i := 0; i < incomingCount; i++ { 60 if inst.IncomingBlock(i) == oldBlock { 61 needsUpdate = true 62 break 63 } 64 } 65 if !needsUpdate { 66 // PHI node has no incoming edge from the old block. 67 continue 68 } 69 phiNodes = append(phiNodes, inst) 70 } 71 } 72 73 // Update PHI nodes. 74 for _, phi := range phiNodes { 75 c.builder.SetInsertPointBefore(phi) 76 newPhi := c.builder.CreatePHI(phi.Type(), "") 77 incomingCount := phi.IncomingCount() 78 incomingVals := make([]llvm.Value, incomingCount) 79 incomingBlocks := make([]llvm.BasicBlock, incomingCount) 80 for i := 0; i < incomingCount; i++ { 81 value := phi.IncomingValue(i) 82 block := phi.IncomingBlock(i) 83 if block == oldBlock { 84 block = newBlock 85 } 86 incomingVals[i] = value 87 incomingBlocks[i] = block 88 } 89 newPhi.AddIncoming(incomingVals, incomingBlocks) 90 phi.ReplaceAllUsesWith(newPhi) 91 phi.EraseFromParentAsInstruction() 92 } 93 94 return newBlock 95 }