diff options
author | Ficture Seven <FICTURE7@gmail.com> | 2020-08-05 02:52:33 +0400 |
---|---|---|
committer | GitHub <noreply@github.com> | 2020-08-05 08:52:33 +1000 |
commit | ee22517d92c48eab9643b6fc8ce4dac2b7e95f57 (patch) | |
tree | 5df92a3e83f9daafba44ad11862683af8185ffaf /ARMeilleure/CodeGen/X86/CodeGenerator.cs | |
parent | a33dc2f4919f7fdc8ea9db41c4c70c38cedfd3df (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
Diffstat (limited to 'ARMeilleure/CodeGen/X86/CodeGenerator.cs')
-rw-r--r-- | ARMeilleure/CodeGen/X86/CodeGenerator.cs | 171 |
1 files changed, 83 insertions, 88 deletions
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) { |