[llvm] faa326d - [RISCV] Add branch+c.mv macrofusion for sifive-p450. (#76169)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Jan 8 15:23:30 PST 2024
Author: Craig Topper
Date: 2024-01-08T15:23:26-08:00
New Revision: faa326de97bf6119dcc42806b07f3523c521ae96
URL: https://github.com/llvm/llvm-project/commit/faa326de97bf6119dcc42806b07f3523c521ae96
DIFF: https://github.com/llvm/llvm-project/commit/faa326de97bf6119dcc42806b07f3523c521ae96.diff
LOG: [RISCV] Add branch+c.mv macrofusion for sifive-p450. (#76169)
sifive-p450 supports a very restricted version of the short forward
branch optimization from the sifive-7-series.
For sifive-p450, a branch over a single c.mv can be macrofused as a
conditional move operation. Due to encoding restrictions on c.mv, we
can't conditionally move from X0. That would require c.li instead.
Added:
llvm/test/CodeGen/RISCV/cmov-branch-opt.ll
Modified:
llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp
llvm/lib/Target/RISCV/RISCVFeatures.td
llvm/lib/Target/RISCV/RISCVISelLowering.cpp
llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
llvm/lib/Target/RISCV/RISCVInstrInfo.td
llvm/lib/Target/RISCV/RISCVProcessors.td
llvm/lib/Target/RISCV/RISCVSubtarget.h
Removed:
################################################################################
diff --git a/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp b/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp
index 24a13f93af880e..a39f0671a6dc28 100644
--- a/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp
+++ b/llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp
@@ -109,6 +109,7 @@ bool RISCVExpandPseudo::expandMI(MachineBasicBlock &MBB,
return expandRV32ZdinxStore(MBB, MBBI);
case RISCV::PseudoRV32ZdinxLD:
return expandRV32ZdinxLoad(MBB, MBBI);
+ case RISCV::PseudoCCMOVGPRNoX0:
case RISCV::PseudoCCMOVGPR:
case RISCV::PseudoCCADD:
case RISCV::PseudoCCSUB:
@@ -191,7 +192,8 @@ bool RISCVExpandPseudo::expandCCOp(MachineBasicBlock &MBB,
Register DestReg = MI.getOperand(0).getReg();
assert(MI.getOperand(4).getReg() == DestReg);
- if (MI.getOpcode() == RISCV::PseudoCCMOVGPR) {
+ if (MI.getOpcode() == RISCV::PseudoCCMOVGPR ||
+ MI.getOpcode() == RISCV::PseudoCCMOVGPRNoX0) {
// Add MV.
BuildMI(TrueBB, DL, TII->get(RISCV::ADDI), DestReg)
.add(MI.getOperand(5))
diff --git a/llvm/lib/Target/RISCV/RISCVFeatures.td b/llvm/lib/Target/RISCV/RISCVFeatures.td
index 59b202606dadaf..bb7a3291085d43 100644
--- a/llvm/lib/Target/RISCV/RISCVFeatures.td
+++ b/llvm/lib/Target/RISCV/RISCVFeatures.td
@@ -1021,6 +1021,12 @@ def TuneShortForwardBranchOpt
def HasShortForwardBranchOpt : Predicate<"Subtarget->hasShortForwardBranchOpt()">;
def NoShortForwardBranchOpt : Predicate<"!Subtarget->hasShortForwardBranchOpt()">;
+def TuneConditionalCompressedMoveFusion
+ : SubtargetFeature<"conditional-cmv-fusion", "HasConditionalCompressedMoveFusion",
+ "true", "Enable branch+c.mv fusion">;
+def HasConditionalMoveFusion : Predicate<"Subtarget->hasConditionalMoveFusion()">;
+def NoConditionalMoveFusion : Predicate<"!Subtarget->hasConditionalMoveFusion()">;
+
def TuneSiFive7 : SubtargetFeature<"sifive7", "RISCVProcFamily", "SiFive7",
"SiFive 7-Series processors",
[TuneNoDefaultUnroll,
diff --git a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
index 79c16cf4c4c361..135b41c7a08502 100644
--- a/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelLowering.cpp
@@ -6920,7 +6920,7 @@ static SDValue combineSelectToBinOp(SDNode *N, SelectionDAG &DAG,
MVT VT = N->getSimpleValueType(0);
SDLoc DL(N);
- if (!Subtarget.hasShortForwardBranchOpt()) {
+ if (!Subtarget.hasConditionalMoveFusion()) {
// (select c, -1, y) -> -c | y
if (isAllOnesConstant(TrueV)) {
SDValue Neg = DAG.getNegative(CondV, DL, VT);
@@ -7084,7 +7084,7 @@ SDValue RISCVTargetLowering::lowerSELECT(SDValue Op, SelectionDAG &DAG) const {
// (select c, t, f) -> (or (czero_eqz t, c), (czero_nez f, c))
// Unless we have the short forward branch optimization.
- if (!Subtarget.hasShortForwardBranchOpt())
+ if (!Subtarget.hasConditionalMoveFusion())
return DAG.getNode(
ISD::OR, DL, VT,
DAG.getNode(RISCVISD::CZERO_EQZ, DL, VT, TrueV, CondV),
@@ -12209,7 +12209,7 @@ static SDValue combineSelectAndUse(SDNode *N, SDValue Slct, SDValue OtherOp,
if (VT.isVector())
return SDValue();
- if (!Subtarget.hasShortForwardBranchOpt()) {
+ if (!Subtarget.hasConditionalMoveFusion()) {
// (select cond, x, (and x, c)) has custom lowering with Zicond.
if ((!Subtarget.hasStdExtZicond() &&
!Subtarget.hasVendorXVentanaCondOps()) ||
@@ -14440,7 +14440,7 @@ static SDValue performSELECTCombine(SDNode *N, SelectionDAG &DAG,
if (SDValue V = useInversedSetcc(N, DAG, Subtarget))
return V;
- if (Subtarget.hasShortForwardBranchOpt())
+ if (Subtarget.hasConditionalMoveFusion())
return SDValue();
SDValue TrueVal = N->getOperand(1);
@@ -15178,7 +15178,7 @@ SDValue RISCVTargetLowering::PerformDAGCombine(SDNode *N,
return DAG.getNode(RISCVISD::SELECT_CC, DL, N->getValueType(0),
{LHS, RHS, CC, TrueV, FalseV});
- if (!Subtarget.hasShortForwardBranchOpt()) {
+ if (!Subtarget.hasConditionalMoveFusion()) {
// (select c, -1, y) -> -c | y
if (isAllOnesConstant(TrueV)) {
SDValue C = DAG.getSetCC(DL, VT, LHS, RHS, CCVal);
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
index 7f6a045a7d042f..a24e8b2d18cb65 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.cpp
@@ -2650,6 +2650,7 @@ bool RISCVInstrInfo::findCommutedOpIndices(const MachineInstr &MI,
case RISCV::TH_MULSH:
// Operands 2 and 3 are commutable.
return fixCommutedOpIndices(SrcOpIdx1, SrcOpIdx2, 2, 3);
+ case RISCV::PseudoCCMOVGPRNoX0:
case RISCV::PseudoCCMOVGPR:
// Operands 4 and 5 are commutable.
return fixCommutedOpIndices(SrcOpIdx1, SrcOpIdx2, 4, 5);
@@ -2806,6 +2807,7 @@ MachineInstr *RISCVInstrInfo::commuteInstructionImpl(MachineInstr &MI,
return TargetInstrInfo::commuteInstructionImpl(WorkingMI, false, OpIdx1,
OpIdx2);
}
+ case RISCV::PseudoCCMOVGPRNoX0:
case RISCV::PseudoCCMOVGPR: {
// CCMOV can be commuted by inverting the condition.
auto CC = static_cast<RISCVCC::CondCode>(MI.getOperand(3).getImm());
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index 2f4744529469bd..e274e9f3898fb7 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -1371,6 +1371,24 @@ def PseudoCCMOVGPR : Pseudo<(outs GPR:$dst),
ReadSFBALU, ReadSFBALU]>;
}
+// This should always expand to a branch+c.mv so the size is 6 or 4 if the
+// branch is compressible.
+let Predicates = [HasConditionalMoveFusion, NoShortForwardBranchOpt],
+ Constraints = "$dst = $falsev", isCommutable = 1, Size = 6 in {
+// This instruction moves $truev to $dst when the condition is true. It will
+// be expanded to control flow in RISCVExpandPseudoInsts.
+// We use GPRNoX0 because c.mv cannot encode X0.
+def PseudoCCMOVGPRNoX0 : Pseudo<(outs GPRNoX0:$dst),
+ (ins GPR:$lhs, GPR:$rhs, ixlenimm:$cc,
+ GPRNoX0:$falsev, GPRNoX0:$truev),
+ [(set GPRNoX0:$dst,
+ (riscv_selectcc_frag:$cc (XLenVT GPR:$lhs),
+ (XLenVT GPR:$rhs),
+ cond, (XLenVT GPRNoX0:$truev),
+ (XLenVT GPRNoX0:$falsev)))]>,
+ Sched<[]>;
+}
+
// Conditional binops, that updates update $dst to (op rs1, rs2) when condition
// is true. Returns $falsev otherwise. Selected by optimizeSelect.
// TODO: Can we use DefaultOperands on the regular binop to accomplish this more
@@ -1519,7 +1537,7 @@ multiclass SelectCC_GPR_rrirr<DAGOperand valty, ValueType vt> {
(IntCCtoRISCVCC $cc), valty:$truev, valty:$falsev)>;
}
-let Predicates = [NoShortForwardBranchOpt] in
+let Predicates = [NoConditionalMoveFusion] in
defm Select_GPR : SelectCC_GPR_rrirr<GPR, XLenVT>;
class SelectCompressOpt<CondCode Cond>
diff --git a/llvm/lib/Target/RISCV/RISCVProcessors.td b/llvm/lib/Target/RISCV/RISCVProcessors.td
index ba8996e710edc0..52800f086129a0 100644
--- a/llvm/lib/Target/RISCV/RISCVProcessors.td
+++ b/llvm/lib/Target/RISCV/RISCVProcessors.td
@@ -232,7 +232,8 @@ def SIFIVE_P450 : RISCVProcessorModel<"sifive-p450", NoSchedModel,
FeatureStdExtZba,
FeatureStdExtZbb,
FeatureStdExtZbs,
- FeatureStdExtZfhmin]>;
+ FeatureStdExtZfhmin],
+ [TuneConditionalCompressedMoveFusion]>;
def SYNTACORE_SCR1_BASE : RISCVProcessorModel<"syntacore-scr1-base",
SyntacoreSCR1Model,
diff --git a/llvm/lib/Target/RISCV/RISCVSubtarget.h b/llvm/lib/Target/RISCV/RISCVSubtarget.h
index 26320b05d9be29..2ba93764facd07 100644
--- a/llvm/lib/Target/RISCV/RISCVSubtarget.h
+++ b/llvm/lib/Target/RISCV/RISCVSubtarget.h
@@ -150,6 +150,13 @@ class RISCVSubtarget : public RISCVGenSubtargetInfo {
bool hasHalfFPLoadStoreMove() const {
return HasStdExtZfhmin || HasStdExtZfbfmin;
}
+
+ bool hasConditionalMoveFusion() const {
+ // Do we support fusing a branch+mv or branch+c.mv as a conditional move.
+ return (hasConditionalCompressedMoveFusion() && hasStdExtCOrZca()) ||
+ hasShortForwardBranchOpt();
+ }
+
bool is64Bit() const { return IsRV64; }
MVT getXLenVT() const {
return is64Bit() ? MVT::i64 : MVT::i32;
diff --git a/llvm/test/CodeGen/RISCV/cmov-branch-opt.ll b/llvm/test/CodeGen/RISCV/cmov-branch-opt.ll
new file mode 100644
index 00000000000000..6ad529ea477c1a
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/cmov-branch-opt.ll
@@ -0,0 +1,461 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv64 -mattr=+c -verify-machineinstrs < %s \
+; RUN: | FileCheck -check-prefix=NOCMOV %s
+; RUN: llc -mtriple=riscv64 -mattr=+conditional-cmv-fusion,+c -verify-machineinstrs < %s \
+; RUN: | FileCheck -check-prefixes=CMOV,CMOV-NOZICOND %s
+; RUN: llc -mtriple=riscv64 -mattr=+conditional-cmv-fusion,+c,+experimental-zicond -verify-machineinstrs < %s \
+; RUN: | FileCheck -check-prefixes=CMOV,CMOV-ZICOND %s
+; RUN: llc -mtriple=riscv64 -mattr=+short-forward-branch-opt -verify-machineinstrs < %s \
+; RUN: | FileCheck -check-prefixes=SHORT_FORWARD,SFB-NOZICOND %s
+; RUN: llc -mtriple=riscv64 -mattr=+short-forward-branch-opt,+c -verify-machineinstrs < %s \
+; RUN: | FileCheck -check-prefixes=SHORT_FORWARD,SFB-NOZICOND %s
+; RUN: llc -mtriple=riscv64 -mattr=+short-forward-branch-opt,+experimental-zicond -verify-machineinstrs < %s \
+; RUN: | FileCheck -check-prefixes=SHORT_FORWARD,SFB-ZICOND %s
+
+; The conditional move optimization in sifive-p450 requires that only a
+; single c.mv instruction appears in the branch shadow.
+
+; The sifive-7-series can predicate an xor.
+
+define signext i32 @test1(i32 signext %x, i32 signext %y, i32 signext %z) {
+; NOCMOV-LABEL: test1:
+; NOCMOV: # %bb.0:
+; NOCMOV-NEXT: snez a2, a2
+; NOCMOV-NEXT: addi a2, a2, -1
+; NOCMOV-NEXT: and a1, a1, a2
+; NOCMOV-NEXT: xor a0, a0, a1
+; NOCMOV-NEXT: ret
+;
+; CMOV-LABEL: test1:
+; CMOV: # %bb.0:
+; CMOV-NEXT: xor a1, a1, a0
+; CMOV-NEXT: bnez a2, .LBB0_2
+; CMOV-NEXT: # %bb.1:
+; CMOV-NEXT: mv a0, a1
+; CMOV-NEXT: .LBB0_2:
+; CMOV-NEXT: ret
+;
+; SHORT_FORWARD-LABEL: test1:
+; SHORT_FORWARD: # %bb.0:
+; SHORT_FORWARD-NEXT: bnez a2, .LBB0_2
+; SHORT_FORWARD-NEXT: # %bb.1:
+; SHORT_FORWARD-NEXT: xor a0, a0, a1
+; SHORT_FORWARD-NEXT: .LBB0_2:
+; SHORT_FORWARD-NEXT: ret
+ %c = icmp eq i32 %z, 0
+ %a = xor i32 %x, %y
+ %b = select i1 %c, i32 %a, i32 %x
+ ret i32 %b
+}
+
+define signext i32 @test2(i32 signext %x, i32 signext %y, i32 signext %z) {
+; NOCMOV-LABEL: test2:
+; NOCMOV: # %bb.0:
+; NOCMOV-NEXT: seqz a2, a2
+; NOCMOV-NEXT: addi a2, a2, -1
+; NOCMOV-NEXT: and a1, a1, a2
+; NOCMOV-NEXT: xor a0, a0, a1
+; NOCMOV-NEXT: ret
+;
+; CMOV-LABEL: test2:
+; CMOV: # %bb.0:
+; CMOV-NEXT: xor a1, a1, a0
+; CMOV-NEXT: beqz a2, .LBB1_2
+; CMOV-NEXT: # %bb.1:
+; CMOV-NEXT: mv a0, a1
+; CMOV-NEXT: .LBB1_2:
+; CMOV-NEXT: ret
+;
+; SHORT_FORWARD-LABEL: test2:
+; SHORT_FORWARD: # %bb.0:
+; SHORT_FORWARD-NEXT: beqz a2, .LBB1_2
+; SHORT_FORWARD-NEXT: # %bb.1:
+; SHORT_FORWARD-NEXT: xor a0, a0, a1
+; SHORT_FORWARD-NEXT: .LBB1_2:
+; SHORT_FORWARD-NEXT: ret
+ %c = icmp eq i32 %z, 0
+ %a = xor i32 %x, %y
+ %b = select i1 %c, i32 %x, i32 %a
+ ret i32 %b
+}
+
+; Make sure we don't share the same basic block for two selects with the same
+; condition.
+define signext i32 @test3(i32 signext %v, i32 signext %w, i32 signext %x, i32 signext %y, i32 signext %z) {
+; NOCMOV-LABEL: test3:
+; NOCMOV: # %bb.0:
+; NOCMOV-NEXT: seqz a4, a4
+; NOCMOV-NEXT: addi a4, a4, -1
+; NOCMOV-NEXT: and a1, a1, a4
+; NOCMOV-NEXT: xor a0, a0, a1
+; NOCMOV-NEXT: and a3, a3, a4
+; NOCMOV-NEXT: xor a2, a2, a3
+; NOCMOV-NEXT: addw a0, a0, a2
+; NOCMOV-NEXT: ret
+;
+; CMOV-LABEL: test3:
+; CMOV: # %bb.0:
+; CMOV-NEXT: xor a1, a1, a0
+; CMOV-NEXT: bnez a4, .LBB2_2
+; CMOV-NEXT: # %bb.1:
+; CMOV-NEXT: mv a1, a0
+; CMOV-NEXT: .LBB2_2:
+; CMOV-NEXT: xor a0, a2, a3
+; CMOV-NEXT: bnez a4, .LBB2_4
+; CMOV-NEXT: # %bb.3:
+; CMOV-NEXT: mv a0, a2
+; CMOV-NEXT: .LBB2_4:
+; CMOV-NEXT: addw a0, a0, a1
+; CMOV-NEXT: ret
+;
+; SHORT_FORWARD-LABEL: test3:
+; SHORT_FORWARD: # %bb.0:
+; SHORT_FORWARD-NEXT: beqz a4, .LBB2_2
+; SHORT_FORWARD-NEXT: # %bb.1:
+; SHORT_FORWARD-NEXT: xor a0, a0, a1
+; SHORT_FORWARD-NEXT: .LBB2_2:
+; SHORT_FORWARD-NEXT: beqz a4, .LBB2_4
+; SHORT_FORWARD-NEXT: # %bb.3:
+; SHORT_FORWARD-NEXT: xor a2, a2, a3
+; SHORT_FORWARD-NEXT: .LBB2_4:
+; SHORT_FORWARD-NEXT: addw a0, a0, a2
+; SHORT_FORWARD-NEXT: ret
+ %c = icmp eq i32 %z, 0
+ %a = xor i32 %v, %w
+ %b = select i1 %c, i32 %v, i32 %a
+ %d = xor i32 %x, %y
+ %e = select i1 %c, i32 %x, i32 %d
+ %f = add i32 %b, %e
+ ret i32 %f
+}
+
+define signext i32 @test4(i32 signext %x, i32 signext %y, i32 signext %z) {
+; NOCMOV-LABEL: test4:
+; NOCMOV: # %bb.0:
+; NOCMOV-NEXT: snez a0, a2
+; NOCMOV-NEXT: addi a0, a0, -1
+; NOCMOV-NEXT: andi a0, a0, 3
+; NOCMOV-NEXT: ret
+;
+; CMOV-NOZICOND-LABEL: test4:
+; CMOV-NOZICOND: # %bb.0:
+; CMOV-NOZICOND-NEXT: li a1, 0
+; CMOV-NOZICOND-NEXT: li a0, 3
+; CMOV-NOZICOND-NEXT: beqz a2, .LBB3_2
+; CMOV-NOZICOND-NEXT: # %bb.1:
+; CMOV-NOZICOND-NEXT: mv a0, a1
+; CMOV-NOZICOND-NEXT: .LBB3_2:
+; CMOV-NOZICOND-NEXT: ret
+;
+; CMOV-ZICOND-LABEL: test4:
+; CMOV-ZICOND: # %bb.0:
+; CMOV-ZICOND-NEXT: li a0, 3
+; CMOV-ZICOND-NEXT: czero.nez a0, a0, a2
+; CMOV-ZICOND-NEXT: ret
+;
+; SFB-NOZICOND-LABEL: test4:
+; SFB-NOZICOND: # %bb.0:
+; SFB-NOZICOND-NEXT: li a0, 3
+; SFB-NOZICOND-NEXT: beqz a2, .LBB3_2
+; SFB-NOZICOND-NEXT: # %bb.1:
+; SFB-NOZICOND-NEXT: li a0, 0
+; SFB-NOZICOND-NEXT: .LBB3_2:
+; SFB-NOZICOND-NEXT: ret
+;
+; SFB-ZICOND-LABEL: test4:
+; SFB-ZICOND: # %bb.0:
+; SFB-ZICOND-NEXT: li a0, 3
+; SFB-ZICOND-NEXT: czero.nez a0, a0, a2
+; SFB-ZICOND-NEXT: ret
+ %c = icmp eq i32 %z, 0
+ %a = select i1 %c, i32 3, i32 0
+ ret i32 %a
+}
+
+define i16 @select_xor_1(i16 %A, i8 %cond) {
+; NOCMOV-LABEL: select_xor_1:
+; NOCMOV: # %bb.0: # %entry
+; NOCMOV-NEXT: slli a1, a1, 63
+; NOCMOV-NEXT: srai a1, a1, 63
+; NOCMOV-NEXT: andi a1, a1, 43
+; NOCMOV-NEXT: xor a0, a0, a1
+; NOCMOV-NEXT: ret
+;
+; CMOV-LABEL: select_xor_1:
+; CMOV: # %bb.0: # %entry
+; CMOV-NEXT: andi a1, a1, 1
+; CMOV-NEXT: xori a2, a0, 43
+; CMOV-NEXT: beqz a1, .LBB4_2
+; CMOV-NEXT: # %bb.1: # %entry
+; CMOV-NEXT: mv a0, a2
+; CMOV-NEXT: .LBB4_2: # %entry
+; CMOV-NEXT: ret
+;
+; SHORT_FORWARD-LABEL: select_xor_1:
+; SHORT_FORWARD: # %bb.0: # %entry
+; SHORT_FORWARD-NEXT: andi a1, a1, 1
+; SHORT_FORWARD-NEXT: beqz a1, .LBB4_2
+; SHORT_FORWARD-NEXT: # %bb.1: # %entry
+; SHORT_FORWARD-NEXT: xori a0, a0, 43
+; SHORT_FORWARD-NEXT: .LBB4_2: # %entry
+; SHORT_FORWARD-NEXT: ret
+entry:
+ %and = and i8 %cond, 1
+ %cmp10 = icmp eq i8 %and, 0
+ %0 = xor i16 %A, 43
+ %1 = select i1 %cmp10, i16 %A, i16 %0
+ ret i16 %1
+}
+
+; Equivalent to above, but with icmp ne (and %cond, 1), 1 instead of
+; icmp eq (and %cond, 1), 0
+define i16 @select_xor_1b(i16 %A, i8 %cond) {
+; NOCMOV-LABEL: select_xor_1b:
+; NOCMOV: # %bb.0: # %entry
+; NOCMOV-NEXT: slli a1, a1, 63
+; NOCMOV-NEXT: srai a1, a1, 63
+; NOCMOV-NEXT: andi a1, a1, 43
+; NOCMOV-NEXT: xor a0, a0, a1
+; NOCMOV-NEXT: ret
+;
+; CMOV-LABEL: select_xor_1b:
+; CMOV: # %bb.0: # %entry
+; CMOV-NEXT: andi a1, a1, 1
+; CMOV-NEXT: xori a2, a0, 43
+; CMOV-NEXT: beqz a1, .LBB5_2
+; CMOV-NEXT: # %bb.1: # %entry
+; CMOV-NEXT: mv a0, a2
+; CMOV-NEXT: .LBB5_2: # %entry
+; CMOV-NEXT: ret
+;
+; SHORT_FORWARD-LABEL: select_xor_1b:
+; SHORT_FORWARD: # %bb.0: # %entry
+; SHORT_FORWARD-NEXT: andi a1, a1, 1
+; SHORT_FORWARD-NEXT: beqz a1, .LBB5_2
+; SHORT_FORWARD-NEXT: # %bb.1: # %entry
+; SHORT_FORWARD-NEXT: xori a0, a0, 43
+; SHORT_FORWARD-NEXT: .LBB5_2: # %entry
+; SHORT_FORWARD-NEXT: ret
+entry:
+ %and = and i8 %cond, 1
+ %cmp10 = icmp ne i8 %and, 1
+ %0 = xor i16 %A, 43
+ %1 = select i1 %cmp10, i16 %A, i16 %0
+ ret i16 %1
+}
+
+define i32 @select_xor_2(i32 %A, i32 %B, i8 %cond) {
+; NOCMOV-LABEL: select_xor_2:
+; NOCMOV: # %bb.0: # %entry
+; NOCMOV-NEXT: slli a2, a2, 63
+; NOCMOV-NEXT: srai a2, a2, 63
+; NOCMOV-NEXT: and a1, a1, a2
+; NOCMOV-NEXT: xor a0, a0, a1
+; NOCMOV-NEXT: ret
+;
+; CMOV-LABEL: select_xor_2:
+; CMOV: # %bb.0: # %entry
+; CMOV-NEXT: andi a2, a2, 1
+; CMOV-NEXT: xor a1, a1, a0
+; CMOV-NEXT: beqz a2, .LBB6_2
+; CMOV-NEXT: # %bb.1: # %entry
+; CMOV-NEXT: mv a0, a1
+; CMOV-NEXT: .LBB6_2: # %entry
+; CMOV-NEXT: ret
+;
+; SFB-ZICOND-LABEL: select_xor_2:
+; SFB-ZICOND: # %bb.0: # %entry
+; SFB-ZICOND-NEXT: andi a2, a2, 1
+; SFB-ZICOND-NEXT: beqz a2, .LBB6_2
+; SFB-ZICOND-NEXT: # %bb.1: # %entry
+; SFB-ZICOND-NEXT: xor a0, a1, a0
+; SFB-ZICOND-NEXT: .LBB6_2: # %entry
+; SFB-ZICOND-NEXT: ret
+entry:
+ %and = and i8 %cond, 1
+ %cmp10 = icmp eq i8 %and, 0
+ %0 = xor i32 %B, %A
+ %1 = select i1 %cmp10, i32 %A, i32 %0
+ ret i32 %1
+}
+
+; Equivalent to above, but with icmp ne (and %cond, 1), 1 instead of
+; icmp eq (and %cond, 1), 0
+define i32 @select_xor_2b(i32 %A, i32 %B, i8 %cond) {
+; NOCMOV-LABEL: select_xor_2b:
+; NOCMOV: # %bb.0: # %entry
+; NOCMOV-NEXT: slli a2, a2, 63
+; NOCMOV-NEXT: srai a2, a2, 63
+; NOCMOV-NEXT: and a1, a1, a2
+; NOCMOV-NEXT: xor a0, a0, a1
+; NOCMOV-NEXT: ret
+;
+; CMOV-LABEL: select_xor_2b:
+; CMOV: # %bb.0: # %entry
+; CMOV-NEXT: andi a2, a2, 1
+; CMOV-NEXT: xor a1, a1, a0
+; CMOV-NEXT: beqz a2, .LBB7_2
+; CMOV-NEXT: # %bb.1: # %entry
+; CMOV-NEXT: mv a0, a1
+; CMOV-NEXT: .LBB7_2: # %entry
+; CMOV-NEXT: ret
+;
+; SFB-ZICOND-LABEL: select_xor_2b:
+; SFB-ZICOND: # %bb.0: # %entry
+; SFB-ZICOND-NEXT: andi a2, a2, 1
+; SFB-ZICOND-NEXT: beqz a2, .LBB7_2
+; SFB-ZICOND-NEXT: # %bb.1: # %entry
+; SFB-ZICOND-NEXT: xor a0, a1, a0
+; SFB-ZICOND-NEXT: .LBB7_2: # %entry
+; SFB-ZICOND-NEXT: ret
+entry:
+ %and = and i8 %cond, 1
+ %cmp10 = icmp ne i8 %and, 1
+ %0 = xor i32 %B, %A
+ %1 = select i1 %cmp10, i32 %A, i32 %0
+ ret i32 %1
+}
+
+define i32 @select_or(i32 %A, i32 %B, i8 %cond) {
+; NOCMOV-LABEL: select_or:
+; NOCMOV: # %bb.0: # %entry
+; NOCMOV-NEXT: slli a2, a2, 63
+; NOCMOV-NEXT: srai a2, a2, 63
+; NOCMOV-NEXT: and a1, a1, a2
+; NOCMOV-NEXT: or a0, a0, a1
+; NOCMOV-NEXT: ret
+;
+; CMOV-LABEL: select_or:
+; CMOV: # %bb.0: # %entry
+; CMOV-NEXT: andi a2, a2, 1
+; CMOV-NEXT: or a1, a1, a0
+; CMOV-NEXT: beqz a2, .LBB8_2
+; CMOV-NEXT: # %bb.1: # %entry
+; CMOV-NEXT: mv a0, a1
+; CMOV-NEXT: .LBB8_2: # %entry
+; CMOV-NEXT: ret
+;
+; SFB-ZICOND-LABEL: select_or:
+; SFB-ZICOND: # %bb.0: # %entry
+; SFB-ZICOND-NEXT: andi a2, a2, 1
+; SFB-ZICOND-NEXT: beqz a2, .LBB8_2
+; SFB-ZICOND-NEXT: # %bb.1: # %entry
+; SFB-ZICOND-NEXT: or a0, a1, a0
+; SFB-ZICOND-NEXT: .LBB8_2: # %entry
+; SFB-ZICOND-NEXT: ret
+entry:
+ %and = and i8 %cond, 1
+ %cmp10 = icmp eq i8 %and, 0
+ %0 = or i32 %B, %A
+ %1 = select i1 %cmp10, i32 %A, i32 %0
+ ret i32 %1
+}
+
+; Equivalent to above, but with icmp ne (and %cond, 1), 1 instead of
+; icmp eq (and %cond, 1), 0
+define i32 @select_or_b(i32 %A, i32 %B, i8 %cond) {
+; NOCMOV-LABEL: select_or_b:
+; NOCMOV: # %bb.0: # %entry
+; NOCMOV-NEXT: slli a2, a2, 63
+; NOCMOV-NEXT: srai a2, a2, 63
+; NOCMOV-NEXT: and a1, a1, a2
+; NOCMOV-NEXT: or a0, a0, a1
+; NOCMOV-NEXT: ret
+;
+; CMOV-LABEL: select_or_b:
+; CMOV: # %bb.0: # %entry
+; CMOV-NEXT: andi a2, a2, 1
+; CMOV-NEXT: or a1, a1, a0
+; CMOV-NEXT: beqz a2, .LBB9_2
+; CMOV-NEXT: # %bb.1: # %entry
+; CMOV-NEXT: mv a0, a1
+; CMOV-NEXT: .LBB9_2: # %entry
+; CMOV-NEXT: ret
+;
+; SFB-ZICOND-LABEL: select_or_b:
+; SFB-ZICOND: # %bb.0: # %entry
+; SFB-ZICOND-NEXT: andi a2, a2, 1
+; SFB-ZICOND-NEXT: beqz a2, .LBB9_2
+; SFB-ZICOND-NEXT: # %bb.1: # %entry
+; SFB-ZICOND-NEXT: or a0, a1, a0
+; SFB-ZICOND-NEXT: .LBB9_2: # %entry
+; SFB-ZICOND-NEXT: ret
+entry:
+ %and = and i8 %cond, 1
+ %cmp10 = icmp ne i8 %and, 1
+ %0 = or i32 %B, %A
+ %1 = select i1 %cmp10, i32 %A, i32 %0
+ ret i32 %1
+}
+
+define i32 @select_or_1(i32 %A, i32 %B, i32 %cond) {
+; NOCMOV-LABEL: select_or_1:
+; NOCMOV: # %bb.0: # %entry
+; NOCMOV-NEXT: slli a2, a2, 63
+; NOCMOV-NEXT: srai a2, a2, 63
+; NOCMOV-NEXT: and a1, a1, a2
+; NOCMOV-NEXT: or a0, a0, a1
+; NOCMOV-NEXT: ret
+;
+; CMOV-LABEL: select_or_1:
+; CMOV: # %bb.0: # %entry
+; CMOV-NEXT: andi a2, a2, 1
+; CMOV-NEXT: or a1, a1, a0
+; CMOV-NEXT: beqz a2, .LBB10_2
+; CMOV-NEXT: # %bb.1: # %entry
+; CMOV-NEXT: mv a0, a1
+; CMOV-NEXT: .LBB10_2: # %entry
+; CMOV-NEXT: ret
+;
+; SFB-ZICOND-LABEL: select_or_1:
+; SFB-ZICOND: # %bb.0: # %entry
+; SFB-ZICOND-NEXT: andi a2, a2, 1
+; SFB-ZICOND-NEXT: beqz a2, .LBB10_2
+; SFB-ZICOND-NEXT: # %bb.1: # %entry
+; SFB-ZICOND-NEXT: or a0, a1, a0
+; SFB-ZICOND-NEXT: .LBB10_2: # %entry
+; SFB-ZICOND-NEXT: ret
+entry:
+ %and = and i32 %cond, 1
+ %cmp10 = icmp eq i32 %and, 0
+ %0 = or i32 %B, %A
+ %1 = select i1 %cmp10, i32 %A, i32 %0
+ ret i32 %1
+}
+
+; Equivalent to above, but with icmp ne (and %cond, 1), 1 instead of
+; icmp eq (and %cond, 1), 0
+define i32 @select_or_1b(i32 %A, i32 %B, i32 %cond) {
+; NOCMOV-LABEL: select_or_1b:
+; NOCMOV: # %bb.0: # %entry
+; NOCMOV-NEXT: slli a2, a2, 63
+; NOCMOV-NEXT: srai a2, a2, 63
+; NOCMOV-NEXT: and a1, a1, a2
+; NOCMOV-NEXT: or a0, a0, a1
+; NOCMOV-NEXT: ret
+;
+; CMOV-LABEL: select_or_1b:
+; CMOV: # %bb.0: # %entry
+; CMOV-NEXT: andi a2, a2, 1
+; CMOV-NEXT: or a1, a1, a0
+; CMOV-NEXT: beqz a2, .LBB11_2
+; CMOV-NEXT: # %bb.1: # %entry
+; CMOV-NEXT: mv a0, a1
+; CMOV-NEXT: .LBB11_2: # %entry
+; CMOV-NEXT: ret
+;
+; SFB-ZICOND-LABEL: select_or_1b:
+; SFB-ZICOND: # %bb.0: # %entry
+; SFB-ZICOND-NEXT: andi a2, a2, 1
+; SFB-ZICOND-NEXT: beqz a2, .LBB11_2
+; SFB-ZICOND-NEXT: # %bb.1: # %entry
+; SFB-ZICOND-NEXT: or a0, a1, a0
+; SFB-ZICOND-NEXT: .LBB11_2: # %entry
+; SFB-ZICOND-NEXT: ret
+entry:
+ %and = and i32 %cond, 1
+ %cmp10 = icmp ne i32 %and, 1
+ %0 = or i32 %B, %A
+ %1 = select i1 %cmp10, i32 %A, i32 %0
+ ret i32 %1
+}
More information about the llvm-commits
mailing list