[AArch64][GlobalISel] Select CSINC and CSINV for G_SELECT with constants

Select the following:

- G_SELECT cc, 0, 1 -> CSINC zreg, zreg, cc
- G_SELECT cc 0, -1 -> CSINV zreg, zreg cc
- G_SELECT cc, 1, f -> CSINC f, zreg, inv_cc
- G_SELECT cc, -1, f -> CSINV f, zreg, inv_cc
- G_SELECT cc, t, 1 -> CSINC t, zreg, cc
- G_SELECT cc, t, -1 -> CSINC t, zreg, cc

(IR example: https://godbolt.org/z/YfPna9)

These correspond to a bunch of the AArch64csel patterns in AArch64InstrInfo.td.

Unfortunately, it doesn't seem like we can import patterns that use NZCV like
those ones do. E.g.

```
def : Pat<(AArch64csel GPR32:$tval, (i32 1), (i32 imm:$cc), NZCV),
          (CSINCWr GPR32:$tval, WZR, (i32 imm:$cc))>;
```

So we have to manually select these for now.

This replaces `selectSelectOpc` with an `emitSelect` function, which performs
these optimizations.

Differential Revision: https://reviews.llvm.org/D90701
This commit is contained in:
Jessica Paquette 2020-11-03 11:08:08 -08:00
parent 410626c9b5
commit d0ba6c4002
3 changed files with 419 additions and 107 deletions

View File

@ -225,6 +225,9 @@ private:
MachineIRBuilder &MIRBuilder) const;
MachineInstr *emitTST(MachineOperand &LHS, MachineOperand &RHS,
MachineIRBuilder &MIRBuilder) const;
MachineInstr *emitSelect(Register Dst, Register LHS, Register RHS,
AArch64CC::CondCode CC,
MachineIRBuilder &MIRBuilder) const;
MachineInstr *emitExtractVectorElt(Optional<Register> DstReg,
const RegisterBank &DstRB, LLT ScalarTy,
Register VecReg, unsigned LaneIdx,
@ -983,17 +986,107 @@ static unsigned selectFPConvOpc(unsigned GenericOpc, LLT DstTy, LLT SrcTy) {
return GenericOpc;
}
static unsigned selectSelectOpc(MachineInstr &I, MachineRegisterInfo &MRI,
const RegisterBankInfo &RBI) {
const TargetRegisterInfo &TRI = *MRI.getTargetRegisterInfo();
bool IsFP = (RBI.getRegBank(I.getOperand(0).getReg(), MRI, TRI)->getID() !=
AArch64::GPRRegBankID);
LLT Ty = MRI.getType(I.getOperand(0).getReg());
if (Ty == LLT::scalar(32))
return IsFP ? AArch64::FCSELSrrr : AArch64::CSELWr;
else if (Ty == LLT::scalar(64) || Ty == LLT::pointer(0, 64))
return IsFP ? AArch64::FCSELDrrr : AArch64::CSELXr;
return 0;
MachineInstr *
AArch64InstructionSelector::emitSelect(Register Dst, Register True,
Register False, AArch64CC::CondCode CC,
MachineIRBuilder &MIB) const {
MachineRegisterInfo &MRI = *MIB.getMRI();
assert(RBI.getRegBank(False, MRI, TRI)->getID() ==
RBI.getRegBank(True, MRI, TRI)->getID() &&
"Expected both select operands to have the same regbank?");
LLT Ty = MRI.getType(True);
if (Ty.isVector())
return nullptr;
const unsigned Size = Ty.getSizeInBits();
assert((Size == 32 || Size == 64) &&
"Expected 32 bit or 64 bit select only?");
const bool Is32Bit = Size == 32;
if (RBI.getRegBank(True, MRI, TRI)->getID() != AArch64::GPRRegBankID) {
unsigned Opc = Is32Bit ? AArch64::FCSELSrrr : AArch64::FCSELDrrr;
auto FCSel = MIB.buildInstr(Opc, {Dst}, {True, False}).addImm(CC);
constrainSelectedInstRegOperands(*FCSel, TII, TRI, RBI);
return &*FCSel;
}
// By default, we'll try and emit a CSEL.
unsigned Opc = Is32Bit ? AArch64::CSELWr : AArch64::CSELXr;
// Helper lambda which tries to use CSINC/CSINV for the instruction when its
// true/false values are constants.
// FIXME: All of these patterns already exist in tablegen. We should be
// able to import these.
auto TryOptSelectCst = [&Opc, &True, &False, &CC, Is32Bit, &MRI]() {
auto TrueCst = getConstantVRegValWithLookThrough(True, MRI);
auto FalseCst = getConstantVRegValWithLookThrough(False, MRI);
if (!TrueCst && !FalseCst)
return false;
Register ZReg = Is32Bit ? AArch64::WZR : AArch64::XZR;
if (TrueCst && FalseCst) {
auto T = TrueCst->Value;
auto F = FalseCst->Value;
if (T == 0 && F == 1) {
// G_SELECT cc, 0, 1 -> CSINC zreg, zreg, cc
Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
True = ZReg;
False = ZReg;
return true;
}
if (T == 0 && F == -1) {
// G_SELECT cc 0, -1 -> CSINV zreg, zreg cc
Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
True = ZReg;
False = ZReg;
return true;
}
}
if (TrueCst) {
auto T = TrueCst->Value;
if (T == 1) {
// G_SELECT cc, 1, f -> CSINC f, zreg, inv_cc
Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
True = False;
False = ZReg;
CC = AArch64CC::getInvertedCondCode(CC);
return true;
}
if (T == -1) {
// G_SELECT cc, -1, f -> CSINV f, zreg, inv_cc
Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
True = False;
False = ZReg;
CC = AArch64CC::getInvertedCondCode(CC);
return true;
}
}
if (FalseCst) {
auto F = FalseCst->Value;
if (F == 1) {
// G_SELECT cc, t, 1 -> CSINC t, zreg, cc
Opc = Is32Bit ? AArch64::CSINCWr : AArch64::CSINCXr;
False = ZReg;
return true;
}
if (F == -1) {
// G_SELECT cc, t, -1 -> CSINC t, zreg, cc
Opc = Is32Bit ? AArch64::CSINVWr : AArch64::CSINVXr;
False = ZReg;
return true;
}
}
return false;
};
TryOptSelectCst();
auto SelectInst = MIB.buildInstr(Opc, {Dst}, {True, False}).addImm(CC);
constrainSelectedInstRegOperands(*SelectInst, TII, TRI, RBI);
return &*SelectInst;
}
/// Returns true if \p P is an unsigned integer comparison predicate.
@ -2831,25 +2924,15 @@ bool AArch64InstructionSelector::select(MachineInstr &I) {
if (tryOptSelect(I))
return true;
Register CSelOpc = selectSelectOpc(I, MRI, RBI);
// Make sure to use an unused vreg instead of wzr, so that the peephole
// optimizations will be able to optimize these.
MachineIRBuilder MIB(I);
Register DeadVReg = MRI.createVirtualRegister(&AArch64::GPR32RegClass);
MachineInstr &TstMI =
*BuildMI(MBB, I, I.getDebugLoc(), TII.get(AArch64::ANDSWri))
.addDef(DeadVReg)
.addUse(CondReg)
.addImm(AArch64_AM::encodeLogicalImmediate(1, 32));
MachineInstr &CSelMI = *BuildMI(MBB, I, I.getDebugLoc(), TII.get(CSelOpc))
.addDef(I.getOperand(0).getReg())
.addUse(TReg)
.addUse(FReg)
.addImm(AArch64CC::NE);
constrainSelectedInstRegOperands(TstMI, TII, TRI, RBI);
constrainSelectedInstRegOperands(CSelMI, TII, TRI, RBI);
auto TstMI = MIB.buildInstr(AArch64::ANDSWri, {DeadVReg}, {CondReg})
.addImm(AArch64_AM::encodeLogicalImmediate(1, 32));
constrainSelectedInstRegOperands(*TstMI, TII, TRI, RBI);
if (!emitSelect(I.getOperand(0).getReg(), TReg, FReg, AArch64CC::NE, MIB))
return false;
I.eraseFromParent();
return true;
}
@ -4132,9 +4215,6 @@ AArch64InstructionSelector::emitCSetForICMP(Register DefReg, unsigned Pred,
bool AArch64InstructionSelector::tryOptSelect(MachineInstr &I) const {
MachineIRBuilder MIB(I);
MachineRegisterInfo &MRI = *MIB.getMRI();
const TargetRegisterInfo &TRI = *MRI.getTargetRegisterInfo();
Register SrcReg1 = I.getOperand(2).getReg();
Register SrcReg2 = I.getOperand(3).getReg();
// We want to recognize this pattern:
//
// $z = G_FCMP pred, $x, $y
@ -4218,37 +4298,8 @@ bool AArch64InstructionSelector::tryOptSelect(MachineInstr &I) const {
}
// Emit the select.
// We may also be able to emit a CSINC if the RHS operand is a 1.
const RegisterBank &SrcRB = *RBI.getRegBank(SrcReg1, MRI, TRI);
auto ValAndVReg =
getConstantVRegValWithLookThrough(SrcReg2, MRI);
if (SrcRB.getID() == AArch64::GPRRegBankID && ValAndVReg &&
ValAndVReg->Value == 1) {
unsigned Size = MRI.getType(SrcReg1).getSizeInBits();
unsigned Opc = 0;
Register Zero;
if (Size == 64) {
Opc = AArch64::CSINCXr;
Zero = AArch64::XZR;
} else {
Opc = AArch64::CSINCWr;
Zero = AArch64::WZR;
}
auto CSINC =
MIB.buildInstr(Opc, {I.getOperand(0).getReg()}, {SrcReg1, Zero})
.addImm(CondCode);
constrainSelectedInstRegOperands(*CSINC, TII, TRI, RBI);
I.eraseFromParent();
return true;
}
unsigned CSelOpc = selectSelectOpc(I, MRI, RBI);
auto CSel =
MIB.buildInstr(CSelOpc, {I.getOperand(0).getReg()},
{I.getOperand(2).getReg(), I.getOperand(3).getReg()})
.addImm(CondCode);
constrainSelectedInstRegOperands(*CSel, TII, TRI, RBI);
emitSelect(I.getOperand(0).getReg(), I.getOperand(2).getReg(),
I.getOperand(3).getReg(), CondCode, MIB);
I.eraseFromParent();
return true;
}

View File

@ -45,10 +45,9 @@ body: |
; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
; CHECK: [[COPY1:%[0-9]+]]:gpr32 = COPY $w1
; CHECK: [[COPY2:%[0-9]+]]:gpr32 = COPY $wzr
; CHECK: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 1
; CHECK: $wzr = ADDSWrr [[COPY]], [[COPY1]], implicit-def $nzcv
; CHECK: [[CSELWr:%[0-9]+]]:gpr32 = CSELWr [[MOVi32imm]], [[COPY2]], 1, implicit $nzcv
; CHECK: $w0 = COPY [[CSELWr]]
; CHECK: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr [[COPY2]], $wzr, 0, implicit $nzcv
; CHECK: $w0 = COPY [[CSINCWr]]
; CHECK: RET_ReallyLR implicit $w0
%0:gpr(s32) = COPY $w0
%1:gpr(s32) = COPY $w1
@ -77,10 +76,9 @@ body: |
; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
; CHECK: [[COPY1:%[0-9]+]]:gpr32 = COPY $w1
; CHECK: [[COPY2:%[0-9]+]]:gpr32 = COPY $wzr
; CHECK: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 1
; CHECK: $wzr = ADDSWrr [[COPY]], [[COPY1]], implicit-def $nzcv
; CHECK: [[CSELWr:%[0-9]+]]:gpr32 = CSELWr [[MOVi32imm]], [[COPY2]], 1, implicit $nzcv
; CHECK: $w0 = COPY [[CSELWr]]
; CHECK: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr [[COPY2]], $wzr, 0, implicit $nzcv
; CHECK: $w0 = COPY [[CSINCWr]]
; CHECK: RET_ReallyLR implicit $w0
%0:gpr(s32) = COPY $w0
%1:gpr(s32) = COPY $w1
@ -109,11 +107,10 @@ body: |
; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
; CHECK: [[COPY1:%[0-9]+]]:gpr32 = COPY $w1
; CHECK: [[COPY2:%[0-9]+]]:gpr32 = COPY $wzr
; CHECK: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 1
; CHECK: [[SUBSWrr:%[0-9]+]]:gpr32 = SUBSWrr [[COPY2]], [[COPY1]], implicit-def $nzcv
; CHECK: [[SUBSWrr1:%[0-9]+]]:gpr32 = SUBSWrr [[COPY]], [[SUBSWrr]], implicit-def $nzcv
; CHECK: [[CSELWr:%[0-9]+]]:gpr32 = CSELWr [[MOVi32imm]], [[COPY2]], 11, implicit $nzcv
; CHECK: $w0 = COPY [[CSELWr]]
; CHECK: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr [[COPY2]], $wzr, 10, implicit $nzcv
; CHECK: $w0 = COPY [[CSINCWr]]
; CHECK: RET_ReallyLR implicit $w0
%0:gpr(s32) = COPY $w0
%1:gpr(s32) = COPY $w1
@ -142,11 +139,10 @@ body: |
; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w0
; CHECK: [[COPY1:%[0-9]+]]:gpr32 = COPY $w1
; CHECK: [[COPY2:%[0-9]+]]:gpr32 = COPY $wzr
; CHECK: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 1
; CHECK: [[SUBSWrr:%[0-9]+]]:gpr32 = SUBSWrr [[COPY2]], [[COPY]], implicit-def $nzcv
; CHECK: [[SUBSWrr1:%[0-9]+]]:gpr32 = SUBSWrr [[SUBSWrr]], [[COPY1]], implicit-def $nzcv
; CHECK: [[CSELWr:%[0-9]+]]:gpr32 = CSELWr [[MOVi32imm]], [[COPY2]], 11, implicit $nzcv
; CHECK: $w0 = COPY [[CSELWr]]
; CHECK: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr [[COPY2]], $wzr, 10, implicit $nzcv
; CHECK: $w0 = COPY [[CSINCWr]]
; CHECK: RET_ReallyLR implicit $w0
%0:gpr(s32) = COPY $w0
%1:gpr(s32) = COPY $w1
@ -175,11 +171,9 @@ body: |
; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
; CHECK: [[COPY1:%[0-9]+]]:gpr64 = COPY $x1
; CHECK: [[COPY2:%[0-9]+]]:gpr64 = COPY $xzr
; CHECK: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 1
; CHECK: [[SUBREG_TO_REG:%[0-9]+]]:gpr64 = SUBREG_TO_REG 0, [[MOVi32imm]], %subreg.sub_32
; CHECK: $xzr = ADDSXrr [[COPY]], [[COPY1]], implicit-def $nzcv
; CHECK: [[CSELXr:%[0-9]+]]:gpr64 = CSELXr [[SUBREG_TO_REG]], [[COPY2]], 1, implicit $nzcv
; CHECK: $x0 = COPY [[CSELXr]]
; CHECK: [[CSINCXr:%[0-9]+]]:gpr64 = CSINCXr [[COPY2]], $xzr, 0, implicit $nzcv
; CHECK: $x0 = COPY [[CSINCXr]]
; CHECK: RET_ReallyLR implicit $x0
%0:gpr(s64) = COPY $x0
%1:gpr(s64) = COPY $x1
@ -208,11 +202,9 @@ body: |
; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
; CHECK: [[COPY1:%[0-9]+]]:gpr64 = COPY $x1
; CHECK: [[COPY2:%[0-9]+]]:gpr64 = COPY $xzr
; CHECK: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 1
; CHECK: [[SUBREG_TO_REG:%[0-9]+]]:gpr64 = SUBREG_TO_REG 0, [[MOVi32imm]], %subreg.sub_32
; CHECK: $xzr = ADDSXrr [[COPY]], [[COPY1]], implicit-def $nzcv
; CHECK: [[CSELXr:%[0-9]+]]:gpr64 = CSELXr [[SUBREG_TO_REG]], [[COPY2]], 1, implicit $nzcv
; CHECK: $x0 = COPY [[CSELXr]]
; CHECK: [[CSINCXr:%[0-9]+]]:gpr64 = CSINCXr [[COPY2]], $xzr, 0, implicit $nzcv
; CHECK: $x0 = COPY [[CSINCXr]]
; CHECK: RET_ReallyLR implicit $x0
%0:gpr(s64) = COPY $x0
%1:gpr(s64) = COPY $x1
@ -241,12 +233,10 @@ body: |
; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
; CHECK: [[COPY1:%[0-9]+]]:gpr64 = COPY $x1
; CHECK: [[COPY2:%[0-9]+]]:gpr64 = COPY $xzr
; CHECK: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 1
; CHECK: [[SUBREG_TO_REG:%[0-9]+]]:gpr64 = SUBREG_TO_REG 0, [[MOVi32imm]], %subreg.sub_32
; CHECK: [[SUBSXrr:%[0-9]+]]:gpr64 = SUBSXrr [[COPY2]], [[COPY1]], implicit-def $nzcv
; CHECK: [[SUBSXrr1:%[0-9]+]]:gpr64 = SUBSXrr [[COPY]], [[SUBSXrr]], implicit-def $nzcv
; CHECK: [[CSELXr:%[0-9]+]]:gpr64 = CSELXr [[SUBREG_TO_REG]], [[COPY2]], 11, implicit $nzcv
; CHECK: $x0 = COPY [[CSELXr]]
; CHECK: [[CSINCXr:%[0-9]+]]:gpr64 = CSINCXr [[COPY2]], $xzr, 10, implicit $nzcv
; CHECK: $x0 = COPY [[CSINCXr]]
; CHECK: RET_ReallyLR implicit $x0
%0:gpr(s64) = COPY $x0
%1:gpr(s64) = COPY $x1
@ -275,12 +265,10 @@ body: |
; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $x0
; CHECK: [[COPY1:%[0-9]+]]:gpr64 = COPY $x1
; CHECK: [[COPY2:%[0-9]+]]:gpr64 = COPY $xzr
; CHECK: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 1
; CHECK: [[SUBREG_TO_REG:%[0-9]+]]:gpr64 = SUBREG_TO_REG 0, [[MOVi32imm]], %subreg.sub_32
; CHECK: [[SUBSXrr:%[0-9]+]]:gpr64 = SUBSXrr [[COPY2]], [[COPY]], implicit-def $nzcv
; CHECK: [[SUBSXrr1:%[0-9]+]]:gpr64 = SUBSXrr [[SUBSXrr]], [[COPY1]], implicit-def $nzcv
; CHECK: [[CSELXr:%[0-9]+]]:gpr64 = CSELXr [[SUBREG_TO_REG]], [[COPY2]], 11, implicit $nzcv
; CHECK: $x0 = COPY [[CSELXr]]
; CHECK: [[CSINCXr:%[0-9]+]]:gpr64 = CSINCXr [[COPY2]], $xzr, 10, implicit $nzcv
; CHECK: $x0 = COPY [[CSINCXr]]
; CHECK: RET_ReallyLR implicit $x0
%0:gpr(s64) = COPY $x0
%1:gpr(s64) = COPY $x1
@ -307,10 +295,9 @@ body: |
; CHECK: liveins: $w0, $w1
; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w1
; CHECK: [[COPY1:%[0-9]+]]:gpr32 = COPY $wzr
; CHECK: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 1
; CHECK: [[ANDSWrr:%[0-9]+]]:gpr32 = ANDSWrr [[COPY1]], [[COPY]], implicit-def $nzcv
; CHECK: [[CSELWr:%[0-9]+]]:gpr32 = CSELWr [[MOVi32imm]], [[COPY1]], 0, implicit $nzcv
; CHECK: $w0 = COPY [[CSELWr]]
; CHECK: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr [[COPY1]], $wzr, 1, implicit $nzcv
; CHECK: $w0 = COPY [[CSINCWr]]
; CHECK: RET_ReallyLR implicit $w0
%0:gpr(s32) = COPY $w0
%1:gpr(s32) = COPY $w1
@ -338,11 +325,9 @@ body: |
; CHECK: liveins: $x0, $x1
; CHECK: [[COPY:%[0-9]+]]:gpr64 = COPY $x1
; CHECK: [[COPY1:%[0-9]+]]:gpr64 = COPY $xzr
; CHECK: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 1
; CHECK: [[SUBREG_TO_REG:%[0-9]+]]:gpr64 = SUBREG_TO_REG 0, [[MOVi32imm]], %subreg.sub_32
; CHECK: [[ANDSXrr:%[0-9]+]]:gpr64 = ANDSXrr [[COPY1]], [[COPY]], implicit-def $nzcv
; CHECK: [[CSELXr:%[0-9]+]]:gpr64 = CSELXr [[SUBREG_TO_REG]], [[COPY1]], 0, implicit $nzcv
; CHECK: $x0 = COPY [[CSELXr]]
; CHECK: [[CSINCXr:%[0-9]+]]:gpr64 = CSINCXr [[COPY1]], $xzr, 1, implicit $nzcv
; CHECK: $x0 = COPY [[CSINCXr]]
; CHECK: RET_ReallyLR implicit $x0
%0:gpr(s64) = COPY $x0
%1:gpr(s64) = COPY $x1
@ -370,11 +355,10 @@ body: |
; CHECK: liveins: $w0, $w1
; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w1
; CHECK: [[COPY1:%[0-9]+]]:gpr32 = COPY $wzr
; CHECK: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 1
; CHECK: [[ANDWrr:%[0-9]+]]:gpr32common = ANDWrr [[COPY1]], [[COPY]]
; CHECK: [[SUBSWri:%[0-9]+]]:gpr32 = SUBSWri [[ANDWrr]], 0, 0, implicit-def $nzcv
; CHECK: [[CSELWr:%[0-9]+]]:gpr32 = CSELWr [[MOVi32imm]], [[COPY1]], 8, implicit $nzcv
; CHECK: $w0 = COPY [[CSELWr]]
; CHECK: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr [[COPY1]], $wzr, 9, implicit $nzcv
; CHECK: $w0 = COPY [[CSINCWr]]
; CHECK: RET_ReallyLR implicit $w0
%0:gpr(s32) = COPY $w0
%1:gpr(s32) = COPY $w1
@ -402,11 +386,10 @@ body: |
; CHECK: liveins: $w0, $w1
; CHECK: [[COPY:%[0-9]+]]:gpr32 = COPY $w1
; CHECK: [[COPY1:%[0-9]+]]:gpr32 = COPY $wzr
; CHECK: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 1
; CHECK: [[ANDWrr:%[0-9]+]]:gpr32common = ANDWrr [[COPY1]], [[COPY]]
; CHECK: [[SUBSWri:%[0-9]+]]:gpr32 = SUBSWri [[ANDWrr]], 42, 0, implicit-def $nzcv
; CHECK: [[CSELWr:%[0-9]+]]:gpr32 = CSELWr [[MOVi32imm]], [[COPY1]], 8, implicit $nzcv
; CHECK: $w0 = COPY [[CSELWr]]
; CHECK: [[CSINCWr:%[0-9]+]]:gpr32 = CSINCWr [[COPY1]], $wzr, 9, implicit $nzcv
; CHECK: $w0 = COPY [[CSINCWr]]
; CHECK: RET_ReallyLR implicit $w0
%0:gpr(s32) = COPY $w0
%1:gpr(s32) = COPY $w1
@ -527,10 +510,8 @@ body: |
; CHECK: liveins: $x0, $x1
; CHECK: %copy:gpr64 = COPY $x1
; CHECK: %zero:gpr64 = COPY $xzr
; CHECK: [[MOVi32imm:%[0-9]+]]:gpr32 = MOVi32imm 1
; CHECK: %one:gpr64 = SUBREG_TO_REG 0, [[MOVi32imm]], %subreg.sub_32
; CHECK: [[ANDSXrs:%[0-9]+]]:gpr64 = ANDSXrs %zero, %copy, 16, implicit-def $nzcv
; CHECK: %select:gpr64 = CSELXr %one, %zero, 0, implicit $nzcv
; CHECK: %select:gpr64 = CSINCXr %zero, $xzr, 1, implicit $nzcv
; CHECK: $x0 = COPY %select
; CHECK: RET_ReallyLR implicit $x0
%copy:gpr(s64) = COPY $x1
@ -561,9 +542,8 @@ body: |
; CHECK: liveins: $w0, $w1
; CHECK: %copy:gpr32 = COPY $w1
; CHECK: %zero:gpr32 = COPY $wzr
; CHECK: %one:gpr32 = MOVi32imm 1
; CHECK: [[ANDSWrs:%[0-9]+]]:gpr32 = ANDSWrs %zero, %copy, 16, implicit-def $nzcv
; CHECK: %select:gpr32 = CSELWr %one, %zero, 0, implicit $nzcv
; CHECK: %select:gpr32 = CSINCWr %zero, $wzr, 1, implicit $nzcv
; CHECK: $w0 = COPY %select
; CHECK: RET_ReallyLR implicit $w0
%copy:gpr(s32) = COPY $w1

View File

@ -64,3 +64,284 @@ body: |
%4:fpr(s64) = G_SELECT %5(s1), %1, %2
$d0 = COPY %4(s64)
RET_ReallyLR implicit $d0
...
---
name: csel
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $w0, $w1, $w2, $w3
; CHECK-LABEL: name: csel
; CHECK: liveins: $w0, $w1, $w2, $w3
; CHECK: %reg0:gpr32 = COPY $w0
; CHECK: %reg1:gpr32 = COPY $w1
; CHECK: %t:gpr32 = COPY $w2
; CHECK: %f:gpr32 = COPY $w3
; CHECK: [[SUBSWrr:%[0-9]+]]:gpr32 = SUBSWrr %reg0, %reg1, implicit-def $nzcv
; CHECK: %select:gpr32 = CSELWr %t, %f, 1, implicit $nzcv
; CHECK: $w0 = COPY %select
; CHECK: RET_ReallyLR implicit $w0
%reg0:gpr(s32) = COPY $w0
%reg1:gpr(s32) = COPY $w1
%cmp:gpr(s32) = G_ICMP intpred(ne), %reg0(s32), %reg1
%cond:gpr(s1) = G_TRUNC %cmp(s32)
%t:gpr(s32) = COPY $w2
%f:gpr(s32) = COPY $w3
%select:gpr(s32) = G_SELECT %cond(s1), %t, %f
$w0 = COPY %select(s32)
RET_ReallyLR implicit $w0
...
---
name: csinc_t_0_f_1
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $w0, $w1
; G_SELECT cc, 0, 1 -> CSINC zreg, zreg, cc
; CHECK-LABEL: name: csinc_t_0_f_1
; CHECK: liveins: $w0, $w1
; CHECK: %reg0:gpr32 = COPY $w0
; CHECK: %reg1:gpr32 = COPY $w1
; CHECK: [[SUBSWrr:%[0-9]+]]:gpr32 = SUBSWrr %reg0, %reg1, implicit-def $nzcv
; CHECK: %select:gpr32 = CSINCWr $wzr, $wzr, 1, implicit $nzcv
; CHECK: $w0 = COPY %select
; CHECK: RET_ReallyLR implicit $w0
%reg0:gpr(s32) = COPY $w0
%reg1:gpr(s32) = COPY $w1
%cmp:gpr(s32) = G_ICMP intpred(ne), %reg0(s32), %reg1
%cond:gpr(s1) = G_TRUNC %cmp(s32)
%t:gpr(s32) = G_CONSTANT i32 0
%f:gpr(s32) = G_CONSTANT i32 1
%select:gpr(s32) = G_SELECT %cond(s1), %t, %f
$w0 = COPY %select(s32)
RET_ReallyLR implicit $w0
...
---
name: csinv_t_0_f_neg_1
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $w0, $w1
; G_SELECT cc 0, -1 -> CSINV zreg, zreg cc
; CHECK-LABEL: name: csinv_t_0_f_neg_1
; CHECK: liveins: $w0, $w1
; CHECK: %reg0:gpr32 = COPY $w0
; CHECK: %reg1:gpr32 = COPY $w1
; CHECK: [[SUBSWrr:%[0-9]+]]:gpr32 = SUBSWrr %reg0, %reg1, implicit-def $nzcv
; CHECK: %select:gpr32 = CSINVWr $wzr, $wzr, 1, implicit $nzcv
; CHECK: $w0 = COPY %select
; CHECK: RET_ReallyLR implicit $w0
%reg0:gpr(s32) = COPY $w0
%reg1:gpr(s32) = COPY $w1
%cmp:gpr(s32) = G_ICMP intpred(ne), %reg0(s32), %reg1
%cond:gpr(s1) = G_TRUNC %cmp(s32)
%t:gpr(s32) = G_CONSTANT i32 0
%f:gpr(s32) = G_CONSTANT i32 -1
%select:gpr(s32) = G_SELECT %cond(s1), %t, %f
$w0 = COPY %select(s32)
RET_ReallyLR implicit $w0
...
---
name: csinc_t_1
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $w0, $w1, $w2
; G_SELECT cc, 1, f -> CSINC f, zreg, inv_cc
; CHECK-LABEL: name: csinc_t_1
; CHECK: liveins: $w0, $w1, $w2
; CHECK: %reg0:gpr32 = COPY $w0
; CHECK: %reg1:gpr32 = COPY $w1
; CHECK: %f:gpr32 = COPY $w2
; CHECK: [[SUBSWrr:%[0-9]+]]:gpr32 = SUBSWrr %reg0, %reg1, implicit-def $nzcv
; CHECK: %select:gpr32 = CSINCWr %f, $wzr, 0, implicit $nzcv
; CHECK: $w0 = COPY %select
; CHECK: RET_ReallyLR implicit $w0
%reg0:gpr(s32) = COPY $w0
%reg1:gpr(s32) = COPY $w1
%cmp:gpr(s32) = G_ICMP intpred(ne), %reg0(s32), %reg1
%cond:gpr(s1) = G_TRUNC %cmp(s32)
%t:gpr(s32) = G_CONSTANT i32 1
%f:gpr(s32) = COPY $w2
%select:gpr(s32) = G_SELECT %cond(s1), %t, %f
$w0 = COPY %select(s32)
RET_ReallyLR implicit $w0
...
---
name: csinv_t_neg_1
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $w0, $w1, $w2
; G_SELECT cc, -1, f -> CSINV f, zreg, inv_cc
; CHECK-LABEL: name: csinv_t_neg_1
; CHECK: liveins: $w0, $w1, $w2
; CHECK: %reg0:gpr32 = COPY $w0
; CHECK: %reg1:gpr32 = COPY $w1
; CHECK: %f:gpr32 = COPY $w2
; CHECK: [[SUBSWrr:%[0-9]+]]:gpr32 = SUBSWrr %reg0, %reg1, implicit-def $nzcv
; CHECK: %select:gpr32 = CSINVWr %f, $wzr, 0, implicit $nzcv
; CHECK: $w0 = COPY %select
; CHECK: RET_ReallyLR implicit $w0
%reg0:gpr(s32) = COPY $w0
%reg1:gpr(s32) = COPY $w1
%cmp:gpr(s32) = G_ICMP intpred(ne), %reg0(s32), %reg1
%cond:gpr(s1) = G_TRUNC %cmp(s32)
%t:gpr(s32) = G_CONSTANT i32 -1
%f:gpr(s32) = COPY $w2
%select:gpr(s32) = G_SELECT %cond(s1), %t, %f
$w0 = COPY %select(s32)
RET_ReallyLR implicit $w0
...
---
name: csinc_f_1
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $w0, $w1, $w2
; G_SELECT cc, t, 1 -> CSINC t, zreg, cc
; CHECK-LABEL: name: csinc_f_1
; CHECK: liveins: $w0, $w1, $w2
; CHECK: %reg0:gpr32 = COPY $w0
; CHECK: %reg1:gpr32 = COPY $w1
; CHECK: %t:gpr32 = COPY $w2
; CHECK: [[SUBSWrr:%[0-9]+]]:gpr32 = SUBSWrr %reg0, %reg1, implicit-def $nzcv
; CHECK: %select:gpr32 = CSINCWr %t, $wzr, 1, implicit $nzcv
; CHECK: $w0 = COPY %select
; CHECK: RET_ReallyLR implicit $w0
%reg0:gpr(s32) = COPY $w0
%reg1:gpr(s32) = COPY $w1
%cmp:gpr(s32) = G_ICMP intpred(ne), %reg0(s32), %reg1
%cond:gpr(s1) = G_TRUNC %cmp(s32)
%t:gpr(s32) = COPY $w2
%f:gpr(s32) = G_CONSTANT i32 1
%select:gpr(s32) = G_SELECT %cond(s1), %t, %f
$w0 = COPY %select(s32)
RET_ReallyLR implicit $w0
...
---
name: csinc_f_neg_1
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $w0, $w1, $w2
; G_SELECT cc, t, -1 -> CSINC t, zreg, cc
; CHECK-LABEL: name: csinc_f_neg_1
; CHECK: liveins: $w0, $w1, $w2
; CHECK: %reg0:gpr32 = COPY $w0
; CHECK: %reg1:gpr32 = COPY $w1
; CHECK: %t:gpr32 = COPY $w2
; CHECK: [[SUBSWrr:%[0-9]+]]:gpr32 = SUBSWrr %reg0, %reg1, implicit-def $nzcv
; CHECK: %select:gpr32 = CSINVWr %t, $wzr, 1, implicit $nzcv
; CHECK: $w0 = COPY %select
; CHECK: RET_ReallyLR implicit $w0
%reg0:gpr(s32) = COPY $w0
%reg1:gpr(s32) = COPY $w1
%cmp:gpr(s32) = G_ICMP intpred(ne), %reg0(s32), %reg1
%cond:gpr(s1) = G_TRUNC %cmp(s32)
%t:gpr(s32) = COPY $w2
%f:gpr(s32) = G_CONSTANT i32 -1
%select:gpr(s32) = G_SELECT %cond(s1), %t, %f
$w0 = COPY %select(s32)
RET_ReallyLR implicit $w0
...
---
name: csinc_t_1_no_cmp
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $w0, $w1
; G_SELECT cc, 1, f -> CSINC f, zreg, inv_cc
; CHECK-LABEL: name: csinc_t_1_no_cmp
; CHECK: liveins: $w0, $w1
; CHECK: %reg0:gpr32 = COPY $w0
; CHECK: %f:gpr32 = COPY $w1
; CHECK: [[ANDSWri:%[0-9]+]]:gpr32 = ANDSWri %reg0, 0, implicit-def $nzcv
; CHECK: %select:gpr32 = CSINCWr %f, $wzr, 0, implicit $nzcv
; CHECK: $w0 = COPY %select
; CHECK: RET_ReallyLR implicit $w0
%reg0:gpr(s32) = COPY $w0
%cond:gpr(s1) = G_TRUNC %reg0(s32)
%t:gpr(s32) = G_CONSTANT i32 1
%f:gpr(s32) = COPY $w1
%select:gpr(s32) = G_SELECT %cond(s1), %t, %f
$w0 = COPY %select(s32)
RET_ReallyLR implicit $w0
...
---
name: csinc_f_1_no_cmp
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $w0, $w1
; G_SELECT cc, t, 1 -> CSINC t, zreg, cc
; CHECK-LABEL: name: csinc_f_1_no_cmp
; CHECK: liveins: $w0, $w1
; CHECK: %reg0:gpr32 = COPY $w0
; CHECK: %t:gpr32 = COPY $w1
; CHECK: [[ANDSWri:%[0-9]+]]:gpr32 = ANDSWri %reg0, 0, implicit-def $nzcv
; CHECK: %select:gpr32 = CSINCWr %t, $wzr, 1, implicit $nzcv
; CHECK: $w0 = COPY %select
; CHECK: RET_ReallyLR implicit $w0
%reg0:gpr(s32) = COPY $w0
%cond:gpr(s1) = G_TRUNC %reg0(s32)
%t:gpr(s32) = COPY $w1
%f:gpr(s32) = G_CONSTANT i32 1
%select:gpr(s32) = G_SELECT %cond(s1), %t, %f
$w0 = COPY %select(s32)
RET_ReallyLR implicit $w0
...
---
name: csinc_t_1_no_cmp_s64
legalized: true
regBankSelected: true
tracksRegLiveness: true
body: |
bb.0:
liveins: $x0, $x1
; G_SELECT cc, 1, f -> CSINC f, zreg, inv_cc
; CHECK-LABEL: name: csinc_t_1_no_cmp_s64
; CHECK: liveins: $x0, $x1
; CHECK: %reg0:gpr64 = COPY $x0
; CHECK: %cond:gpr32 = COPY %reg0.sub_32
; CHECK: %f:gpr64 = COPY $x1
; CHECK: [[ANDSWri:%[0-9]+]]:gpr32 = ANDSWri %cond, 0, implicit-def $nzcv
; CHECK: %select:gpr64 = CSINCXr %f, $xzr, 0, implicit $nzcv
; CHECK: $x0 = COPY %select
; CHECK: RET_ReallyLR implicit $x0
%reg0:gpr(s64) = COPY $x0
%cond:gpr(s1) = G_TRUNC %reg0(s64)
%t:gpr(s64) = G_CONSTANT i64 1
%f:gpr(s64) = COPY $x1
%select:gpr(s64) = G_SELECT %cond(s1), %t, %f
$x0 = COPY %select(s64)
RET_ReallyLR implicit $x0