Example #1
0
 void CreateGraphStructure()
 {
     for (int i = 0; i < blocks.Length; i++) {
         blocks[i] = new SsaBlock(cfg.Nodes[i]);
     }
     for (int i = 0; i < blocks.Length; i++) {
         foreach (ControlFlowNode node in cfg.Nodes[i].Successors) {
             blocks[i].Successors.Add(blocks[node.BlockIndex]);
             blocks[node.BlockIndex].Predecessors.Add(blocks[i]);
         }
     }
 }
 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 #3
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 #4
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 #5
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);
            }
        }
Example #6
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);
            }
        }
        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);
                        }
                    }
                }
            }
        }
		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 #9
0
        void CreateInstructions(int blockIndex)
        {
            ControlFlowNode cfgNode = cfg.Nodes[blockIndex];
            SsaBlock        block   = blocks[blockIndex];

            int stackSize = stackSizeAtBlockStart[blockIndex];

            Debug.Assert(stackSize >= 0);

            List <Instruction> prefixes = new List <Instruction>();

            foreach (Instruction inst in cfgNode.Instructions)
            {
                if (inst.OpCode.OpCodeType == OpCodeType.Prefix)
                {
                    prefixes.Add(inst);
                    continue;
                }

                int popCount = inst.GetPopDelta() ?? stackSize;
                stackSize -= popCount;
                if (stackSize < 0)
                {
                    throw new InvalidProgramException("IL stack underflow");
                }

                int pushCount = inst.GetPushDelta();
                if (stackSize + pushCount > stackLocations.Length)
                {
                    throw new InvalidProgramException("IL stack overflow");
                }

                SsaVariable   target;
                SsaVariable[] operands;
                DetermineOperands(stackSize, inst, popCount, pushCount, out target, out operands);

                Instruction[] prefixArray = prefixes.Count > 0 ? prefixes.ToArray() : null;
                prefixes.Clear();

                // ignore NOP instructions
                if (!(inst.OpCode == OpCodes.Nop || inst.OpCode == OpCodes.Pop))
                {
                    block.Instructions.Add(new SsaInstruction(block, inst, target, operands, prefixArray));
                }
                stackSize += pushCount;
            }

            foreach (ControlFlowEdge edge in cfgNode.Outgoing)
            {
                int newStackSize;
                switch (edge.Type)
                {
                case JumpType.Normal:
                    newStackSize = stackSize;
                    break;

                case JumpType.EndFinally:
                    if (stackSize != 0)
                    {
                        throw new NotSupportedException("stacksize must be 0 in endfinally edge");
                    }
                    newStackSize = 0;
                    break;

                case JumpType.JumpToExceptionHandler:
                    switch (edge.Target.NodeType)
                    {
                    case ControlFlowNodeType.FinallyOrFaultHandler:
                        newStackSize = 0;
                        break;

                    case ControlFlowNodeType.ExceptionalExit:
                    case ControlFlowNodeType.CatchHandler:
                        newStackSize = 1;
                        break;

                    default:
                        throw new NotSupportedException("unsupported target node type: " + edge.Target.NodeType);
                    }
                    break;

                default:
                    throw new NotSupportedException("unsupported jump type: " + edge.Type);
                }

                int nextStackSize = stackSizeAtBlockStart[edge.Target.BlockIndex];
                if (nextStackSize == -1)
                {
                    stackSizeAtBlockStart[edge.Target.BlockIndex] = newStackSize;
                    CreateInstructions(edge.Target.BlockIndex);
                }
                else if (nextStackSize != newStackSize)
                {
                    throw new InvalidProgramException("Stack size doesn't match");
                }
            }
        }
Example #10
0
            internal void Visit(SsaBlock block)
            {
                // duplicate top of all stacks
                foreach (var stack in versionStacks)
                {
                    if (stack != null)
                    {
                        stack.Push(stack.Peek());
                    }
                }

                foreach (SsaInstruction s in block.Instructions)
                {
                    // replace all uses of variables being processed with their current version.
                    if (s.SpecialOpCode != SpecialOpCode.Phi)
                    {
                        for (int i = 0; i < s.Operands.Length; i++)
                        {
                            var stack = versionStacks[s.Operands[i].OriginalVariableIndex];
                            if (stack != null)
                            {
                                s.Operands[i] = stack.Peek();
                            }
                        }
                    }
                    // if we're writing to a variable we should process:
                    if (s.Target != null)
                    {
                        int targetIndex = s.Target.OriginalVariableIndex;
                        if (versionStacks[targetIndex] != null)
                        {
                            s.Target = MakeNewVersion(targetIndex);
                            s.Target.IsSingleAssignment = true;
                            s.Target.Definition         = s;

                            // we already pushed our entry for this SsaBlock at the beginning (where we duplicated all stacks),
                            // so now replace the top element
                            versionStacks[targetIndex].Pop();
                            versionStacks[targetIndex].Push(s.Target);
                        }
                    }
                }

                foreach (SsaBlock succ in block.Successors)
                {
                    int j = succ.Predecessors.IndexOf(block);
                    Debug.Assert(j >= 0);
                    foreach (SsaInstruction f in succ.Instructions)
                    {
                        if (f.SpecialOpCode == SpecialOpCode.Phi)
                        {
                            var stack = versionStacks[f.Target.OriginalVariableIndex];
                            if (stack != null)
                            {
                                f.Operands[j] = stack.Peek();
                            }
                        }
                    }
                }
                foreach (ControlFlowNode child in transform.cfg.Nodes[block.BlockIndex].DominatorTreeChildren)
                {
                    Visit(transform.ssaForm.Blocks[child.BlockIndex]);
                }
                // restore stacks:
                foreach (var stack in versionStacks)
                {
                    if (stack != null)
                    {
                        stack.Pop();
                    }
                }
            }
		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 #12
0
		void CreateGraphStructure()
		{
			for (int i = 0; i < blocks.Length; i++) {
				blocks[i] = new SsaBlock(cfg.Nodes[i]);
			}
			for (int i = 0; i < blocks.Length; i++) {
				foreach (ControlFlowNode node in cfg.Nodes[i].Successors) {
					blocks[i].Successors.Add(blocks[node.BlockIndex]);
					blocks[node.BlockIndex].Predecessors.Add(blocks[i]);
				}
			}
		}
Example #13
0
        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);
            }
        }
Example #14
0
        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 #15
0
            internal void Visit(SsaBlock block)
            {
                // duplicate top of all stacks
                foreach (var stack in versionStacks) {
                    if (stack != null)
                        stack.Push(stack.Peek());
                }

                foreach (SsaInstruction s in block.Instructions) {
                    // replace all uses of variables being processed with their current version.
                    if (s.SpecialOpCode != SpecialOpCode.Phi) {
                        for (int i = 0; i < s.Operands.Length; i++) {
                            var stack = versionStacks[s.Operands[i].OriginalVariableIndex];
                            if (stack != null)
                                s.Operands[i] = stack.Peek();
                        }
                    }
                    // if we're writing to a variable we should process:
                    if (s.Target != null) {
                        int targetIndex = s.Target.OriginalVariableIndex;
                        if (versionStacks[targetIndex] != null) {
                            s.Target = MakeNewVersion(targetIndex);
                            s.Target.IsSingleAssignment = true;
                            s.Target.Definition = s;

                            // we already pushed our entry for this SsaBlock at the beginning (where we duplicated all stacks),
                            // so now replace the top element
                            versionStacks[targetIndex].Pop();
                            versionStacks[targetIndex].Push(s.Target);
                        }
                    }
                }

                foreach (SsaBlock succ in block.Successors) {
                    int j = succ.Predecessors.IndexOf(block);
                    Debug.Assert(j >= 0);
                    foreach (SsaInstruction f in succ.Instructions) {
                        if (f.SpecialOpCode == SpecialOpCode.Phi) {
                            var stack = versionStacks[f.Target.OriginalVariableIndex];
                            if (stack != null) {
                                f.Operands[j] = stack.Peek();
                            }
                        }
                    }
                }
                foreach (ControlFlowNode child in transform.cfg.Nodes[block.BlockIndex].DominatorTreeChildren)
                    Visit(transform.ssaForm.Blocks[child.BlockIndex]);
                // restore stacks:
                foreach (var stack in versionStacks) {
                    if (stack != null)
                        stack.Pop();
                }
            }