예제 #1
0
파일: EnterSSA.cs 프로젝트: djlw78/Mosa
        private void UpdateUses(Context ctx, IDictionary <StackOperand, StackOperand> liveOut)
        {
            int index = 0;

            foreach (Operand op1 in ctx.Operands)
            {
                // Is this a stack operand?
                StackOperand op = op1 as StackOperand;

                if (op != null)
                {
                    StackOperand ssa;
                    // Determine the most recent version
                    Debug.Assert(liveOut.TryGetValue(op, out ssa), "Stack operand not in live variable list.");

                    ssa = liveOut[op];

                    // Replace the use with the most recent version
                    ctx.SetOperand(index++, ssa);

                    if (TRACING.TraceInfo)
                    {
                        Trace.WriteLine(String.Format("\\tUse {0} has been replaced with {1}", op, ssa));
                    }
                }
            }
        }
        /// <summary>
        /// Replaces the operand.
        /// </summary>
        /// <param name="lr">The lr.</param>
        /// <param name="replacement">The replacement.</param>
        private void ReplaceOperand(LiveRange lr, RegisterOperand replacement)
        {
            int opIdx;

            // Iterate all definition sites first
            foreach (int index in lr.Op.Definitions.ToArray())
            {
                Context def = new Context(InstructionSet, index);
                if (def.Offset == lr.Start)
                {
                    opIdx = 0;
                    foreach (Operand r in def.Results)
                    {
                        // Is this the operand?
                        if (object.ReferenceEquals(r, lr.Op))
                        {
                            def.SetResult(opIdx, replacement);
                        }

                        opIdx++;
                    }

                    break;
                }
            }

            // Iterate all use sites
            foreach (int index in lr.Op.Uses.ToArray())
            {
                Context instr = new Context(InstructionSet, index);

                if (instr.Offset <= lr.Start)
                {
                    // A use on instr.Offset == lr.Start is one from a previous definition!!
                }
                else if (instr.Offset <= lr.End)
                {
                    opIdx = 0;
                    foreach (Operand r in instr.Operands)
                    {
                        // Is this the operand?
                        if (object.ReferenceEquals(r, lr.Op))
                        {
                            instr.SetOperand(opIdx, replacement);
                        }

                        opIdx++;
                    }
                }
                else
                {
                    break;
                }
            }
        }
예제 #3
0
        /// <summary>
        /// Assigns the operands from CIL stack.
        /// </summary>
        /// <param name="ctx">The context.</param>
        /// <param name="currentStack">The current stack.</param>
        private void AssignOperandsFromCILStack(Context ctx, Stack <Operand> currentStack)
        {
            for (int index = ctx.OperandCount - 1; index >= 0; --index)
            {
                if (ctx.GetOperand(index) != null)
                {
                    continue;
                }

                ctx.SetOperand(index, currentStack.Pop());
            }
        }
예제 #4
0
 /// <summary>
 /// Assigns the operands from CIL stack.
 /// </summary>
 /// <param name="ctx">The context.</param>
 /// <param name="currentStack">The current stack.</param>
 private static void AssignOperandsFromCILStack(Context ctx, IList <Operand> currentStack)
 {
     for (int index = ctx.OperandCount - 1; index >= 0; --index)
     {
         if (ctx.GetOperand(index) == null)
         {
             Operand operand = currentStack[currentStack.Count - 1];
             currentStack.RemoveAt(currentStack.Count - 1);
             ctx.SetOperand(index, operand);
         }
     }
 }
예제 #5
0
        /// <summary>
        /// Replaces the instrinsic call site
        /// </summary>
        /// <param name="context">The context.</param>
        /// <param name="typeSystem">The type system.</param>
        public void ReplaceIntrinsicCall(Context context, ITypeSystem typeSystem)
        {
            SigType u4 = new SigType(Runtime.Metadata.CilElementType.U4);

            // Retrieve register context
            context.SetInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(u4, GeneralPurposeRegister.EAX), new MemoryOperand(u4, GeneralPurposeRegister.ESP, new IntPtr(28)));

            // Restore registers (Note: EAX and EDX are NOT restored!)
            context.AppendInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(u4, GeneralPurposeRegister.EDX), new MemoryOperand(u4, GeneralPurposeRegister.EAX, new IntPtr(28)));
            context.AppendInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(u4, GeneralPurposeRegister.EBX), new MemoryOperand(u4, GeneralPurposeRegister.EAX, new IntPtr(4)));
            context.AppendInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(u4, GeneralPurposeRegister.EDI), new MemoryOperand(u4, GeneralPurposeRegister.EAX, new IntPtr(20)));
            context.AppendInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(u4, GeneralPurposeRegister.ESI), new MemoryOperand(u4, GeneralPurposeRegister.EAX, new IntPtr(16)));
            context.AppendInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(u4, GeneralPurposeRegister.ESP), new MemoryOperand(u4, GeneralPurposeRegister.EAX, new IntPtr(32)));
            context.AppendInstruction(CPUx86.Instruction.MovInstruction, new RegisterOperand(u4, GeneralPurposeRegister.EBP), new MemoryOperand(u4, GeneralPurposeRegister.EAX, new IntPtr(24)));

            // Jmp to EIP (stored in EDX)
            context.AppendInstruction(CPUx86.Instruction.JmpInstruction);
            context.SetOperand(0, new RegisterOperand(u4, GeneralPurposeRegister.EDX));
        }
        /// <summary>
        /// Assigns registers to operands of the instruction.
        /// </summary>
        /// <param name="ctx">The context.</param>
        private void AssignRegisters(Context ctx)
        {
            // Retrieve the register constraints for the instruction
            IRegisterConstraint rc = null; // _architecture.GetRegisterConstraint(instr);	// FIXME PG - pass context instead???

            // Operand index
            int opIdx;

            if (rc == null && TRACING.TraceWarning)
                Trace.WriteLine(String.Format(@"Failed to get register constraints for instruction {0}!", ctx.Instruction.ToString(ctx)));

            // Only process the instruction, if we have constraints...
            if (rc != null) {
                /* FIXME: Spill used registers, if they are in use :(
                 * It is not as simple as it sounds, as the register may be used by the instruction itself,
                 * but dirty afterwards anyways. So we need to decide this at some later point depending on
                 * the arg list. If the register is also a result reg, and they represent the same operand,
                 * we may get away without spilling... Oo?
                 */
                //Register[] used = rc.GetRegistersUsed();

                opIdx = 0;

                Context at = ctx.Clone();

                foreach (Operand op in ctx.Operands) {
                    // Only allocate registers, if we really have to.
                    if (!rc.IsValidOperand(opIdx, op)) {
                        // The register operand allocated
                        RegisterOperand rop;
                        // List of compatible registers
                        Register[] regs = rc.GetRegistersForOperand(opIdx);
                        Debug.Assert(null != regs, @"IRegisterConstraint.GetRegistersForOperand returned null.");
                        Debug.Assert(0 != regs.Length, @"WTF IRegisterConstraint.GetRegistersForOperand returned zero-length array - what shall we pass then if no register/memory?");

                        // Is this operand in a register?
                        rop = GetRegisterOfOperand(op);
                        if (rop != null && Array.IndexOf(regs, rop.Register) == -1) {
                            // Spill the register...
                            SpillRegister(ctx, op, rop);
                            rop = null;
                        }

                        // Attempt to allocate a free register
                        if (rop == null) {
                            rop = AllocateRegister(regs, op);
                            if (rop != null) {
                                // We need to place a load here... :(
                                InsertMove(ctx, rop, op);
                            }
                        }

                        // Still failed to get one? Spill!
                        if (rop == null) {
                            // Darn, need to spill one... Always use the first one.
                            rop = SpillRegister(at, op.Type, regs);

                            // We need to place a load here... :(
                            InsertMove(at, rop, op);
                        }

                        // Assign the register
                        Debug.Assert(rop != null, @"Whoa: Failed to allocate a register operand??");
                        AssignRegister(rop, op, at);
                        ctx.SetOperand(opIdx, rop); // FIXME PG - opIdx? hmmm. is this phidata?
                    }

                    opIdx++;
                }

                opIdx = 0;
                foreach (Operand res in ctx.Results) {
                    // FIXME: Check support first, spill if register is target and in use
                    if (!rc.IsValidResult(opIdx, res)) {
                        // Is this operand in a register?
                        RegisterOperand rop = GetRegisterOfOperand(res);
                        if (rop == null && !rc.IsValidResult(opIdx, res) && res.Uses.Count == 0)
                            // Do not allocate: Not in a register, allows memory & has no uses... oO wtf?
                            continue;

                        // Retrieve compliant registers
                        Register[] regs = rc.GetRegistersForResult(opIdx);

                        // Do we already have a register?
                        if (rop != null && Array.IndexOf(regs, rop.Register) == -1) {
                            // Hmm, current register doesn't match, release it - since we're overwriting the operand,
                            // we don't need to spill. This should be safe.
                            _activeOperands[rop.Register.Index] = null;
                        }

                        // Allocate a register
                        if (rop == null)
                            rop = AllocateRegister(regs, res);

                        // Do we need to spill?
                        if (rop == null) {
                            // Darn, need to spill one...
                            rop = SpillRegister(at, res.Type, regs);
                            // We don't need to place a load here, as we're defining the register...
                        }

                        // Assign the register
                        Debug.Assert(null != rop, @"Whoa: Failed to allocate a register operand??");
                        AssignRegister(rop, res, at);
                        ctx.SetResult(opIdx, rop); // FIXME PG - same
                    }
                    else {
                        RegisterOperand rop = res as RegisterOperand;
                        if (rop != null)
                            SpillRegisterIfInUse(ctx, rop);
                    }

                    opIdx++;
                }
            }
        }
        /// <summary>
        /// Assigns the operands from CIL stack.
        /// </summary>
        /// <param name="ctx">The context.</param>
        /// <param name="currentStack">The current stack.</param>
        private void AssignOperandsFromCILStack(Context ctx, Stack<Operand> currentStack)
        {
            for (int index = ctx.OperandCount - 1; index >= 0; --index)
            {
                if (ctx.GetOperand(index) != null)
                    continue;

                ctx.SetOperand(index, currentStack.Pop());
            }
        }
예제 #8
0
 /// <summary>
 /// Assigns the operands from CIL stack.
 /// </summary>
 /// <param name="ctx">The context.</param>
 /// <param name="currentStack">The current stack.</param>
 private static void AssignOperandsFromCILStack(Context ctx, IList<Operand> currentStack)
 {
     for (int index = ctx.OperandCount - 1; index >= 0; --index)
     {
         if (ctx.GetOperand (index) == null)
         {
             Operand operand = currentStack[currentStack.Count - 1];
             currentStack.RemoveAt (currentStack.Count - 1);
             ctx.SetOperand (index, operand);
         }
     }
 }
        /// <summary>
        /// Replaces the operand.
        /// </summary>
        /// <param name="lr">The lr.</param>
        /// <param name="replacement">The replacement.</param>
        private void ReplaceOperand(LiveRange lr, RegisterOperand replacement)
        {
            int opIdx;

            // Iterate all definition sites first
            foreach (int index in lr.Op.Definitions.ToArray()) {
                Context def = new Context(InstructionSet, index);
                if (def.Offset == lr.Start) {
                    opIdx = 0;
                    foreach (Operand r in def.Results) {
                        // Is this the operand?
                        if (object.ReferenceEquals(r, lr.Op))
                            def.SetResult(opIdx, replacement);

                        opIdx++;
                    }

                    break;
                }
            }

            // Iterate all use sites
            foreach (int index in lr.Op.Uses.ToArray()) {
                Context instr = new Context(InstructionSet, index);

                if (instr.Offset <= lr.Start) {
                    // A use on instr.Offset == lr.Start is one From a previous definition!!
                }
                else if (instr.Offset <= lr.End) {
                    opIdx = 0;
                    foreach (Operand r in instr.Operands) {
                        // Is this the operand?
                        if (object.ReferenceEquals(r, lr.Op))
                            instr.SetOperand(opIdx, replacement);

                        opIdx++;
                    }
                }
                else {
                    break;
                }
            }
        }
        /// <summary>
        /// Replaces the instruction with an internal call.
        /// </summary>
        /// <param name="ctx">The transformation context.</param>
        /// <param name="internalCallTarget">The internal call target.</param>
        private void ReplaceWithInternalCall(Context ctx, VmCall internalCallTarget)
        {
            RuntimeType rt = RuntimeBase.Instance.TypeLoader.GetType(@"Mosa.Runtime.RuntimeBase");
            RuntimeMethod callTarget = FindMethod(rt, internalCallTarget.ToString());

            ctx.ReplaceInstructionOnly(IR.Instruction.CallInstruction);
            ctx.SetOperand(0, SymbolOperand.FromMethod(callTarget));
        }
        /// <summary>
        /// Processes a method call instruction.
        /// </summary>
        /// <param name="ctx">The transformation context.</param>
        /// <param name="destinationOperand">The operand, which holds the call destination.</param>
        /// <param name="resultOperand"></param>
        /// <param name="operands"></param>
        private void ProcessInvokeInstruction(Context ctx, Operand destinationOperand, Operand resultOperand, List<Operand> operands)
        {
            ctx.SetInstruction(Instruction.CallInstruction, (byte)(operands.Count + 1), (byte)(resultOperand != null ? 1 : 0));
            ctx.SetResult(resultOperand);

            int operandIndex = 0;
            ctx.SetOperand(operandIndex++, destinationOperand);
            foreach (Operand op in operands)
            {
                ctx.SetOperand(operandIndex++, op);
            }
        }
        /// <summary>
        /// Visitation function for <see cref="ICILVisitor.Newarr"/>.
        /// </summary>
        /// <param name="ctx">The context.</param>
        public void Newarr(Context ctx)
        {
            Operand thisReference = ctx.Result;
            Debug.Assert(thisReference != null, @"Newobj didn't specify class signature?");

            SZArraySigType arrayType = (SZArraySigType)ctx.Result.Type;
            ClassSigType elementSigType = arrayType.ElementType as ClassSigType;
            RuntimeType elementType = RuntimeBase.Instance.TypeLoader.GetType(this.MethodCompiler.Method, this.MethodCompiler.Assembly, elementSigType.Token);
            Debug.Assert(elementType != null, @"Newarr didn't specify class signature?");

            Operand lengthOperand = ctx.Operand1;
            int elementSize = elementType.Size;

            // HACK: If we can't determine the size now, assume 16 bytes per array element.
            if (elementSize == 0)
            {
                elementSize = 16;
            }

            ReplaceWithInternalCall(ctx, VmCall.AllocateArray);

            ctx.SetOperand(1, new ConstantOperand(BuiltInSigType.IntPtr, 0));
            ctx.SetOperand(2, new ConstantOperand(BuiltInSigType.Int32, elementSize));
            ctx.SetOperand(3, lengthOperand);
            ctx.OperandCount = 4;
        }
예제 #13
0
        /// <summary>
        /// Assigns registers to operands of the instruction.
        /// </summary>
        /// <param name="ctx">The context.</param>
        private void AssignRegisters(Context ctx)
        {
            // Retrieve the register constraints for the instruction
            IRegisterConstraint rc = null;             // _architecture.GetRegisterConstraint(instr);	// FIXME PG - pass context instead???

            // Operand index
            int opIdx;

            if (rc == null && TRACING.TraceWarning)
            {
                Trace.WriteLine(String.Format(@"Failed to get register constraints for instruction {0}!", ctx.Instruction.ToString(ctx)));
            }

            // Only process the instruction, if we have constraints...
            if (rc != null)
            {
                /* FIXME: Spill used registers, if they are in use :(
                 * It is not as simple as it sounds, as the register may be used by the instruction itself,
                 * but dirty afterwards anyways. So we need to decide this at some later point depending on
                 * the arg list. If the register is also a result reg, and they represent the same operand,
                 * we may get away without spilling... Oo?
                 */
                //Register[] used = rc.GetRegistersUsed();

                opIdx = 0;

                Context at = ctx.Clone();

                foreach (Operand op in ctx.Operands)
                {
                    // Only allocate registers, if we really have to.
                    if (!rc.IsValidOperand(opIdx, op))
                    {
                        // The register operand allocated
                        RegisterOperand rop;
                        // List of compatible registers
                        Register[] regs = rc.GetRegistersForOperand(opIdx);
                        Debug.Assert(null != regs, @"IRegisterConstraint.GetRegistersForOperand returned null.");
                        Debug.Assert(0 != regs.Length, @"WTF IRegisterConstraint.GetRegistersForOperand returned zero-length array - what shall we pass then if no register/memory?");

                        // Is this operand in a register?
                        rop = GetRegisterOfOperand(op);
                        if (rop != null && Array.IndexOf(regs, rop.Register) == -1)
                        {
                            // Spill the register...
                            SpillRegister(ctx, op, rop);
                            rop = null;
                        }

                        // Attempt to allocate a free register
                        if (rop == null)
                        {
                            rop = AllocateRegister(regs, op);
                            if (rop != null)
                            {
                                // We need to place a load here... :(
                                InsertMove(ctx, rop, op);
                            }
                        }

                        // Still failed to get one? Spill!
                        if (rop == null)
                        {
                            // Darn, need to spill one... Always use the first one.
                            rop = SpillRegister(at, op.Type, regs);

                            // We need to place a load here... :(
                            InsertMove(at, rop, op);
                        }

                        // Assign the register
                        Debug.Assert(rop != null, @"Whoa: Failed to allocate a register operand??");
                        AssignRegister(rop, op, at);
                        ctx.SetOperand(opIdx, rop);                         // FIXME PG - opIdx? hmmm. is this phidata?
                    }

                    opIdx++;
                }

                opIdx = 0;
                foreach (Operand res in ctx.Results)
                {
                    // FIXME: Check support first, spill if register is target and in use
                    if (!rc.IsValidResult(opIdx, res))
                    {
                        // Is this operand in a register?
                        RegisterOperand rop = GetRegisterOfOperand(res);
                        if (rop == null && !rc.IsValidResult(opIdx, res) && res.Uses.Count == 0)
                        {
                            // Do not allocate: Not in a register, allows memory & has no uses... oO wtf?
                            continue;
                        }

                        // Retrieve compliant registers
                        Register[] regs = rc.GetRegistersForResult(opIdx);

                        // Do we already have a register?
                        if (rop != null && Array.IndexOf(regs, rop.Register) == -1)
                        {
                            // Hmm, current register doesn't match, release it - since we're overwriting the operand,
                            // we don't need to spill. This should be safe.
                            _activeOperands[rop.Register.Index] = null;
                        }

                        // Allocate a register
                        if (rop == null)
                        {
                            rop = AllocateRegister(regs, res);
                        }

                        // Do we need to spill?
                        if (rop == null)
                        {
                            // Darn, need to spill one...
                            rop = SpillRegister(at, res.Type, regs);
                            // We don't need to place a load here, as we're defining the register...
                        }

                        // Assign the register
                        Debug.Assert(null != rop, @"Whoa: Failed to allocate a register operand??");
                        AssignRegister(rop, res, at);
                        ctx.SetResult(opIdx, rop);                         // FIXME PG - same
                    }
                    else
                    {
                        RegisterOperand rop = res as RegisterOperand;
                        if (rop != null)
                        {
                            SpillRegisterIfInUse(ctx, rop);
                        }
                    }

                    opIdx++;
                }
            }
        }
        /// <summary>
        /// Replaces the instruction with an internal call.
        /// </summary>
        /// <param name="context">The transformation context.</param>
        /// <param name="internalCallTarget">The internal call target.</param>
        private void ReplaceWithVmCall(Context context, VmCall internalCallTarget)
        {
            RuntimeType type = typeSystem.GetType(@"Mosa.Internal.Runtime");
            Debug.Assert(type != null, "Cannot find Mosa.Internal.Runtime");

            RuntimeMethod method = type.FindMethod(internalCallTarget.ToString());
            Debug.Assert(method != null, "Cannot find method: " + internalCallTarget.ToString());

            context.ReplaceInstructionOnly(IR.Instruction.CallInstruction);
            context.SetOperand(0, SymbolOperand.FromMethod(method));
        }
        /// <summary>
        /// Visitation function for Newarr instruction.
        /// </summary>
        /// <param name="context">The context.</param>
        public void Newarr(Context context)
        {
            Operand thisReference = context.Result;
            Debug.Assert(thisReference != null, @"Newobj didn't specify class signature?");

            SZArraySigType arrayType = (SZArraySigType)context.Result.Type;
            ClassSigType elementSigType = arrayType.ElementType as ClassSigType;
            RuntimeType elementType = typeModule.GetType(elementSigType.Token);
            Debug.Assert(elementType != null, @"Newarr didn't specify class signature?");

            Operand lengthOperand = context.Operand1;
            int elementSize = typeLayout.GetTypeSize(elementType);

            // HACK: If we can't determine the size now, assume 16 bytes per array element.
            if (elementSize == 0)
            {
                elementSize = 16;
            }

            ReplaceWithVmCall(context, VmCall.AllocateArray);

            context.SetOperand(1, new ConstantOperand(BuiltInSigType.IntPtr, 0));
            context.SetOperand(2, new ConstantOperand(BuiltInSigType.Int32, elementSize));
            context.SetOperand(3, lengthOperand);
            context.OperandCount = 4;
        }
        /// <summary>
        /// Replaces the instruction with an internal call.
        /// </summary>
        /// <param name="context">The transformation context.</param>
        /// <param name="internalCallTarget">The internal call target.</param>
        private void ReplaceWithVmCall(Context context, VmCall internalCallTarget)
        {
            RuntimeType rt = typeSystem.GetType(@"Mosa.Vm.Runtime");
            Debug.Assert(rt != null, "@rt / @callTarget=" + internalCallTarget.ToString());

            RuntimeMethod callTarget = rt.FindMethod(internalCallTarget.ToString());
            Debug.Assert(callTarget != null, "@callTarget=" + internalCallTarget.ToString());

            context.ReplaceInstructionOnly(IR.Instruction.CallInstruction);
            context.SetOperand(0, SymbolOperand.FromMethod(callTarget));
        }