/// <summary> /// Emits the specified platform instruction. /// </summary> /// <param name="node">The context.</param> /// <param name="emitter">The emitter.</param> protected override void Emit(InstructionNode node, MachineCodeEmitter emitter) { Debug.Assert(node.Result == node.Operand1, node.ToString()); OpCode opCode = ComputeOpCode(node.Result, node.Operand1, node.Operand2); emitter.Emit(opCode, node.Result, node.Operand2); }
private void AssertEqualCodified( InstructionNode instruction, int expectedResult) { var number = Codifier.Codify(instruction); Assert.Equal(expectedResult, number); var uncodifiedInstruction = Codifier.UncodifyInstruction(number); Assert.Equal(instruction.ToString(), uncodifiedInstruction.ToString()); }
private void IfThenElse(InstructionNode node) { MainTrace?.Log(node.ToString()); var result = GetVariableState(node.Result); var operand1 = GetVariableState(node.Operand2); var operand2 = GetVariableState(node.Operand3); if (result.IsOverDefined) { return; } if (operand1.IsOverDefined || operand1.IsOverDefined) { UpdateToOverDefined(result); } else if (operand1.HasOnlyConstants && operand2.HasOnlyConstants) { foreach (var c in operand1.Constants) { UpdateToConstant(result, c); if (result.IsOverDefined) { return; } } foreach (var c in operand2.Constants) { UpdateToConstant(result, c); if (result.IsOverDefined) { return; } } } else if (operand1.IsUnknown || operand2.IsUnknown) { Debug.Assert(result.IsUnknown); } else { UpdateToOverDefined(result); } }
/// <summary> /// Logs the instructions in the given enumerable to the trace. /// </summary> /// <param name="traceLog">The trace log.</param> /// <param name="node">The context.</param> private static void LogInstructions(TraceLog traceLog, InstructionNode node) { for (; !node.IsBlockEndInstruction; node = node.Next) { if (node.IsEmpty) { continue; } traceLog.Log(node.ToString()); if (node.IsBlockEndInstruction) { return; } } }
protected override void EmitInstruction(InstructionNode node, BaseCodeEmitter codeEmitter) { long start = codeEmitter.CurrentPosition; base.EmitInstruction(node, codeEmitter); long end = codeEmitter.CurrentPosition; var instruction = simAdapter.Convert(node, MethodCompiler.Method, BasicBlocks, (byte)(end - start)); if (instruction != null) { stage.AddInstruction(symbol, start, instruction); } stage.AddSourceInformation(symbol, start, node.Offset.ToString() + "\t0x" + node.Offset.ToString("X") + "\t" + node.Block.ToString() + "\t" + symbol + "\t" + node.ToString()); }
/// <summary> /// Folds an integer operation on constants /// </summary> /// <param name="node">The node.</param> private void ConstantFoldingIntegerOperations(InstructionNode node) { if (node.IsEmpty) return; if (!(node.Instruction == IRInstruction.AddSigned || node.Instruction == IRInstruction.AddUnsigned || node.Instruction == IRInstruction.SubSigned || node.Instruction == IRInstruction.SubUnsigned || node.Instruction == IRInstruction.LogicalAnd || node.Instruction == IRInstruction.LogicalOr || node.Instruction == IRInstruction.LogicalXor || node.Instruction == IRInstruction.MulSigned || node.Instruction == IRInstruction.MulUnsigned || node.Instruction == IRInstruction.DivSigned || node.Instruction == IRInstruction.DivUnsigned || node.Instruction == IRInstruction.ArithmeticShiftRight || node.Instruction == IRInstruction.ShiftLeft || node.Instruction == IRInstruction.ShiftRight)) return; if (!node.Result.IsVirtualRegister) return; Operand result = node.Result; Operand op1 = node.Operand1; Operand op2 = node.Operand2; if (!op1.IsConstant || !op2.IsConstant) return; // Divide by zero! if ((node.Instruction == IRInstruction.DivSigned || node.Instruction == IRInstruction.DivUnsigned) && op2.IsConstant && op2.IsConstantZero) return; Operand constant = null; if (node.Instruction == IRInstruction.AddSigned || node.Instruction == IRInstruction.AddUnsigned) { constant = Operand.CreateConstant(result.Type, op1.ConstantUnsignedLongInteger + op2.ConstantUnsignedLongInteger); } else if (node.Instruction == IRInstruction.SubSigned || node.Instruction == IRInstruction.SubUnsigned) { constant = Operand.CreateConstant(result.Type, op1.ConstantUnsignedLongInteger - op2.ConstantUnsignedLongInteger); } else if (node.Instruction == IRInstruction.LogicalAnd) { constant = Operand.CreateConstant(result.Type, op1.ConstantUnsignedLongInteger & op2.ConstantUnsignedLongInteger); } else if (node.Instruction == IRInstruction.LogicalOr) { constant = Operand.CreateConstant(result.Type, op1.ConstantUnsignedLongInteger | op2.ConstantUnsignedLongInteger); } else if (node.Instruction == IRInstruction.LogicalXor) { constant = Operand.CreateConstant(result.Type, op1.ConstantUnsignedLongInteger ^ op2.ConstantUnsignedLongInteger); } else if (node.Instruction == IRInstruction.MulSigned || node.Instruction == IRInstruction.MulUnsigned) { constant = Operand.CreateConstant(result.Type, op1.ConstantUnsignedLongInteger * op2.ConstantUnsignedLongInteger); } else if (node.Instruction == IRInstruction.DivUnsigned) { constant = Operand.CreateConstant(result.Type, op1.ConstantUnsignedLongInteger / op2.ConstantUnsignedLongInteger); } else if (node.Instruction == IRInstruction.DivSigned) { constant = Operand.CreateConstant(result.Type, op1.ConstantSignedLongInteger / op2.ConstantSignedLongInteger); } else if (node.Instruction == IRInstruction.ArithmeticShiftRight) { constant = Operand.CreateConstant(result.Type, ((long)op1.ConstantUnsignedLongInteger) >> (int)op2.ConstantUnsignedLongInteger); } else if (node.Instruction == IRInstruction.ShiftRight) { constant = Operand.CreateConstant(result.Type, op1.ConstantUnsignedLongInteger >> (int)op2.ConstantUnsignedLongInteger); } else if (node.Instruction == IRInstruction.ShiftLeft) { constant = Operand.CreateConstant(result.Type, op1.ConstantUnsignedLongInteger << (int)op2.ConstantUnsignedLongInteger); } if (constant == null) return; AddOperandUsageToWorkList(node); if (trace.Active) trace.Log("*** ConstantFoldingIntegerOperations"); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); node.SetInstruction(IRInstruction.Move, node.Result, constant); constantFoldingIntegerOperationsCount++; changeCount++; if (trace.Active) trace.Log("AFTER: \t" + node.ToString()); }
private void ConstantFoldingAdditionAndSubstraction(InstructionNode node) { if (node.IsEmpty) return; if (!(node.Instruction == IRInstruction.AddSigned || node.Instruction == IRInstruction.AddUnsigned || node.Instruction == IRInstruction.SubSigned || node.Instruction == IRInstruction.SubUnsigned)) return; if (!node.Result.IsVirtualRegister) return; if (node.Result.Definitions.Count != 1) return; if (!node.Operand2.IsConstant) return; if (node.Result.Uses.Count != 1) return; var node2 = node.Result.Uses[0]; if (!(node2.Instruction == IRInstruction.AddSigned || node2.Instruction == IRInstruction.AddUnsigned || node2.Instruction == IRInstruction.SubSigned || node2.Instruction == IRInstruction.SubUnsigned)) return; if (!node2.Result.IsVirtualRegister) return; if (!node2.Operand2.IsConstant) return; Debug.Assert(node2.Result.Definitions.Count == 1); bool add = true; if ((node.Instruction == IRInstruction.AddSigned || node.Instruction == IRInstruction.AddUnsigned) && (node2.Instruction == IRInstruction.SubSigned || node2.Instruction == IRInstruction.SubUnsigned)) { add = false; } else if ((node.Instruction == IRInstruction.SubSigned || node.Instruction == IRInstruction.SubUnsigned) && (node2.Instruction == IRInstruction.AddSigned || node2.Instruction == IRInstruction.AddUnsigned)) { add = false; } ulong r = add ? node.Operand2.ConstantUnsignedLongInteger + node2.Operand2.ConstantUnsignedLongInteger : node.Operand2.ConstantUnsignedLongInteger - node2.Operand2.ConstantUnsignedLongInteger; Debug.Assert(node2.Result.Definitions.Count == 1); if (trace.Active) trace.Log("*** ConstantFoldingAdditionAndSubstraction"); AddOperandUsageToWorkList(node2); AddOperandUsageToWorkList(node); if (trace.Active) trace.Log("BEFORE:\t" + node2.ToString()); node2.SetInstruction(IRInstruction.Move, node2.Result, node.Result); if (trace.Active) trace.Log("AFTER: \t" + node2.ToString()); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); node.Operand2 = Operand.CreateConstant(node.Operand2.Type, r); if (trace.Active) trace.Log("AFTER: \t" + node.ToString()); constantFoldingAdditionAndSubstractionCount++; changeCount++; }
/// <summary> /// Simplifies subtraction where both operands are the same /// </summary> /// <param name="node">The node.</param> private void ArithmeticSimplificationSubtraction(InstructionNode node) { if (node.IsEmpty) return; if (!(node.Instruction == IRInstruction.SubSigned || node.Instruction == IRInstruction.SubUnsigned)) return; if (!node.Result.IsVirtualRegister) return; Operand result = node.Result; Operand op1 = node.Operand1; Operand op2 = node.Operand2; if (op1 != op2) return; AddOperandUsageToWorkList(node); if (trace.Active) trace.Log("*** ArithmeticSimplificationSubtraction"); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); node.SetInstruction(IRInstruction.Move, result, Operand.CreateConstant(node.Result.Type, 0)); arithmeticSimplificationSubtractionCount++; changeCount++; }
/// <summary> /// Strength reduction for multiplication when one of the constants is zero or one /// </summary> /// <param name="node">The node.</param> private void ArithmeticSimplificationMultiplication(InstructionNode node) { if (node.IsEmpty) return; if (!(node.Instruction == IRInstruction.MulSigned || node.Instruction == IRInstruction.MulUnsigned)) return; if (!node.Result.IsVirtualRegister) return; if (!node.Operand2.IsConstant) return; Operand result = node.Result; Operand op1 = node.Operand1; Operand op2 = node.Operand2; if (op2.IsConstantZero) { AddOperandUsageToWorkList(node); if (trace.Active) trace.Log("*** ArithmeticSimplificationMultiplication"); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); node.SetInstruction(IRInstruction.Move, result, Operand.CreateConstant(node.Result.Type, 0)); arithmeticSimplificationMultiplicationCount++; if (trace.Active) trace.Log("AFTER: \t" + node.ToString()); changeCount++; return; } if (op2.IsConstantOne) { AddOperandUsageToWorkList(node); if (trace.Active) trace.Log("*** ArithmeticSimplificationMultiplication"); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); node.SetInstruction(IRInstruction.Move, result, op1); arithmeticSimplificationMultiplicationCount++; if (trace.Active) trace.Log("AFTER: \t" + node.ToString()); changeCount++; return; } if (IsPowerOfTwo(op2.ConstantUnsignedLongInteger)) { uint shift = GetPowerOfTwo(op2.ConstantUnsignedLongInteger); if (shift < 32) { AddOperandUsageToWorkList(node); if (trace.Active) trace.Log("*** ArithmeticSimplificationMultiplication"); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); node.SetInstruction(IRInstruction.ShiftLeft, result, op1, Operand.CreateConstant(TypeSystem, (int)shift)); arithmeticSimplificationMultiplicationCount++; if (trace.Active) trace.Log("AFTER: \t" + node.ToString()); changeCount++; return; } } }
/// <summary> /// Strength reduction for integer addition when one of the constants is zero /// </summary> /// <param name="node">The node.</param> private void ArithmeticSimplificationAdditionAndSubstraction(InstructionNode node) { if (node.IsEmpty) return; if (!(node.Instruction == IRInstruction.AddSigned || node.Instruction == IRInstruction.AddUnsigned || node.Instruction == IRInstruction.SubSigned || node.Instruction == IRInstruction.SubUnsigned)) return; if (!node.Result.IsVirtualRegister) return; Operand result = node.Result; Operand op1 = node.Operand1; Operand op2 = node.Operand2; if (op2.IsConstant && !op1.IsConstant && op2.IsConstantZero) { AddOperandUsageToWorkList(node); if (trace.Active) trace.Log("*** ArithmeticSimplificationAdditionAndSubstraction"); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); node.SetInstruction(IRInstruction.Move, result, op1); if (trace.Active) trace.Log("AFTER: \t" + node.ToString()); arithmeticSimplificationAdditionAndSubstractionCount++; changeCount++; return; } }
/// <summary> /// Simplifies extended moves with a constant /// </summary> /// <param name="node">The node.</param> private void SimplifyExtendedMoveWithConstant(InstructionNode node) { if (node.IsEmpty) return; if (!(node.Instruction == IRInstruction.ZeroExtendedMove || node.Instruction == IRInstruction.SignExtendedMove)) return; if (!node.Result.IsVirtualRegister) return; if (node.Result.Definitions.Count != 1) return; if (!node.Operand1.IsConstant) return; Operand result = node.Result; Operand op1 = node.Operand1; Operand newOperand; if (node.Instruction == IRInstruction.ZeroExtendedMove && result.IsUnsigned && op1.IsSigned) { var newConstant = Unsign(op1.Type, op1.ConstantSignedLongInteger); newOperand = Operand.CreateConstant(node.Result.Type, newConstant); } else { newOperand = Operand.CreateConstant(node.Result.Type, op1.ConstantUnsignedLongInteger); } AddOperandUsageToWorkList(node); if (trace.Active) trace.Log("*** SimplifyExtendedMoveWithConstant"); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); node.SetInstruction(IRInstruction.Move, result, newOperand); simplifyExtendedMoveWithConstantCount++; changeCount++; if (trace.Active) trace.Log("AFTER: \t" + node.ToString()); }
private void ConstantMoveToRight(InstructionNode node) { if (node.IsEmpty) return; if (!(node.Instruction == IRInstruction.AddSigned || node.Instruction == IRInstruction.AddUnsigned || node.Instruction == IRInstruction.MulSigned || node.Instruction == IRInstruction.MulUnsigned || node.Instruction == IRInstruction.LogicalAnd || node.Instruction == IRInstruction.LogicalOr || node.Instruction == IRInstruction.LogicalXor)) return; if (node.Operand2.IsConstant) return; if (!node.Operand1.IsConstant) return; AddOperandUsageToWorkList(node); if (trace.Active) trace.Log("*** ConstantMoveToRight"); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); var op1 = node.Operand1; node.Operand1 = node.Operand2; node.Operand2 = op1; if (trace.Active) trace.Log("AFTER: \t" + node.ToString()); constantMoveToRightCount++; changeCount++; }
/// <summary> /// Folds the constant phi instruction. /// </summary> /// <param name="node">The node.</param> private void ConstantFoldingPhi(InstructionNode node) { if (node.IsEmpty) return; if (node.Instruction != IRInstruction.Phi) return; if (node.Result.Definitions.Count != 1) return; if (!node.Result.IsInteger) return; Operand operand1 = node.Operand1; Operand result = node.Result; foreach (var operand in node.Operands) { if (!operand.IsConstant) return; if (operand.ConstantUnsignedLongInteger != operand1.ConstantUnsignedLongInteger) return; } if (trace.Active) trace.Log("*** FoldConstantPhiInstruction"); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); AddOperandUsageToWorkList(node); node.SetInstruction(IRInstruction.Move, result, operand1); if (trace.Active) trace.Log("AFTER: \t" + node.ToString()); constantFoldingPhiCount++; changeCount++; }
private void RemoveUselessPhi(InstructionNode node) { if (node.IsEmpty) return; if (node.Instruction != IRInstruction.Phi) return; if (node.Result.Definitions.Count != 1) return; var result = node.Result; foreach (var use in node.Result.Uses) { if (use != node) return; } AddOperandUsageToWorkList(node); if (trace.Active) trace.Log("REMOVED:\t" + node.ToString()); node.SetInstruction(IRInstruction.Nop); removeUselessPhiCount++; }
/// <summary> /// Arithmetics the simplification rem unsigned modulus. /// </summary> /// <param name="node">The node.</param> private void ArithmeticSimplificationRemUnsignedModulus(InstructionNode node) { if (node.IsEmpty) return; if (!(node.Instruction == IRInstruction.RemUnsigned)) return; if (!node.Result.IsVirtualRegister) return; if (!node.Operand2.IsConstant) return; if (node.Operand2.ConstantUnsignedLongInteger == 0) return; if (!IsPowerOfTwo(node.Operand2.ConstantUnsignedLongInteger)) return; Operand result = node.Result; Operand op1 = node.Operand1; Operand op2 = node.Operand2; if (op2.ConstantUnsignedLongInteger == 0) { AddOperandUsageToWorkList(node); if (trace.Active) trace.Log("*** ArithmeticSimplificationRemUnsignedModulus"); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); node.SetInstruction(IRInstruction.Move, result, Operand.CreateConstant(TypeSystem, 0)); arithmeticSimplificationModulus++; changeCount++; if (trace.Active) trace.Log("AFTER: \t" + node.ToString()); return; } int power = GetPowerOfTwo(op2.ConstantUnsignedLongInteger); var mask = (1 << power) - 1; var constant = Operand.CreateConstant(TypeSystem, mask); AddOperandUsageToWorkList(node); if (trace.Active) trace.Log("*** ArithmeticSimplificationRemUnsignedModulus"); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); node.SetInstruction(IRInstruction.LogicalAnd, result, op1, constant); arithmeticSimplificationModulus++; changeCount++; if (trace.Active) trace.Log("AFTER: \t" + node.ToString()); return; }
/// <summary> /// Arithmetics the simplification rem signed modulus. /// </summary> /// <param name="node">The node.</param> private void ArithmeticSimplificationRemSignedModulus(InstructionNode node) { if (node.IsEmpty) return; if (!(node.Instruction == IRInstruction.RemSigned)) return; if (!node.Result.IsVirtualRegister) return; if (!node.Operand2.IsConstant) return; if (node.Operand2.ConstantUnsignedLongInteger != 1) return; Operand result = node.Result; Operand op1 = node.Operand1; Operand op2 = node.Operand2; AddOperandUsageToWorkList(node); if (trace.Active) trace.Log("*** ArithmeticSimplificationRemSignedModulus"); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); node.SetInstruction(IRInstruction.Move, result, Operand.CreateConstant(TypeSystem, 0)); arithmeticSimplificationModulus++; changeCount++; if (trace.Active) trace.Log("AFTER: \t" + node.ToString()); return; }
private void ConstantFoldingDivision(InstructionNode node) { if (!(node.Instruction == IRInstruction.DivSigned || node.Instruction == IRInstruction.DivUnsigned)) return; if (!node.Result.IsVirtualRegister) return; if (node.Result.Definitions.Count != 1) return; if (!node.Operand2.IsResolvedConstant) return; if (node.Result.Uses.Count != 1) return; var node2 = node.Result.Uses[0]; if (!(node2.Instruction == IRInstruction.DivSigned || node2.Instruction == IRInstruction.DivUnsigned)) return; if (!node2.Result.IsVirtualRegister) return; if (!node2.Operand2.IsResolvedConstant) return; Debug.Assert(node2.Result.Definitions.Count == 1); ulong r = (node2.Instruction == IRInstruction.DivSigned) ? (ulong)(node.Operand2.ConstantSignedLongInteger / node2.Operand2.ConstantSignedLongInteger) : node.Operand2.ConstantUnsignedLongInteger / node2.Operand2.ConstantUnsignedLongInteger; if (trace.Active) trace.Log("*** ConstantFoldingDivision"); AddOperandUsageToWorkList(node2); AddOperandUsageToWorkList(node); if (trace.Active) trace.Log("BEFORE:\t" + node2.ToString()); node2.SetInstruction(IRInstruction.MoveInteger, node2.Result, node.Result); if (trace.Active) trace.Log("AFTER: \t" + node2.ToString()); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); node.Operand2 = Operand.CreateConstant(node.Operand2.Type, r); if (trace.Active) trace.Log("AFTER: \t" + node.ToString()); constantFoldingDivisionCount++; changeCount++; }
/// <summary> /// Removes the useless move and dead code /// </summary> /// <param name="node">The node.</param> private void DeadCodeElimination(InstructionNode node) { if (node.IsEmpty) return; if (node.ResultCount != 1) return; if (!node.Result.IsVirtualRegister) return; if (node.Result.Definitions.Count != 1) return; if (node.Instruction == IRInstruction.Call || node.Instruction == IRInstruction.IntrinsicMethodCall) return; if (node.Instruction == IRInstruction.Move && node.Operand1.IsVirtualRegister && node.Operand1 == node.Result) { if (trace.Active) trace.Log("*** DeadCodeElimination"); if (trace.Active) trace.Log("REMOVED:\t" + node.ToString()); AddOperandUsageToWorkList(node); node.SetInstruction(IRInstruction.Nop); instructionsRemovedCount++; deadCodeEliminationCount++; changeCount++; return; } if (node.Result.Uses.Count != 0) return; if (trace.Active) trace.Log("*** DeadCodeElimination"); if (trace.Active) trace.Log("REMOVED:\t" + node.ToString()); AddOperandUsageToWorkList(node); node.SetInstruction(IRInstruction.Nop); instructionsRemovedCount++; deadCodeEliminationCount++; changeCount++; return; }
/// <summary> /// Simplifies the phi. /// </summary> /// <param name="node">The node.</param> private void SimplifyPhi(InstructionNode node) { if (node.IsEmpty) return; if (node.Instruction != IRInstruction.Phi) return; if (node.OperandCount != 1) return; if (node.Result.Definitions.Count != 1) return; if (trace.Active) trace.Log("*** SimplifyPhiInstruction"); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); AddOperandUsageToWorkList(node); node.SetInstruction(IRInstruction.Move, node.Result, node.Operand1); if (trace.Active) trace.Log("AFTER: \t" + node.ToString()); simplifyPhiCount++; changeCount++; }
private void DeadCodeEliminationPhi(InstructionNode node) { if (node.IsEmpty) return; if (node.Instruction != IRInstruction.Phi) return; if (node.Result.Definitions.Count != 1) return; var result = node.Result; foreach (var use in result.Uses) { if (use != node) return; } AddOperandUsageToWorkList(node); if (trace.Active) trace.Log("*** DeadCodeEliminationPhi"); if (trace.Active) trace.Log("REMOVED:\t" + node.ToString()); node.SetInstruction(IRInstruction.Nop); deadCodeEliminationPhi++; changeCount++; }
/// <summary> /// Strength reduction for logical operators /// </summary> /// <param name="node">The node.</param> private void ArithmeticSimplificationLogicalOperators(InstructionNode node) { if (node.IsEmpty) return; if (!(node.Instruction == IRInstruction.LogicalAnd || node.Instruction == IRInstruction.LogicalOr)) return; if (!node.Result.IsVirtualRegister) return; if (!node.Operand2.IsConstant) return; Operand result = node.Result; Operand op1 = node.Operand1; Operand op2 = node.Operand2; if (node.Instruction == IRInstruction.LogicalOr) { if (op2.IsConstantZero) { AddOperandUsageToWorkList(node); if (trace.Active) trace.Log("*** ArithmeticSimplificationLogicalOperators"); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); node.SetInstruction(IRInstruction.Move, result, op1); arithmeticSimplificationLogicalOperatorsCount++; changeCount++; if (trace.Active) trace.Log("AFTER: \t" + node.ToString()); return; } } else if (node.Instruction == IRInstruction.LogicalAnd) { if (op2.IsConstantZero) { AddOperandUsageToWorkList(node); if (trace.Active) trace.Log("*** ArithmeticSimplificationLogicalOperators"); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); node.SetInstruction(IRInstruction.Move, result, Operand.CreateConstant(node.Result.Type, 0)); arithmeticSimplificationLogicalOperatorsCount++; changeCount++; if (trace.Active) trace.Log("AFTER: \t" + node.ToString()); return; } if (((result.IsI4 || result.IsU4 || result.IsI || result.IsU) && op2.ConstantUnsignedInteger == 0xFFFFFFFF) || ((result.IsI8 || result.IsU8) && op2.ConstantUnsignedLongInteger == 0xFFFFFFFFFFFFFFFF)) { AddOperandUsageToWorkList(node); if (trace.Active) trace.Log("*** ArithmeticSimplificationLogicalOperators"); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); node.SetInstruction(IRInstruction.Move, result, op1); arithmeticSimplificationLogicalOperatorsCount++; changeCount++; if (trace.Active) trace.Log("AFTER: \t" + node.ToString()); return; } } // TODO: Add more strength reductions especially for AND w/ 0xFF, 0xFFFF, 0xFFFFFFFF, etc when source or destination are same or smaller }
/// <summary> /// Folds integer compare branch. /// </summary> /// <param name="node">The node.</param> private void FoldIntegerCompareBranch(InstructionNode node) { if (node.IsEmpty) return; if (node.Instruction != IRInstruction.IntegerCompareBranch) return; Debug.Assert(node.OperandCount == 2); Operand op1 = node.Operand1; Operand op2 = node.Operand2; if (!op1.IsConstant || !op2.IsConstant) return; Operand result = node.Result; InstructionNode nextNode = node.Next; if (nextNode.Instruction != IRInstruction.Jmp) return; if (node.BranchTargets[0] == nextNode.BranchTargets[0]) { if (trace.Active) trace.Log("*** FoldIntegerCompareBranch-Useless"); if (trace.Active) trace.Log("REMOVED:\t" + node.ToString()); AddOperandUsageToWorkList(node); node.SetInstruction(IRInstruction.Nop); instructionsRemovedCount++; foldIntegerCompareBranchCount++; changeCount++; return; } bool compareResult = true; switch (node.ConditionCode) { case ConditionCode.Equal: compareResult = (op1.ConstantUnsignedLongInteger == op2.ConstantUnsignedLongInteger); break; case ConditionCode.NotEqual: compareResult = (op1.ConstantUnsignedLongInteger != op2.ConstantUnsignedLongInteger); break; case ConditionCode.GreaterOrEqual: compareResult = (op1.ConstantUnsignedLongInteger >= op2.ConstantUnsignedLongInteger); break; case ConditionCode.GreaterThan: compareResult = (op1.ConstantUnsignedLongInteger > op2.ConstantUnsignedLongInteger); break; case ConditionCode.LessOrEqual: compareResult = (op1.ConstantUnsignedLongInteger <= op2.ConstantUnsignedLongInteger); break; case ConditionCode.LessThan: compareResult = (op1.ConstantUnsignedLongInteger < op2.ConstantUnsignedLongInteger); break; // TODO: Add more default: return; } BasicBlock notTaken; InstructionNode notUsed; if (trace.Active) trace.Log("*** FoldIntegerCompareBranch"); if (compareResult) { notTaken = nextNode.BranchTargets[0]; if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); node.SetInstruction(IRInstruction.Jmp, node.BranchTargets[0]); if (trace.Active) trace.Log("AFTER:\t" + node.ToString()); notUsed = nextNode; } else { notTaken = node.BranchTargets[0]; notUsed = node; } if (trace.Active) trace.Log("REMOVED:\t" + node.ToString()); AddOperandUsageToWorkList(notUsed); notUsed.SetInstruction(IRInstruction.Nop); instructionsRemovedCount++; foldIntegerCompareBranchCount++; changeCount++; // if target block no longer has any predecessors (or the only predecessor is itself), remove all instructions from it. CheckAndClearEmptyBlock(notTaken); }
/// <summary> /// Strength reduction shift operators. /// </summary> /// <param name="node">The node.</param> private void ArithmeticSimplificationShiftOperators(InstructionNode node) { if (node.IsEmpty) return; if (!(node.Instruction == IRInstruction.ShiftLeft || node.Instruction == IRInstruction.ShiftRight || node.Instruction == IRInstruction.ArithmeticShiftRight)) return; if (!node.Result.IsVirtualRegister) return; if (!node.Operand2.IsConstant) return; Operand result = node.Result; Operand op1 = node.Operand1; Operand op2 = node.Operand2; if (op2.IsConstantZero || op1.IsConstantZero) { AddOperandUsageToWorkList(node); if (trace.Active) trace.Log("*** ArithmeticSimplificationShiftOperators"); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); node.SetInstruction(IRInstruction.Move, result, op1); arithmeticSimplificationShiftOperators++; changeCount++; if (trace.Active) trace.Log("AFTER: \t" + node.ToString()); return; } }
private void FoldLoadStoreOffsets(InstructionNode node) { if (node.IsEmpty) return; if (!(node.Instruction == IRInstruction.Load || node.Instruction == IRInstruction.Store || node.Instruction == IRInstruction.LoadSignExtended || node.Instruction == IRInstruction.LoadZeroExtended)) return; if (!node.Operand2.IsConstant) return; if (!node.Operand1.IsVirtualRegister) return; if (node.Operand1.Uses.Count != 1) return; var node2 = node.Operand1.Definitions[0]; if (!(node2.Instruction == IRInstruction.AddSigned || node2.Instruction == IRInstruction.SubSigned || node2.Instruction == IRInstruction.AddUnsigned || node2.Instruction == IRInstruction.SubUnsigned)) return; if (!node2.Operand2.IsConstant) return; Operand constant; if (node2.Instruction == IRInstruction.AddUnsigned || node2.Instruction == IRInstruction.AddSigned) { constant = Operand.CreateConstant(node.Operand2.Type, node2.Operand2.ConstantSignedLongInteger + node.Operand2.ConstantSignedLongInteger); } else { constant = Operand.CreateConstant(node.Operand2.Type, node.Operand2.ConstantSignedLongInteger - node2.Operand2.ConstantSignedLongInteger); } if (trace.Active) trace.Log("*** FoldLoadStoreOffsets"); AddOperandUsageToWorkList(node); AddOperandUsageToWorkList(node2); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); node.Operand1 = node2.Operand1; node.Operand2 = constant; if (trace.Active) trace.Log("AFTER: \t" + node.ToString()); if (trace.Active) trace.Log("REMOVED:\t" + node2.ToString()); node2.SetInstruction(IRInstruction.Nop); foldLoadStoreOffsetsCount++; instructionsRemovedCount++; changeCount++; }
private void CombineIntegerCompareBranch(InstructionNode node) { if (node.IsEmpty) return; if (node.Instruction != IRInstruction.IntegerCompareBranch) return; if (!(node.ConditionCode == ConditionCode.NotEqual || node.ConditionCode == ConditionCode.Equal)) return; if (!((node.Operand1.IsVirtualRegister && node.Operand2.IsConstant && node.Operand2.IsConstantZero) || (node.Operand2.IsVirtualRegister && node.Operand1.IsConstant && node.Operand1.IsConstantZero))) return; var operand = (node.Operand2.IsConstant && node.Operand2.IsConstantZero) ? node.Operand1 : node.Operand2; if (operand.Uses.Count != 1) return; if (operand.Definitions.Count != 1) return; var node2 = operand.Definitions[0]; if (node2.Instruction != IRInstruction.IntegerCompare) return; AddOperandUsageToWorkList(node2); AddOperandUsageToWorkList(node); if (trace.Active) trace.Log("*** CombineIntegerCompareBranch"); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); node.ConditionCode = node.ConditionCode == ConditionCode.NotEqual ? node2.ConditionCode : node2.ConditionCode.GetOpposite(); node.Operand1 = node2.Operand1; node.Operand2 = node2.Operand2; if (trace.Active) trace.Log("AFTER: \t" + node.ToString()); if (trace.Active) trace.Log("REMOVED:\t" + node2.ToString()); node2.SetInstruction(IRInstruction.Nop); combineIntegerCompareBranchCount++; instructionsRemovedCount++; changeCount++; }
private void NormalizeConstantTo32Bit(InstructionNode node) { if (node.IsEmpty) return; if (node.ResultCount != 1) return; if (!node.Result.IsInt) return; if (node.Instruction == IRInstruction.LogicalAnd || node.Instruction == IRInstruction.LogicalOr || node.Instruction == IRInstruction.LogicalXor || node.Instruction == IRInstruction.LogicalNot) { if (node.Operand1.IsConstant && node.Operand1.IsLong) { if (trace.Active) trace.Log("*** NormalizeConstantTo32Bit"); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); node.Operand1 = Operand.CreateConstant(TypeSystem, (int)(node.Operand1.ConstantUnsignedLongInteger & uint.MaxValue)); changeCount++; if (trace.Active) trace.Log("AFTER: \t" + node.ToString()); AddOperandUsageToWorkList(node); } if (node.OperandCount >= 2 && node.Operand2.IsConstant && node.Operand2.IsLong) { if (trace.Active) trace.Log("*** NormalizeConstantTo32Bit"); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); node.Operand2 = Operand.CreateConstant(TypeSystem, (int)(node.Operand2.ConstantUnsignedLongInteger & uint.MaxValue)); changeCount++; if (trace.Active) trace.Log("AFTER: \t" + node.ToString()); AddOperandUsageToWorkList(node); } } }
/// <summary> /// Folds the integer compare on constants /// </summary> /// <param name="node">The node.</param> private void ConstantFoldingIntegerCompare(InstructionNode node) { if (node.IsEmpty) return; if (node.Instruction != IRInstruction.IntegerCompare) return; if (!node.Result.IsVirtualRegister) return; Operand result = node.Result; Operand op1 = node.Operand1; Operand op2 = node.Operand2; if (!op1.IsConstant || !op2.IsConstant) return; if (!op1.IsValueType || !op2.IsValueType) return; bool compareResult = true; switch (node.ConditionCode) { case ConditionCode.Equal: compareResult = (op1.ConstantUnsignedLongInteger == op2.ConstantUnsignedLongInteger); break; case ConditionCode.NotEqual: compareResult = (op1.ConstantUnsignedLongInteger != op2.ConstantUnsignedLongInteger); break; case ConditionCode.GreaterOrEqual: compareResult = (op1.ConstantUnsignedLongInteger >= op2.ConstantUnsignedLongInteger); break; case ConditionCode.GreaterThan: compareResult = (op1.ConstantUnsignedLongInteger > op2.ConstantUnsignedLongInteger); break; case ConditionCode.LessOrEqual: compareResult = (op1.ConstantUnsignedLongInteger <= op2.ConstantUnsignedLongInteger); break; case ConditionCode.LessThan: compareResult = (op1.ConstantUnsignedLongInteger < op2.ConstantUnsignedLongInteger); break; // TODO: Add more default: return; } AddOperandUsageToWorkList(node); if (trace.Active) trace.Log("*** ConstantFoldingIntegerCompare"); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); node.SetInstruction(IRInstruction.Move, result, Operand.CreateConstant(result.Type, compareResult ? 1 : 0)); constantFoldingIntegerCompareCount++; changeCount++; if (trace.Active) trace.Log("AFTER: \t" + node.ToString()); }
private void ReduceZeroExtendedMove(InstructionNode node) { if (node.IsEmpty) return; if (node.Instruction != IRInstruction.ZeroExtendedMove) return; if (!node.Operand1.IsVirtualRegister) return; if (!node.Result.IsVirtualRegister) return; if (trace.Active) trace.Log("*** ReduceZeroExtendedMove"); AddOperandUsageToWorkList(node); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); node.SetInstruction(IRInstruction.Move, node.Result, node.Operand1); if (trace.Active) trace.Log("AFTER: \t" + node.ToString()); reduceZeroExtendedMoveCount++; changeCount++; }
private void ConstantFoldingLogicalOr(InstructionNode node) { if (node.IsEmpty) return; if (node.Instruction != IRInstruction.LogicalOr) return; if (!node.Result.IsVirtualRegister) return; if (node.Result.Definitions.Count != 1) return; if (!node.Operand2.IsConstant) return; if (node.Result.Uses.Count != 1) return; var node2 = node.Result.Uses[0]; if (node2.Instruction != IRInstruction.LogicalOr) return; if (!node2.Result.IsVirtualRegister) return; if (!node2.Operand2.IsConstant) return; Debug.Assert(node2.Result.Definitions.Count == 1); ulong r = node.Operand2.ConstantUnsignedLongInteger | node2.Operand2.ConstantUnsignedLongInteger; if (trace.Active) trace.Log("*** ConstantFoldingLogicalOr"); AddOperandUsageToWorkList(node2); AddOperandUsageToWorkList(node); if (trace.Active) trace.Log("BEFORE:\t" + node2.ToString()); node2.SetInstruction(IRInstruction.Move, node2.Result, node.Result); if (trace.Active) trace.Log("AFTER: \t" + node2.ToString()); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); node.Operand2 = Operand.CreateConstant(node.Operand2.Type, r); if (trace.Active) trace.Log("AFTER: \t" + node.ToString()); constantFoldingLogicalOrCount++; changeCount++; }
/// <summary> /// Removes the unless integer compare branch. /// </summary> /// <param name="node">The node.</param> private void RemoveUselessIntegerCompareBranch(InstructionNode node) { if (node.IsEmpty) return; if (node.Instruction != IRInstruction.IntegerCompareBranch) return; if (node.Block.NextBlocks.Count != 1) return; if (trace.Active) trace.Log("REMOVED:\t" + node.ToString()); AddOperandUsageToWorkList(node); node.SetInstruction(IRInstruction.Nop); instructionsRemovedCount++; removeUselessIntegerCompareBranch++; changeCount++; }
/// <summary> /// Simple copy propagation. /// </summary> /// <param name="node">The node.</param> private void SimpleForwardCopyPropagation(InstructionNode node) { if (node.IsEmpty) return; if (node.Instruction != IRInstruction.Move) return; if (!node.Result.IsVirtualRegister) return; if (node.Result.Definitions.Count != 1) return; if (node.Operand1.Definitions.Count != 1) return; if (node.Operand1.IsConstant) return; if (!node.Operand1.IsVirtualRegister) return; // If the pointer or reference types are different, we can not copy propagation because type information would be lost. // Also if the operand sign is different, we cannot do it as it requires a signed/unsigned extended move, not a normal move if (!CanCopyPropagation(node.Result, node.Operand1)) return; Operand destination = node.Result; Operand source = node.Operand1; if (ContainsAddressOf(destination)) return; // for each statement T that uses operand, substituted c in statement T AddOperandUsageToWorkList(node); foreach (var useNode in destination.Uses.ToArray()) { for (int i = 0; i < useNode.OperandCount; i++) { var operand = useNode.GetOperand(i); if (destination == operand) { if (trace.Active) trace.Log("*** SimpleForwardCopyPropagation"); if (trace.Active) trace.Log("BEFORE:\t" + useNode.ToString()); useNode.SetOperand(i, source); simpleForwardCopyPropagationCount++; changeCount++; if (trace.Active) trace.Log("AFTER: \t" + useNode.ToString()); } } } Debug.Assert(destination.Uses.Count == 0); if (trace.Active) trace.Log("REMOVED:\t" + node.ToString()); AddOperandUsageToWorkList(node); node.SetInstruction(IRInstruction.Nop); instructionsRemovedCount++; changeCount++; }
/// <summary> /// Simplifies sign/zero extended move /// </summary> /// <param name="node">The node.</param> private void SimplifyExtendedMove(InstructionNode node) { if (node.IsEmpty) return; if (!(node.Instruction == IRInstruction.ZeroExtendedMove || node.Instruction == IRInstruction.SignExtendedMove)) return; if (!node.Result.IsVirtualRegister || !node.Operand1.IsVirtualRegister) return; if (!((NativePointerSize == 4 && node.Result.IsInt && (node.Operand1.IsInt || node.Operand1.IsU || node.Operand1.IsI)) || (NativePointerSize == 4 && node.Operand1.IsInt && (node.Result.IsInt || node.Result.IsU || node.Result.IsI)) || (NativePointerSize == 8 && node.Result.IsLong && (node.Operand1.IsLong || node.Operand1.IsU || node.Operand1.IsI)) || (NativePointerSize == 8 && node.Operand1.IsLong && (node.Result.IsLong || node.Result.IsU || node.Result.IsI)))) return; AddOperandUsageToWorkList(node); if (trace.Active) trace.Log("*** SimplifyExtendedMove"); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); node.SetInstruction(IRInstruction.Move, node.Result, node.Operand1); simplifyExtendedMoveCount++; if (trace.Active) trace.Log("AFTER: \t" + node.ToString()); changeCount++; }
private void Phi(InstructionNode node) { MainTrace?.Log(node.ToString()); var result = GetVariableState(node.Result); if (result.IsOverDefined) { return; } var sourceBlocks = node.PhiBlocks; var currentBlock = node.Block; MainTrace?.Log($"Loop: {currentBlock.PreviousBlocks.Count}"); for (var index = 0; index < currentBlock.PreviousBlocks.Count; index++) { var predecessor = sourceBlocks[index]; phiStatements.AddIfNew(predecessor, node); bool executable = blockStates[predecessor.Sequence]; MainTrace?.Log($"# {index}: {predecessor} {(executable ? "Yes" : "No")}"); if (!executable) { continue; } if (result.IsOverDefined) { continue; } var op = node.GetOperand(index); var operand = GetVariableState(op); MainTrace?.Log($"# {index}: {operand}"); CheckAndUpdateNullAssignment(result, operand); if (operand.IsOverDefined) { UpdateToOverDefined(result); continue; } else if (operand.IsSingleConstant) { UpdateToConstant(result, operand.ConstantUnsignedLongInteger); continue; } else if (operand.HasMultipleConstants) { foreach (var c in operand.Constants) { UpdateToConstant(result, c); if (result.IsOverDefined) { break; } } } } }
/// <summary> /// Strength reduction for division when one of the constants is zero or one /// </summary> /// <param name="node">The node.</param> private void ArithmeticSimplificationDivision(InstructionNode node) { if (!(node.Instruction == IRInstruction.DivSigned || node.Instruction == IRInstruction.DivUnsigned)) return; if (!node.Result.IsVirtualRegister) return; Operand result = node.Result; Operand op1 = node.Operand1; Operand op2 = node.Operand2; if (!op2.IsResolvedConstant || op2.IsConstantZero) { // Possible divide by zero return; } if (op1.IsResolvedConstant && op1.IsConstantZero) { AddOperandUsageToWorkList(node); if (trace.Active) trace.Log("*** ArithmeticSimplificationDivision"); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); node.SetInstruction(IRInstruction.MoveInteger, result, ConstantZero); arithmeticSimplificationDivisionCount++; changeCount++; if (trace.Active) trace.Log("AFTER: \t" + node.ToString()); return; } if (op2.IsResolvedConstant && op2.IsConstantOne) { AddOperandUsageToWorkList(node); if (trace.Active) trace.Log("*** ArithmeticSimplificationDivision"); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); node.SetInstruction(IRInstruction.MoveInteger, result, op1); arithmeticSimplificationDivisionCount++; changeCount++; if (trace.Active) trace.Log("AFTER: \t" + node.ToString()); return; } if (node.Instruction == IRInstruction.DivUnsigned && IsPowerOfTwo(op2.ConstantUnsignedLongInteger)) { int shift = GetPowerOfTwo(op2.ConstantUnsignedLongInteger); if (shift < 32) { AddOperandUsageToWorkList(node); if (trace.Active) trace.Log("*** ArithmeticSimplificationDivision"); if (trace.Active) trace.Log("BEFORE:\t" + node.ToString()); node.SetInstruction(IRInstruction.ShiftRight, result, op1, Operand.CreateConstant(TypeSystem, (int)shift)); arithmeticSimplificationDivisionCount++; changeCount++; if (trace.Active) trace.Log("AFTER: \t" + node.ToString()); return; } } }