func checkInstr(instr ssa.Instruction, blockDomTree *analysis.DominatorTree) error { thisBlockNode := blockDomTree.NodeForBlock(instr.Block()) if _, ok := instr.(*ssa.Phi); !ok { for _, op := range ssa.GetOperands(instr) { if opInstr, ok := op.(ssa.Instruction); ok { opInstrBlock := opInstr.Block() if thisBlockNode.DominatedBy(blockDomTree.NodeForBlock(opInstrBlock), true) { continue } else if opInstrBlock == instr.Block() { if opInstrBlock.InstrIndex(opInstr) < opInstrBlock.InstrIndex(instr) { continue } } return &InstrError{ Instr: instr, Message: "Instruction is not dominated by operand `" + ssa.ValueString(op) + "`", } } } } switch i := instr.(type) { case *ssa.BinOp: return checkBinOp(i) case *ssa.Load: return checkLoad(i) case *ssa.Call: return checkCall(i) case *ssa.Alloc: return checkAlloc(i) case *ssa.Store: return checkStore(i) case *ssa.Convert: return checkConvert(i) case *ssa.ICmp: return checkICmp(i) case *ssa.CondBr: return checkCondBr(i) case *ssa.Br: return checkBr(i) case *ssa.Phi: return checkPhi(i, blockDomTree) case *ssa.Ret: return checkRet(i) case *ssa.GEP: return checkGEP(i) case *ssa.Unreachable: // do nothing default: panic("unim") } return nil }
func checkPhi(instr *ssa.Phi, dom *analysis.DominatorTree) error { if err := errIfNonFirstClassType(instr.Type(), instr); err != nil { return err } incomingBlockMap := make(map[*ssa.Block]bool, instr.NumIncoming()) for _, pred := range dom.BlockCFG().NodeForBlock(instr.Block()).Prev() { incomingBlockMap[pred.Block()] = false } for i := 0; i < instr.NumIncoming(); i++ { val, block := instr.GetIncoming(i) if seen, exists := incomingBlockMap[block]; !exists { return &InstrError{ Instr: instr, Message: "Impossible incoming block `" + block.Name() + "`", } } else if seen { return &InstrError{ Instr: instr, Message: "Duplicate incoming block `" + block.Name() + "`", } } if err := errIfMismatchedTypes(instr.Type(), val.Type(), instr); err != nil { return err } incomingBlockMap[block] = true if valInstr, ok := val.(ssa.Instruction); ok { // for an incoming value to be valid, the incoming block must be dominated by the block the value comes from if !dom.NodeForBlock(block).DominatedBy(dom.NodeForBlock(valInstr.Block()), false) { return &InstrError{ Instr: instr, Message: fmt.Sprintf("Value `%s` must dominate block `%s`", val.Name(), block.Name()), } } } } for block, seen := range incomingBlockMap { if !seen { return &InstrError{ Instr: instr, Message: "Missing incoming block `" + block.Name() + "`", } } } return nil }