diff options
Diffstat (limited to 'ARMeilleure/CodeGen/X86')
| -rw-r--r-- | ARMeilleure/CodeGen/X86/CodeGenerator.cs | 171 | ||||
| -rw-r--r-- | ARMeilleure/CodeGen/X86/PreAllocator.cs | 32 | ||||
| -rw-r--r-- | ARMeilleure/CodeGen/X86/X86Condition.cs | 25 |
3 files changed, 125 insertions, 103 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) { 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 |
