void createNoBranch(BasicBlock deadCodeBasicBlock) { // Set the dead code block above some other block. var exitBranch = new NoBranchTarget(); exitBranch.sourceBasicBlock = deadCodeBasicBlock; deadCodeBasicBlock.exitBranch = exitBranch; BasicBlock targetBlock = null; do { targetBlock = randomTargetBlock(); // Skip blocks that already have a "no branch" as entry. foreach (var entryBranch in targetBlock.entryBranches) { if (entryBranch is NoBranchTarget) { targetBlock = null; break; } } } while(targetBlock == null); targetBlock.entryBranches.Add(exitBranch); exitBranch.takenTarget = targetBlock; }
// insert the given new target basic block (given by start and end block) between the given no branch to manipulate public void insertBasicBlockBetweenBranch(NoBranchTarget branchToManipulate, BasicBlock newTargetStart, BasicBlock newTargetEnd, UnconditionalBranchTarget exitBranch) { // get the basic block from that the branch is taken and the basic block to that the branch is taken BasicBlock introBasicBlock = branchToManipulate.sourceBasicBlock; BasicBlock outroBasicBlock = branchToManipulate.takenTarget; this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulate.takenTarget, newTargetStart, newTargetEnd, exitBranch, ref exitBranch.takenTarget); }
// insert the given new target basic block between the given no branch to manipulate public void insertBasicBlockBetweenBranch(NoBranchTarget branchToManipulate, BasicBlock newTarget, ConditionalBranchTarget exitBranch, bool useTakenBranch) { // get the basic block from that the branch is taken and the basic block to that the branch is taken BasicBlock introBasicBlock = branchToManipulate.sourceBasicBlock; BasicBlock outroBasicBlock = branchToManipulate.takenTarget; // check wether to use the taken or not taken part of the exit branch if (useTakenBranch) { this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulate.takenTarget, newTarget, newTarget, exitBranch, ref exitBranch.takenTarget); } else { this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulate.takenTarget, newTarget, newTarget, exitBranch, ref exitBranch.notTakenTarget); } }
// insert the given new target basic block between the given conditional branch to manipulate public void insertBasicBlockBetweenBranch(NoBranchTarget branchToManipulate, BasicBlock newTarget, SwitchBranchTarget exitBranch, int switchTakenBranchIdx) { // get the basic block from that the branch is taken and the basic block to that the branch is taken BasicBlock introBasicBlock = branchToManipulate.sourceBasicBlock; BasicBlock outroBasicBlock = branchToManipulate.takenTarget; BasicBlock tempTakenTarget = null; this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulate.takenTarget, newTarget, newTarget, exitBranch, ref tempTakenTarget); // fill switch taken branch list with null when index is out of range while (exitBranch.takenTarget.Count() <= switchTakenBranchIdx) { exitBranch.takenTarget.Add(null); } exitBranch.takenTarget[switchTakenBranchIdx] = tempTakenTarget; }
// this function splits a basic block on the given index public void splitBasicBlock(BasicBlock firstPartBB, int splitIndex) { // check if the index is out of bounds if (splitIndex >= firstPartBB.operations.Count()) { throw new ArgumentException("Index is equal or greater than existing basic block operations."); } // check if there are at least 2 operations inside the basic block to split if (firstPartBB.operations.Count() < 2) { throw new ArgumentException("Too few operations in basic block for splitting."); } // create the new basic block that will become the second part of the basic block to split BasicBlock secondPartBB = new BasicBlock(); // move the exit basic blocks to the new created basic block // and make the new created basic block the exit of the splitted one secondPartBB.exitBranch = firstPartBB.exitBranch; secondPartBB.exitBranch.sourceBasicBlock = secondPartBB; NoBranchTarget tempExitBranch = new NoBranchTarget(); tempExitBranch.takenTarget = secondPartBB; tempExitBranch.sourceBasicBlock = firstPartBB; firstPartBB.exitBranch = tempExitBranch; // add splitted basic block branch // to the entries of the new basic block secondPartBB.entryBranches.Add(tempExitBranch); // distribute the instructions to the basic blocks List <IOperation> previousOperations = new List <IOperation>(); List <IOperation> nextOperations = new List <IOperation>(); for (int operationIdx = 0; operationIdx < firstPartBB.operations.Count(); operationIdx++) { if (operationIdx < splitIndex) { previousOperations.Add(firstPartBB.operations.ElementAt(operationIdx)); } else { nextOperations.Add(firstPartBB.operations.ElementAt(operationIdx)); } } firstPartBB.operations = previousOperations; secondPartBB.operations = nextOperations; // add a semantic id to the new basic block if (firstPartBB.semanticId == -1) { secondPartBB.semanticId = -1; } else { int highestSemanticId = 0; foreach (BasicBlock tempBB in methodCfg.basicBlocks) { if (tempBB.semanticId > highestSemanticId) { highestSemanticId = tempBB.semanticId; } } secondPartBB.semanticId = highestSemanticId + 1; } // add new basic block to the cfg methodCfg.basicBlocks.Add(secondPartBB); }
// insert the given new target basic block (given by start and end block) between the given conditional branch to manipulate public void insertBasicBlockBetweenBranch(ConditionalBranchTarget branchToManipulate, bool manipulateTakenBranch, BasicBlock newTargetStart, BasicBlock newTargetEnd, NoBranchTarget exitBranch) { // get the basic block from that the branch is taken and the basic block to that the branch is taken BasicBlock introBasicBlock = branchToManipulate.sourceBasicBlock; BasicBlock outroBasicBlock = null; // manipulate the correct branch if (manipulateTakenBranch) { outroBasicBlock = branchToManipulate.takenTarget; this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulate.takenTarget, newTargetStart, newTargetEnd, exitBranch, ref exitBranch.takenTarget); } else { outroBasicBlock = branchToManipulate.notTakenTarget; this.insertBasicBlockBetweenBranch(introBasicBlock, outroBasicBlock, branchToManipulate, ref branchToManipulate.notTakenTarget, newTargetStart, newTargetEnd, exitBranch, ref exitBranch.takenTarget); } }
// this function replaces a basic block inside the cfg (oldBasicBlock) with a construction of new basic blocks (newBasicBlockStart and newBasicBlockEnd) public void replaceBasicBlock(BasicBlock oldBasicBlock, BasicBlock newBasicBlockStart, BasicBlock newBasicBlockEnd) { // add new basic blocks to cfg this.addBasicBlockToCfgRecursively(newBasicBlockStart); // add entry branches that enter the old basic block to the new basic block newBasicBlockStart.entryBranches.AddRange(oldBasicBlock.entryBranches); // exchange the target of the entry branches from the old basic block to the new one foreach (IBranchTarget entryBranch in new List <IBranchTarget>(oldBasicBlock.entryBranches)) { if ((entryBranch as NoBranchTarget) != null) { NoBranchTarget tempEntryBranch = (entryBranch as NoBranchTarget); // check sanity of entry branch if (tempEntryBranch.takenTarget != oldBasicBlock) { throw new ArgumentException("Entry branch must have old basic block as target."); } // set new basic block as target tempEntryBranch.takenTarget = newBasicBlockStart; } else if ((entryBranch as UnconditionalBranchTarget) != null) { UnconditionalBranchTarget tempEntryBranch = (entryBranch as UnconditionalBranchTarget); // check sanity of entry branch if (tempEntryBranch.takenTarget != oldBasicBlock) { throw new ArgumentException("Entry branch must have old basic block as target."); } // set new basic block as target tempEntryBranch.takenTarget = newBasicBlockStart; } else if ((entryBranch as ConditionalBranchTarget) != null) { ConditionalBranchTarget tempEntryBranch = (entryBranch as ConditionalBranchTarget); bool sanity = false; // change all branches to the old basic block to the new basic block if (tempEntryBranch.takenTarget == oldBasicBlock) { tempEntryBranch.takenTarget = newBasicBlockStart; sanity = true; } if (tempEntryBranch.notTakenTarget == oldBasicBlock) { tempEntryBranch.notTakenTarget = newBasicBlockStart; sanity = true; } // check sanity of entry branch if (!sanity) { throw new ArgumentException("Entry branch must have old basic block as target."); } } else if ((entryBranch as SwitchBranchTarget) != null) { SwitchBranchTarget tempEntryBranch = (entryBranch as SwitchBranchTarget); bool sanity = false; // change all branches to the old basic block to the new basic block if (tempEntryBranch.notTakenTarget == oldBasicBlock) { tempEntryBranch.notTakenTarget = newBasicBlockStart; sanity = true; } for (int idx = 0; idx < tempEntryBranch.takenTarget.Count(); idx++) { if (tempEntryBranch.takenTarget.ElementAt(idx) == oldBasicBlock) { tempEntryBranch.takenTarget[idx] = newBasicBlockStart; sanity = true; } } // check sanity of entry branch if (!sanity) { throw new ArgumentException("Entry branch must have old basic block as target."); } } else { throw new ArgumentException("Not yet implemented."); } // remove entry branch from the old basic block entry branches list oldBasicBlock.entryBranches.Remove(entryBranch); } IBranchTarget exitBranch = oldBasicBlock.exitBranch; // change the exit branch of the old basic block to be the exit branch of the new one exitBranch.sourceBasicBlock = newBasicBlockEnd; newBasicBlockEnd.exitBranch = exitBranch; // check if the old basic block was the start basic block of the cfg // => change it to the new basic block if (this.methodCfg.startBasicBlock == oldBasicBlock) { this.methodCfg.startBasicBlock = newBasicBlockStart; } // remove old basic block if it still belongs to the cfg if (this.methodCfg.basicBlocks.Contains(oldBasicBlock)) { this.methodCfg.basicBlocks.Remove(oldBasicBlock); } }