aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFicture Seven <FICTURE7@gmail.com>2020-08-05 02:52:33 +0400
committerGitHub <noreply@github.com>2020-08-05 08:52:33 +1000
commitee22517d92c48eab9643b6fc8ce4dac2b7e95f57 (patch)
tree5df92a3e83f9daafba44ad11862683af8185ffaf
parenta33dc2f4919f7fdc8ea9db41c4c70c38cedfd3df (diff)
Improve branch operations (#1442)
* Add Compare instruction * Add BranchIf instruction * Use test when BranchIf & Compare against 0 * Propagate Compare into BranchIfTrue/False use - Propagate Compare operations into their BranchIfTrue/False use and turn these into a BranchIf. - Clean up Comparison enum. * Replace BranchIfTrue/False with BranchIf * Use BranchIf in EmitPtPointerLoad - Using BranchIf early instead of BranchIfTrue/False improves LCQ and reduces the amount of work needed by the Optimizer. EmitPtPointerLoader was a/the big producer of BranchIfTrue/False. - Fix asserts firing when assembling BitwiseAnd because of type mismatch in EmitStoreExclusive. This is harmless and should not cause any diffs. * Increment PPTC interval version * Improve IRDumper for BranchIf & Compare * Use BranchIf in EmitNativeCall * Clean up * Do not emit test when immediately preceded by and
-rw-r--r--ARMeilleure/CodeGen/Optimizations/Optimizer.cs114
-rw-r--r--ARMeilleure/CodeGen/X86/CodeGenerator.cs171
-rw-r--r--ARMeilleure/CodeGen/X86/PreAllocator.cs32
-rw-r--r--ARMeilleure/CodeGen/X86/X86Condition.cs25
-rw-r--r--ARMeilleure/Diagnostics/IRDumper.cs19
-rw-r--r--ARMeilleure/Instructions/InstEmitFlowHelper.cs11
-rw-r--r--ARMeilleure/Instructions/InstEmitMemoryExHelper.cs2
-rw-r--r--ARMeilleure/Instructions/InstEmitMemoryHelper.cs4
-rw-r--r--ARMeilleure/IntermediateRepresentation/Comparison.cs24
-rw-r--r--ARMeilleure/IntermediateRepresentation/Instruction.cs14
-rw-r--r--ARMeilleure/Translation/EmitterContext.cs38
-rw-r--r--ARMeilleure/Translation/PTC/Ptc.cs2
12 files changed, 311 insertions, 145 deletions
diff --git a/ARMeilleure/CodeGen/Optimizations/Optimizer.cs b/ARMeilleure/CodeGen/Optimizations/Optimizer.cs
index 06118bfd..438010a2 100644
--- a/ARMeilleure/CodeGen/Optimizations/Optimizer.cs
+++ b/ARMeilleure/CodeGen/Optimizations/Optimizer.cs
@@ -2,6 +2,8 @@ using ARMeilleure.IntermediateRepresentation;
using ARMeilleure.Translation;
using System.Diagnostics;
+using static ARMeilleure.IntermediateRepresentation.OperandHelper;
+
namespace ARMeilleure.CodeGen.Optimizations
{
static class Optimizer
@@ -42,13 +44,25 @@ namespace ARMeilleure.CodeGen.Optimizations
Simplification.RunPass(operation);
- if (DestIsLocalVar(operation) && IsPropagableCopy(operation))
- {
- PropagateCopy(operation);
+ if (DestIsLocalVar(operation))
+ {
+ if (IsPropagableCompare(operation))
+ {
+ modified |= PropagateCompare(operation);
- RemoveNode(block, node);
+ if (modified && IsUnused(operation))
+ {
+ RemoveNode(block, node);
+ }
+ }
+ else if (IsPropagableCopy(operation))
+ {
+ PropagateCopy(operation);
- modified = true;
+ RemoveNode(block, node);
+
+ modified = true;
+ }
}
node = nextNode;
@@ -88,6 +102,91 @@ namespace ARMeilleure.CodeGen.Optimizations
while (modified);
}
+ private static bool PropagateCompare(Operation compOp)
+ {
+ // Try to propagate Compare operations into their BranchIf uses, when these BranchIf uses are in the form
+ // of:
+ //
+ // - BranchIf %x, 0x0, Equal ;; i.e BranchIfFalse %x
+ // - BranchIf %x, 0x0, NotEqual ;; i.e BranchIfTrue %x
+ //
+ // The commutative property of Equal and NotEqual is taken into consideration as well.
+ //
+ // For example:
+ //
+ // %x = Compare %a, %b, comp
+ // BranchIf %x, 0x0, NotEqual
+ //
+ // =>
+ //
+ // BranchIf %a, %b, comp
+
+ static bool IsZeroBranch(Operation operation, out Comparison compType)
+ {
+ compType = Comparison.Equal;
+
+ if (operation.Instruction != Instruction.BranchIf)
+ {
+ return false;
+ }
+
+ Operand src1 = operation.GetSource(0);
+ Operand src2 = operation.GetSource(1);
+ Operand comp = operation.GetSource(2);
+
+ compType = (Comparison)comp.AsInt32();
+
+ return (src1.Kind == OperandKind.Constant && src1.Value == 0) ||
+ (src2.Kind == OperandKind.Constant && src2.Value == 0);
+ }
+
+ bool modified = false;
+
+ Operand dest = compOp.Destination;
+ Operand src1 = compOp.GetSource(0);
+ Operand src2 = compOp.GetSource(1);
+ Operand comp = compOp.GetSource(2);
+
+ Comparison compType = (Comparison)comp.AsInt32();
+
+ Node[] uses = dest.Uses.ToArray();
+
+ foreach (Node use in uses)
+ {
+ if (!(use is Operation operation))
+ {
+ continue;
+ }
+
+ // If operation is a BranchIf and has a constant value 0 in its RHS or LHS source operands.
+ if (IsZeroBranch(operation, out Comparison otherCompType))
+ {
+ Comparison propCompType;
+
+ if (otherCompType == Comparison.NotEqual)
+ {
+ propCompType = compType;
+ }
+ else if (otherCompType == Comparison.Equal)
+ {
+ propCompType = compType.Invert();
+ }
+ else
+ {
+ continue;
+ }
+
+ operation.SetSource(0, src1);
+ operation.SetSource(1, src2);
+ operation.SetSource(2, Const((int)propCompType));
+
+ modified = true;
+ }
+ }
+
+ return modified;
+ }
+
private static void PropagateCopy(Operation copyOp)
{
// Propagate copy source operand to all uses of the destination operand.
@@ -143,6 +242,11 @@ namespace ARMeilleure.CodeGen.Optimizations
|| operation.Instruction == Instruction.CompareAndSwap8);
}
+ private static bool IsPropagableCompare(Operation operation)
+ {
+ return operation.Instruction == Instruction.Compare;
+ }
+
private static bool IsPropagableCopy(Operation operation)
{
if (operation.Instruction != Instruction.Copy)
diff --git a/ARMeilleure/CodeGen/X86/CodeGenerator.cs b/ARMeilleure/CodeGen/X86/CodeGenerator.cs
index f04be52d..f2d4c462 100644
--- a/ARMeilleure/CodeGen/X86/CodeGenerator.cs
+++ b/ARMeilleure/CodeGen/X86/CodeGenerator.cs
@@ -33,24 +33,14 @@ namespace ARMeilleure.CodeGen.X86
Add(Instruction.BitwiseNot, GenerateBitwiseNot);
Add(Instruction.BitwiseOr, GenerateBitwiseOr);
Add(Instruction.Branch, GenerateBranch);
- Add(Instruction.BranchIfFalse, GenerateBranchIfFalse);
- Add(Instruction.BranchIfTrue, GenerateBranchIfTrue);
+ Add(Instruction.BranchIf, GenerateBranchIf);
Add(Instruction.ByteSwap, GenerateByteSwap);
Add(Instruction.Call, GenerateCall);
Add(Instruction.Clobber, GenerateClobber);
+ Add(Instruction.Compare, GenerateCompare);
Add(Instruction.CompareAndSwap, GenerateCompareAndSwap);
Add(Instruction.CompareAndSwap16, GenerateCompareAndSwap16);
Add(Instruction.CompareAndSwap8, GenerateCompareAndSwap8);
- Add(Instruction.CompareEqual, GenerateCompareEqual);
- Add(Instruction.CompareGreater, GenerateCompareGreater);
- Add(Instruction.CompareGreaterOrEqual, GenerateCompareGreaterOrEqual);
- Add(Instruction.CompareGreaterOrEqualUI, GenerateCompareGreaterOrEqualUI);
- Add(Instruction.CompareGreaterUI, GenerateCompareGreaterUI);
- Add(Instruction.CompareLess, GenerateCompareLess);
- Add(Instruction.CompareLessOrEqual, GenerateCompareLessOrEqual);
- Add(Instruction.CompareLessOrEqualUI, GenerateCompareLessOrEqualUI);
- Add(Instruction.CompareLessUI, GenerateCompareLessUI);
- Add(Instruction.CompareNotEqual, GenerateCompareNotEqual);
Add(Instruction.ConditionalSelect, GenerateConditionalSelect);
Add(Instruction.ConvertI64ToI32, GenerateConvertI64ToI32);
Add(Instruction.ConvertToFP, GenerateConvertToFP);
@@ -474,6 +464,8 @@ namespace ARMeilleure.CodeGen.X86
Debug.Assert(dest.Type.IsInteger());
+ // Note: GenerateCompareCommon makes the assumption that BitwiseAnd will emit only a single `and`
+ // instruction.
context.Assembler.And(dest, src2, dest.Type);
}
@@ -525,22 +517,17 @@ namespace ARMeilleure.CodeGen.X86
context.JumpTo(context.CurrBlock.Branch);
}
- private static void GenerateBranchIfFalse(CodeGenContext context, Operation operation)
+ private static void GenerateBranchIf(CodeGenContext context, Operation operation)
{
- Operand source = operation.GetSource(0);
-
- context.Assembler.Test(source, source, source.Type);
+ Operand comp = operation.GetSource(2);
- context.JumpTo(X86Condition.Equal, context.CurrBlock.Branch);
- }
+ Debug.Assert(comp.Kind == OperandKind.Constant);
- private static void GenerateBranchIfTrue(CodeGenContext context, Operation operation)
- {
- Operand source = operation.GetSource(0);
+ var cond = ((Comparison)comp.AsInt32()).ToX86Condition();
- context.Assembler.Test(source, source, source.Type);
+ GenerateCompareCommon(context, operation);
- context.JumpTo(X86Condition.NotEqual, context.CurrBlock.Branch);
+ context.JumpTo(cond, context.CurrBlock.Branch);
}
private static void GenerateByteSwap(CodeGenContext context, Operation operation)
@@ -566,6 +553,60 @@ namespace ARMeilleure.CodeGen.X86
// register allocator, we don't need to produce any code.
}
+ private static void GenerateCompare(CodeGenContext context, Operation operation)
+ {
+ Operand dest = operation.Destination;
+ Operand comp = operation.GetSource(2);
+
+ Debug.Assert(dest.Type == OperandType.I32);
+ Debug.Assert(comp.Kind == OperandKind.Constant);
+
+ var cond = ((Comparison)comp.AsInt32()).ToX86Condition();
+
+ GenerateCompareCommon(context, operation);
+
+ context.Assembler.Setcc(dest, cond);
+ context.Assembler.Movzx8(dest, dest, OperandType.I32);
+ }
+
+ private static void GenerateCompareCommon(CodeGenContext context, Operation operation)
+ {
+ Operand src1 = operation.GetSource(0);
+ Operand src2 = operation.GetSource(1);
+
+ EnsureSameType(src1, src2);
+
+ Debug.Assert(src1.Type.IsInteger());
+
+ if (src2.Kind == OperandKind.Constant && src2.Value == 0)
+ {
+ if (MatchOperation(operation.ListPrevious, Instruction.BitwiseAnd, src1.Type, src1.GetRegister()))
+ {
+ // Since the `test` and `and` instruction set the status flags in the same way, we can omit the
+ // `test r,r` instruction when it is immediately preceded by an `and r,*` instruction.
+ //
+ // For example:
+ //
+ // and eax, 0x3
+ // test eax, eax
+ // jz .L0
+ //
+ // =>
+ //
+ // and eax, 0x3
+ // jz .L0
+ }
+ else
+ {
+ context.Assembler.Test(src1, src1, src1.Type);
+ }
+ }
+ else
+ {
+ context.Assembler.Cmp(src1, src2, src1.Type);
+ }
+ }
+
private static void GenerateCompareAndSwap(CodeGenContext context, Operation operation)
{
Operand src1 = operation.GetSource(0);
@@ -615,71 +656,6 @@ namespace ARMeilleure.CodeGen.X86
context.Assembler.Cmpxchg8(memOp, src3);
}
- private static void GenerateCompareEqual(CodeGenContext context, Operation operation)
- {
- GenerateCompare(context, operation, X86Condition.Equal);
- }
-
- private static void GenerateCompareGreater(CodeGenContext context, Operation operation)
- {
- GenerateCompare(context, operation, X86Condition.Greater);
- }
-
- private static void GenerateCompareGreaterOrEqual(CodeGenContext context, Operation operation)
- {
- GenerateCompare(context, operation, X86Condition.GreaterOrEqual);
- }
-
- private static void GenerateCompareGreaterOrEqualUI(CodeGenContext context, Operation operation)
- {
- GenerateCompare(context, operation, X86Condition.AboveOrEqual);
- }
-
- private static void GenerateCompareGreaterUI(CodeGenContext context, Operation operation)
- {
- GenerateCompare(context, operation, X86Condition.Above);
- }
-
- private static void GenerateCompareLess(CodeGenContext context, Operation operation)
- {
- GenerateCompare(context, operation, X86Condition.Less);
- }
-
- private static void GenerateCompareLessOrEqual(CodeGenContext context, Operation operation)
- {
- GenerateCompare(context, operation, X86Condition.LessOrEqual);
- }
-
- private static void GenerateCompareLessOrEqualUI(CodeGenContext context, Operation operation)
- {
- GenerateCompare(context, operation, X86Condition.BelowOrEqual);
- }
-
- private static void GenerateCompareLessUI(CodeGenContext context, Operation operation)
- {
- GenerateCompare(context, operation, X86Condition.Below);
- }
-
- private static void GenerateCompareNotEqual(CodeGenContext context, Operation operation)
- {
- GenerateCompare(context, operation, X86Condition.NotEqual);
- }
-
- private static void GenerateCompare(CodeGenContext context, Operation operation, X86Condition condition)
- {
- Operand dest = operation.Destination;
- Operand src1 = operation.GetSource(0);
- Operand src2 = operation.GetSource(1);
-
- EnsureSameType(src1, src2);
-
- Debug.Assert(dest.Type == OperandType.I32);
-
- context.Assembler.Cmp(src1, src2, src1.Type);
- context.Assembler.Setcc(dest, condition);
- context.Assembler.Movzx8(dest, dest, OperandType.I32);
- }
-
private static void GenerateConditionalSelect(CodeGenContext context, Operation operation)
{
Operand dest = operation.Destination;
@@ -1561,6 +1537,25 @@ namespace ARMeilleure.CodeGen.X86
context.Assembler.Pshufd(dest, dest, 0xfc);
}
+ private static bool MatchOperation(Node node, Instruction inst, OperandType destType, Register destReg)
+ {
+ if (!(node is Operation operation) || node.DestinationsCount == 0)
+ {
+ return false;
+ }
+
+ if (operation.Instruction != inst)
+ {
+ return false;
+ }
+
+ Operand dest = operation.Destination;
+
+ return dest.Kind == OperandKind.Register &&
+ dest.Type == destType &&
+ dest.GetRegister() == destReg;
+ }
+
[Conditional("DEBUG")]
private static void ValidateUnOp(Operand dest, Operand source)
{
diff --git a/ARMeilleure/CodeGen/X86/PreAllocator.cs b/ARMeilleure/CodeGen/X86/PreAllocator.cs
index b76e9416..2f430b6f 100644
--- a/ARMeilleure/CodeGen/X86/PreAllocator.cs
+++ b/ARMeilleure/CodeGen/X86/PreAllocator.cs
@@ -154,7 +154,7 @@ namespace ARMeilleure.CodeGen.X86
// -- Doing so may allow us to encode the constant as operand 2 and avoid a copy.
// - If the constant is on operand 2, we check if the instruction supports it,
// if not, we also add a copy. 64-bits constants are usually not supported.
- if (IsCommutative(inst))
+ if (IsCommutative(operation))
{
src2 = operation.GetSource(1);
@@ -1348,16 +1348,8 @@ namespace ARMeilleure.CodeGen.X86
case Instruction.BitwiseAnd:
case Instruction.BitwiseExclusiveOr:
case Instruction.BitwiseOr:
- case Instruction.CompareEqual:
- case Instruction.CompareGreater:
- case Instruction.CompareGreaterOrEqual:
- case Instruction.CompareGreaterOrEqualUI:
- case Instruction.CompareGreaterUI:
- case Instruction.CompareLess:
- case Instruction.CompareLessOrEqual:
- case Instruction.CompareLessOrEqualUI:
- case Instruction.CompareLessUI:
- case Instruction.CompareNotEqual:
+ case Instruction.BranchIf:
+ case Instruction.Compare:
case Instruction.Multiply:
case Instruction.RotateRight:
case Instruction.ShiftLeft:
@@ -1376,18 +1368,28 @@ namespace ARMeilleure.CodeGen.X86
return false;
}
- private static bool IsCommutative(Instruction inst)
+ private static bool IsCommutative(Operation operation)
{
- switch (inst)
+ switch (operation.Instruction)
{
case Instruction.Add:
case Instruction.BitwiseAnd:
case Instruction.BitwiseExclusiveOr:
case Instruction.BitwiseOr:
- case Instruction.CompareEqual:
- case Instruction.CompareNotEqual:
case Instruction.Multiply:
return true;
+
+ case Instruction.BranchIf:
+ case Instruction.Compare:
+ {
+ Operand comp = operation.GetSource(2);
+
+ Debug.Assert(comp.Kind == OperandKind.Constant);
+
+ var compType = (Comparison)comp.AsInt32();
+
+ return compType == Comparison.Equal || compType == Comparison.NotEqual;
+ }
}
return false;
diff --git a/ARMeilleure/CodeGen/X86/X86Condition.cs b/ARMeilleure/CodeGen/X86/X86Condition.cs
index a17c6d6c..c82cbdec 100644
--- a/ARMeilleure/CodeGen/X86/X86Condition.cs
+++ b/ARMeilleure/CodeGen/X86/X86Condition.cs
@@ -1,3 +1,6 @@
+using ARMeilleure.IntermediateRepresentation;
+using System;
+
namespace ARMeilleure.CodeGen.X86
{
enum X86Condition
@@ -19,4 +22,26 @@ namespace ARMeilleure.CodeGen.X86
LessOrEqual = 0xe,
Greater = 0xf
}
+
+ static class ComparisonX86Extensions
+ {
+ public static X86Condition ToX86Condition(this Comparison comp)
+ {
+ return comp switch
+ {
+ Comparison.Equal => X86Condition.Equal,
+ Comparison.NotEqual => X86Condition.NotEqual,
+ Comparison.Greater => X86Condition.Greater,
+ Comparison.LessOrEqual => X86Condition.LessOrEqual,
+ Comparison.GreaterUI => X86Condition.Above,
+ Comparison.LessOrEqualUI => X86Condition.BelowOrEqual,
+ Comparison.GreaterOrEqual => X86Condition.GreaterOrEqual,
+ Comparison.Less => X86Condition.Less,
+ Comparison.GreaterOrEqualUI => X86Condition.AboveOrEqual,
+ Comparison.LessUI => X86Condition.Below,
+
+ _ => throw new ArgumentException(null, nameof(comp))
+ };
+ }
+ }
} \ No newline at end of file
diff --git a/ARMeilleure/Diagnostics/IRDumper.cs b/ARMeilleure/Diagnostics/IRDumper.cs
index 7ff76077..0f0d72c1 100644
--- a/ARMeilleure/Diagnostics/IRDumper.cs
+++ b/ARMeilleure/Diagnostics/IRDumper.cs
@@ -198,6 +198,8 @@ namespace ARMeilleure.Diagnostics
break;
case Operation operation:
+ bool comparison = false;
+
_builder.Append(operation.Instruction);
if (operation.Instruction == Instruction.Extended)
@@ -206,17 +208,32 @@ namespace ARMeilleure.Diagnostics
_builder.Append('.').Append(intrinOp.Intrinsic);
}
+ else if (operation.Instruction == Instruction.BranchIf ||
+ operation.Instruction == Instruction.Compare)
+ {
+ comparison = true;
+ }
_builder.Append(' ');
for (int index = 0; index < operation.SourcesCount; index++)
{
- DumpOperand(operation.GetSource(index));
+ Operand source = operation.GetSource(index);
if (index < operation.SourcesCount - 1)
{
+ DumpOperand(source);
+
_builder.Append(", ");
}
+ else if (comparison)
+ {
+ _builder.Append((Comparison)source.AsInt32());
+ }
+ else
+ {
+ DumpOperand(source);
+ }
}
break;
}
diff --git a/ARMeilleure/Instructions/InstEmitFlowHelper.cs b/ARMeilleure/Instructions/InstEmitFlowHelper.cs
index 6906f782..1ce0cdaa 100644
--- a/ARMeilleure/Instructions/InstEmitFlowHelper.cs
+++ b/ARMeilleure/Instructions/InstEmitFlowHelper.cs
@@ -163,17 +163,18 @@ namespace ARMeilleure.Instructions
context.LoadFromContext();
- // Note: The return value of a translated function is always an Int64 with the
- // address execution has returned to. We expect this address to be immediately after the
- // current instruction, if it isn't we keep returning until we reach the dispatcher.
+ // Note: The return value of a translated function is always an Int64 with the address execution has
+ // returned to. We expect this address to be immediately after the current instruction, if it isn't we
+ // keep returning until we reach the dispatcher.
Operand nextAddr = Const((long)op.Address + op.OpCodeSizeInBytes);
// Try to continue within this block.
- // If the return address isn't to our next instruction, we need to return so the JIT can figure out what to do.
+ // If the return address isn't to our next instruction, we need to return so the JIT can figure out
+ // what to do.
Operand lblContinue = context.GetLabel(nextAddr.Value);
// We need to clear out the call flag for the return address before comparing it.
- context.BranchIfTrue(lblContinue, context.ICompareEqual(context.BitwiseAnd(returnAddress, Const(~CallFlag)), nextAddr));
+ context.BranchIf(lblContinue, context.BitwiseAnd(returnAddress, Const(~CallFlag)), nextAddr, Comparison.Equal);
context.Return(returnAddress);
}
diff --git a/ARMeilleure/Instructions/InstEmitMemoryExHelper.cs b/ARMeilleure/Instructions/InstEmitMemoryExHelper.cs
index a22cd235..5b890dd3 100644
--- a/ARMeilleure/Instructions/InstEmitMemoryExHelper.cs
+++ b/ARMeilleure/Instructions/InstEmitMemoryExHelper.cs
@@ -92,7 +92,7 @@ namespace ARMeilleure.Instructions
Operand exAddr = context.Load(address.Type, exAddrPtr);
// STEP 1: Check if we have exclusive access to this memory region. If not, fail and skip store.
- Operand maskedAddress = context.BitwiseAnd(address, Const(GetExclusiveAddressMask()));
+ Operand maskedAddress = context.BitwiseAnd(address, Const(address.Type, GetExclusiveAddressMask()));
Operand exFailed = context.ICompareNotEqual(exAddr, maskedAddress);
diff --git a/ARMeilleure/Instructions/InstEmitMemoryHelper.cs b/ARMeilleure/Instructions/InstEmitMemoryHelper.cs
index 1fe82b62..9b6476dd 100644
--- a/ARMeilleure/Instructions/InstEmitMemoryHelper.cs
+++ b/ARMeilleure/Instructions/InstEmitMemoryHelper.cs
@@ -403,7 +403,7 @@ namespace ARMeilleure.Instructions
if (lblSlowPath != null)
{
- context.BranchIfTrue(lblSlowPath, context.ICompareLessOrEqual(pte, Const(0L)));
+ context.BranchIf(lblSlowPath, pte, Const(0L), Comparison.LessOrEqual);
}
else
{
@@ -414,7 +414,7 @@ namespace ARMeilleure.Instructions
Operand lblNotWatched = Label();
// Is the page currently being monitored for modifications? If so we need to call MarkRegionAsModified.
- context.BranchIfTrue(lblNotWatched, context.ICompareGreaterOrEqual(pte, Const(0L)));
+ context.BranchIf(lblNotWatched, pte, Const(0L), Comparison.GreaterOrEqual);
// Mark the region as modified. Size here doesn't matter as address is assumed to be size aligned here.
context.Call(typeof(NativeInterface).GetMethod(nameof(NativeInterface.MarkRegionAsModified)), address, Const(1UL));
diff --git a/ARMeilleure/IntermediateRepresentation/Comparison.cs b/ARMeilleure/IntermediateRepresentation/Comparison.cs
new file mode 100644
index 00000000..628ce105
--- /dev/null
+++ b/ARMeilleure/IntermediateRepresentation/Comparison.cs
@@ -0,0 +1,24 @@
+namespace ARMeilleure.IntermediateRepresentation
+{
+ enum Comparison
+ {
+ Equal = 0,
+ NotEqual = 1,
+ Greater = 2,
+ LessOrEqual = 3,
+ GreaterUI = 4,
+ LessOrEqualUI = 5,
+ GreaterOrEqual = 6,
+ Less = 7,
+ GreaterOrEqualUI = 8,
+ LessUI = 9
+ }
+
+ static class ComparisonExtensions
+ {
+ public static Comparison Invert(this Comparison comp)
+ {
+ return (Comparison)((int)comp ^ 1);
+ }
+ }
+}
diff --git a/ARMeilleure/IntermediateRepresentation/Instruction.cs b/ARMeilleure/IntermediateRepresentation/Instruction.cs
index 8ffaf3dc..c583a2f2 100644
--- a/ARMeilleure/IntermediateRepresentation/Instruction.cs
+++ b/ARMeilleure/IntermediateRepresentation/Instruction.cs
@@ -8,23 +8,13 @@ namespace ARMeilleure.IntermediateRepresentation
BitwiseNot,
BitwiseOr,
Branch,
- BranchIfFalse,
- BranchIfTrue,
+ BranchIf,
ByteSwap,
Call,
+ Compare,
CompareAndSwap,
CompareAndSwap16,
CompareAndSwap8,
- CompareEqual,
- CompareGreater,
- CompareGreaterOrEqual,
- CompareGreaterOrEqualUI,
- CompareGreaterUI,
- CompareLess,
- CompareLessOrEqual,
- CompareLessOrEqualUI,
- CompareLessUI,
- CompareNotEqual,
ConditionalSelect,
ConvertI64ToI32,
ConvertToFP,
diff --git a/ARMeilleure/Translation/EmitterContext.cs b/ARMeilleure/Translation/EmitterContext.cs
index 7abab9e1..a6cc55df 100644
--- a/ARMeilleure/Translation/EmitterContext.cs
+++ b/ARMeilleure/Translation/EmitterContext.cs
@@ -62,18 +62,21 @@ namespace ARMeilleure.Translation
BranchToLabel(label);
}
- public void BranchIfFalse(Operand label, Operand op1)
+ public void BranchIf(Operand label, Operand op1, Operand op2, Comparison comp)
{
- Add(Instruction.BranchIfFalse, null, op1);
+ Add(Instruction.BranchIf, null, op1, op2, Const((int)comp));
BranchToLabel(label);
}
- public void BranchIfTrue(Operand label, Operand op1)
+ public void BranchIfFalse(Operand label, Operand op1)
{
- Add(Instruction.BranchIfTrue, null, op1);
+ BranchIf(label, op1, Const(op1.Type, 0), Comparison.Equal);
+ }
- BranchToLabel(label);
+ public void BranchIfTrue(Operand label, Operand op1)
+ {
+ BranchIf(label, op1, Const(op1.Type, 0), Comparison.NotEqual);
}
public Operand ByteSwap(Operand op1)
@@ -243,54 +246,59 @@ namespace ARMeilleure.Translation
return Add(Instruction.DivideUI, Local(op1.Type), op1, op2);
}
+ public Operand ICompare(Operand op1, Operand op2, Comparison comp)
+ {
+ return Add(Instruction.Compare, Local(OperandType.I32), op1, op2, Const((int)comp));
+ }
+
public Operand ICompareEqual(Operand op1, Operand op2)
{
- return Add(Instruction.CompareEqual, Local(OperandType.I32), op1, op2);
+ return ICompare(op1, op2, Comparison.Equal);
}
public Operand ICompareGreater(Operand op1, Operand op2)
{
- return Add(Instruction.CompareGreater, Local(OperandType.I32), op1, op2);
+ return ICompare(op1, op2, Comparison.Greater);
}
public Operand ICompareGreaterOrEqual(Operand op1, Operand op2)
{
- return Add(Instruction.CompareGreaterOrEqual, Local(OperandType.I32), op1, op2);
+ return ICompare(op1, op2, Comparison.GreaterOrEqual);
}
public Operand ICompareGreaterOrEqualUI(Operand op1, Operand op2)
{
- return Add(Instruction.CompareGreaterOrEqualUI, Local(OperandType.I32), op1, op2);
+ return ICompare(op1, op2, Comparison.GreaterOrEqualUI);
}
public Operand ICompareGreaterUI(Operand op1, Operand op2)
{
- return Add(Instruction.CompareGreaterUI, Local(OperandType.I32), op1, op2);
+ return ICompare(op1, op2, Comparison.GreaterUI);
}
public Operand ICompareLess(Operand op1, Operand op2)
{
- return Add(Instruction.CompareLess, Local(OperandType.I32), op1, op2);
+ return ICompare(op1, op2, Comparison.Less);
}
public Operand ICompareLessOrEqual(Operand op1, Operand op2)
{
- return Add(Instruction.CompareLessOrEqual, Local(OperandType.I32), op1, op2);
+ return ICompare(op1, op2, Comparison.LessOrEqual);
}
public Operand ICompareLessOrEqualUI(Operand op1, Operand op2)
{
- return Add(Instruction.CompareLessOrEqualUI, Local(OperandType.I32), op1, op2);
+ return ICompare(op1, op2, Comparison.LessOrEqualUI);
}
public Operand ICompareLessUI(Operand op1, Operand op2)
{
- return Add(Instruction.CompareLessUI, Local(OperandType.I32), op1, op2);
+ return ICompare(op1, op2, Comparison.LessUI);
}
public Operand ICompareNotEqual(Operand op1, Operand op2)
{
- return Add(Instruction.CompareNotEqual, Local(OperandType.I32), op1, op2);
+ return ICompare(op1, op2, Comparison.NotEqual);
}
public Operand Load(OperandType type, Operand address)
diff --git a/ARMeilleure/Translation/PTC/Ptc.cs b/ARMeilleure/Translation/PTC/Ptc.cs
index dfb9fe91..257af722 100644
--- a/ARMeilleure/Translation/PTC/Ptc.cs
+++ b/ARMeilleure/Translation/PTC/Ptc.cs
@@ -20,7 +20,7 @@ namespace ARMeilleure.Translation.PTC
{
private const string HeaderMagic = "PTChd";
- private const int InternalVersion = 18; //! To be incremented manually for each change to the ARMeilleure project.
+ private const int InternalVersion = 19; //! To be incremented manually for each change to the ARMeilleure project.
private const string BaseDir = "Ryujinx";