public override void Run(IRContext context) { var unresolved = new List <IRBasicBlock>(); foreach (var block in context.Function.BasicBlocks.AsEnumerable().Reverse()) { if (block.SwitchFollow != null) { foreach (var uBlock in unresolved) { if (block.SwitchFollow.ReversePostOrderIndex > uBlock.ReversePostOrderIndex) { uBlock.IfFollow = block.SwitchFollow; } } unresolved.RemoveAll(a => a.IfFollow != null); continue; } //and not some loop thingie if (block.Successors.Count != 2 || block.BlockJump.IsLoopJump || block.SwitchFollow != null) { continue; } IRBasicBlock follow = null; int followInEdges = 0; for (int i = block.ReversePostOrderIndex + 1; i < context.Function.BasicBlocks.Count; i++) { var dominatedBlock = context.Function.BasicBlocks[i]; if (dominatedBlock.ImmediateDominator != block) { continue; } int followInEdgesNew = dominatedBlock.Predecessors.Count - dominatedBlock.BackEdgeCount; //if (followInEdgesNew >= followInEdges) { follow = dominatedBlock; followInEdges = followInEdgesNew; } } if (follow != null && followInEdges > 1) { block.IfFollow = follow; foreach (var uBlock in unresolved) { if (follow.ReversePostOrderIndex > uBlock.ReversePostOrderIndex) { uBlock.IfFollow = follow; } } unresolved.RemoveAll(a => a.IfFollow != null); } else { unresolved.Add(block); } } }
public IRReturn(IRBasicBlock parentBlock, IRExpression returnValue) : base(parentBlock) { ReturnValue = returnValue; if (!(ReturnValue is null)) { Uses.UnionWith(ReturnValue.GetAllVariables()); } }
private bool IsBackEdge(IRBasicBlock p, IRBasicBlock s) { if (p.PreOrderIndex < s.PreOrderIndex) { return(false); } s.BackEdgeCount++; return(true); }
public IRAssignment(IRBasicBlock parentBlock, IRExpression destination, IRExpression source) : base(parentBlock) { Destination = destination; Source = source; if (Destination is IRVariable v) { Defs.Add(v); } Uses.UnionWith(Source.GetAllVariables()); }
public IRStore(IRBasicBlock parentBlock, IRType type, IRExpression address, IRExpression operand) : base(parentBlock) { if (type == IRPrimitive.Void || type == IRPrimitive.Bool) { throw new IRTypeException(); } Type = type; Address = address; Operand = operand; Uses.UnionWith(Address.GetAllVariables()); Uses.UnionWith(Operand.GetAllVariables()); }
public override void Run(IRContext context) { var intervals = IRBasicBlock.GetIntervalSequence(context.Function.BasicBlocks, context.Function.BasicBlocks[0]); foreach (var gi in intervals) { var ni = gi.SelectMany(g => g.GetNodes()).ToArray(); foreach (var intervalNode in gi) { var headBBlock = intervalNode.GetHeadBasicBlock(); var nodes = intervalNode.GetAllBasicBlocks().ToArray(); IRBasicBlock latchNode = null; foreach (var predecessor in headBBlock.Predecessors) { if (!nodes.Contains(predecessor) || !IsBackEdge(predecessor, headBBlock)) { continue; } if (latchNode == null || predecessor.ReversePostOrderIndex > latchNode.ReversePostOrderIndex) { latchNode = predecessor; } } if (latchNode != null) { //todo: case level check headBBlock.LatchNode = latchNode; FindLoopNodes(context.Function, headBBlock, latchNode, nodes); latchNode.IsLatchNode = true; } } } }
public override IEnumerable <IRInstruction> GetIRInstructions(IRContext context, IRBasicBlock parentBlock) { yield return(new IRReturn(parentBlock, VariableUses.Count == 0 ? null : context.VariableMapping[VariableUses.First()])); }
public override IEnumerable <IRInstruction> GetIRInstructions(IRContext context, IRBasicBlock parentBlock) { switch (Instruction.Id) { case ArmInstructionId.ARM_INS_ADD: if (Instruction.Details.Operands[0].Register.Id == ArmRegisterId.ARM_REG_PC) { yield break; } if (Instruction.DisassembleMode == ArmDisassembleMode.Thumb && Instruction.Details.Operands.Length == 2) { yield return(new IRAssignment(parentBlock, GetIROperand(context, 0), GetIROperand(context, 0) + GetIRSecondOperand(context, 1))); } else if (Instruction.DisassembleMode == ArmDisassembleMode.Thumb && Instruction.Details.Operands.Length == 3 && Instruction.Details.Operands[2].Type == ArmOperandType.Immediate && Instruction.Details.Operands[2].Immediate == 0) { yield return(new IRAssignment(parentBlock, GetIROperand(context, 0), GetIROperand(context, 1))); } else { yield return(new IRAssignment(parentBlock, GetIROperand(context, 0), GetIROperand(context, 1) + GetIRSecondOperand(context, 2))); } break; case ArmInstructionId.ARM_INS_SUB: if (Instruction.DisassembleMode == ArmDisassembleMode.Thumb && Instruction.Details.Operands.Length == 2) { yield return(new IRAssignment(parentBlock, GetIROperand(context, 0), GetIROperand(context, 0) - GetIRSecondOperand(context, 1))); } else { yield return(new IRAssignment(parentBlock, GetIROperand(context, 0), GetIROperand(context, 1) - GetIRSecondOperand(context, 2))); } break; case ArmInstructionId.ARM_INS_RSB: yield return(new IRAssignment(parentBlock, GetIROperand(context, 0), GetIRSecondOperand(context, 2) - GetIROperand(context, 1))); break; case ArmInstructionId.ARM_INS_AND: yield return(new IRAssignment(parentBlock, GetIROperand(context, 0), GetIROperand(context, 1) & GetIRSecondOperand(context, 2))); break; case ArmInstructionId.ARM_INS_ORR: yield return(new IRAssignment(parentBlock, GetIROperand(context, 0), GetIROperand(context, 1) | GetIRSecondOperand(context, 2))); break; case ArmInstructionId.ARM_INS_EOR: yield return(new IRAssignment(parentBlock, GetIROperand(context, 0), GetIROperand(context, 1) ^ GetIRSecondOperand(context, 2))); break; case ArmInstructionId.ARM_INS_BIC: yield return(new IRAssignment(parentBlock, GetIROperand(context, 0), GetIROperand(context, 1) & ~GetIRSecondOperand(context, 2))); break; case ArmInstructionId.ARM_INS_LSL: if (Instruction.DisassembleMode == ArmDisassembleMode.Arm) { goto case ArmInstructionId.ARM_INS_MOV; } yield return(new IRAssignment(parentBlock, GetIROperand(context, 0), GetIROperand(context, 1).ShiftLeft(GetIRSecondOperand(context, 2)))); break; case ArmInstructionId.ARM_INS_LSR: if (Instruction.DisassembleMode == ArmDisassembleMode.Arm) { goto case ArmInstructionId.ARM_INS_MOV; } yield return(new IRAssignment(parentBlock, GetIROperand(context, 0), GetIROperand(context, 1).ShiftRightLogical(GetIRSecondOperand(context, 2)))); break; case ArmInstructionId.ARM_INS_ASR: if (Instruction.DisassembleMode == ArmDisassembleMode.Arm) { goto case ArmInstructionId.ARM_INS_MOV; } yield return(new IRAssignment(parentBlock, GetIROperand(context, 0), GetIROperand(context, 1).ShiftRightArithmetic(GetIRSecondOperand(context, 2)))); break; case ArmInstructionId.ARM_INS_ROR: if (Instruction.DisassembleMode == ArmDisassembleMode.Arm) { goto case ArmInstructionId.ARM_INS_MOV; } throw new NotImplementedException(); break; case ArmInstructionId.ARM_INS_RRX: if (Instruction.DisassembleMode == ArmDisassembleMode.Arm) { goto case ArmInstructionId.ARM_INS_MOV; } throw new NotImplementedException(); break; case ArmInstructionId.ARM_INS_MOV: yield return(new IRAssignment(parentBlock, GetIROperand(context, 0), GetIRSecondOperand(context, 1))); break; case ArmInstructionId.ARM_INS_MVN: yield return(new IRAssignment(parentBlock, GetIROperand(context, 0), ~GetIRSecondOperand(context, 1))); break; case ArmInstructionId.ARM_INS_MUL: yield return(new IRAssignment(parentBlock, GetIROperand(context, 0), GetIROperand(context, 1) * GetIROperand(context, 2))); break; case ArmInstructionId.ARM_INS_MLA: yield return(new IRAssignment(parentBlock, GetIROperand(context, 0), GetIROperand(context, 1) * GetIROperand(context, 2) + GetIROperand(context, 3))); break; case ArmInstructionId.ARM_INS_SMULL: yield return(new IRAssignment(parentBlock, GetIROperand(context, 0), (GetIROperand(context, 2).Cast(IRPrimitive.S32).Cast(IRPrimitive.S64) * GetIROperand(context, 3).Cast(IRPrimitive.S32).Cast(IRPrimitive.S64)).Cast(IRPrimitive.U32))); yield return(new IRAssignment(parentBlock, GetIROperand(context, 1), (GetIROperand(context, 2).Cast(IRPrimitive.S32).Cast(IRPrimitive.S64) * GetIROperand(context, 3).Cast(IRPrimitive.S32).Cast(IRPrimitive.S64)).ShiftRightLogical(32) .Cast(IRPrimitive.U32))); break; case ArmInstructionId.ARM_INS_LDR: case ArmInstructionId.ARM_INS_LDRH: case ArmInstructionId.ARM_INS_LDRSH: case ArmInstructionId.ARM_INS_LDRB: case ArmInstructionId.ARM_INS_LDRSB: { IRType type = IRPrimitive.Void; switch (Instruction.Id) { case ArmInstructionId.ARM_INS_LDR: type = IRPrimitive.U32; break; case ArmInstructionId.ARM_INS_LDRH: type = IRPrimitive.U16; break; case ArmInstructionId.ARM_INS_LDRSH: type = IRPrimitive.S16; break; case ArmInstructionId.ARM_INS_LDRB: type = IRPrimitive.U8; break; case ArmInstructionId.ARM_INS_LDRSB: type = IRPrimitive.S8; break; } if (Instruction.Details.WriteBack) { throw new NotImplementedException("Unimplemented instruction!"); } if (Instruction.Details.Operands[1].Memory.Base.Id == ArmRegisterId.ARM_REG_SP) { yield return(new IRAssignment(parentBlock, GetIROperand(context, 0), context.VariableMapping[VariableUses.First(v => v.Location == VariableLocation.Stack)])); break; } if (Instruction.Details.Operands[1].Memory.Index == null && Instruction.Details.Operands[1].Memory.Displacement == 0) { yield return(new IRAssignment(parentBlock, GetIROperand(context, 0), new IRDerefExpression(type, GetIROperand(context, 1)).Cast(IRPrimitive.U32))); break; } else if (Instruction.Details.Operands[1].Memory.Index == null) { var deref = new IRDerefExpression(type, GetIROperand(context, 1) + (uint)Instruction.Details.Operands[1].Memory.Displacement); yield return(new IRAssignment(parentBlock, GetIROperand(context, 0), deref.Cast(IRPrimitive.U32))); break; } else { if (Instruction.Details.Operands[1].ShiftOperation == ArmShiftOperation.Invalid || (Instruction.Details.Operands[1].ShiftOperation == ArmShiftOperation.ARM_SFT_LSL && Instruction.Details.Operands[1].ShiftValue == 0)) { var deref = new IRDerefExpression(type, GetIROperand(context, 1) + GetIROperand(context, 2)); yield return(new IRAssignment(parentBlock, GetIROperand(context, 0), deref.Cast(IRPrimitive.U32))); break; } else { throw new NotImplementedException("Unimplemented instruction!"); } } } case ArmInstructionId.ARM_INS_STR: case ArmInstructionId.ARM_INS_STRH: case ArmInstructionId.ARM_INS_STRB: { var type = IRPrimitive.Void; switch (Instruction.Id) { case ArmInstructionId.ARM_INS_STR: type = IRPrimitive.U32; break; case ArmInstructionId.ARM_INS_STRH: type = IRPrimitive.U16; break; case ArmInstructionId.ARM_INS_STRB: type = IRPrimitive.U8; break; } if (Instruction.Details.WriteBack) { throw new NotImplementedException("Unimplemented instruction!"); } if (Instruction.Details.Operands[1].Memory.Base.Id == ArmRegisterId.ARM_REG_SP) { yield return(new IRAssignment(parentBlock, context.VariableMapping[VariableDefs.First(v => v.Location == VariableLocation.Stack)], GetIROperand(context, 0))); break; } if (Instruction.Details.Operands[1].Memory.Index == null && Instruction.Details.Operands[1].Memory.Displacement == 0) { yield return(new IRStore(parentBlock, type, GetIROperand(context, 1), GetIROperand(context, 0))); break; } else if (Instruction.Details.Operands[1].Memory.Index == null) { yield return(new IRStore(parentBlock, type, GetIROperand(context, 1) + (uint)Instruction.Details.Operands[1].Memory.Displacement, GetIROperand(context, 0))); break; } else { if (Instruction.Details.Operands[1].ShiftOperation == ArmShiftOperation.Invalid || (Instruction.Details.Operands[1].ShiftOperation == ArmShiftOperation.ARM_SFT_LSL && Instruction.Details.Operands[1].ShiftValue == 0)) { yield return(new IRStore(parentBlock, type, GetIROperand(context, 1) + GetIROperand(context, 2), GetIROperand(context, 0))); break; } else { throw new NotImplementedException("Unimplemented instruction!"); } } } case ArmInstructionId.ARM_INS_BL: yield return(new IRAssignment(parentBlock, context.VariableMapping[VariableDefs .First(v => v.Location == VariableLocation.Register && v.Address == 0)], new IRCallExpression(IRPrimitive.U32, $"sub_{Instruction.Details.Operands[0].Immediate:X08}", context.VariableMapping[VariableUses .First(v => v.Location == VariableLocation.Register && v.Address == 0)], context.VariableMapping[VariableUses .First(v => v.Location == VariableLocation.Register && v.Address == 1)], context.VariableMapping[VariableUses .First(v => v.Location == VariableLocation.Register && v.Address == 2)], context.VariableMapping[VariableUses .First(v => v.Location == VariableLocation.Register && v.Address == 3)] ))); break; case ArmInstructionId.ARM_INS_BLX: if (Instruction.Details.Operands[0].Type == ArmOperandType.Immediate) { goto case ArmInstructionId.ARM_INS_BL; } yield return(new IRAssignment(parentBlock, context.VariableMapping[VariableDefs .First(v => v.Location == VariableLocation.Register && v.Address == 0)], new IRCallExpression(IRPrimitive.U32, ((Variable)Operands[0].op).Name, context.VariableMapping[VariableUses .First(v => v.Location == VariableLocation.Register && v.Address == 0)], context.VariableMapping[VariableUses .First(v => v.Location == VariableLocation.Register && v.Address == 1)], context.VariableMapping[VariableUses .First(v => v.Location == VariableLocation.Register && v.Address == 2)], context.VariableMapping[VariableUses .First(v => v.Location == VariableLocation.Register && v.Address == 3)] ))); break; case ArmInstructionId.ARM_INS_LDM: if (Instruction.Details.Operands[0].Register.Id == ArmRegisterId.ARM_REG_SP && Instruction.Details.WriteBack) { break; } goto default; case ArmInstructionId.ARM_INS_STMDB: if (Instruction.Details.Operands[0].Register.Id == ArmRegisterId.ARM_REG_SP && Instruction.Details.WriteBack) { break; } goto default; case ArmInstructionId.ARM_INS_PUSH: case ArmInstructionId.ARM_INS_POP: case ArmInstructionId.ARM_INS_CMP: case ArmInstructionId.ARM_INS_B: case ArmInstructionId.ARM_INS_BX: break; default: throw new NotImplementedException("Unimplemented instruction!"); } }
protected IRInstruction(IRBasicBlock parentBlock) { ParentBlock = parentBlock; }
public override IEnumerable <IRInstruction> GetIRInstructions(IRContext context, IRBasicBlock parentBlock) { yield return(new IRAssignment(parentBlock, context.VariableMapping[(Variable)Operands[0].op], Constant)); }
public override void Run(IRContext context) { for (int i = context.Function.BasicBlocks.Count - 1; i >= 0; i--) { var block = context.Function.BasicBlocks[i]; if (block.LoopHead != block || block.LoopType != LoopType.DoWhile) { continue; } //find all loop invariant things var defs = new HashSet <IRVariable>(); var uses = new HashSet <IRVariable>(); for (int j = block.ReversePostOrderIndex; j <= block.LatchNode.ReversePostOrderIndex; j++) { var loopBlock = context.Function.BasicBlocks[j]; if (loopBlock.LoopHead != block) { continue; } foreach (var instruction in loopBlock.Instructions) { defs.UnionWith(instruction.Defs); uses.UnionWith(instruction.Uses); } } var candidates = new HashSet <IRVariable>(defs); candidates.IntersectWith(uses); var condVars = new HashSet <IRVariable>(candidates); condVars.IntersectWith(block.LatchNode.BlockJump.Uses); if (condVars.Count != 1) { continue; } var condVar = condVars.First(); var condVarDefs = block.FindDefs(block.Instructions.First(), condVar); int inLoopCount = condVarDefs.Count(v => v.ParentBlock.LoopHead == block); int outLoopCount = condVarDefs.Length - inLoopCount; if (outLoopCount != 1 || inLoopCount != 1) { continue; } var initialDef = condVarDefs.First(v => v.ParentBlock.LoopHead != block); if (!(initialDef is IRAssignment initialAssgn)) { continue; } var ifExpr = block.LatchNode.BlockJump.Condition.CloneComplete(); ifExpr.Substitute(condVar, initialAssgn.Source); ifExpr = ifExpr.ReverseConditionSides(); if (!(ifExpr is IRComparisonExpression cmp && cmp.OperandA is IRConstant && cmp.OperandB is IRConstant)) { var invIfExpr = ifExpr.CloneComplete().InverseCondition(); IRBasicBlock ifBlock = null; for (int j = i - 1; j >= 0; j--) { var b = context.Function.BasicBlocks[j]; if (b.BlockJump != null && ((b.BlockJump.Destination != block.LoopFollow && b.BlockJump.Condition.Equals(ifExpr)) || (b.BlockJump.Destination == block.LoopFollow && b.BlockJump.Condition.Equals(invIfExpr)))) { ifBlock = b; break; } } if (ifBlock == null) { continue; } block.ForLoopInitialIf = ifBlock; ifBlock.ForLoopHead = block; //if we found the if block, we need to check for hoisted variables which are declared just before the loop var hoistBlock = ifBlock.Successors.First(s => s != block.LoopFollow); if (hoistBlock != block) { if (hoistBlock.Successors.Count != 1 || hoistBlock.Successors[0] != block) { throw new Exception(); } var hoistVars = new HashSet <IRVariable>(); var hoistInsts = new Dictionary <IRVariable, IRAssignment>(); foreach (var instruction in hoistBlock.Instructions) { if (!(instruction is IRAssignment assg) || !(assg.Destination is IRVariable hoistVar)) { continue; } hoistInsts.Add(hoistVar, assg); hoistVars.Add(hoistVar); } var invariantVars = new HashSet <IRVariable>(hoistVars); invariantVars.ExceptWith(defs); //invariantVars should be the vars that were invariant-hoisted out of the loop //we can now simply substitute them back foreach (var invariantVar in invariantVars) { var hoistInst = hoistInsts[invariantVar]; var hoistUses = hoistBlock.FindUses(hoistInst, invariantVar); foreach (var use in hoistUses) { use.SubstituteUse(invariantVar, hoistInst.Source); } hoistBlock.Instructions.Remove(hoistInst); } hoistVars.ExceptWith(invariantVars); var strengthVars = new HashSet <IRVariable>(hoistVars); strengthVars.IntersectWith(candidates); foreach (var strengthVar in strengthVars) { var hoistInst = hoistInsts[strengthVar]; var hoistDefs = block.FindDefs(0, strengthVar); if (hoistDefs.Length != 2) { continue; } if (!(hoistDefs.FirstOrDefault(d => d != hoistInst) is IRAssignment assg)) { continue; } if (!(assg.Source is IRBinaryExpression bin) || bin.Operator != IRBinaryOperator.Add) { continue; } var mulFactor = bin.OperandA.Equals(strengthVar) ? bin.OperandB : bin.OperandA; var mulExpr = condVar * mulFactor; var hoistUses = hoistBlock.FindUses(hoistInst, strengthVar); foreach (var use in hoistUses) { use.SubstituteUse(strengthVar, mulExpr); } hoistBlock.Instructions.Remove(hoistInst); assg.ParentBlock.Instructions.Remove(assg); } if (hoistBlock.Instructions.Count != 0) { continue; } ifBlock.Successors[ifBlock.Successors.IndexOf(hoistBlock)] = block; block.Predecessors[block.Predecessors.IndexOf(hoistBlock)] = ifBlock; hoistBlock.Predecessors.Clear(); hoistBlock.Successors.Clear(); } } block.LoopType = LoopType.For; //move update of loop var to end of latch block if (condVarDefs.Length != 2) { throw new Exception(); } var loopVarDef = condVarDefs.First(v => v is IRAssignment && v.ParentBlock.LoopHead == block);//v.ParentBlock == block.LatchNode); loopVarDef.ParentBlock.Instructions.Remove(loopVarDef); block.LatchNode.Instructions.Insert(block.LatchNode.Instructions.Count - 1, loopVarDef); } }
public IntervalNode(IRBasicBlock block) { Block = block; }
public override IEnumerable <IRInstruction> GetIRInstructions(IRContext context, IRBasicBlock parentBlock) { yield return(new IRJump(parentBlock, context.BasicBlockMapping[Destination], FlagsUseOperand == null || Condition == ArmConditionCode.ARM_CC_AL ? null : VariableUseLocs[(Variable)FlagsUseOperand].First().GetIRPredicateCode(context, Condition))); }
public override IEnumerable <IRInstruction> GetIRInstructions(IRContext context, IRBasicBlock parentBlock) { var a = context.VariableMapping[(Variable)Operands[2].op].Cast(IRPrimitive.U64) | context.VariableMapping[(Variable)Operands[3].op].Cast(IRPrimitive.U64).ShiftLeft(32); IRExpression b; if (Operands[4].op is Constant && Operands[5].op is Constant) { b = ((Constant)Operands[4].op).Value | ((ulong)((Constant)Operands[5].op).Value << 32); } else if (Operands[4].op is Constant && Operands[5].op is Variable) { uint constant = ((Constant)Operands[4].op).Value; if (constant == 0) { b = context.VariableMapping[(Variable)Operands[5].op].Cast(IRPrimitive.U64).ShiftLeft(32); } else { b = (ulong)((Constant)Operands[4].op).Value | context.VariableMapping[(Variable)Operands[5].op].Cast(IRPrimitive.U64).ShiftLeft(32); } } else if (Operands[4].op is Variable && Operands[5].op is Constant) { uint constant = ((Constant)Operands[5].op).Value; if (constant == 0) { b = context.VariableMapping[(Variable)Operands[4].op].Cast(IRPrimitive.U64); } else { b = context.VariableMapping[(Variable)Operands[4].op].Cast(IRPrimitive.U64) | ((ulong)((Constant)Operands[5].op).Value << 32); } } else { b = context.VariableMapping[(Variable)Operands[4].op].Cast(IRPrimitive.U64) | context.VariableMapping[(Variable)Operands[5].op].Cast(IRPrimitive.U64).ShiftLeft(32); } yield return(new IRAssignment(parentBlock, context.VariableMapping[(Variable)Operands[0].op], (a + b).Cast(IRPrimitive.U32))); yield return(new IRAssignment(parentBlock, context.VariableMapping[(Variable)Operands[1].op], (a + b).ShiftRightLogical(32).Cast(IRPrimitive.U32))); }
private void FindLoopNodes(IRFunction func, IRBasicBlock headNode, IRBasicBlock latchNode, IRBasicBlock[] intervalNodes) { headNode.LoopHead = headNode; var loopNodes = new List <IRBasicBlock>(); loopNodes.Add(headNode); for (int i = headNode.ReversePostOrderIndex + 1; i < latchNode.ReversePostOrderIndex; i++) { var block = func.BasicBlocks[i]; if (loopNodes.Contains(block.ImmediateDominator) && intervalNodes.Contains(block)) { loopNodes.Add(block); if (block.LoopHead == null) { block.LoopHead = headNode; } } } latchNode.LoopHead = headNode; if (latchNode != headNode) { loopNodes.Add(latchNode); } if (latchNode.Successors.Count == 2) { var latchElseBlock = latchNode.BlockJump.Destination; var latchIfBlock = latchNode.Successors.First(s => s != latchElseBlock); // if (headNode.Successors.Count == 2 || latchNode == headNode) // { // var headElseBlock = headNode.BlockBranch.Destination; // var headIfBlock = headNode.Successors.First(s => s != headElseBlock); // // if (latchNode == headNode || (loopNodes.Contains(headElseBlock) && loopNodes.Contains(headIfBlock))) // // { // headNode.LoopType = LoopType.Repeat; // if (latchIfBlock == headIfBlock) // headNode.LoopFollow = latchElseBlock; // else // headNode.LoopFollow = latchIfBlock; // // } // // else // // { // // headNode.LoopType = LoopType.While; // // if (loopNodes.Contains(headIfBlock)) // // headNode.LoopFollow = headElseBlock; // // else // // headNode.LoopFollow = headIfBlock; // // } // } // else // { headNode.LoopType = LoopType.DoWhile; if (latchIfBlock == headNode) { headNode.LoopFollow = latchElseBlock; } else { headNode.LoopFollow = latchIfBlock; } latchNode.BlockJump.IsLoopJump = true; // } } else { //todo } }