From ee22517d92c48eab9643b6fc8ce4dac2b7e95f57 Mon Sep 17 00:00:00 2001 From: Ficture Seven Date: Wed, 5 Aug 2020 02:52:33 +0400 Subject: [PATCH] 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 --- .../CodeGen/Optimizations/Optimizer.cs | 114 +++++++++++- ARMeilleure/CodeGen/X86/CodeGenerator.cs | 171 +++++++++--------- ARMeilleure/CodeGen/X86/PreAllocator.cs | 32 ++-- ARMeilleure/CodeGen/X86/X86Condition.cs | 25 +++ ARMeilleure/Diagnostics/IRDumper.cs | 19 +- .../Instructions/InstEmitFlowHelper.cs | 11 +- .../Instructions/InstEmitMemoryExHelper.cs | 2 +- .../Instructions/InstEmitMemoryHelper.cs | 4 +- .../IntermediateRepresentation/Comparison.cs | 24 +++ .../IntermediateRepresentation/Instruction.cs | 14 +- ARMeilleure/Translation/EmitterContext.cs | 38 ++-- ARMeilleure/Translation/PTC/Ptc.cs | 2 +- 12 files changed, 311 insertions(+), 145 deletions(-) create mode 100644 ARMeilleure/IntermediateRepresentation/Comparison.cs diff --git a/ARMeilleure/CodeGen/Optimizations/Optimizer.cs b/ARMeilleure/CodeGen/Optimizations/Optimizer.cs index 06118bfd6..438010a2e 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 f04be52da..f2d4c4627 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); + 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) { diff --git a/ARMeilleure/CodeGen/X86/PreAllocator.cs b/ARMeilleure/CodeGen/X86/PreAllocator.cs index b76e94169..2f430b6fb 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 a17c6d6c5..c82cbdec5 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 7ff760772..0f0d72c15 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 6906f7820..1ce0cdaa3 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 a22cd235f..5b890dd39 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 1fe82b62c..9b6476ddf 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 000000000..628ce1051 --- /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 8ffaf3dc9..c583a2f2b 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 7abab9e14..a6cc55dfb 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 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) diff --git a/ARMeilleure/Translation/PTC/Ptc.cs b/ARMeilleure/Translation/PTC/Ptc.cs index dfb9fe91e..257af7220 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";