Index: llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h =================================================================== --- llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h +++ llvm/lib/Target/X86/MCTargetDesc/X86BaseInfo.h @@ -101,6 +101,248 @@ COND_INVALID }; + + // The classification for the first instruction in macro fusion. + enum class FirstMacroFusionInstKind { + // TEST + Test, + // CMP + Cmp, + // AND + And, + // ADD, SUB + AddSub, + // INC, DEC + IncDec, + // Not valid as a first macro fusion instruction + Invalid + }; + + enum class SecondMacroFusionInstKind { + // JA, JB and variants. + AB, + // JE, JL, JG and variants. + ELG, + // JS, JP, JO and variants + SPO, + // Not a fusible jump. + Invalid, + }; + + /// classifyFirstOpcodeInMacroFusion - return the type of the first + /// instruction in macro-fusion. + inline FirstMacroFusionInstKind + classifyFirstOpcodeInMacroFusion(unsigned Opcode) { + switch (Opcode) { + default: + return FirstMacroFusionInstKind::Invalid; + // TEST + case X86::TEST16i16: + case X86::TEST16mr: + case X86::TEST16ri: + case X86::TEST16rr: + case X86::TEST32i32: + case X86::TEST32mr: + case X86::TEST32ri: + case X86::TEST32rr: + case X86::TEST64i32: + case X86::TEST64mr: + case X86::TEST64ri32: + case X86::TEST64rr: + case X86::TEST8i8: + case X86::TEST8mr: + case X86::TEST8ri: + case X86::TEST8rr: + return FirstMacroFusionInstKind::Test; + case X86::AND16i16: + case X86::AND16ri: + case X86::AND16ri8: + case X86::AND16rm: + case X86::AND16rr: + case X86::AND16rr_REV: + case X86::AND32i32: + case X86::AND32ri: + case X86::AND32ri8: + case X86::AND32rm: + case X86::AND32rr: + case X86::AND32rr_REV: + case X86::AND64i32: + case X86::AND64ri32: + case X86::AND64ri8: + case X86::AND64rm: + case X86::AND64rr: + case X86::AND64rr_REV: + case X86::AND8i8: + case X86::AND8ri: + case X86::AND8ri8: + case X86::AND8rm: + case X86::AND8rr: + case X86::AND8rr_REV: + return FirstMacroFusionInstKind::And; + // CMP + case X86::CMP16i16: + case X86::CMP16mr: + case X86::CMP16ri: + case X86::CMP16ri8: + case X86::CMP16rm: + case X86::CMP16rr: + case X86::CMP16rr_REV: + case X86::CMP32i32: + case X86::CMP32mr: + case X86::CMP32ri: + case X86::CMP32ri8: + case X86::CMP32rm: + case X86::CMP32rr: + case X86::CMP32rr_REV: + case X86::CMP64i32: + case X86::CMP64mr: + case X86::CMP64ri32: + case X86::CMP64ri8: + case X86::CMP64rm: + case X86::CMP64rr: + case X86::CMP64rr_REV: + case X86::CMP8i8: + case X86::CMP8mr: + case X86::CMP8ri: + case X86::CMP8ri8: + case X86::CMP8rm: + case X86::CMP8rr: + case X86::CMP8rr_REV: + return FirstMacroFusionInstKind::Cmp; + // ADD + case X86::ADD16i16: + case X86::ADD16ri: + case X86::ADD16ri8: + case X86::ADD16rm: + case X86::ADD16rr: + case X86::ADD16rr_REV: + case X86::ADD32i32: + case X86::ADD32ri: + case X86::ADD32ri8: + case X86::ADD32rm: + case X86::ADD32rr: + case X86::ADD32rr_REV: + case X86::ADD64i32: + case X86::ADD64ri32: + case X86::ADD64ri8: + case X86::ADD64rm: + case X86::ADD64rr: + case X86::ADD64rr_REV: + case X86::ADD8i8: + case X86::ADD8ri: + case X86::ADD8ri8: + case X86::ADD8rm: + case X86::ADD8rr: + case X86::ADD8rr_REV: + // SUB + case X86::SUB16i16: + case X86::SUB16ri: + case X86::SUB16ri8: + case X86::SUB16rm: + case X86::SUB16rr: + case X86::SUB16rr_REV: + case X86::SUB32i32: + case X86::SUB32ri: + case X86::SUB32ri8: + case X86::SUB32rm: + case X86::SUB32rr: + case X86::SUB32rr_REV: + case X86::SUB64i32: + case X86::SUB64ri32: + case X86::SUB64ri8: + case X86::SUB64rm: + case X86::SUB64rr: + case X86::SUB64rr_REV: + case X86::SUB8i8: + case X86::SUB8ri: + case X86::SUB8ri8: + case X86::SUB8rm: + case X86::SUB8rr: + case X86::SUB8rr_REV: + return FirstMacroFusionInstKind::AddSub; + // INC + case X86::INC16r: + case X86::INC16r_alt: + case X86::INC32r: + case X86::INC32r_alt: + case X86::INC64r: + case X86::INC8r: + // DEC + case X86::DEC16r: + case X86::DEC16r_alt: + case X86::DEC32r: + case X86::DEC32r_alt: + case X86::DEC64r: + case X86::DEC8r: + return FirstMacroFusionInstKind::IncDec; + } + } + + /// classifySecondCondCodeInMacroFusion - return the type of the second + /// instruction in macro-fusion. + inline SecondMacroFusionInstKind + classifySecondCondCodeInMacroFusion(X86::CondCode CC) { + if (CC == X86::COND_INVALID) + return SecondMacroFusionInstKind::Invalid; + + switch (CC) { + default: + return SecondMacroFusionInstKind::Invalid; + // JE,JZ + case X86::COND_E: + // JNE,JNZ + case X86::COND_NE: + // JL,JNGE + case X86::COND_L: + // JLE,JNG + case X86::COND_LE: + // JG,JNLE + case X86::COND_G: + // JGE,JNL + case X86::COND_GE: + return SecondMacroFusionInstKind::ELG; + // JB,JC + case X86::COND_B: + // JNA,JBE + case X86::COND_BE: + // JA,JNBE + case X86::COND_A: + // JAE,JNC,JNB + case X86::COND_AE: + return SecondMacroFusionInstKind::AB; + // JS + case X86::COND_S: + // JNS + case X86::COND_NS: + // JP,JPE + case X86::COND_P: + // JNP,JPO + case X86::COND_NP: + // JO + case X86::COND_O: + // JNO + case X86::COND_NO: + return SecondMacroFusionInstKind::SPO; + } + } + + inline bool isMacroFused(FirstMacroFusionInstKind FirstKind, + SecondMacroFusionInstKind SecondKind) { + switch (FirstKind) { + case X86::FirstMacroFusionInstKind::Test: + case X86::FirstMacroFusionInstKind::And: + return true; + case X86::FirstMacroFusionInstKind::Cmp: + case X86::FirstMacroFusionInstKind::AddSub: + return SecondKind == X86::SecondMacroFusionInstKind::AB || + SecondKind == X86::SecondMacroFusionInstKind::ELG; + case X86::FirstMacroFusionInstKind::IncDec: + return SecondKind == X86::SecondMacroFusionInstKind::ELG; + case X86::FirstMacroFusionInstKind::Invalid: + return false; + } + llvm_unreachable("unknown fusion type"); + } } // end namespace X86; /// X86II - This namespace holds all of the target specific flags that Index: llvm/lib/Target/X86/X86MacroFusion.cpp =================================================================== --- llvm/lib/Target/X86/X86MacroFusion.cpp +++ llvm/lib/Target/X86/X86MacroFusion.cpp @@ -11,6 +11,7 @@ // //===----------------------------------------------------------------------===// +#include "MCTargetDesc/X86BaseInfo.h" #include "X86MacroFusion.h" #include "X86Subtarget.h" #include "llvm/CodeGen/MacroFusion.h" @@ -18,160 +19,13 @@ using namespace llvm; -namespace { - -// The classification for the first instruction. -enum class FirstInstrKind { Test, Cmp, And, ALU, IncDec, Invalid }; - -// The classification for the second instruction (jump). -enum class JumpKind { - // JE, JL, JG and variants. - ELG, - // JA, JB and variants. - AB, - // JS, JP, JO and variants. - SPO, - // Not a fusable jump. - Invalid, -}; - -} // namespace - -static FirstInstrKind classifyFirst(const MachineInstr &MI) { - switch (MI.getOpcode()) { - default: - return FirstInstrKind::Invalid; - case X86::TEST8rr: - case X86::TEST16rr: - case X86::TEST32rr: - case X86::TEST64rr: - case X86::TEST8ri: - case X86::TEST16ri: - case X86::TEST32ri: - case X86::TEST64ri32: - case X86::TEST8mr: - case X86::TEST16mr: - case X86::TEST32mr: - case X86::TEST64mr: - return FirstInstrKind::Test; - case X86::AND16ri: - case X86::AND16ri8: - case X86::AND16rm: - case X86::AND16rr: - case X86::AND32ri: - case X86::AND32ri8: - case X86::AND32rm: - case X86::AND32rr: - case X86::AND64ri32: - case X86::AND64ri8: - case X86::AND64rm: - case X86::AND64rr: - case X86::AND8ri: - case X86::AND8rm: - case X86::AND8rr: - return FirstInstrKind::And; - case X86::CMP16ri: - case X86::CMP16ri8: - case X86::CMP16rm: - case X86::CMP16rr: - case X86::CMP16mr: - case X86::CMP32ri: - case X86::CMP32ri8: - case X86::CMP32rm: - case X86::CMP32rr: - case X86::CMP32mr: - case X86::CMP64ri32: - case X86::CMP64ri8: - case X86::CMP64rm: - case X86::CMP64rr: - case X86::CMP64mr: - case X86::CMP8ri: - case X86::CMP8rm: - case X86::CMP8rr: - case X86::CMP8mr: - return FirstInstrKind::Cmp; - case X86::ADD16ri: - case X86::ADD16ri8: - case X86::ADD16ri8_DB: - case X86::ADD16ri_DB: - case X86::ADD16rm: - case X86::ADD16rr: - case X86::ADD16rr_DB: - case X86::ADD32ri: - case X86::ADD32ri8: - case X86::ADD32ri8_DB: - case X86::ADD32ri_DB: - case X86::ADD32rm: - case X86::ADD32rr: - case X86::ADD32rr_DB: - case X86::ADD64ri32: - case X86::ADD64ri32_DB: - case X86::ADD64ri8: - case X86::ADD64ri8_DB: - case X86::ADD64rm: - case X86::ADD64rr: - case X86::ADD64rr_DB: - case X86::ADD8ri: - case X86::ADD8ri_DB: - case X86::ADD8rm: - case X86::ADD8rr: - case X86::ADD8rr_DB: - case X86::SUB16ri: - case X86::SUB16ri8: - case X86::SUB16rm: - case X86::SUB16rr: - case X86::SUB32ri: - case X86::SUB32ri8: - case X86::SUB32rm: - case X86::SUB32rr: - case X86::SUB64ri32: - case X86::SUB64ri8: - case X86::SUB64rm: - case X86::SUB64rr: - case X86::SUB8ri: - case X86::SUB8rm: - case X86::SUB8rr: - return FirstInstrKind::ALU; - case X86::INC16r: - case X86::INC32r: - case X86::INC64r: - case X86::INC8r: - case X86::DEC16r: - case X86::DEC32r: - case X86::DEC64r: - case X86::DEC8r: - return FirstInstrKind::IncDec; - } +static X86::FirstMacroFusionInstKind classifyFirst(const MachineInstr &MI) { + return X86::classifyFirstOpcodeInMacroFusion(MI.getOpcode()); } -static JumpKind classifySecond(const MachineInstr &MI) { +static X86::SecondMacroFusionInstKind classifySecond(const MachineInstr &MI) { X86::CondCode CC = X86::getCondFromBranch(MI); - if (CC == X86::COND_INVALID) - return JumpKind::Invalid; - - switch (CC) { - default: - return JumpKind::Invalid; - case X86::COND_E: - case X86::COND_NE: - case X86::COND_L: - case X86::COND_LE: - case X86::COND_G: - case X86::COND_GE: - return JumpKind::ELG; - case X86::COND_B: - case X86::COND_BE: - case X86::COND_A: - case X86::COND_AE: - return JumpKind::AB; - case X86::COND_S: - case X86::COND_NS: - case X86::COND_P: - case X86::COND_NP: - case X86::COND_O: - case X86::COND_NO: - return JumpKind::SPO; - } + return X86::classifySecondCondCodeInMacroFusion(CC); } /// Check if the instr pair, FirstMI and SecondMI, should be fused @@ -187,40 +41,27 @@ if (!(ST.hasBranchFusion() || ST.hasMacroFusion())) return false; - const JumpKind BranchKind = classifySecond(SecondMI); + const X86::SecondMacroFusionInstKind BranchKind = classifySecond(SecondMI); - if (BranchKind == JumpKind::Invalid) + if (BranchKind == X86::SecondMacroFusionInstKind::Invalid) return false; // Second cannot be fused with anything. if (FirstMI == nullptr) return true; // We're only checking whether Second can be fused at all. - const FirstInstrKind TestKind = classifyFirst(*FirstMI); + const X86::FirstMacroFusionInstKind TestKind = classifyFirst(*FirstMI); if (ST.hasBranchFusion()) { // Branch fusion can merge CMP and TEST with all conditional jumps. - return (TestKind == FirstInstrKind::Cmp || - TestKind == FirstInstrKind::Test); + return (TestKind == X86::FirstMacroFusionInstKind::Cmp || + TestKind == X86::FirstMacroFusionInstKind::Test); } if (ST.hasMacroFusion()) { - // Macro Fusion rules are a bit more complex. See Agner Fog's - // Microarchitecture table 9.2 "Instruction Fusion". - switch (TestKind) { - case FirstInstrKind::Test: - case FirstInstrKind::And: - return true; - case FirstInstrKind::Cmp: - case FirstInstrKind::ALU: - return BranchKind == JumpKind::ELG || BranchKind == JumpKind::AB; - case FirstInstrKind::IncDec: - return BranchKind == JumpKind::ELG; - case FirstInstrKind::Invalid: - return false; - } + return X86::isMacroFused(TestKind, BranchKind); } - llvm_unreachable("unknown branch fusion type"); + llvm_unreachable("unknown fusion type"); } namespace llvm {