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
This commit is contained in:
parent
a33dc2f491
commit
ee22517d92
@ -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,7 +44,18 @@ namespace ARMeilleure.CodeGen.Optimizations
|
||||
|
||||
Simplification.RunPass(operation);
|
||||
|
||||
if (DestIsLocalVar(operation) && IsPropagableCopy(operation))
|
||||
if (DestIsLocalVar(operation))
|
||||
{
|
||||
if (IsPropagableCompare(operation))
|
||||
{
|
||||
modified |= PropagateCompare(operation);
|
||||
|
||||
if (modified && IsUnused(operation))
|
||||
{
|
||||
RemoveNode(block, node);
|
||||
}
|
||||
}
|
||||
else if (IsPropagableCopy(operation))
|
||||
{
|
||||
PropagateCopy(operation);
|
||||
|
||||
@ -50,6 +63,7 @@ namespace ARMeilleure.CodeGen.Optimizations
|
||||
|
||||
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)
|
||||
|
@ -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);
|
||||
Operand comp = operation.GetSource(2);
|
||||
|
||||
context.Assembler.Test(source, source, source.Type);
|
||||
Debug.Assert(comp.Kind == OperandKind.Constant);
|
||||
|
||||
context.JumpTo(X86Condition.Equal, context.CurrBlock.Branch);
|
||||
}
|
||||
var cond = ((Comparison)comp.AsInt32()).ToX86Condition();
|
||||
|
||||
private static void GenerateBranchIfTrue(CodeGenContext context, Operation operation)
|
||||
{
|
||||
Operand source = operation.GetSource(0);
|
||||
GenerateCompareCommon(context, operation);
|
||||
|
||||
context.Assembler.Test(source, source, source.Type);
|
||||
|
||||
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)
|
||||
{
|
||||
|
@ -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;
|
||||
|
@ -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))
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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));
|
||||
|
24
ARMeilleure/IntermediateRepresentation/Comparison.cs
Normal file
24
ARMeilleure/IntermediateRepresentation/Comparison.cs
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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,
|
||||
|
@ -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 BranchIfFalse(Operand label, Operand op1)
|
||||
{
|
||||
BranchIf(label, op1, Const(op1.Type, 0), Comparison.Equal);
|
||||
}
|
||||
|
||||
public void BranchIfTrue(Operand label, Operand op1)
|
||||
{
|
||||
Add(Instruction.BranchIfTrue, null, op1);
|
||||
|
||||
BranchToLabel(label);
|
||||
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)
|
||||
|
@ -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";
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user