Index: llvm/lib/Target/AArch64/AArch64.td =================================================================== --- llvm/lib/Target/AArch64/AArch64.td +++ llvm/lib/Target/AArch64/AArch64.td @@ -128,6 +128,10 @@ "fuse-aes", "HasFuseAES", "true", "CPU fuses AES crypto operations">; +def FeatureFuseCCSelect : SubtargetFeature< + "fuse-csel", "HasFuseCCSelect", "true", + "CPU fuses conditional select operations">; + def FeatureFuseLiterals : SubtargetFeature< "fuse-literals", "HasFuseLiterals", "true", "CPU fuses literal generation operations">; @@ -352,6 +356,7 @@ FeatureFPARMv8, FeatureFuseAddress, FeatureFuseAES, + FeatureFuseCCSelect, FeatureFuseLiterals, FeatureLSLFast, FeatureNEON, Index: llvm/lib/Target/AArch64/AArch64MacroFusion.cpp =================================================================== --- llvm/lib/Target/AArch64/AArch64MacroFusion.cpp +++ llvm/lib/Target/AArch64/AArch64MacroFusion.cpp @@ -213,6 +213,57 @@ return false; } +// Fuse compare and conditional select. +static bool isCCSelectPair(const MachineInstr *FirstMI, + const MachineInstr &SecondMI) { + unsigned SecondOpcode = SecondMI.getOpcode(); + + // 32 bits + if (SecondOpcode == AArch64::CSELWr) { + // Assume the 1st instr to be a wildcard if it is unspecified. + if (!FirstMI) + return true; + + if (FirstMI->definesRegister(AArch64::WZR)) + switch (FirstMI->getOpcode()) { + case AArch64::SUBSWrs: + if (AArch64InstrInfo::hasShiftedReg(*FirstMI)) + return false; + return true; + case AArch64::SUBSWrx: + if (AArch64InstrInfo::hasExtendedReg(*FirstMI)) + return false; + return true; + case AArch64::SUBSWrr: + case AArch64::SUBSWri: + return true; + } + } + // 64 bits + else if (SecondOpcode == AArch64::CSELXr) { + // Assume the 1st instr to be a wildcard if it is unspecified. + if (!FirstMI) + return true; + + if (FirstMI->definesRegister(AArch64::XZR)) + switch (FirstMI->getOpcode()) { + case AArch64::SUBSXrs: + if (AArch64InstrInfo::hasShiftedReg(*FirstMI)) + return false; + return true; + case AArch64::SUBSXrx: + case AArch64::SUBSXrx64: + if (AArch64InstrInfo::hasExtendedReg(*FirstMI)) + return false; + return true; + case AArch64::SUBSXrr: + case AArch64::SUBSXri: + return true; + } + } + return false; +} + /// \brief Check if the instr pair, FirstMI and SecondMI, should be fused /// together. Given SecondMI, when FirstMI is unspecified, then check if /// SecondMI may be part of a fused pair at all. @@ -232,6 +283,8 @@ return true; if (ST.hasFuseAddress() && isAddressLdStPair(FirstMI, SecondMI)) return true; + if (ST.hasFuseCCSelect() && isCCSelectPair(FirstMI, SecondMI)) + return true; return false; } Index: llvm/lib/Target/AArch64/AArch64Subtarget.h =================================================================== --- llvm/lib/Target/AArch64/AArch64Subtarget.h +++ llvm/lib/Target/AArch64/AArch64Subtarget.h @@ -113,6 +113,7 @@ bool HasArithmeticCbzFusion = false; bool HasFuseAddress = false; bool HasFuseAES = false; + bool HasFuseCCSelect = false; bool HasFuseLiterals = false; bool DisableLatencySchedHeuristic = false; bool UseRSqrt = false; @@ -239,12 +240,13 @@ bool hasArithmeticCbzFusion() const { return HasArithmeticCbzFusion; } bool hasFuseAddress() const { return HasFuseAddress; } bool hasFuseAES() const { return HasFuseAES; } + bool hasFuseCCSelect() const { return HasFuseCCSelect; } bool hasFuseLiterals() const { return HasFuseLiterals; } /// \brief Return true if the CPU supports any kind of instruction fusion. bool hasFusion() const { return hasArithmeticBccFusion() || hasArithmeticCbzFusion() || - hasFuseAES() || hasFuseLiterals(); + hasFuseAES() || hasFuseCCSelect() || hasFuseLiterals(); } bool useRSqrt() const { return UseRSqrt; }