// TODO: // 1. If first branch is to the next basic block, // then swap branch condition, replace branch target with jump target, and remove jump instruction. // part of code: ConditionCode = GetOppositeConditionCode(ConditionCode); // 2. If the basic block contains only a single jump instruction, rewrite all jumps to avoid it. protected override void Run() { var trace = CreateTrace(); for (int f = 0; f < BasicBlocks.Count - 1; f++) { var from = BasicBlocks[f]; var next = BasicBlocks[f + 1]; Context context = new Context(InstructionSet, from, from.EndIndex); context.GotoPrevious(); while (context.IsEmpty) { context.GotoPrevious(); } if (context.Instruction.FlowControl != FlowControl.UnconditionalBranch) continue; Debug.Assert(context.Instruction.FlowControl == FlowControl.UnconditionalBranch); Debug.Assert(context.BranchTargets.Length == 1); var target = context.BranchTargets[0]; if (next.Label != target) continue; context.Remove(); } }
/// <summary> /// Replaces the intrinsic call site /// </summary> /// <param name="context">The context.</param> /// <param name="typeSystem">The type system.</param> void IIntrinsicMethod.ReplaceIntrinsicCall(Context context, ITypeSystem typeSystem, IList<RuntimeParameter> parameters) { // TODO context.Remove(); }
/// <summary> /// Visitation function for SwitchInstruction. /// </summary> /// <param name="context">The context.</param> void IIRVisitor.Switch(Context context) { int[] targets = context.BranchTargets; Operand operand = context.Operand1; context.Remove(); for (int i = 0; i < targets.Length - 1; ++i) { context.AppendInstruction(X86.Cmp, null, operand, Operand.CreateConstant(BuiltInSigType.IntPtr, i)); context.AppendInstruction(X86.Branch, ConditionCode.Equal); context.SetBranch(targets[i]); } }
/// <summary> /// Empties the block of all instructions. /// </summary> /// <param name="block">The block.</param> protected void EmptyBlockOfAllInstructions(BasicBlock block) { var ctx = new Context(InstructionSet, block); Debug.Assert(ctx.IsBlockStartInstruction); ctx.GotoNext(); while (!ctx.IsBlockEndInstruction) { if (!ctx.IsEmpty) { ctx.Remove(); } ctx.GotoNext(); } }
/// <summary> /// Visitation function for Return. /// </summary> /// <param name="context">The context.</param> void IIRVisitor.Return(Context context) { Debug.Assert(context.BranchTargets != null); if (context.Operand1 != null) { // HACK - to support test suit on windows //if (context.Operand1.IsR) //{ // Operand stack = methodCompiler.StackLayout.AddStackLocal(context.Operand1.Type); // Context before = context.InsertBefore(); // architecture.InsertMoveInstruction(before, stack, context.Operand1); // before.AppendInstruction(X86.Fld, null, stack); //} var returnOperand = context.Operand1; context.Remove(); CallingConvention.SetReturnValue(TypeLayout, context, returnOperand); context.AppendInstruction(X86.Jmp); context.SetBranch(Int32.MaxValue); } else { context.SetInstruction(X86.Jmp); context.SetBranch(Int32.MaxValue); } }
/// <summary> /// Visitation function for <see cref="IX86Visitor.Movzx"/> instructions. /// </summary> /// <param name="context">The context.</param> void IX86Visitor.Movzx(Context context) { // Movsx can not use ESI or EDI registers if (context.Operand1.IsCPURegister && (context.Operand1.Register == GeneralPurposeRegister.ESI || context.Operand1.Register == GeneralPurposeRegister.EDI)) { Debug.Assert(context.Result.IsCPURegister); Operand dest = context.Result; Operand source = context.Operand1; if (source.Register != dest.Register) { context.SetInstruction(X86.Mov, dest, source); } else { context.Remove(); } if (dest.IsShort || dest.IsChar) { context.AppendInstruction(X86.And, dest, dest, Operand.CreateConstantUnsignedInt(TypeSystem, (uint)0xffff)); } else if (dest.IsByte || dest.IsBoolean) { context.AppendInstruction(X86.And, dest, dest, Operand.CreateConstantUnsignedInt(TypeSystem, (uint)0xff)); } } }
/// <summary> /// Visitation function for <see cref="IX86Visitor.Movsx"/> instructions. /// </summary> /// <param name="context">The context.</param> void IX86Visitor.Movsx(Context context) { // Movsx can not use ESI or EDI registers if (context.Operand1.IsCPURegister && (context.Operand1.Register == GeneralPurposeRegister.ESI || context.Operand1.Register == GeneralPurposeRegister.EDI)) { Operand dest = context.Result; Operand source = context.Operand1; if (source.Register != dest.Register) { context.SetInstruction(X86.Mov, dest, source); } else { context.Remove(); } if (source.IsShort || source.IsChar) { context.AppendInstruction(X86.And, dest, dest, Operand.CreateConstantUnsignedInt(MethodCompiler.TypeSystem, (uint)0x0000ffff)); context.AppendInstruction(X86.Xor, dest, dest, Operand.CreateConstantUnsignedInt(MethodCompiler.TypeSystem, (uint)0x00010000)); context.AppendInstruction(X86.Sub, dest, dest, Operand.CreateConstantUnsignedInt(MethodCompiler.TypeSystem, (uint)0x00010000)); } else if (source.IsByte || source.IsBoolean) { context.AppendInstruction(X86.And, dest, dest, Operand.CreateConstantUnsignedInt(MethodCompiler.TypeSystem, (uint)0x000000ff)); context.AppendInstruction(X86.Xor, dest, dest, Operand.CreateConstantUnsignedInt(MethodCompiler.TypeSystem, (uint)0x00000100)); context.AppendInstruction(X86.Sub, dest, dest, Operand.CreateConstantUnsignedInt(MethodCompiler.TypeSystem, (uint)0x00000100)); } } }
/// <summary> /// Visitation function for SwitchInstruction. /// </summary> /// <param name="context">The context.</param> void IR.IIRVisitor.SwitchInstruction(Context context) { IBranch branch = context.Branch; Operand operand = context.Operand1; context.Remove(); for (int i = 0; i < branch.Targets.Length - 1; ++i) { context.AppendInstruction(Instruction.CmpInstruction, operand, new ConstantOperand(BuiltInSigType.IntPtr, i)); context.AppendInstruction(Instruction.BranchInstruction, IR.ConditionCode.Equal); context.SetBranch(branch.Targets[i]); } }
/// <summary> /// Processes the phi instruction. /// </summary> /// <param name="block">The block.</param> /// <param name="context">The context.</param> private void ProcessPhiInstruction(BasicBlock block, Context context) { for (var predecessorIndex = 0; predecessorIndex < block.PreviousBlocks.Count; ++predecessorIndex) { var predecessor = block.PreviousBlocks[predecessorIndex]; var operand = context.GetOperand(predecessorIndex); this.InsertCopyStatement(predecessor, context.Result, operand); } context.Remove(); }