mirror of
https://github.com/Ryujinx/Ryujinx.git
synced 2024-08-18 14:48:44 +02:00
* Fix type mismatch in `BitwiseAnd` simplification `TryEliminateBitwiseAnd` would turn the `BitwiseAnd` operation into a copy of the wrong type. E.g: Before `Simplification`: ```llvm i64 %0 = BitwiseAnd i64 0x0, %1 ``` After `Simplication`: ```llvm i64 %0 = Copy i32 0x0 ``` Since the with the changes in #2515, we iterate in reverse order and `Simplication`, `ConstantFolding` does not indicate if it modified the CFG, the second pass to "retype" the copy into the proper destination type does not happen. This also blocked copy propagation since its destination type did not match with its source type. But in the cases I've seen, the `PreAllocator` would insert a copy for the propagated constant, which results in no diffs. Since the copy remained as is, asserts are fired when generating it. * Set PPTC version
183 lines
5.8 KiB
C#
183 lines
5.8 KiB
C#
using ARMeilleure.IntermediateRepresentation;
|
|
using System;
|
|
using static ARMeilleure.IntermediateRepresentation.Operand.Factory;
|
|
|
|
namespace ARMeilleure.CodeGen.Optimizations
|
|
{
|
|
static class Simplification
|
|
{
|
|
public static void RunPass(Operation operation)
|
|
{
|
|
switch (operation.Instruction)
|
|
{
|
|
case Instruction.Add:
|
|
if (operation.GetSource(0).Relocatable ||
|
|
operation.GetSource(1).Relocatable)
|
|
{
|
|
break;
|
|
}
|
|
|
|
TryEliminateBinaryOpComutative(operation, 0);
|
|
break;
|
|
|
|
case Instruction.BitwiseAnd:
|
|
TryEliminateBitwiseAnd(operation);
|
|
break;
|
|
|
|
case Instruction.BitwiseOr:
|
|
TryEliminateBitwiseOr(operation);
|
|
break;
|
|
|
|
case Instruction.BitwiseExclusiveOr:
|
|
TryEliminateBitwiseExclusiveOr(operation);
|
|
break;
|
|
|
|
case Instruction.ConditionalSelect:
|
|
TryEliminateConditionalSelect(operation);
|
|
break;
|
|
|
|
case Instruction.Divide:
|
|
TryEliminateBinaryOpY(operation, 1);
|
|
break;
|
|
|
|
case Instruction.Multiply:
|
|
TryEliminateBinaryOpComutative(operation, 1);
|
|
break;
|
|
|
|
case Instruction.ShiftLeft:
|
|
case Instruction.ShiftRightSI:
|
|
case Instruction.ShiftRightUI:
|
|
case Instruction.Subtract:
|
|
TryEliminateBinaryOpY(operation, 0);
|
|
break;
|
|
}
|
|
}
|
|
|
|
private static void TryEliminateBitwiseAnd(Operation operation)
|
|
{
|
|
// Try to recognize and optimize those 3 patterns (in order):
|
|
// x & 0xFFFFFFFF == x, 0xFFFFFFFF & y == y,
|
|
// x & 0x00000000 == 0x00000000, 0x00000000 & y == 0x00000000
|
|
Operand x = operation.GetSource(0);
|
|
Operand y = operation.GetSource(1);
|
|
|
|
if (IsConstEqual(x, AllOnes(x.Type)))
|
|
{
|
|
operation.TurnIntoCopy(y);
|
|
}
|
|
else if (IsConstEqual(y, AllOnes(y.Type)))
|
|
{
|
|
operation.TurnIntoCopy(x);
|
|
}
|
|
else if (IsConstEqual(x, 0) || IsConstEqual(y, 0))
|
|
{
|
|
operation.TurnIntoCopy(Const(x.Type, 0));
|
|
}
|
|
}
|
|
|
|
private static void TryEliminateBitwiseOr(Operation operation)
|
|
{
|
|
// Try to recognize and optimize those 3 patterns (in order):
|
|
// x | 0x00000000 == x, 0x00000000 | y == y,
|
|
// x | 0xFFFFFFFF == 0xFFFFFFFF, 0xFFFFFFFF | y == 0xFFFFFFFF
|
|
Operand x = operation.GetSource(0);
|
|
Operand y = operation.GetSource(1);
|
|
|
|
if (IsConstEqual(x, 0))
|
|
{
|
|
operation.TurnIntoCopy(y);
|
|
}
|
|
else if (IsConstEqual(y, 0))
|
|
{
|
|
operation.TurnIntoCopy(x);
|
|
}
|
|
else if (IsConstEqual(x, AllOnes(x.Type)) || IsConstEqual(y, AllOnes(y.Type)))
|
|
{
|
|
operation.TurnIntoCopy(Const(AllOnes(x.Type)));
|
|
}
|
|
}
|
|
|
|
private static void TryEliminateBitwiseExclusiveOr(Operation operation)
|
|
{
|
|
// Try to recognize and optimize those 2 patterns (in order):
|
|
// x ^ y == 0x00000000 when x == y
|
|
// 0x00000000 ^ y == y, x ^ 0x00000000 == x
|
|
Operand x = operation.GetSource(0);
|
|
Operand y = operation.GetSource(1);
|
|
|
|
if (x == y && x.Type.IsInteger())
|
|
{
|
|
operation.TurnIntoCopy(Const(x.Type, 0));
|
|
}
|
|
else
|
|
{
|
|
TryEliminateBinaryOpComutative(operation, 0);
|
|
}
|
|
}
|
|
|
|
private static void TryEliminateBinaryOpY(Operation operation, ulong comparand)
|
|
{
|
|
Operand x = operation.GetSource(0);
|
|
Operand y = operation.GetSource(1);
|
|
|
|
if (IsConstEqual(y, comparand))
|
|
{
|
|
operation.TurnIntoCopy(x);
|
|
}
|
|
}
|
|
|
|
private static void TryEliminateBinaryOpComutative(Operation operation, ulong comparand)
|
|
{
|
|
Operand x = operation.GetSource(0);
|
|
Operand y = operation.GetSource(1);
|
|
|
|
if (IsConstEqual(x, comparand))
|
|
{
|
|
operation.TurnIntoCopy(y);
|
|
}
|
|
else if (IsConstEqual(y, comparand))
|
|
{
|
|
operation.TurnIntoCopy(x);
|
|
}
|
|
}
|
|
|
|
private static void TryEliminateConditionalSelect(Operation operation)
|
|
{
|
|
Operand cond = operation.GetSource(0);
|
|
|
|
if (cond.Kind != OperandKind.Constant)
|
|
{
|
|
return;
|
|
}
|
|
|
|
// The condition is constant, we can turn it into a copy, and select
|
|
// the source based on the condition value.
|
|
int srcIndex = cond.Value != 0 ? 1 : 2;
|
|
|
|
Operand source = operation.GetSource(srcIndex);
|
|
|
|
operation.TurnIntoCopy(source);
|
|
}
|
|
|
|
private static bool IsConstEqual(Operand operand, ulong comparand)
|
|
{
|
|
if (operand.Kind != OperandKind.Constant || !operand.Type.IsInteger())
|
|
{
|
|
return false;
|
|
}
|
|
|
|
return operand.Value == comparand;
|
|
}
|
|
|
|
private static ulong AllOnes(OperandType type)
|
|
{
|
|
switch (type)
|
|
{
|
|
case OperandType.I32: return ~0U;
|
|
case OperandType.I64: return ~0UL;
|
|
}
|
|
|
|
throw new ArgumentException("Invalid operand type \"" + type + "\".");
|
|
}
|
|
}
|
|
} |