Example #1
0
        private SsaFormBuilder(MethodDefinition method, ControlFlowGraph cfg)
        {
            this.method = method;
            this.cfg    = cfg;

            this.blocks = new SsaBlock[cfg.Nodes.Count];
            this.stackSizeAtBlockStart = new int[cfg.Nodes.Count];
            for (int i = 0; i < stackSizeAtBlockStart.Length; i++)
            {
                stackSizeAtBlockStart[i] = -1;
            }
            stackSizeAtBlockStart[cfg.EntryPoint.BlockIndex] = 0;

            this.parameters = new SsaVariable[method.Parameters.Count + (method.HasThis ? 1 : 0)];
            if (method.HasThis)
            {
                parameters[0] = new SsaVariable(method.Body.ThisParameter);
            }
            for (int i = 0; i < method.Parameters.Count; i++)
            {
                parameters[i + (method.HasThis ? 1 : 0)] = new SsaVariable(method.Parameters[i]);
            }

            this.locals = new SsaVariable[method.Body.Variables.Count];
            for (int i = 0; i < locals.Length; i++)
            {
                locals[i] = new SsaVariable(method.Body.Variables[i]);
            }

            this.stackLocations = new SsaVariable[method.Body.MaxStackSize];
            for (int i = 0; i < stackLocations.Length; i++)
            {
                stackLocations[i] = new SsaVariable(i);
            }
        }
Example #2
0
		private SsaFormBuilder(MethodDefinition method, ControlFlowGraph cfg)
		{
			this.method = method;
			this.cfg = cfg;
			
			this.blocks = new SsaBlock[cfg.Nodes.Count];
			this.stackSizeAtBlockStart = new int[cfg.Nodes.Count];
			for (int i = 0; i < stackSizeAtBlockStart.Length; i++) {
				stackSizeAtBlockStart[i] = -1;
			}
			stackSizeAtBlockStart[cfg.EntryPoint.BlockIndex] = 0;
			
			this.parameters = new SsaVariable[method.Parameters.Count + (method.HasThis ? 1 : 0)];
			if (method.HasThis)
				parameters[0] = new SsaVariable(method.Body.ThisParameter);
			for (int i = 0; i < method.Parameters.Count; i++)
				parameters[i + (method.HasThis ? 1 : 0)] = new SsaVariable(method.Parameters[i]);
			
			this.locals = new SsaVariable[method.Body.Variables.Count];
			for (int i = 0; i < locals.Length; i++)
				locals[i] = new SsaVariable(method.Body.Variables[i]);
			
			this.stackLocations = new SsaVariable[method.Body.MaxStackSize];
			for (int i = 0; i < stackLocations.Length; i++) {
				stackLocations[i] = new SsaVariable(i);
			}
		}
Example #3
0
		public SsaVariable(SsaVariable original, string newName)
		{
			Name = newName;
			IsStackLocation = original.IsStackLocation;
			OriginalVariableIndex = original.OriginalVariableIndex;
			Parameter = original.Parameter;
			Variable = original.Variable;
		}
Example #4
0
 public SsaVariable(SsaVariable original, string newName)
 {
     this.Name                  = newName;
     this.IsStackLocation       = original.IsStackLocation;
     this.OriginalVariableIndex = original.OriginalVariableIndex;
     this.Parameter             = original.Parameter;
     this.Variable              = original.Variable;
 }
Example #5
0
		public SsaVariable(SsaVariable original, string newName)
		{
			this.Name = newName;
			this.IsStackLocation = original.IsStackLocation;
			this.OriginalVariableIndex = original.OriginalVariableIndex;
			this.Parameter = original.Parameter;
			this.Variable = original.Variable;
		}
Example #6
0
 public SsaVariable(SsaVariable original, string newName)
 {
     Name                  = newName;
     IsStackLocation       = original.IsStackLocation;
     OriginalVariableIndex = original.OriginalVariableIndex;
     Parameter             = original.Parameter;
     Variable              = original.Variable;
 }
 public void ReplaceVariableInOperands(SsaVariable oldVar, SsaVariable newVar)
 {
     for (int i = 0; i < this.Operands.Length; i++)
     {
         if (this.Operands[i] == oldVar)
         {
             this.Operands[i] = newVar;
         }
     }
 }
Example #8
0
        public static void RemoveDeadAssignments(SsaForm ssaForm)
        {
            HashSet <SsaVariable> liveVariables = new HashSet <SsaVariable>();

            // find variables that are used directly
            foreach (SsaBlock block in ssaForm.Blocks)
            {
                foreach (SsaInstruction inst in block.Instructions)
                {
                    if (!CanRemoveAsDeadCode(inst))
                    {
                        if (inst.Target != null)
                        {
                            liveVariables.Add(inst.Target);
                        }
                        foreach (SsaVariable op in inst.Operands)
                        {
                            liveVariables.Add(op);
                        }
                    }
                }
            }
            Queue <SsaVariable> queue = new Queue <SsaVariable>(liveVariables);

            // find variables that are used indirectly
            while (queue.Count > 0)
            {
                SsaVariable v = queue.Dequeue();
                if (v.IsSingleAssignment)
                {
                    foreach (SsaVariable op in v.Definition.Operands)
                    {
                        if (liveVariables.Add(op))
                        {
                            queue.Enqueue(op);
                        }
                    }
                }
            }
            // remove assignments to all unused variables
            foreach (SsaBlock block in ssaForm.Blocks)
            {
                block.Instructions.RemoveAll(
                    inst =>
                {
                    if (inst.Target != null && !liveVariables.Contains(inst.Target))
                    {
                        Debug.Assert(inst.Target.IsSingleAssignment);
                        return(true);
                    }
                    return(false);
                });
            }
            ssaForm.ComputeVariableUsage();             // update usage after we modified stuff
        }
Example #9
0
        void DetermineOperands(int stackSize, Instruction inst, int popCount, int pushCount, out SsaVariable target, out SsaVariable[] operands)
        {
            switch (inst.OpCode.Code)
            {
            case Code.Ldarg:
                operands = new SsaVariable[] { ssaForm.GetOriginalVariable((ParameterReference)inst.Operand) };
                target   = stackLocations[stackSize];
                break;

            case Code.Starg:
                operands = new SsaVariable[] { stackLocations[stackSize] };
                target   = ssaForm.GetOriginalVariable((ParameterReference)inst.Operand);
                break;

            case Code.Ldloc:
                operands = new SsaVariable[] { ssaForm.GetOriginalVariable((VariableReference)inst.Operand) };
                target   = stackLocations[stackSize];
                break;

            case Code.Stloc:
                operands = new SsaVariable[] { stackLocations[stackSize] };
                target   = ssaForm.GetOriginalVariable((VariableReference)inst.Operand);
                break;

            case Code.Dup:
                operands = new SsaVariable[] { stackLocations[stackSize] };
                target   = stackLocations[stackSize + 1];
                break;

            default:
                operands = new SsaVariable[popCount];
                for (int i = 0; i < popCount; i++)
                {
                    operands[i] = stackLocations[stackSize + i];
                }

                switch (pushCount)
                {
                case 0:
                    target = null;
                    break;

                case 1:
                    target = stackLocations[stackSize];
                    break;

                default:
                    throw new NotSupportedException("unsupported pushCount=" + pushCount);
                }
                break;
            }
        }
 public SsaInstruction(SsaBlock parentBlock, Instruction instruction, SsaVariable target, SsaVariable[] operands,
                       Instruction[] prefixes    = null, SpecialOpCode specialOpCode = SpecialOpCode.None,
                       TypeReference typeOperand = null)
 {
     this.ParentBlock   = parentBlock;
     this.Instruction   = instruction;
     this.Prefixes      = prefixes ?? emptyInstructionArray;
     this.Target        = target;
     this.Operands      = operands ?? emptyVariableArray;
     this.SpecialOpCode = specialOpCode;
     this.TypeOperand   = typeOperand;
     Debug.Assert((typeOperand != null) == (specialOpCode == SpecialOpCode.Exception || specialOpCode == SpecialOpCode.InitObj));
 }
Example #11
0
        internal SsaForm(SsaBlock[] blocks, SsaVariable[] parameters, SsaVariable[] locals, SsaVariable[] stackLocations, bool methodHasThis)
        {
            this.parameters = parameters;
            this.locals = locals;
            this.Blocks = new ReadOnlyCollection<SsaBlock>(blocks);
            this.OriginalVariables = new ReadOnlyCollection<SsaVariable>(parameters.Concat(locals).Concat(stackLocations).ToList());
            this.methodHasThis = methodHasThis;

            Debug.Assert(EntryPoint.NodeType == ControlFlowNodeType.EntryPoint);
            Debug.Assert(RegularExit.NodeType == ControlFlowNodeType.RegularExit);
            Debug.Assert(ExceptionalExit.NodeType == ControlFlowNodeType.ExceptionalExit);
            for (int i = 0; i < this.OriginalVariables.Count; i++) {
                this.OriginalVariables[i].OriginalVariableIndex = i;
            }
        }
Example #12
0
        private void MakeByRefCallSimple(SsaBlock block, ref int instructionIndexInBlock, IMethodSignature targetMethod)
        {
            SsaInstruction inst = block.Instructions[instructionIndexInBlock];

            for (int i = 0; i < inst.Operands.Length; i++)
            {
                SsaVariable operand = inst.Operands[i];
                if (operand.IsSingleAssignment && operand.Usage.Count == 1 && IsLoadAddress(operand.Definition))
                {
                    // address is used for this method call only

                    Instruction loadAddressInstruction = operand.Definition.Instruction;

                    // find target parameter type:
                    bool isOut;
                    if (i == 0 && targetMethod.HasThis)
                    {
                        isOut = false;
                    }
                    else
                    {
                        ParameterDefinition parameter = targetMethod.Parameters[i - (targetMethod.HasThis ? 1 : 0)];
                        isOut = parameter.IsOut;
                    }

                    SsaVariable addressTakenOf = GetVariableFromLoadAddressInstruction(loadAddressInstruction);

                    // insert "Prepare" instruction on front
                    SpecialOpCode loadOpCode = isOut ? SpecialOpCode.PrepareByOutCall : SpecialOpCode.PrepareByRefCall;
                    block.Instructions.Insert(instructionIndexInBlock++, new SsaInstruction(
                                                  block, null, operand, new SsaVariable[] { addressTakenOf }, specialOpCode: loadOpCode));

                    // insert "WriteAfterByRefOrOutCall" instruction after call
                    block.Instructions.Insert(instructionIndexInBlock + 1, new SsaInstruction(
                                                  block, null, addressTakenOf, new SsaVariable[] { operand }, specialOpCode: SpecialOpCode.WriteAfterByRefOrOutCall));

                    couldSimplifySomething = true;

                    // remove the loadAddressInstruction later
                    // (later because it might be defined in the current block and we don't want instructionIndex to become invalid)
                    redundantLoadAddressInstructions.Add(operand.Definition);
                }
            }
        }
Example #13
0
            SsaVariable MakeNewVersion(int variableIndex)
            {
                int         versionCounter = ++versionCounters[variableIndex];
                SsaVariable x = inputVariables[variableIndex];

                if (versionCounter == 1)
                {
                    return(x);
                }
                else
                {
                    if (x.IsStackLocation)
                    {
                        return(new SsaVariable(x, "temp" + (transform.tempVariableCounter++)));
                    }
                    else
                    {
                        return(new SsaVariable(x, x.Name + "_" + versionCounter));
                    }
                }
            }
Example #14
0
        private void MakeLoadFieldCallSimple(SsaBlock block, ref int instructionIndexInBlock)
        {
            SsaInstruction inst = block.Instructions[instructionIndexInBlock];

            Debug.Assert(inst.Operands.Length == 1);
            SsaVariable operand = inst.Operands[0];

            if (operand.IsSingleAssignment && operand.Usage.Count == 1 && IsLoadAddress(operand.Definition))
            {
                // insert special "PrepareForFieldAccess" instruction in front
                block.Instructions.Insert(instructionIndexInBlock++, new SsaInstruction(
                                              inst.ParentBlock, null, operand,
                                              new SsaVariable[] { GetVariableFromLoadAddressInstruction(operand.Definition.Instruction) },
                                              specialOpCode: SpecialOpCode.PrepareForFieldAccess));

                couldSimplifySomething = true;

                // remove the loadAddressInstruction later
                redundantLoadAddressInstructions.Add(operand.Definition);
            }
        }
 /// <summary>
 /// When any instructions stores its result in a stack location that's used only once in a 'stloc' or 'starg' instruction,
 /// we optimize this to directly store in the target location.
 /// As optimization this is redundant (does the same as copy propagation), but it'll make us keep the variables named
 /// after locals instead of keeping the temps as using only the simple copy propagation would do.
 /// </summary>
 public static void DirectlyStoreToVariables(SsaForm ssaForm)
 {
     foreach (SsaBlock block in ssaForm.Blocks)
     {
         block.Instructions.RemoveAll(
             inst => {
             if (inst.Instruction != null && (inst.Instruction.OpCode == OpCodes.Stloc || inst.Instruction.OpCode == OpCodes.Starg))
             {
                 SsaVariable target = inst.Target;
                 SsaVariable temp   = inst.Operands[0];
                 if (target.IsSingleAssignment && temp.IsSingleAssignment && temp.Usage.Count == 1 && temp.IsStackLocation)
                 {
                     temp.Definition.Target = target;
                     return(true);
                 }
             }
             return(false);
         });
     }
     ssaForm.ComputeVariableUsage();             // update usage after we modified stuff
 }
Example #16
0
        private void MakeInitObjCallSimple(SsaBlock block, ref int instructionIndexInBlock)
        {
            SsaInstruction inst = block.Instructions[instructionIndexInBlock];

            Debug.Assert(inst.Operands.Length == 1);
            SsaVariable operand = inst.Operands[0];

            if (operand.IsSingleAssignment && operand.Usage.Count == 1 && IsLoadAddress(operand.Definition))
            {
                // replace instruction with special "InitObj" instruction
                block.Instructions[instructionIndexInBlock] = new SsaInstruction(
                    inst.ParentBlock, null, GetVariableFromLoadAddressInstruction(operand.Definition.Instruction), null,
                    specialOpCode: SpecialOpCode.InitObj,
                    typeOperand: (TypeReference)inst.Instruction.Operand);

                couldSimplifySomething = true;

                // remove the loadAddressInstruction later
                redundantLoadAddressInstructions.Add(operand.Definition);
            }
        }
Example #17
0
        void PlacePhiFunctions(SsaVariable variable)
        {
            cfg.ResetVisited();
            HashSet <SsaBlock>      blocksWithPhi = new HashSet <SsaBlock>();
            Queue <ControlFlowNode> worklist      = new Queue <ControlFlowNode>();

            foreach (SsaInstruction writeInstruction in writeToOriginalVariables[variable.OriginalVariableIndex])
            {
                ControlFlowNode cfgNode = cfg.Nodes[writeInstruction.ParentBlock.BlockIndex];
                if (!cfgNode.Visited)
                {
                    cfgNode.Visited = true;
                    worklist.Enqueue(cfgNode);
                }
            }
            while (worklist.Count > 0)
            {
                ControlFlowNode cfgNode = worklist.Dequeue();
                foreach (ControlFlowNode dfNode in cfgNode.DominanceFrontier)
                {
                    // we don't need phi functions in the exit node
                    if (dfNode.NodeType == ControlFlowNodeType.RegularExit || dfNode.NodeType == ControlFlowNodeType.ExceptionalExit)
                    {
                        continue;
                    }
                    SsaBlock y = ssaForm.Blocks[dfNode.BlockIndex];
                    if (blocksWithPhi.Add(y))
                    {
                        // add a phi instruction in y
                        SsaVariable[] operands = Enumerable.Repeat(variable, dfNode.Incoming.Count).ToArray();
                        y.Instructions.Insert(0, new SsaInstruction(y, null, variable, operands, specialOpCode: SpecialOpCode.Phi));
                        if (!dfNode.Visited)
                        {
                            dfNode.Visited = true;
                            worklist.Enqueue(dfNode);
                        }
                    }
                }
            }
        }
		public void ReplaceVariableInOperands(SsaVariable oldVar, SsaVariable newVar)
		{
			for (int i = 0; i < this.Operands.Length; i++) {
				if (this.Operands[i] == oldVar)
					this.Operands[i] = newVar;
			}
		}
Example #19
0
		void DetermineOperands(int stackSize, Instruction inst, int popCount, int pushCount, out SsaVariable target, out SsaVariable[] operands)
		{
			switch (inst.OpCode.Code) {
				case Code.Ldarg:
					operands = new SsaVariable[] { ssaForm.GetOriginalVariable((ParameterReference)inst.Operand) };
					target = stackLocations[stackSize];
					break;
				case Code.Starg:
					operands = new SsaVariable[] { stackLocations[stackSize] };
					target = ssaForm.GetOriginalVariable((ParameterReference)inst.Operand);
					break;
				case Code.Ldloc:
					operands = new SsaVariable[] { ssaForm.GetOriginalVariable((VariableReference)inst.Operand) };
					target = stackLocations[stackSize];
					break;
				case Code.Stloc:
					operands = new SsaVariable[] { stackLocations[stackSize] };
					target = ssaForm.GetOriginalVariable((VariableReference)inst.Operand);
					break;
				case Code.Dup:
					operands = new SsaVariable[] { stackLocations[stackSize] };
					target = stackLocations[stackSize + 1];
					break;
				default:
					operands = new SsaVariable[popCount];
					for (int i = 0; i < popCount; i++) {
						operands[i] = stackLocations[stackSize + i];
					}

					switch (pushCount) {
						case 0:
							target = null;
							break;
						case 1:
							target = stackLocations[stackSize];
							break;
						default:
							throw new NotSupportedException("unsupported pushCount=" + pushCount);
					}
					break;
			}
		}
		public SsaInstruction(SsaBlock parentBlock, Instruction instruction, SsaVariable target, SsaVariable[] operands,
		                      Instruction[] prefixes = null, SpecialOpCode specialOpCode = SpecialOpCode.None,
		                      TypeReference typeOperand = null)
		{
			this.ParentBlock = parentBlock;
			this.Instruction = instruction;
			this.Prefixes = prefixes ?? emptyInstructionArray;
			this.Target = target;
			this.Operands = operands ?? emptyVariableArray;
			this.SpecialOpCode = specialOpCode;
			this.TypeOperand = typeOperand;
			Debug.Assert((typeOperand != null) == (specialOpCode == SpecialOpCode.Exception || specialOpCode == SpecialOpCode.InitObj));
		}
Example #21
0
 void PlacePhiFunctions(SsaVariable variable)
 {
     cfg.ResetVisited();
     HashSet<SsaBlock> blocksWithPhi = new HashSet<SsaBlock>();
     Queue<ControlFlowNode> worklist = new Queue<ControlFlowNode>();
     foreach (SsaInstruction writeInstruction in writeToOriginalVariables[variable.OriginalVariableIndex]) {
         ControlFlowNode cfgNode = cfg.Nodes[writeInstruction.ParentBlock.BlockIndex];
         if (!cfgNode.Visited) {
             cfgNode.Visited = true;
             worklist.Enqueue(cfgNode);
         }
     }
     while (worklist.Count > 0) {
         ControlFlowNode cfgNode = worklist.Dequeue();
         foreach (ControlFlowNode dfNode in cfgNode.DominanceFrontier) {
             // we don't need phi functions in the exit node
             if (dfNode.NodeType == ControlFlowNodeType.RegularExit || dfNode.NodeType == ControlFlowNodeType.ExceptionalExit)
                 continue;
             SsaBlock y = ssaForm.Blocks[dfNode.BlockIndex];
             if (blocksWithPhi.Add(y)) {
                 // add a phi instruction in y
                 SsaVariable[] operands = Enumerable.Repeat(variable, dfNode.Incoming.Count).ToArray();
                 y.Instructions.Insert(0, new SsaInstruction(y, null, variable, operands, specialOpCode: SpecialOpCode.Phi));
                 if (!dfNode.Visited) {
                     dfNode.Visited = true;
                     worklist.Enqueue(dfNode);
                 }
             }
         }
     }
 }