Example #1
0
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
}
Example #2
0
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
}