private static void _DeadVarsAlgortihm(Function func, Variable.State state) { /* * Before the algorithm starts we ensure that all instructions have a * list of dead variables which is filled with all the variables present in * the function. During the algorithm we will remove the variables from these * lists that are not really dead at the given point. */ SetAllVariablesAsDead(func, state); /* * If we are going upwards (looking for FREE dead variables), we start from * the point called "fake exit block", the one and only ultimate endpoint * of all functions ever created. Thank you Kohlmann! * * If going downwards (looking for NOT_INITIALIZED dead variables), * we start from the very first basic block (func.BasicBlocks[0]). */ BasicBlock block = (state == Variable.State.Free) ? func.GetFakeExitBasicBlock() : func.GetEntranceBasicBlock(); /* * We go through all the instructions and deal with all their * referenced variables. At the and of this we will have the list of the dead * variables for all instructions. */ recursive(block, state); /* * In the end we clear the done_ids list, so it won't influence the algorithm's * future runs (if these will exist). */ DoneIDs.Clear(); }
/// <summary> /// Recursive function to get to all the instructions of the Function. /// </summary> /// <param name="actual">Actual BasicBlock</param> private static void recursive(BasicBlock actual, Variable.State state) { /* * We deal with every original(1) instruction in the basic block, * and in every instruction we deal with every referenced variable. * The referenced variables should be removed from the dead variables list * in all the instructions accesible from here. * * (1): Only the original instructions determine whether a variable is dead * or not, because the fake instructions work with dead variables only. * * deal_with_var() - it will be described in detail in the forthcoming parts */ foreach (Instruction ins in actual.Instructions) { if (/*ins.isFake == false*/ true) { foreach (Variable var in ins.RefVariables) { DealWithVariable(var, ins, state); } } } /* * We have finished the task with this basic block, and we should not * come back here anymore, so we save its ID into the done_ids list. */ DoneIDs.Add(actual.ID); /* * Now that this basic block is finished we should do the same things * with its predecessors recursively. * We only should deal with the basic blocks not marked as done. */ List <BasicBlock> bblist = (state == Variable.State.Free) ? actual.getPredecessors : actual.getSuccessors; foreach (BasicBlock block in bblist) { if (!DoneIDs.Contains(block.ID)) { recursive(block, state); } } }
/// <summary> /// Fills the DeadVariables lists with the variables that aren't already in them. /// </summary> /// <param name="func">Actual Function</param> private static void SetAllVariablesAsDead(Function func, Variable.State state) { foreach (BasicBlock bb in func.BasicBlocks) { foreach (Instruction inst in bb.Instructions) { foreach (Variable var in func.LocalVariables) { /* We add it in the list only if it is not already there. */ if (!inst.DeadVariables.ContainsKey(var)) { /* * If it's an input parameter we don't use it as NOT_INITIALIZED, * and if it's a fake input parameter we don't use it at all. */ if (var.kind != Variable.Kind.Input || (!var.fake && state != Variable.State.Not_Initialized)) { inst.DeadVariables.Add(var, state); } } } } } }
/// <summary> /// Recursive function to set a Variable as alive in the proper places. /// </summary> /// <param name="var">the Variable we are dealing with</param> /// <param name="ins">Actual Instruction</param> private static void DealWithVariable(Variable var, Instruction ins, Variable.State state) { /* * This variable is used somewhere after this instruction, so it is alive here. * * DeadVariables - it contains the dead variables at the point of the given instruction */ ins.DeadVariables.Remove(var); /* * GetPrecedingInstructions() * - gives a list of the instructions followed by the actual instruction * - if we are in the middle of the basic block, then it consists of only one instruction * - if we are at the beginning of the basic block then it is the list of all * the predecessing basic block's last instruction * - if we are at the beginning of the first basic block (the one with no predecessors) * then it is an empty list, meaning that we have nothing left to do here */ List <Instruction> inslist = (state == Variable.State.Free) ? ins.GetPrecedingInstructions() : ins.GetFollowingInstructions(); /* * Now we have that list of instructions, we should do the same thing we have done * to this instruction, assuming that it had not been done already. */ foreach (Instruction i in inslist) { /* * If the variable is not in the instruction's dead variables list, then it indicates * that we have dealt with this instruction. */ if (i.DeadVariables.ContainsKey(var) && i.DeadVariables[var] == state) { DealWithVariable(var, i, state); } } }
/// <summary> /// Function to check state collisions for the RefreshNext() method. /// </summary> /// <param name="actual">The actual instruction.</param> /// <param name="var">The actual variable.</param> /// <param name="state">The state we want to refresh to.</param> /// <returns>The state we should refresh to.</returns> public static Variable.State CheckPrecedingStates(Instruction actual, Variable var, Variable.State state) { /* * We only have to do anything, if the instruction is on the beginning of * a basic block, because at that point states can collide. */ if (!actual.Equals(actual.parent.Instructions.First())) { return(state); } /* So we get all states from the preceding instructions. */ List <Variable.State> preceding_states = GetPrecedingStates(actual, var); /* We only have to do anything if there are more than one of those. */ if (preceding_states.Count() > 1 && state == Variable.State.Free) { if (preceding_states.Contains(Variable.State.Not_Initialized)) { /* FREE meets NOT_INITIALIZED */ state = Variable.State.Not_Initialized; } else if (preceding_states.Contains(Variable.State.Filled)) { /* FREE meets FILLED */ state = Variable.State.Filled; } } return(state); }
/* * This function is called when we encounter a change in a dead variable's state. * So we want to push this change through all the instructions, and deal with * this variable only. * * However we can't just overwrite the statement without any check... */ private static void RefreshNext(Instruction ins, Variable var, Variable.State state) { /* * If this instruction uses this variable as well, or this instruction * uses a pointer that points to this variable then its state must not * be changed, because it's perfect as it is right now. */ if (ins.RefVariables.Contains(var)) { /* This instruction uses this variable. */ return; } /* * We have to do anything only if the variable is in this instruction is * dead, and it's state differs from the new state. */ if (ins.DeadVariables.ContainsKey(var) && // This variable is dead. ins.DeadVariables[var] != state) // The state differs. { foreach (Variable v in ins.RefVariables) { if (ins.DeadPointers.ContainsKey(v) && ins.DeadPointers[v].PointsTo.Equals(var)) { /* The instruction uses a pointer that points to this variable. */ return; } } /* * Now we are at the point, that maybe we have to change the state. * Although it's not sure, because if the instruction has more than one predecessors, * then the actual state might not change anything. * For example: NOT_INITIALIZED meets FREE, or FREE meets FILLED. * * NOTE: we don't know right now what to do if NOT_INIT meets FILLED... */ state = DataAnalysis.CheckPrecedingStates(ins, var, state); ins.DeadVariables[var] = state; foreach (Instruction inst in ins.GetFollowingInstructions()) { RefreshNext(inst, var, state); } } /* * Another case for doing something when we pass a dead pointer with changed state. * In this case we do not have to look for variables pointing to that one. * * WARNING FOR FUTURE: (1) */ if (ins.DeadPointers.ContainsKey(var) && // This is a dead pointer. ins.DeadPointers[var].State != state) // The states differ. { /* Just like in the previous case, we have to check all the preceding states for collisions. */ state = DataAnalysis.CheckPrecedingStates(ins, var, state); ins.DeadPointers[var].State = state; foreach (Instruction inst in ins.GetFollowingInstructions()) { RefreshNext(inst, var, state); } } }
/// <summary> /// Constructor. /// </summary> /// <param name="state">The state of the pointer.</param> /// <param name="var">The variable it points to.</param> public PointerData(Variable.State state, Variable var) { State = state; PointsTo = var; }