forked from OSchip/llvm-project
[AArch64][GlobalISel] Swap compare operands when it may be profitable
This adds support for swapping comparison operands when it may introduce new
folding opportunities.
This is roughly the same as the code added to AArch64ISelLowering in
162435e7b5
.
For an example of a testcase which exercises this, see
llvm/test/CodeGen/AArch64/swap-compare-operands.ll
(Godbolt for that testcase: https://godbolt.org/z/43WEMb)
The idea behind this is that sometimes, we may be able to fold away, say, a
shift or extend in a compare by swapping its operands.
e.g. in the case of this compare:
```
lsl x8, x0, #1
cmp x8, x1
cset w0, lt
```
The following is equivalent:
```
cmp x1, x0, lsl #1
cset w0, gt
```
Most of the code here is just a reimplementation of what already exists in
AArch64ISelLowering.
(See `getCmpOperandFoldingProfit` and `getAArch64Cmp` for the equivalent code.)
Note that most of the AND code in the testcase doesn't actually fold. It seems
like we're missing selection support for that sort of fold right now, since SDAG
happily folds these away (e.g testSwapCmpWithShiftedZeroExtend8_32 in the
original .ll testcase)
Differential Revision: https://reviews.llvm.org/D89422
This commit is contained in:
parent
b6f22fa5fe
commit
49c3565b9b
|
@ -127,7 +127,14 @@ def adjust_icmp_imm : GICombineRule <
|
|||
(apply [{ applyAdjustICmpImmAndPred(*${root}, ${matchinfo}, B, Observer); }])
|
||||
>;
|
||||
|
||||
def icmp_lowering : GICombineGroup<[adjust_icmp_imm]>;
|
||||
def swap_icmp_operands : GICombineRule <
|
||||
(defs root:$root),
|
||||
(match (wip_match_opcode G_ICMP):$root,
|
||||
[{ return trySwapICmpOperands(*${root}, MRI); }]),
|
||||
(apply [{ applySwapICmpOperands(*${root}, Observer); }])
|
||||
>;
|
||||
|
||||
def icmp_lowering : GICombineGroup<[adjust_icmp_imm, swap_icmp_operands]>;
|
||||
|
||||
def extractvecelt_pairwise_add_matchdata : GIDefMatchData<"std::tuple<unsigned, LLT, Register>">;
|
||||
def extractvecelt_pairwise_add : GICombineRule<
|
||||
|
|
|
@ -29,10 +29,31 @@ AArch64GISelUtils::getAArch64VectorSplat(const MachineInstr &MI,
|
|||
return RegOrConstant(Src);
|
||||
}
|
||||
|
||||
Optional<int64_t> AArch64GISelUtils::getAArch64VectorSplatScalar(
|
||||
const MachineInstr &MI, const MachineRegisterInfo &MRI) {
|
||||
Optional<int64_t>
|
||||
AArch64GISelUtils::getAArch64VectorSplatScalar(const MachineInstr &MI,
|
||||
const MachineRegisterInfo &MRI) {
|
||||
auto Splat = getAArch64VectorSplat(MI, MRI);
|
||||
if (!Splat || Splat->isReg())
|
||||
return None;
|
||||
return Splat->getCst();
|
||||
}
|
||||
|
||||
bool AArch64GISelUtils::isCMN(const MachineInstr *MaybeSub,
|
||||
const CmpInst::Predicate &Pred,
|
||||
const MachineRegisterInfo &MRI) {
|
||||
// Match:
|
||||
//
|
||||
// %sub = G_SUB 0, %y
|
||||
// %cmp = G_ICMP eq/ne, %sub, %z
|
||||
//
|
||||
// Or
|
||||
//
|
||||
// %sub = G_SUB 0, %y
|
||||
// %cmp = G_ICMP eq/ne, %z, %sub
|
||||
if (!MaybeSub || MaybeSub->getOpcode() != TargetOpcode::G_SUB ||
|
||||
!CmpInst::isEquality(Pred))
|
||||
return false;
|
||||
auto MaybeZero =
|
||||
getConstantVRegValWithLookThrough(MaybeSub->getOperand(1).getReg(), MRI);
|
||||
return MaybeZero && MaybeZero->Value.getZExtValue() == 0;
|
||||
}
|
||||
|
|
|
@ -15,9 +15,12 @@
|
|||
#include "llvm/ADT/Optional.h"
|
||||
#include "llvm/CodeGen/GlobalISel/Utils.h"
|
||||
#include "llvm/CodeGen/Register.h"
|
||||
#include "MCTargetDesc/AArch64AddressingModes.h"
|
||||
#include "llvm/IR/InstrTypes.h"
|
||||
#include <cstdint>
|
||||
|
||||
namespace llvm {
|
||||
|
||||
namespace AArch64GISelUtils {
|
||||
|
||||
/// \returns true if \p C is a legal immediate operand for an arithmetic
|
||||
|
@ -36,6 +39,11 @@ Optional<RegOrConstant> getAArch64VectorSplat(const MachineInstr &MI,
|
|||
Optional<int64_t> getAArch64VectorSplatScalar(const MachineInstr &MI,
|
||||
const MachineRegisterInfo &MRI);
|
||||
|
||||
/// \returns true if \p MaybeSub and \p Pred are part of a CMN tree for an
|
||||
/// integer compare.
|
||||
bool isCMN(const MachineInstr *MaybeSub, const CmpInst::Predicate &Pred,
|
||||
const MachineRegisterInfo &MRI);
|
||||
|
||||
} // namespace AArch64GISelUtils
|
||||
} // namespace llvm
|
||||
|
||||
|
|
|
@ -18,6 +18,7 @@
|
|||
#include "AArch64RegisterInfo.h"
|
||||
#include "AArch64Subtarget.h"
|
||||
#include "AArch64TargetMachine.h"
|
||||
#include "AArch64GlobalISelUtils.h"
|
||||
#include "MCTargetDesc/AArch64AddressingModes.h"
|
||||
#include "MCTargetDesc/AArch64MCTargetDesc.h"
|
||||
#include "llvm/ADT/Optional.h"
|
||||
|
@ -4577,37 +4578,10 @@ MachineInstr *AArch64InstructionSelector::tryFoldIntegerCompare(
|
|||
//
|
||||
// cmn z, y
|
||||
|
||||
// Helper lambda to detect the subtract followed by the compare.
|
||||
// Takes in the def of the LHS or RHS, and checks if it's a subtract from 0.
|
||||
auto IsCMN = [&](MachineInstr *DefMI, const AArch64CC::CondCode &CC) {
|
||||
if (!DefMI || DefMI->getOpcode() != TargetOpcode::G_SUB)
|
||||
return false;
|
||||
|
||||
// Need to make sure NZCV is the same at the end of the transformation.
|
||||
if (CC != AArch64CC::EQ && CC != AArch64CC::NE)
|
||||
return false;
|
||||
|
||||
// We want to match against SUBs.
|
||||
if (DefMI->getOpcode() != TargetOpcode::G_SUB)
|
||||
return false;
|
||||
|
||||
// Make sure that we're getting
|
||||
// x = G_SUB 0, y
|
||||
auto ValAndVReg =
|
||||
getConstantVRegValWithLookThrough(DefMI->getOperand(1).getReg(), MRI);
|
||||
if (!ValAndVReg || ValAndVReg->Value != 0)
|
||||
return false;
|
||||
|
||||
// This can safely be represented as a CMN.
|
||||
return true;
|
||||
};
|
||||
|
||||
// Check if the RHS or LHS of the G_ICMP is defined by a SUB
|
||||
MachineInstr *LHSDef = getDefIgnoringCopies(LHS.getReg(), MRI);
|
||||
MachineInstr *RHSDef = getDefIgnoringCopies(RHS.getReg(), MRI);
|
||||
CmpInst::Predicate P = (CmpInst::Predicate)Predicate.getPredicate();
|
||||
const AArch64CC::CondCode CC = changeICMPPredToAArch64CC(P);
|
||||
|
||||
auto P = static_cast<CmpInst::Predicate>(Predicate.getPredicate());
|
||||
// Given this:
|
||||
//
|
||||
// x = G_SUB 0, y
|
||||
|
@ -4616,7 +4590,7 @@ MachineInstr *AArch64InstructionSelector::tryFoldIntegerCompare(
|
|||
// Produce this:
|
||||
//
|
||||
// cmn y, z
|
||||
if (IsCMN(LHSDef, CC))
|
||||
if (isCMN(LHSDef, P, MRI))
|
||||
return emitCMN(LHSDef->getOperand(2), RHS, MIRBuilder);
|
||||
|
||||
// Same idea here, but with the RHS of the compare instead:
|
||||
|
@ -4629,7 +4603,7 @@ MachineInstr *AArch64InstructionSelector::tryFoldIntegerCompare(
|
|||
// Produce this:
|
||||
//
|
||||
// cmn z, y
|
||||
if (IsCMN(RHSDef, CC))
|
||||
if (isCMN(RHSDef, P, MRI))
|
||||
return emitCMN(LHS, RHSDef->getOperand(2), MIRBuilder);
|
||||
|
||||
// Given this:
|
||||
|
|
|
@ -735,6 +735,113 @@ static bool applyBuildVectorToDup(MachineInstr &MI, MachineRegisterInfo &MRI,
|
|||
return true;
|
||||
}
|
||||
|
||||
/// \returns how many instructions would be saved by folding a G_ICMP's shift
|
||||
/// and/or extension operations.
|
||||
static unsigned getCmpOperandFoldingProfit(Register CmpOp,
|
||||
const MachineRegisterInfo &MRI) {
|
||||
// No instructions to save if there's more than one use or no uses.
|
||||
if (!MRI.hasOneNonDBGUse(CmpOp))
|
||||
return 0;
|
||||
|
||||
// FIXME: This is duplicated with the selector. (See: selectShiftedRegister)
|
||||
auto IsSupportedExtend = [&](const MachineInstr &MI) {
|
||||
if (MI.getOpcode() == TargetOpcode::G_SEXT_INREG)
|
||||
return true;
|
||||
if (MI.getOpcode() != TargetOpcode::G_AND)
|
||||
return false;
|
||||
auto ValAndVReg =
|
||||
getConstantVRegValWithLookThrough(MI.getOperand(2).getReg(), MRI);
|
||||
if (!ValAndVReg)
|
||||
return false;
|
||||
uint64_t Mask = ValAndVReg->Value.getZExtValue();
|
||||
return (Mask == 0xFF || Mask == 0xFFFF || Mask == 0xFFFFFFFF);
|
||||
};
|
||||
|
||||
MachineInstr *Def = getDefIgnoringCopies(CmpOp, MRI);
|
||||
if (IsSupportedExtend(*Def))
|
||||
return 1;
|
||||
|
||||
unsigned Opc = Def->getOpcode();
|
||||
if (Opc != TargetOpcode::G_SHL && Opc != TargetOpcode::G_ASHR &&
|
||||
Opc != TargetOpcode::G_LSHR)
|
||||
return 0;
|
||||
|
||||
auto MaybeShiftAmt =
|
||||
getConstantVRegValWithLookThrough(Def->getOperand(2).getReg(), MRI);
|
||||
if (!MaybeShiftAmt)
|
||||
return 0;
|
||||
uint64_t ShiftAmt = MaybeShiftAmt->Value.getZExtValue();
|
||||
MachineInstr *ShiftLHS =
|
||||
getDefIgnoringCopies(Def->getOperand(1).getReg(), MRI);
|
||||
|
||||
// Check if we can fold an extend and a shift.
|
||||
// FIXME: This is duplicated with the selector. (See:
|
||||
// selectArithExtendedRegister)
|
||||
if (IsSupportedExtend(*ShiftLHS))
|
||||
return (ShiftAmt <= 4) ? 2 : 1;
|
||||
|
||||
LLT Ty = MRI.getType(Def->getOperand(0).getReg());
|
||||
if (Ty.isVector())
|
||||
return 0;
|
||||
unsigned ShiftSize = Ty.getSizeInBits();
|
||||
if ((ShiftSize == 32 && ShiftAmt <= 31) ||
|
||||
(ShiftSize == 64 && ShiftAmt <= 63))
|
||||
return 1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
/// \returns true if it would be profitable to swap the LHS and RHS of a G_ICMP
|
||||
/// instruction \p MI.
|
||||
static bool trySwapICmpOperands(MachineInstr &MI,
|
||||
const MachineRegisterInfo &MRI) {
|
||||
assert(MI.getOpcode() == TargetOpcode::G_ICMP);
|
||||
// Swap the operands if it would introduce a profitable folding opportunity.
|
||||
// (e.g. a shift + extend).
|
||||
//
|
||||
// For example:
|
||||
// lsl w13, w11, #1
|
||||
// cmp w13, w12
|
||||
// can be turned into:
|
||||
// cmp w12, w11, lsl #1
|
||||
|
||||
// Don't swap if there's a constant on the RHS, because we know we can fold
|
||||
// that.
|
||||
Register RHS = MI.getOperand(3).getReg();
|
||||
auto RHSCst = getConstantVRegValWithLookThrough(RHS, MRI);
|
||||
if (RHSCst && isLegalArithImmed(RHSCst->Value.getSExtValue()))
|
||||
return false;
|
||||
|
||||
Register LHS = MI.getOperand(2).getReg();
|
||||
auto Pred = static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
|
||||
auto GetRegForProfit = [&](Register Reg) {
|
||||
MachineInstr *Def = getDefIgnoringCopies(Reg, MRI);
|
||||
return isCMN(Def, Pred, MRI) ? Def->getOperand(2).getReg() : Reg;
|
||||
};
|
||||
|
||||
// Don't have a constant on the RHS. If we swap the LHS and RHS of the
|
||||
// compare, would we be able to fold more instructions?
|
||||
Register TheLHS = GetRegForProfit(LHS);
|
||||
Register TheRHS = GetRegForProfit(RHS);
|
||||
|
||||
// If the LHS is more likely to give us a folding opportunity, then swap the
|
||||
// LHS and RHS.
|
||||
return (getCmpOperandFoldingProfit(TheLHS, MRI) >
|
||||
getCmpOperandFoldingProfit(TheRHS, MRI));
|
||||
}
|
||||
|
||||
static bool applySwapICmpOperands(MachineInstr &MI,
|
||||
GISelChangeObserver &Observer) {
|
||||
auto Pred = static_cast<CmpInst::Predicate>(MI.getOperand(1).getPredicate());
|
||||
Register LHS = MI.getOperand(2).getReg();
|
||||
Register RHS = MI.getOperand(3).getReg();
|
||||
Observer.changedInstr(MI);
|
||||
MI.getOperand(1).setPredicate(CmpInst::getSwappedPredicate(Pred));
|
||||
MI.getOperand(2).setReg(RHS);
|
||||
MI.getOperand(3).setReg(LHS);
|
||||
Observer.changedInstr(MI);
|
||||
return true;
|
||||
}
|
||||
|
||||
#define AARCH64POSTLEGALIZERLOWERINGHELPER_GENCOMBINERHELPER_DEPS
|
||||
#include "AArch64GenPostLegalizeGILowering.inc"
|
||||
#undef AARCH64POSTLEGALIZERLOWERINGHELPER_GENCOMBINERHELPER_DEPS
|
||||
|
|
|
@ -0,0 +1,737 @@
|
|||
# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py
|
||||
# RUN: llc -mtriple=aarch64 -run-pass=aarch64-postlegalizer-lowering -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=LOWER
|
||||
# RUN: llc -mtriple=aarch64 -global-isel -start-before=aarch64-postlegalizer-lowering -stop-after=instruction-select -verify-machineinstrs %s -o - | FileCheck %s --check-prefix=SELECT
|
||||
#
|
||||
# Check that we swap the order of operands on comparisons when it is likely
|
||||
# to introduce a folding opportunity.
|
||||
#
|
||||
# The condition code for the compare should be changed when appropriate.
|
||||
#
|
||||
# TODO: emitBinOp doesn't know about selectArithExtendedRegister, so some of
|
||||
# these cases don't hit in selection yet.
|
||||
|
||||
...
|
||||
---
|
||||
name: swap_sextinreg_lhs
|
||||
legalized: true
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.0:
|
||||
liveins: $x0, $x1
|
||||
|
||||
; LOWER-LABEL: name: swap_sextinreg_lhs
|
||||
; LOWER: liveins: $x0, $x1
|
||||
; LOWER: %reg:_(s64) = COPY $x0
|
||||
; LOWER: %cmp_lhs:_(s64) = G_SEXT_INREG %reg, 8
|
||||
; LOWER: %cmp_rhs:_(s64) = COPY $x1
|
||||
; LOWER: %cmp:_(s32) = G_ICMP intpred(sle), %cmp_rhs(s64), %cmp_lhs
|
||||
; LOWER: $w0 = COPY %cmp(s32)
|
||||
; LOWER: RET_ReallyLR implicit $w0
|
||||
; SELECT-LABEL: name: swap_sextinreg_lhs
|
||||
; SELECT: liveins: $x0, $x1
|
||||
; SELECT: %reg:gpr64all = COPY $x0
|
||||
; SELECT: [[COPY:%[0-9]+]]:gpr32all = COPY %reg.sub_32
|
||||
; SELECT: [[COPY1:%[0-9]+]]:gpr32 = COPY [[COPY]]
|
||||
; SELECT: %cmp_rhs:gpr64sp = COPY $x1
|
||||
; SELECT: [[SUBSXrx:%[0-9]+]]:gpr64 = SUBSXrx %cmp_rhs, [[COPY1]], 32, implicit-def $nzcv
|
||||
; SELECT: %cmp:gpr32 = CSINCWr $wzr, $wzr, 12, implicit $nzcv
|
||||
; SELECT: $w0 = COPY %cmp
|
||||
; SELECT: RET_ReallyLR implicit $w0
|
||||
%reg:_(s64) = COPY $x0
|
||||
%cmp_lhs:_(s64) = G_SEXT_INREG %reg, 8
|
||||
%cmp_rhs:_(s64) = COPY $x1
|
||||
%cmp:_(s32) = G_ICMP intpred(sge), %cmp_lhs(s64), %cmp_rhs
|
||||
$w0 = COPY %cmp(s32)
|
||||
RET_ReallyLR implicit $w0
|
||||
|
||||
...
|
||||
---
|
||||
name: dont_swap_more_than_one_use
|
||||
legalized: true
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.0:
|
||||
liveins: $x0, $x1
|
||||
|
||||
; The LHS of the compare is used in an add, and a second compare. Don't
|
||||
; swap, since we don't gain any folding opportunities here.
|
||||
|
||||
; LOWER-LABEL: name: dont_swap_more_than_one_use
|
||||
; LOWER: liveins: $x0, $x1
|
||||
; LOWER: %reg0:_(s64) = COPY $x0
|
||||
; LOWER: %cmp_lhs:_(s64) = G_SEXT_INREG %reg0, 8
|
||||
; LOWER: %add:_(s64) = G_ADD %cmp_lhs, %reg0
|
||||
; LOWER: %cmp2:_(s32) = G_ICMP intpred(sge), %cmp_lhs(s64), %add
|
||||
; LOWER: $w0 = COPY %cmp2(s32)
|
||||
; LOWER: RET_ReallyLR implicit $w0
|
||||
; SELECT-LABEL: name: dont_swap_more_than_one_use
|
||||
; SELECT: liveins: $x0, $x1
|
||||
; SELECT: %reg0:gpr64 = COPY $x0
|
||||
; SELECT: %cmp_lhs:gpr64 = SBFMXri %reg0, 0, 7
|
||||
; SELECT: %add:gpr64 = ADDXrr %cmp_lhs, %reg0
|
||||
; SELECT: [[SUBSXrr:%[0-9]+]]:gpr64 = SUBSXrr %cmp_lhs, %add, implicit-def $nzcv
|
||||
; SELECT: %cmp2:gpr32 = CSINCWr $wzr, $wzr, 11, implicit $nzcv
|
||||
; SELECT: $w0 = COPY %cmp2
|
||||
; SELECT: RET_ReallyLR implicit $w0
|
||||
%reg0:_(s64) = COPY $x0
|
||||
%cmp_lhs:_(s64) = G_SEXT_INREG %reg0, 8
|
||||
%reg1:_(s64) = COPY $x1
|
||||
%cmp1:_(s32) = G_ICMP intpred(sge), %cmp_lhs(s64), %reg1
|
||||
|
||||
%add:_(s64) = G_ADD %cmp_lhs(s64), %reg0
|
||||
%cmp2:_(s32) = G_ICMP intpred(sge), %cmp_lhs(s64), %add
|
||||
|
||||
$w0 = COPY %cmp2(s32)
|
||||
RET_ReallyLR implicit $w0
|
||||
|
||||
...
|
||||
---
|
||||
name: dont_swap_legal_arith_immed_on_rhs
|
||||
legalized: true
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.0:
|
||||
liveins: $x0, $x1
|
||||
; Arithmetic immediates can be folded into compares. If we have one, then
|
||||
; don't bother changing anything.
|
||||
|
||||
; LOWER-LABEL: name: dont_swap_legal_arith_immed_on_rhs
|
||||
; LOWER: liveins: $x0, $x1
|
||||
; LOWER: %reg:_(s64) = COPY $x0
|
||||
; LOWER: %cmp_lhs:_(s64) = G_SEXT_INREG %reg, 8
|
||||
; LOWER: %cmp_rhs:_(s64) = G_CONSTANT i64 12
|
||||
; LOWER: %cmp:_(s32) = G_ICMP intpred(sge), %cmp_lhs(s64), %cmp_rhs
|
||||
; LOWER: $w0 = COPY %cmp(s32)
|
||||
; LOWER: RET_ReallyLR implicit $w0
|
||||
; SELECT-LABEL: name: dont_swap_legal_arith_immed_on_rhs
|
||||
; SELECT: liveins: $x0, $x1
|
||||
; SELECT: %reg:gpr64 = COPY $x0
|
||||
; SELECT: %cmp_lhs:gpr64common = SBFMXri %reg, 0, 7
|
||||
; SELECT: [[SUBSXri:%[0-9]+]]:gpr64 = SUBSXri %cmp_lhs, 12, 0, implicit-def $nzcv
|
||||
; SELECT: %cmp:gpr32 = CSINCWr $wzr, $wzr, 11, implicit $nzcv
|
||||
; SELECT: $w0 = COPY %cmp
|
||||
; SELECT: RET_ReallyLR implicit $w0
|
||||
%reg:_(s64) = COPY $x0
|
||||
%cmp_lhs:_(s64) = G_SEXT_INREG %reg, 8
|
||||
%cmp_rhs:_(s64) = G_CONSTANT i64 12
|
||||
%cmp:_(s32) = G_ICMP intpred(sge), %cmp_lhs(s64), %cmp_rhs
|
||||
$w0 = COPY %cmp(s32)
|
||||
RET_ReallyLR implicit $w0
|
||||
|
||||
...
|
||||
---
|
||||
name: swap_non_arith_immed_on_rhs
|
||||
legalized: true
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.0:
|
||||
liveins: $x0, $x1
|
||||
; If we have a non-arithmetic immediate on the rhs, then we can swap to get
|
||||
; a guaranteed folding opportunity.
|
||||
|
||||
; LOWER-LABEL: name: swap_non_arith_immed_on_rhs
|
||||
; LOWER: liveins: $x0, $x1
|
||||
; LOWER: %reg:_(s64) = COPY $x0
|
||||
; LOWER: %cmp_lhs:_(s64) = G_SEXT_INREG %reg, 8
|
||||
; LOWER: %cmp_rhs:_(s64) = G_CONSTANT i64 1234567
|
||||
; LOWER: %cmp:_(s32) = G_ICMP intpred(sle), %cmp_rhs(s64), %cmp_lhs
|
||||
; LOWER: $w0 = COPY %cmp(s32)
|
||||
; LOWER: RET_ReallyLR implicit $w0
|
||||
; SELECT-LABEL: name: swap_non_arith_immed_on_rhs
|
||||
; SELECT: liveins: $x0, $x1
|
||||
; SELECT: %reg:gpr64all = COPY $x0
|
||||
; SELECT: [[COPY:%[0-9]+]]:gpr32all = COPY %reg.sub_32
|
||||
; SELECT: [[COPY1:%[0-9]+]]:gpr32 = COPY [[COPY]]
|
||||
; SELECT: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 1234567
|
||||
; SELECT: %cmp_rhs:gpr64sp = SUBREG_TO_REG 0, [[MOVi32imm]], %subreg.sub_32
|
||||
; SELECT: [[SUBSXrx:%[0-9]+]]:gpr64 = SUBSXrx %cmp_rhs, [[COPY1]], 32, implicit-def $nzcv
|
||||
; SELECT: %cmp:gpr32 = CSINCWr $wzr, $wzr, 12, implicit $nzcv
|
||||
; SELECT: $w0 = COPY %cmp
|
||||
; SELECT: RET_ReallyLR implicit $w0
|
||||
%reg:_(s64) = COPY $x0
|
||||
%cmp_lhs:_(s64) = G_SEXT_INREG %reg, 8
|
||||
%cmp_rhs:_(s64) = G_CONSTANT i64 1234567
|
||||
%cmp:_(s32) = G_ICMP intpred(sge), %cmp_lhs(s64), %cmp_rhs
|
||||
$w0 = COPY %cmp(s32)
|
||||
RET_ReallyLR implicit $w0
|
||||
|
||||
...
|
||||
---
|
||||
name: swap_and_lhs_0xFF
|
||||
legalized: true
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.0:
|
||||
liveins: $x0, $x1
|
||||
; LOWER-LABEL: name: swap_and_lhs_0xFF
|
||||
; LOWER: liveins: $x0, $x1
|
||||
; LOWER: %cmp_rhs:_(s64) = COPY $x1
|
||||
; LOWER: %and_lhs:_(s64) = COPY $x0
|
||||
; LOWER: %cst:_(s64) = G_CONSTANT i64 255
|
||||
; LOWER: %cmp_lhs:_(s64) = G_AND %and_lhs, %cst
|
||||
; LOWER: %cmp:_(s32) = G_ICMP intpred(sle), %cmp_rhs(s64), %cmp_lhs
|
||||
; LOWER: $w0 = COPY %cmp(s32)
|
||||
; LOWER: RET_ReallyLR implicit $w0
|
||||
; SELECT-LABEL: name: swap_and_lhs_0xFF
|
||||
; SELECT: liveins: $x0, $x1
|
||||
; SELECT: %cmp_rhs:gpr64sp = COPY $x1
|
||||
; SELECT: %and_lhs:gpr64all = COPY $x0
|
||||
; SELECT: [[COPY:%[0-9]+]]:gpr32all = COPY %and_lhs.sub_32
|
||||
; SELECT: [[COPY1:%[0-9]+]]:gpr32 = COPY [[COPY]]
|
||||
; SELECT: [[SUBSXrx:%[0-9]+]]:gpr64 = SUBSXrx %cmp_rhs, [[COPY1]], 0, implicit-def $nzcv
|
||||
; SELECT: %cmp:gpr32 = CSINCWr $wzr, $wzr, 12, implicit $nzcv
|
||||
; SELECT: $w0 = COPY %cmp
|
||||
; SELECT: RET_ReallyLR implicit $w0
|
||||
%cmp_rhs:_(s64) = COPY $x1
|
||||
|
||||
%and_lhs:_(s64) = COPY $x0
|
||||
%cst:_(s64) = G_CONSTANT i64 255
|
||||
%cmp_lhs:_(s64) = G_AND %and_lhs, %cst(s64)
|
||||
|
||||
%cmp:_(s32) = G_ICMP intpred(sge), %cmp_lhs(s64), %cmp_rhs
|
||||
$w0 = COPY %cmp(s32)
|
||||
RET_ReallyLR implicit $w0
|
||||
|
||||
...
|
||||
---
|
||||
name: swap_and_lhs_0xFFFF
|
||||
legalized: true
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.0:
|
||||
liveins: $x0, $x1
|
||||
; LOWER-LABEL: name: swap_and_lhs_0xFFFF
|
||||
; LOWER: liveins: $x0, $x1
|
||||
; LOWER: %cmp_rhs:_(s64) = COPY $x1
|
||||
; LOWER: %cst:_(s64) = G_CONSTANT i64 65535
|
||||
; LOWER: %and_lhs:_(s64) = COPY $x0
|
||||
; LOWER: %cmp_lhs:_(s64) = G_AND %and_lhs, %cst
|
||||
; LOWER: %cmp:_(s32) = G_ICMP intpred(sle), %cmp_rhs(s64), %cmp_lhs
|
||||
; LOWER: $w0 = COPY %cmp(s32)
|
||||
; LOWER: RET_ReallyLR implicit $w0
|
||||
; SELECT-LABEL: name: swap_and_lhs_0xFFFF
|
||||
; SELECT: liveins: $x0, $x1
|
||||
; SELECT: %cmp_rhs:gpr64sp = COPY $x1
|
||||
; SELECT: %and_lhs:gpr64all = COPY $x0
|
||||
; SELECT: [[COPY:%[0-9]+]]:gpr32all = COPY %and_lhs.sub_32
|
||||
; SELECT: [[COPY1:%[0-9]+]]:gpr32 = COPY [[COPY]]
|
||||
; SELECT: [[SUBSXrx:%[0-9]+]]:gpr64 = SUBSXrx %cmp_rhs, [[COPY1]], 8, implicit-def $nzcv
|
||||
; SELECT: %cmp:gpr32 = CSINCWr $wzr, $wzr, 12, implicit $nzcv
|
||||
; SELECT: $w0 = COPY %cmp
|
||||
; SELECT: RET_ReallyLR implicit $w0
|
||||
%cmp_rhs:_(s64) = COPY $x1
|
||||
|
||||
%cst:_(s64) = G_CONSTANT i64 65535
|
||||
%and_lhs:_(s64) = COPY $x0
|
||||
%cmp_lhs:_(s64) = G_AND %and_lhs, %cst(s64)
|
||||
|
||||
%cmp:_(s32) = G_ICMP intpred(sge), %cmp_lhs(s64), %cmp_rhs
|
||||
$w0 = COPY %cmp(s32)
|
||||
RET_ReallyLR implicit $w0
|
||||
|
||||
...
|
||||
---
|
||||
name: swap_and_lhs_0xFFFFFFFF
|
||||
legalized: true
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.0:
|
||||
liveins: $x0, $x1
|
||||
; LOWER-LABEL: name: swap_and_lhs_0xFFFFFFFF
|
||||
; LOWER: liveins: $x0, $x1
|
||||
; LOWER: %cmp_rhs:_(s64) = COPY $x1
|
||||
; LOWER: %and_lhs:_(s64) = COPY $x0
|
||||
; LOWER: %cst:_(s64) = G_CONSTANT i64 4294967295
|
||||
; LOWER: %cmp_lhs:_(s64) = G_AND %and_lhs, %cst
|
||||
; LOWER: %cmp:_(s32) = G_ICMP intpred(sle), %cmp_rhs(s64), %cmp_lhs
|
||||
; LOWER: $w0 = COPY %cmp(s32)
|
||||
; LOWER: RET_ReallyLR implicit $w0
|
||||
; SELECT-LABEL: name: swap_and_lhs_0xFFFFFFFF
|
||||
; SELECT: liveins: $x0, $x1
|
||||
; SELECT: %cmp_rhs:gpr64sp = COPY $x1
|
||||
; SELECT: %and_lhs:gpr64all = COPY $x0
|
||||
; SELECT: [[COPY:%[0-9]+]]:gpr32all = COPY %and_lhs.sub_32
|
||||
; SELECT: [[COPY1:%[0-9]+]]:gpr32 = COPY [[COPY]]
|
||||
; SELECT: [[SUBSXrx:%[0-9]+]]:gpr64 = SUBSXrx %cmp_rhs, [[COPY1]], 16, implicit-def $nzcv
|
||||
; SELECT: %cmp:gpr32 = CSINCWr $wzr, $wzr, 12, implicit $nzcv
|
||||
; SELECT: $w0 = COPY %cmp
|
||||
; SELECT: RET_ReallyLR implicit $w0
|
||||
%cmp_rhs:_(s64) = COPY $x1
|
||||
|
||||
%and_lhs:_(s64) = COPY $x0
|
||||
%cst:_(s64) = G_CONSTANT i64 4294967295
|
||||
%cmp_lhs:_(s64) = G_AND %and_lhs, %cst(s64)
|
||||
|
||||
%cmp:_(s32) = G_ICMP intpred(sge), %cmp_lhs(s64), %cmp_rhs
|
||||
$w0 = COPY %cmp(s32)
|
||||
RET_ReallyLR implicit $w0
|
||||
|
||||
...
|
||||
---
|
||||
name: dont_swap_and_lhs_wrong_mask
|
||||
legalized: true
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.0:
|
||||
liveins: $x0, $x1
|
||||
; 7 isn't an extend mask for G_AND, so there's no folding opportunities
|
||||
; here.
|
||||
;
|
||||
; LOWER-LABEL: name: dont_swap_and_lhs_wrong_mask
|
||||
; LOWER: liveins: $x0, $x1
|
||||
; LOWER: %cmp_rhs:_(s64) = COPY $x1
|
||||
; LOWER: %and_lhs:_(s64) = COPY $x0
|
||||
; LOWER: %not_an_extend_mask:_(s64) = G_CONSTANT i64 7
|
||||
; LOWER: %cmp_lhs:_(s64) = G_AND %and_lhs, %not_an_extend_mask
|
||||
; LOWER: %cmp:_(s32) = G_ICMP intpred(sge), %cmp_lhs(s64), %cmp_rhs
|
||||
; LOWER: $w0 = COPY %cmp(s32)
|
||||
; LOWER: RET_ReallyLR implicit $w0
|
||||
; SELECT-LABEL: name: dont_swap_and_lhs_wrong_mask
|
||||
; SELECT: liveins: $x0, $x1
|
||||
; SELECT: %cmp_rhs:gpr64 = COPY $x1
|
||||
; SELECT: %and_lhs:gpr64 = COPY $x0
|
||||
; SELECT: %cmp_lhs:gpr64common = ANDXri %and_lhs, 4098
|
||||
; SELECT: [[SUBSXrr:%[0-9]+]]:gpr64 = SUBSXrr %cmp_lhs, %cmp_rhs, implicit-def $nzcv
|
||||
; SELECT: %cmp:gpr32 = CSINCWr $wzr, $wzr, 11, implicit $nzcv
|
||||
; SELECT: $w0 = COPY %cmp
|
||||
; SELECT: RET_ReallyLR implicit $w0
|
||||
%cmp_rhs:_(s64) = COPY $x1
|
||||
|
||||
%and_lhs:_(s64) = COPY $x0
|
||||
%not_an_extend_mask:_(s64) = G_CONSTANT i64 7
|
||||
%cmp_lhs:_(s64) = G_AND %and_lhs, %not_an_extend_mask(s64)
|
||||
|
||||
%cmp:_(s32) = G_ICMP intpred(sge), %cmp_lhs(s64), %cmp_rhs
|
||||
$w0 = COPY %cmp(s32)
|
||||
RET_ReallyLR implicit $w0
|
||||
|
||||
...
|
||||
---
|
||||
name: swap_shl_lhs
|
||||
legalized: true
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.0:
|
||||
liveins: $x0, $x1
|
||||
|
||||
; LOWER-LABEL: name: swap_shl_lhs
|
||||
; LOWER: liveins: $x0, $x1
|
||||
; LOWER: %cmp_rhs:_(s64) = COPY $x1
|
||||
; LOWER: %shl_lhs:_(s64) = COPY $x0
|
||||
; LOWER: %cst:_(s64) = G_CONSTANT i64 1
|
||||
; LOWER: %cmp_lhs:_(s64) = G_SHL %shl_lhs, %cst(s64)
|
||||
; LOWER: %cmp:_(s32) = G_ICMP intpred(sgt), %cmp_rhs(s64), %cmp_lhs
|
||||
; LOWER: $w0 = COPY %cmp(s32)
|
||||
; LOWER: RET_ReallyLR implicit $w0
|
||||
; SELECT-LABEL: name: swap_shl_lhs
|
||||
; SELECT: liveins: $x0, $x1
|
||||
; SELECT: %cmp_rhs:gpr64 = COPY $x1
|
||||
; SELECT: %shl_lhs:gpr64 = COPY $x0
|
||||
; SELECT: [[SUBSXrs:%[0-9]+]]:gpr64 = SUBSXrs %cmp_rhs, %shl_lhs, 1, implicit-def $nzcv
|
||||
; SELECT: %cmp:gpr32 = CSINCWr $wzr, $wzr, 13, implicit $nzcv
|
||||
; SELECT: $w0 = COPY %cmp
|
||||
; SELECT: RET_ReallyLR implicit $w0
|
||||
%cmp_rhs:_(s64) = COPY $x1
|
||||
|
||||
%shl_lhs:_(s64) = COPY $x0
|
||||
%cst:_(s64) = G_CONSTANT i64 1
|
||||
%cmp_lhs:_(s64) = G_SHL %shl_lhs, %cst(s64)
|
||||
|
||||
%cmp:_(s32) = G_ICMP intpred(slt), %cmp_lhs(s64), %cmp_rhs
|
||||
$w0 = COPY %cmp(s32)
|
||||
RET_ReallyLR implicit $w0
|
||||
|
||||
...
|
||||
---
|
||||
name: swap_ashr_lhs
|
||||
legalized: true
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.0:
|
||||
liveins: $x0, $x1
|
||||
|
||||
; LOWER-LABEL: name: swap_ashr_lhs
|
||||
; LOWER: liveins: $x0, $x1
|
||||
; LOWER: %cmp_rhs:_(s64) = COPY $x1
|
||||
; LOWER: %ashr_lhs:_(s64) = COPY $x0
|
||||
; LOWER: %cst:_(s64) = G_CONSTANT i64 1
|
||||
; LOWER: %cmp_lhs:_(s64) = G_ASHR %ashr_lhs, %cst(s64)
|
||||
; LOWER: %cmp:_(s32) = G_ICMP intpred(sgt), %cmp_rhs(s64), %cmp_lhs
|
||||
; LOWER: $w0 = COPY %cmp(s32)
|
||||
; LOWER: RET_ReallyLR implicit $w0
|
||||
; SELECT-LABEL: name: swap_ashr_lhs
|
||||
; SELECT: liveins: $x0, $x1
|
||||
; SELECT: %cmp_rhs:gpr64 = COPY $x1
|
||||
; SELECT: %ashr_lhs:gpr64 = COPY $x0
|
||||
; SELECT: [[SUBSXrs:%[0-9]+]]:gpr64 = SUBSXrs %cmp_rhs, %ashr_lhs, 129, implicit-def $nzcv
|
||||
; SELECT: %cmp:gpr32 = CSINCWr $wzr, $wzr, 13, implicit $nzcv
|
||||
; SELECT: $w0 = COPY %cmp
|
||||
; SELECT: RET_ReallyLR implicit $w0
|
||||
%cmp_rhs:_(s64) = COPY $x1
|
||||
|
||||
%ashr_lhs:_(s64) = COPY $x0
|
||||
%cst:_(s64) = G_CONSTANT i64 1
|
||||
%cmp_lhs:_(s64) = G_ASHR %ashr_lhs, %cst(s64)
|
||||
|
||||
%cmp:_(s32) = G_ICMP intpred(slt), %cmp_lhs(s64), %cmp_rhs
|
||||
$w0 = COPY %cmp(s32)
|
||||
RET_ReallyLR implicit $w0
|
||||
|
||||
...
|
||||
---
|
||||
name: swap_lshr_lhs
|
||||
legalized: true
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.0:
|
||||
liveins: $x0, $x1
|
||||
|
||||
; LOWER-LABEL: name: swap_lshr_lhs
|
||||
; LOWER: liveins: $x0, $x1
|
||||
; LOWER: %cmp_rhs:_(s64) = COPY $x1
|
||||
; LOWER: %lshr_lhs:_(s64) = COPY $x0
|
||||
; LOWER: %cst:_(s64) = G_CONSTANT i64 1
|
||||
; LOWER: %cmp_lhs:_(s64) = G_LSHR %lshr_lhs, %cst(s64)
|
||||
; LOWER: %cmp:_(s32) = G_ICMP intpred(sgt), %cmp_rhs(s64), %cmp_lhs
|
||||
; LOWER: $w0 = COPY %cmp(s32)
|
||||
; LOWER: RET_ReallyLR implicit $w0
|
||||
; SELECT-LABEL: name: swap_lshr_lhs
|
||||
; SELECT: liveins: $x0, $x1
|
||||
; SELECT: %cmp_rhs:gpr64 = COPY $x1
|
||||
; SELECT: %lshr_lhs:gpr64 = COPY $x0
|
||||
; SELECT: [[SUBSXrs:%[0-9]+]]:gpr64 = SUBSXrs %cmp_rhs, %lshr_lhs, 65, implicit-def $nzcv
|
||||
; SELECT: %cmp:gpr32 = CSINCWr $wzr, $wzr, 13, implicit $nzcv
|
||||
; SELECT: $w0 = COPY %cmp
|
||||
; SELECT: RET_ReallyLR implicit $w0
|
||||
%cmp_rhs:_(s64) = COPY $x1
|
||||
|
||||
%lshr_lhs:_(s64) = COPY $x0
|
||||
%cst:_(s64) = G_CONSTANT i64 1
|
||||
%cmp_lhs:_(s64) = G_LSHR %lshr_lhs, %cst(s64)
|
||||
|
||||
%cmp:_(s32) = G_ICMP intpred(slt), %cmp_lhs(s64), %cmp_rhs
|
||||
$w0 = COPY %cmp(s32)
|
||||
RET_ReallyLR implicit $w0
|
||||
|
||||
...
|
||||
---
|
||||
name: dont_swap_shift_s64_cst_too_large
|
||||
legalized: true
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.0:
|
||||
liveins: $x0, $x1
|
||||
|
||||
; Constant for the shift must be <= 63.
|
||||
|
||||
; LOWER-LABEL: name: dont_swap_shift_s64_cst_too_large
|
||||
; LOWER: liveins: $x0, $x1
|
||||
; LOWER: %cmp_rhs:_(s64) = COPY $x1
|
||||
; LOWER: %shl_lhs:_(s64) = COPY $x0
|
||||
; LOWER: %too_large:_(s64) = G_CONSTANT i64 64
|
||||
; LOWER: %cmp_lhs:_(s64) = G_SHL %shl_lhs, %too_large(s64)
|
||||
; LOWER: %cmp:_(s32) = G_ICMP intpred(slt), %cmp_lhs(s64), %cmp_rhs
|
||||
; LOWER: $w0 = COPY %cmp(s32)
|
||||
; LOWER: RET_ReallyLR implicit $w0
|
||||
; SELECT-LABEL: name: dont_swap_shift_s64_cst_too_large
|
||||
; SELECT: liveins: $x0, $x1
|
||||
; SELECT: %cmp_rhs:gpr64 = COPY $x1
|
||||
; SELECT: %shl_lhs:gpr64 = COPY $x0
|
||||
; SELECT: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 64
|
||||
; SELECT: %too_large:gpr64 = SUBREG_TO_REG 0, [[MOVi32imm]], %subreg.sub_32
|
||||
; SELECT: %cmp_lhs:gpr64 = LSLVXr %shl_lhs, %too_large
|
||||
; SELECT: [[SUBSXrr:%[0-9]+]]:gpr64 = SUBSXrr %cmp_lhs, %cmp_rhs, implicit-def $nzcv
|
||||
; SELECT: %cmp:gpr32 = CSINCWr $wzr, $wzr, 10, implicit $nzcv
|
||||
; SELECT: $w0 = COPY %cmp
|
||||
; SELECT: RET_ReallyLR implicit $w0
|
||||
%cmp_rhs:_(s64) = COPY $x1
|
||||
|
||||
%shl_lhs:_(s64) = COPY $x0
|
||||
%too_large:_(s64) = G_CONSTANT i64 64
|
||||
%cmp_lhs:_(s64) = G_SHL %shl_lhs, %too_large(s64)
|
||||
|
||||
%cmp:_(s32) = G_ICMP intpred(slt), %cmp_lhs(s64), %cmp_rhs
|
||||
$w0 = COPY %cmp(s32)
|
||||
RET_ReallyLR implicit $w0
|
||||
|
||||
|
||||
...
|
||||
---
|
||||
name: dont_swap_shift_s32_cst_too_large
|
||||
legalized: true
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.0:
|
||||
liveins: $w0, $w1
|
||||
|
||||
; Constant for the shift must be <= 32.
|
||||
|
||||
; LOWER-LABEL: name: dont_swap_shift_s32_cst_too_large
|
||||
; LOWER: liveins: $w0, $w1
|
||||
; LOWER: %cmp_rhs:_(s32) = COPY $w1
|
||||
; LOWER: %shl_lhs:_(s32) = COPY $w0
|
||||
; LOWER: %cst:_(s32) = G_CONSTANT i32 32
|
||||
; LOWER: %cmp_lhs:_(s32) = G_SHL %shl_lhs, %cst(s32)
|
||||
; LOWER: %cmp:_(s32) = G_ICMP intpred(slt), %cmp_lhs(s32), %cmp_rhs
|
||||
; LOWER: $w0 = COPY %cmp(s32)
|
||||
; LOWER: RET_ReallyLR implicit $w0
|
||||
; SELECT-LABEL: name: dont_swap_shift_s32_cst_too_large
|
||||
; SELECT: liveins: $w0, $w1
|
||||
; SELECT: %cmp_rhs:gpr32 = COPY $w1
|
||||
; SELECT: %shl_lhs:gpr32 = COPY $w0
|
||||
; SELECT: %cst:gpr32 = MOVi32imm 32
|
||||
; SELECT: %cmp_lhs:gpr32 = LSLVWr %shl_lhs, %cst
|
||||
; SELECT: [[SUBSWrr:%[0-9]+]]:gpr32 = SUBSWrr %cmp_lhs, %cmp_rhs, implicit-def $nzcv
|
||||
; SELECT: %cmp:gpr32 = CSINCWr $wzr, $wzr, 10, implicit $nzcv
|
||||
; SELECT: $w0 = COPY %cmp
|
||||
; SELECT: RET_ReallyLR implicit $w0
|
||||
%cmp_rhs:_(s32) = COPY $w1
|
||||
|
||||
%shl_lhs:_(s32) = COPY $w0
|
||||
%cst:_(s32) = G_CONSTANT i32 32
|
||||
%cmp_lhs:_(s32) = G_SHL %shl_lhs, %cst(s32)
|
||||
|
||||
%cmp:_(s32) = G_ICMP intpred(slt), %cmp_lhs(s32), %cmp_rhs
|
||||
$w0 = COPY %cmp(s32)
|
||||
RET_ReallyLR implicit $w0
|
||||
|
||||
...
|
||||
---
|
||||
name: dont_swap_cmn_lhs_no_folding_opportunities
|
||||
legalized: true
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.0.entry:
|
||||
liveins: $x0, $x1
|
||||
|
||||
; No reason to swap a CMN on the LHS when it won't introduce a constant
|
||||
; folding opportunity. We can recognise CMNs on the LHS and RHS, so there's
|
||||
; nothing to gain here.
|
||||
|
||||
; LOWER-LABEL: name: dont_swap_cmn_lhs_no_folding_opportunities
|
||||
; LOWER: liveins: $x0, $x1
|
||||
; LOWER: %cmp_rhs:_(s64) = COPY $x1
|
||||
; LOWER: %sub_rhs:_(s64) = COPY $x0
|
||||
; LOWER: %zero:_(s64) = G_CONSTANT i64 0
|
||||
; LOWER: %cmp_lhs:_(s64) = G_SUB %zero, %sub_rhs
|
||||
; LOWER: %cmp:_(s32) = G_ICMP intpred(ne), %cmp_lhs(s64), %cmp_rhs
|
||||
; LOWER: $w0 = COPY %cmp(s32)
|
||||
; LOWER: RET_ReallyLR implicit $w0
|
||||
; SELECT-LABEL: name: dont_swap_cmn_lhs_no_folding_opportunities
|
||||
; SELECT: liveins: $x0, $x1
|
||||
; SELECT: %cmp_rhs:gpr64 = COPY $x1
|
||||
; SELECT: %sub_rhs:gpr64 = COPY $x0
|
||||
; SELECT: [[ADDSXrr:%[0-9]+]]:gpr64 = ADDSXrr %sub_rhs, %cmp_rhs, implicit-def $nzcv
|
||||
; SELECT: %cmp:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv
|
||||
; SELECT: $w0 = COPY %cmp
|
||||
; SELECT: RET_ReallyLR implicit $w0
|
||||
%cmp_rhs:_(s64) = COPY $x1
|
||||
|
||||
%sub_rhs:_(s64) = COPY $x0
|
||||
%zero:_(s64) = G_CONSTANT i64 0
|
||||
%cmp_lhs:_(s64) = G_SUB %zero, %sub_rhs
|
||||
|
||||
%cmp:_(s32) = G_ICMP intpred(ne), %cmp_lhs(s64), %cmp_rhs
|
||||
$w0 = COPY %cmp(s32)
|
||||
RET_ReallyLR implicit $w0
|
||||
|
||||
...
|
||||
---
|
||||
name: swap_cmn_lhs
|
||||
legalized: true
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.0.entry:
|
||||
liveins: $x0, $x1
|
||||
|
||||
; Swap when we can see a constant folding opportunity through the sub on
|
||||
; the LHS.
|
||||
|
||||
|
||||
; LOWER-LABEL: name: swap_cmn_lhs
|
||||
; LOWER: liveins: $x0, $x1
|
||||
; LOWER: %cmp_rhs:_(s64) = COPY $x1
|
||||
; LOWER: %shl_lhs:_(s64) = COPY $x0
|
||||
; LOWER: %zero:_(s64) = G_CONSTANT i64 0
|
||||
; LOWER: %cst:_(s64) = G_CONSTANT i64 63
|
||||
; LOWER: %sub_rhs:_(s64) = G_SHL %shl_lhs, %cst(s64)
|
||||
; LOWER: %cmp_lhs:_(s64) = G_SUB %zero, %sub_rhs
|
||||
; LOWER: %cmp:_(s32) = G_ICMP intpred(ne), %cmp_rhs(s64), %cmp_lhs
|
||||
; LOWER: $w0 = COPY %cmp(s32)
|
||||
; LOWER: RET_ReallyLR implicit $w0
|
||||
; SELECT-LABEL: name: swap_cmn_lhs
|
||||
; SELECT: liveins: $x0, $x1
|
||||
; SELECT: %cmp_rhs:gpr64 = COPY $x1
|
||||
; SELECT: %shl_lhs:gpr64 = COPY $x0
|
||||
; SELECT: [[ADDSXrs:%[0-9]+]]:gpr64 = ADDSXrs %cmp_rhs, %shl_lhs, 63, implicit-def $nzcv
|
||||
; SELECT: %cmp:gpr32 = CSINCWr $wzr, $wzr, 0, implicit $nzcv
|
||||
; SELECT: $w0 = COPY %cmp
|
||||
; SELECT: RET_ReallyLR implicit $w0
|
||||
%cmp_rhs:_(s64) = COPY $x1
|
||||
|
||||
%shl_lhs:_(s64) = COPY $x0
|
||||
%zero:_(s64) = G_CONSTANT i64 0
|
||||
%cst:_(s64) = G_CONSTANT i64 63
|
||||
%sub_rhs:_(s64) = G_SHL %shl_lhs, %cst(s64)
|
||||
%cmp_lhs:_(s64) = G_SUB %zero, %sub_rhs
|
||||
|
||||
%cmp:_(s32) = G_ICMP intpred(ne), %cmp_lhs(s64), %cmp_rhs
|
||||
$w0 = COPY %cmp(s32)
|
||||
RET_ReallyLR implicit $w0
|
||||
|
||||
...
|
||||
---
|
||||
name: dont_swap_cmn_lhs_when_rhs_more_profitable
|
||||
legalized: true
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.0.entry:
|
||||
liveins: $x0, $x1
|
||||
|
||||
; Don't swap when the RHS's subtract offers a better constant folding
|
||||
; opportunity than the LHS's subtract.
|
||||
;
|
||||
; In this case, the RHS has a supported extend, plus a shift with a constant
|
||||
; <= 4.
|
||||
|
||||
; LOWER-LABEL: name: dont_swap_cmn_lhs_when_rhs_more_profitable
|
||||
; LOWER: liveins: $x0, $x1
|
||||
; LOWER: %zero:_(s64) = G_CONSTANT i64 0
|
||||
; LOWER: %reg0:_(s64) = COPY $x0
|
||||
; LOWER: %shl_cst:_(s64) = G_CONSTANT i64 63
|
||||
; LOWER: %shl:_(s64) = G_SHL %reg0, %shl_cst(s64)
|
||||
; LOWER: %cmp_lhs:_(s64) = G_SUB %zero, %shl
|
||||
; LOWER: %reg1:_(s64) = COPY $x1
|
||||
; LOWER: %sext_in_reg:_(s64) = G_SEXT_INREG %reg1, 1
|
||||
; LOWER: %ashr_cst:_(s64) = G_CONSTANT i64 3
|
||||
; LOWER: %ashr:_(s64) = G_ASHR %sext_in_reg, %ashr_cst(s64)
|
||||
; LOWER: %cmp_rhs:_(s64) = G_SUB %zero, %ashr
|
||||
; LOWER: %cmp:_(s32) = G_ICMP intpred(eq), %cmp_lhs(s64), %cmp_rhs
|
||||
; LOWER: $w0 = COPY %cmp(s32)
|
||||
; LOWER: RET_ReallyLR implicit $w0
|
||||
; SELECT-LABEL: name: dont_swap_cmn_lhs_when_rhs_more_profitable
|
||||
; SELECT: liveins: $x0, $x1
|
||||
; SELECT: %reg0:gpr64 = COPY $x0
|
||||
; SELECT: %shl:gpr64 = UBFMXri %reg0, 1, 0
|
||||
; SELECT: %zero:gpr64 = COPY $xzr
|
||||
; SELECT: %reg1:gpr64 = COPY $x1
|
||||
; SELECT: %sext_in_reg:gpr64 = SBFMXri %reg1, 0, 0
|
||||
; SELECT: %cmp_rhs:gpr64 = SUBSXrs %zero, %sext_in_reg, 131, implicit-def $nzcv
|
||||
; SELECT: [[ADDSXrr:%[0-9]+]]:gpr64 = ADDSXrr %shl, %cmp_rhs, implicit-def $nzcv
|
||||
; SELECT: %cmp:gpr32 = CSINCWr $wzr, $wzr, 1, implicit $nzcv
|
||||
; SELECT: $w0 = COPY %cmp
|
||||
; SELECT: RET_ReallyLR implicit $w0
|
||||
%zero:_(s64) = G_CONSTANT i64 0
|
||||
|
||||
%reg0:_(s64) = COPY $x0
|
||||
%shl_cst:_(s64) = G_CONSTANT i64 63
|
||||
%shl:_(s64) = G_SHL %reg0, %shl_cst(s64)
|
||||
%cmp_lhs:_(s64) = G_SUB %zero, %shl
|
||||
|
||||
%reg1:_(s64) = COPY $x1
|
||||
%sext_in_reg:_(s64) = G_SEXT_INREG %reg1, 1
|
||||
%ashr_cst:_(s64) = G_CONSTANT i64 3
|
||||
%ashr:_(s64) = G_ASHR %sext_in_reg, %ashr_cst(s64)
|
||||
%cmp_rhs:_(s64) = G_SUB %zero, %ashr
|
||||
|
||||
%cmp:_(s32) = G_ICMP intpred(eq), %cmp_lhs(s64), %cmp_rhs
|
||||
$w0 = COPY %cmp(s32)
|
||||
RET_ReallyLR implicit $w0
|
||||
|
||||
...
|
||||
---
|
||||
name: dont_swap_rhs_with_supported_extend
|
||||
legalized: true
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.0:
|
||||
liveins: $x0, $x1
|
||||
; The RHS offers more constant folding opportunities than the LHS.
|
||||
|
||||
; LOWER-LABEL: name: dont_swap_rhs_with_supported_extend
|
||||
; LOWER: liveins: $x0, $x1
|
||||
; LOWER: %reg0:_(s64) = COPY $x0
|
||||
; LOWER: %lhs_cst:_(s64) = G_CONSTANT i64 1
|
||||
; LOWER: %cmp_lhs:_(s64) = G_SHL %reg0, %lhs_cst(s64)
|
||||
; LOWER: %reg1:_(s64) = COPY $x1
|
||||
; LOWER: %and_mask:_(s64) = G_CONSTANT i64 255
|
||||
; LOWER: %and:_(s64) = G_AND %reg1, %and_mask
|
||||
; LOWER: %rhs_cst:_(s64) = G_CONSTANT i64 1
|
||||
; LOWER: %cmp_rhs:_(s64) = G_ASHR %and, %rhs_cst(s64)
|
||||
; LOWER: %cmp:_(s32) = G_ICMP intpred(slt), %cmp_lhs(s64), %cmp_rhs
|
||||
; LOWER: $w0 = COPY %cmp(s32)
|
||||
; LOWER: RET_ReallyLR implicit $w0
|
||||
; SELECT-LABEL: name: dont_swap_rhs_with_supported_extend
|
||||
; SELECT: liveins: $x0, $x1
|
||||
; SELECT: %reg0:gpr64 = COPY $x0
|
||||
; SELECT: %cmp_lhs:gpr64 = UBFMXri %reg0, 63, 62
|
||||
; SELECT: %reg1:gpr64 = COPY $x1
|
||||
; SELECT: %and:gpr64common = ANDXri %reg1, 4103
|
||||
; SELECT: [[SUBSXrs:%[0-9]+]]:gpr64 = SUBSXrs %cmp_lhs, %and, 129, implicit-def $nzcv
|
||||
; SELECT: %cmp:gpr32 = CSINCWr $wzr, $wzr, 10, implicit $nzcv
|
||||
; SELECT: $w0 = COPY %cmp
|
||||
; SELECT: RET_ReallyLR implicit $w0
|
||||
%reg0:_(s64) = COPY $x0
|
||||
%lhs_cst:_(s64) = G_CONSTANT i64 1
|
||||
%cmp_lhs:_(s64) = G_SHL %reg0, %lhs_cst(s64)
|
||||
|
||||
%reg1:_(s64) = COPY $x1
|
||||
%and_mask:_(s64) = G_CONSTANT i64 255
|
||||
%and:_(s64) = G_AND %reg1, %and_mask(s64)
|
||||
%rhs_cst:_(s64) = G_CONSTANT i64 1
|
||||
%cmp_rhs:_(s64) = G_ASHR %and, %rhs_cst(s64)
|
||||
|
||||
%cmp:_(s32) = G_ICMP intpred(slt), %cmp_lhs(s64), %cmp_rhs
|
||||
$w0 = COPY %cmp(s32)
|
||||
RET_ReallyLR implicit $w0
|
||||
|
||||
|
||||
...
|
||||
---
|
||||
name: swap_rhs_with_supported_extend
|
||||
legalized: true
|
||||
tracksRegLiveness: true
|
||||
body: |
|
||||
bb.0:
|
||||
liveins: $x0, $x1
|
||||
|
||||
; In this case, both the LHS and RHS are fed by a supported extend. However,
|
||||
; the LHS' shift has a constant <= 4. This makes it more profitable, so
|
||||
; we should swap the operands.
|
||||
|
||||
; LOWER-LABEL: name: swap_rhs_with_supported_extend
|
||||
; LOWER: liveins: $x0, $x1
|
||||
; LOWER: %reg0:_(s64) = COPY $x0
|
||||
; LOWER: %and_mask:_(s64) = G_CONSTANT i64 255
|
||||
; LOWER: %and:_(s64) = G_AND %reg0, %and_mask
|
||||
; LOWER: %lhs_cst:_(s64) = G_CONSTANT i64 1
|
||||
; LOWER: %cmp_lhs:_(s64) = G_SHL %and, %lhs_cst(s64)
|
||||
; LOWER: %rhs_cst:_(s64) = G_CONSTANT i64 5
|
||||
; LOWER: %cmp_rhs:_(s64) = G_ASHR %and, %rhs_cst(s64)
|
||||
; LOWER: %cmp:_(s32) = G_ICMP intpred(slt), %cmp_rhs(s64), %cmp_lhs
|
||||
; LOWER: $w0 = COPY %cmp(s32)
|
||||
; LOWER: RET_ReallyLR implicit $w0
|
||||
; SELECT-LABEL: name: swap_rhs_with_supported_extend
|
||||
; SELECT: liveins: $x0, $x1
|
||||
; SELECT: %reg0:gpr64 = COPY $x0
|
||||
; SELECT: %and:gpr64common = ANDXri %reg0, 4103
|
||||
; SELECT: [[COPY:%[0-9]+]]:gpr32all = COPY %reg0.sub_32
|
||||
; SELECT: [[COPY1:%[0-9]+]]:gpr32 = COPY [[COPY]]
|
||||
; SELECT: %cmp_rhs:gpr64common = SBFMXri %and, 5, 63
|
||||
; SELECT: [[SUBSXrx:%[0-9]+]]:gpr64 = SUBSXrx %cmp_rhs, [[COPY1]], 1, implicit-def $nzcv
|
||||
; SELECT: %cmp:gpr32 = CSINCWr $wzr, $wzr, 10, implicit $nzcv
|
||||
; SELECT: $w0 = COPY %cmp
|
||||
; SELECT: RET_ReallyLR implicit $w0
|
||||
%reg0:_(s64) = COPY $x0
|
||||
%and_mask:_(s64) = G_CONSTANT i64 255
|
||||
%and:_(s64) = G_AND %reg0, %and_mask(s64)
|
||||
|
||||
%lhs_cst:_(s64) = G_CONSTANT i64 1
|
||||
%cmp_lhs:_(s64) = G_SHL %and, %lhs_cst(s64)
|
||||
|
||||
%rhs_cst:_(s64) = G_CONSTANT i64 5
|
||||
%cmp_rhs:_(s64) = G_ASHR %and, %rhs_cst(s64)
|
||||
|
||||
%cmp:_(s32) = G_ICMP intpred(sgt), %cmp_lhs(s64), %cmp_rhs
|
||||
$w0 = COPY %cmp(s32)
|
||||
RET_ReallyLR implicit $w0
|
Loading…
Reference in New Issue