private static CILBB BuildCILCFG(Instruction start) { if (start == null) { throw new ArgumentNullException("start"); } List <CILBB> cilbblist = new List <CILBB>(); Instruction instr = start; // Determine leading instructions starting each basic block: // The first instruction is a leader. // The target of a conditional or an unconditional goto/jump instruction is a leader. // The instruction that immediately follows a conditional or an unconditional goto/jump instruction is a leader. List <Instruction> leaders = new List <Instruction>(); leaders.Add(instr); bool afterTrailer = false; while (instr != null) { if (afterTrailer) { if (!leaders.Contains(instr)) { leaders.Add(instr); } afterTrailer = false; } CILOpCodes opcode = (CILOpCodes)instr.OpCode.Value; bool isBranch = opcode > CILOpCodes.Ret && opcode < CILOpCodes.Switch; if (isBranch) { if (!leaders.Contains(instr.Operand as Instruction)) { leaders.Add(instr.Operand as Instruction); } } afterTrailer = isBranch || opcode == CILOpCodes.Ret; instr = instr.Next; } // Starting from a leader, the set of all following instructions until and not including the next leader is // the basic block corresponding to the starting leader. List <Instruction> trailers = new List <Instruction>(); foreach (Instruction leader in leaders) { CILBB cilbb = new CILBB(); cilbb.code.Add(leader); Instruction cur = leader.Next; while (cur != null && !leaders.Contains(cur)) { cilbb.code.Add(cur); cur = cur.Next; } trailers.Add(cilbb.code.Last()); cilbblist.Add(cilbb); } // Perform linking of CIL basic blocks. for (int i = 0; i < cilbblist.Count; i++) { Instruction trailer = trailers[i]; CILOpCodes trailerCode = (CILOpCodes)trailer.OpCode.Value; bool uncondBranch = trailerCode == CILOpCodes.Br_S || trailerCode == CILOpCodes.Br; bool condBranch = !uncondBranch && trailerCode > CILOpCodes.Ret && trailerCode < CILOpCodes.Switch; if (condBranch) { cilbblist[i].target = cilbblist.Single(cilbb => cilbb.code.First().Offset == (trailer.Operand as Instruction).Offset); cilbblist[i].successor = cilbblist.Single(cilbb => cilbb.code.First().Offset == trailer.Next.Offset); } else if (trailerCode != CILOpCodes.Ret) { cilbblist[i].successor = uncondBranch ? cilbblist.Single(cilbb => cilbb.code.First().Offset == (trailer.Operand as Instruction).Offset) : ((trailer.Next == null) ? null : cilbblist.Single(cilbb => cilbb.code.First().Offset == trailer.Next.Offset)); } } return(cilbblist[0]); }
// IL basic block will have a separate IR implementation for each stack type context. private static CILBBImplementation BuildIRCFG(CILBB cilbb, Stack <Tuple <Tuple <GenericOperand, bool>, InstructionSelector> > stack, Dictionary <CILBB, List <CILBBImplementation> > cilbbimpls, IList <FormalParameter> parameters, IList <VirtualRegister> variables, bool result, IList <SpecialRegister> srpool, IDictionary <MethodInfo, Subprogram> spmap, Func <Type, StateSpaces, InstructionSelector.DynamicRegister> regalloc) { if (cilbb == null) { if (stack.Count > 0) { throw new InvalidProgramException("Evaluation stack must be empty at return moment."); } else { return(null); } } else { List <CILBBImplementation> impls; if (!cilbbimpls.TryGetValue(cilbb, out impls)) { impls = new List <CILBBImplementation>(); cilbbimpls.Add(cilbb, impls); } CILBBImplementation impl = impls.Find(im => im.TypeContextEqual(stack)); bool handleNext = false; if (impl != null) { if (!impl.Implements(stack)) { impl.Simulate(stack); handleNext = true; } } else { impl = new CILBBImplementation(cilbb.code, stack, parameters, variables, result, srpool, spmap, regalloc); impls.Add(impl); handleNext = true; } if (handleNext) { impl.Successor = BuildIRCFG(cilbb.successor, new Stack <Tuple <Tuple <GenericOperand, bool>, InstructionSelector> >(stack.Reverse()), cilbbimpls, parameters, variables, result, srpool, spmap, regalloc); if (cilbb.target != null) { impl.Target = BuildIRCFG(cilbb.target, new Stack <Tuple <Tuple <GenericOperand, bool>, InstructionSelector> >(stack.Reverse()), cilbbimpls, parameters, variables, result, srpool, spmap, regalloc); } } return(impl); } }