[llvm] r318735 - [RISCV] Implement lowering of ISD::SELECT
Alex Bradbury via llvm-commits
llvm-commits at lists.llvm.org
Mon Nov 20 23:51:32 PST 2017
Author: asb
Date: Mon Nov 20 23:51:32 2017
New Revision: 318735
URL: http://llvm.org/viewvc/llvm-project?rev=318735&view=rev
Log:
[RISCV] Implement lowering of ISD::SELECT
Although ISD::SELECT_CC is a more natural match for RISCVISD::SELECT_CC (and
ultimately the integer RISC-V conditional branch instructions), we choose to
expand ISD::SELECT_CC and lower ISD::SELECT. The appropriate compare+branch
will be created in the case where an ISD::SELECT condition value is created by
an ISD::SETCC node, which operates on XLen types. Other datatypes such as
floating point don't have conditional branch instructions, and lowering
ISD::SELECT allows more flexibility for handling these cases.
Differential Revision: https://reviews.llvm.org/D29937
Added:
llvm/trunk/test/CodeGen/RISCV/bare-select.ll
llvm/trunk/test/CodeGen/RISCV/select-cc.ll
Modified:
llvm/trunk/lib/Target/RISCV/RISCVISelLowering.cpp
llvm/trunk/lib/Target/RISCV/RISCVISelLowering.h
llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td
Modified: llvm/trunk/lib/Target/RISCV/RISCVISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/RISCVISelLowering.cpp?rev=318735&r1=318734&r2=318735&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/RISCVISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/RISCV/RISCVISelLowering.cpp Mon Nov 20 23:51:32 2017
@@ -56,6 +56,9 @@ RISCVTargetLowering::RISCVTargetLowering
setOperationAction(ISD::GlobalAddress, XLenVT, Custom);
setOperationAction(ISD::BR_CC, XLenVT, Expand);
+ setOperationAction(ISD::SELECT, XLenVT, Custom);
+ setOperationAction(ISD::SELECT_CC, XLenVT, Expand);
+
setBooleanContents(ZeroOrOneBooleanContent);
// Function alignments (log2).
@@ -63,6 +66,45 @@ RISCVTargetLowering::RISCVTargetLowering
setPrefFunctionAlignment(3);
}
+// Changes the condition code and swaps operands if necessary, so the SetCC
+// operation matches one of the comparisons supported directly in the RISC-V
+// ISA.
+static void normaliseSetCC(SDValue &LHS, SDValue &RHS, ISD::CondCode &CC) {
+ switch (CC) {
+ default:
+ break;
+ case ISD::SETGT:
+ case ISD::SETLE:
+ case ISD::SETUGT:
+ case ISD::SETULE:
+ CC = ISD::getSetCCSwappedOperands(CC);
+ std::swap(LHS, RHS);
+ break;
+ }
+}
+
+// Return the RISC-V branch opcode that matches the given DAG integer
+// condition code. The CondCode must be one of those supported by the RISC-V
+// ISA (see normaliseSetCC).
+static unsigned getBranchOpcodeForIntCondCode(ISD::CondCode CC) {
+ switch (CC) {
+ default:
+ llvm_unreachable("Unsupported CondCode");
+ case ISD::SETEQ:
+ return RISCV::BEQ;
+ case ISD::SETNE:
+ return RISCV::BNE;
+ case ISD::SETLT:
+ return RISCV::BLT;
+ case ISD::SETGE:
+ return RISCV::BGE;
+ case ISD::SETULT:
+ return RISCV::BLTU;
+ case ISD::SETUGE:
+ return RISCV::BGEU;
+ }
+}
+
SDValue RISCVTargetLowering::LowerOperation(SDValue Op,
SelectionDAG &DAG) const {
switch (Op.getOpcode()) {
@@ -70,6 +112,8 @@ SDValue RISCVTargetLowering::LowerOperat
report_fatal_error("unimplemented operand");
case ISD::GlobalAddress:
return lowerGlobalAddress(Op, DAG);
+ case ISD::SELECT:
+ return lowerSELECT(Op, DAG);
}
}
@@ -95,6 +139,112 @@ SDValue RISCVTargetLowering::lowerGlobal
}
}
+SDValue RISCVTargetLowering::lowerSELECT(SDValue Op, SelectionDAG &DAG) const {
+ SDValue CondV = Op.getOperand(0);
+ SDValue TrueV = Op.getOperand(1);
+ SDValue FalseV = Op.getOperand(2);
+ SDLoc DL(Op);
+ MVT XLenVT = Subtarget.getXLenVT();
+
+ // If the result type is XLenVT and CondV is the output of a SETCC node
+ // which also operated on XLenVT inputs, then merge the SETCC node into the
+ // lowered RISCVISD::SELECT_CC to take advantage of the integer
+ // compare+branch instructions. i.e.:
+ // (select (setcc lhs, rhs, cc), truev, falsev)
+ // -> (riscvisd::select_cc lhs, rhs, cc, truev, falsev)
+ if (Op.getSimpleValueType() == XLenVT && CondV.getOpcode() == ISD::SETCC &&
+ CondV.getOperand(0).getSimpleValueType() == XLenVT) {
+ SDValue LHS = CondV.getOperand(0);
+ SDValue RHS = CondV.getOperand(1);
+ auto CC = cast<CondCodeSDNode>(CondV.getOperand(2));
+ ISD::CondCode CCVal = CC->get();
+
+ normaliseSetCC(LHS, RHS, CCVal);
+
+ SDValue TargetCC = DAG.getConstant(CCVal, DL, XLenVT);
+ SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Glue);
+ SDValue Ops[] = {LHS, RHS, TargetCC, TrueV, FalseV};
+ return DAG.getNode(RISCVISD::SELECT_CC, DL, VTs, Ops);
+ }
+
+ // Otherwise:
+ // (select condv, truev, falsev)
+ // -> (riscvisd::select_cc condv, zero, setne, truev, falsev)
+ SDValue Zero = DAG.getConstant(0, DL, XLenVT);
+ SDValue SetNE = DAG.getConstant(ISD::SETNE, DL, XLenVT);
+
+ SDVTList VTs = DAG.getVTList(Op.getValueType(), MVT::Glue);
+ SDValue Ops[] = {CondV, Zero, SetNE, TrueV, FalseV};
+
+ return DAG.getNode(RISCVISD::SELECT_CC, DL, VTs, Ops);
+}
+
+MachineBasicBlock *
+RISCVTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
+ MachineBasicBlock *BB) const {
+ const TargetInstrInfo &TII = *BB->getParent()->getSubtarget().getInstrInfo();
+ DebugLoc DL = MI.getDebugLoc();
+
+ assert(MI.getOpcode() == RISCV::Select_GPR_Using_CC_GPR &&
+ "Unexpected instr type to insert");
+
+ // To "insert" a SELECT instruction, we actually have to insert the triangle
+ // control-flow pattern. The incoming instruction knows the destination vreg
+ // to set, the condition code register to branch on, the true/false values to
+ // select between, and the condcode to use to select the appropriate branch.
+ //
+ // We produce the following control flow:
+ // HeadMBB
+ // | \
+ // | IfFalseMBB
+ // | /
+ // TailMBB
+ const BasicBlock *LLVM_BB = BB->getBasicBlock();
+ MachineFunction::iterator I = ++BB->getIterator();
+
+ MachineBasicBlock *HeadMBB = BB;
+ MachineFunction *F = BB->getParent();
+ MachineBasicBlock *TailMBB = F->CreateMachineBasicBlock(LLVM_BB);
+ MachineBasicBlock *IfFalseMBB = F->CreateMachineBasicBlock(LLVM_BB);
+
+ F->insert(I, IfFalseMBB);
+ F->insert(I, TailMBB);
+ // Move all remaining instructions to TailMBB.
+ TailMBB->splice(TailMBB->begin(), HeadMBB,
+ std::next(MachineBasicBlock::iterator(MI)), HeadMBB->end());
+ // Update machine-CFG edges by transferring all successors of the current
+ // block to the new block which will contain the Phi node for the select.
+ TailMBB->transferSuccessorsAndUpdatePHIs(HeadMBB);
+ // Set the successors for HeadMBB.
+ HeadMBB->addSuccessor(IfFalseMBB);
+ HeadMBB->addSuccessor(TailMBB);
+
+ // Insert appropriate branch.
+ unsigned LHS = MI.getOperand(1).getReg();
+ unsigned RHS = MI.getOperand(2).getReg();
+ auto CC = static_cast<ISD::CondCode>(MI.getOperand(3).getImm());
+ unsigned Opcode = getBranchOpcodeForIntCondCode(CC);
+
+ BuildMI(HeadMBB, DL, TII.get(Opcode))
+ .addReg(LHS)
+ .addReg(RHS)
+ .addMBB(TailMBB);
+
+ // IfFalseMBB just falls through to TailMBB.
+ IfFalseMBB->addSuccessor(TailMBB);
+
+ // %Result = phi [ %TrueValue, HeadMBB ], [ %FalseValue, IfFalseMBB ]
+ BuildMI(*TailMBB, TailMBB->begin(), DL, TII.get(RISCV::PHI),
+ MI.getOperand(0).getReg())
+ .addReg(MI.getOperand(4).getReg())
+ .addMBB(HeadMBB)
+ .addReg(MI.getOperand(5).getReg())
+ .addMBB(IfFalseMBB);
+
+ MI.eraseFromParent(); // The pseudo instruction is gone now.
+ return TailMBB;
+}
+
// Calling Convention Implementation.
#include "RISCVGenCallingConv.inc"
@@ -326,6 +476,8 @@ const char *RISCVTargetLowering::getTarg
return "RISCVISD::RET_FLAG";
case RISCVISD::CALL:
return "RISCVISD::CALL";
+ case RISCVISD::SELECT_CC:
+ return "RISCVISD::SELECT_CC";
}
return nullptr;
}
Modified: llvm/trunk/lib/Target/RISCV/RISCVISelLowering.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/RISCVISelLowering.h?rev=318735&r1=318734&r2=318735&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/RISCVISelLowering.h (original)
+++ llvm/trunk/lib/Target/RISCV/RISCVISelLowering.h Mon Nov 20 23:51:32 2017
@@ -25,7 +25,8 @@ namespace RISCVISD {
enum NodeType : unsigned {
FIRST_NUMBER = ISD::BUILTIN_OP_END,
RET_FLAG,
- CALL
+ CALL,
+ SELECT_CC
};
}
@@ -42,6 +43,10 @@ public:
// This method returns the name of a target specific DAG node.
const char *getTargetNodeName(unsigned Opcode) const override;
+ MachineBasicBlock *
+ EmitInstrWithCustomInserter(MachineInstr &MI,
+ MachineBasicBlock *BB) const override;
+
private:
// Lower incoming arguments, copy physregs into vregs
SDValue LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv,
@@ -60,6 +65,7 @@ private:
return true;
}
SDValue lowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
+ SDValue lowerSELECT(SDValue Op, SelectionDAG &DAG) const;
};
}
Modified: llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td?rev=318735&r1=318734&r2=318735&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td (original)
+++ llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td Mon Nov 20 23:51:32 2017
@@ -22,6 +22,9 @@ def SDT_RISCVCallSeqStart : SDCallSeqSta
SDTCisVT<1, i32>]>;
def SDT_RISCVCallSeqEnd : SDCallSeqEnd<[SDTCisVT<0, i32>,
SDTCisVT<1, i32>]>;
+def SDT_RISCVSelectCC : SDTypeProfile<1, 5, [SDTCisSameAs<1, 2>,
+ SDTCisSameAs<0, 4>,
+ SDTCisSameAs<4, 5>]>;
def Call : SDNode<"RISCVISD::CALL", SDT_RISCVCall,
@@ -33,6 +36,8 @@ def CallSeqEnd : SDNode<"ISD::CALLSEQ_
[SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>;
def RetFlag : SDNode<"RISCVISD::RET_FLAG", SDTNone,
[SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>;
+def SelectCC : SDNode<"RISCVISD::SELECT_CC", SDT_RISCVSelectCC,
+ [SDNPInGlue]>;
//===----------------------------------------------------------------------===//
// Operand and SDNode transformation definitions.
@@ -100,6 +105,9 @@ def simm21_lsb0 : Operand<OtherVT> {
let DecoderMethod = "decodeSImmOperandAndLsl1<21>";
}
+// A parameterized register class alternative to i32imm/i64imm from Target.td.
+def ixlenimm : Operand<XLenVT>;
+
// Standalone (codegen-only) immleaf patterns.
def simm32 : ImmLeaf<XLenVT, [{return isInt<32>(Imm);}]>;
@@ -320,6 +328,13 @@ def : PatGprSimm12<setlt, SLTI>;
def : PatGprGpr<setult, SLTU>;
def : PatGprSimm12<setult, SLTIU>;
+let usesCustomInserter = 1 in
+def Select_GPR_Using_CC_GPR
+ : Pseudo<(outs GPR:$dst),
+ (ins GPR:$lhs, GPR:$rhs, ixlenimm:$imm, GPR:$src, GPR:$src2),
+ [(set XLenVT:$dst, (SelectCC GPR:$lhs, GPR:$rhs,
+ (XLenVT imm:$imm), GPR:$src, GPR:$src2))]>;
+
/// Branches and jumps
// Match `(brcond (CondOp ..), ..)` and lower to the appropriate RISC-V branch
Added: llvm/trunk/test/CodeGen/RISCV/bare-select.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/RISCV/bare-select.ll?rev=318735&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/RISCV/bare-select.ll (added)
+++ llvm/trunk/test/CodeGen/RISCV/bare-select.ll Mon Nov 20 23:51:32 2017
@@ -0,0 +1,18 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
+; RUN: | FileCheck %s -check-prefix=RV32I
+
+define i32 @bare_select(i1 %a, i32 %b, i32 %c) {
+; RV32I-LABEL: bare_select:
+; RV32I: # BB#0:
+; RV32I-NEXT: andi a0, a0, 1
+; RV32I-NEXT: addi a3, zero, 0
+; RV32I-NEXT: bne a0, a3, .LBB0_2
+; RV32I-NEXT: # BB#1:
+; RV32I-NEXT: addi a1, a2, 0
+; RV32I-NEXT: .LBB0_2:
+; RV32I-NEXT: addi a0, a1, 0
+; RV32I-NEXT: jalr zero, ra, 0
+ %1 = select i1 %a, i32 %b, i32 %c
+ ret i32 %1
+}
Added: llvm/trunk/test/CodeGen/RISCV/select-cc.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/RISCV/select-cc.ll?rev=318735&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/RISCV/select-cc.ll (added)
+++ llvm/trunk/test/CodeGen/RISCV/select-cc.ll Mon Nov 20 23:51:32 2017
@@ -0,0 +1,100 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s \
+; RUN: | FileCheck -check-prefix=RV32I %s
+
+define i32 @foo(i32 %a, i32 *%b) {
+; RV32I-LABEL: foo:
+; RV32I: # BB#0:
+; RV32I-NEXT: lw a2, 0(a1)
+; RV32I-NEXT: beq a0, a2, .LBB0_2
+; RV32I-NEXT: # BB#1:
+; RV32I-NEXT: addi a0, a2, 0
+; RV32I-NEXT: .LBB0_2:
+; RV32I-NEXT: lw a2, 0(a1)
+; RV32I-NEXT: bne a0, a2, .LBB0_4
+; RV32I-NEXT: # BB#3:
+; RV32I-NEXT: addi a0, a2, 0
+; RV32I-NEXT: .LBB0_4:
+; RV32I-NEXT: lw a2, 0(a1)
+; RV32I-NEXT: bltu a2, a0, .LBB0_6
+; RV32I-NEXT: # BB#5:
+; RV32I-NEXT: addi a0, a2, 0
+; RV32I-NEXT: .LBB0_6:
+; RV32I-NEXT: lw a2, 0(a1)
+; RV32I-NEXT: bgeu a0, a2, .LBB0_8
+; RV32I-NEXT: # BB#7:
+; RV32I-NEXT: addi a0, a2, 0
+; RV32I-NEXT: .LBB0_8:
+; RV32I-NEXT: lw a2, 0(a1)
+; RV32I-NEXT: bltu a0, a2, .LBB0_10
+; RV32I-NEXT: # BB#9:
+; RV32I-NEXT: addi a0, a2, 0
+; RV32I-NEXT: .LBB0_10:
+; RV32I-NEXT: lw a2, 0(a1)
+; RV32I-NEXT: bgeu a2, a0, .LBB0_12
+; RV32I-NEXT: # BB#11:
+; RV32I-NEXT: addi a0, a2, 0
+; RV32I-NEXT: .LBB0_12:
+; RV32I-NEXT: lw a2, 0(a1)
+; RV32I-NEXT: blt a2, a0, .LBB0_14
+; RV32I-NEXT: # BB#13:
+; RV32I-NEXT: addi a0, a2, 0
+; RV32I-NEXT: .LBB0_14:
+; RV32I-NEXT: lw a2, 0(a1)
+; RV32I-NEXT: bge a0, a2, .LBB0_16
+; RV32I-NEXT: # BB#15:
+; RV32I-NEXT: addi a0, a2, 0
+; RV32I-NEXT: .LBB0_16:
+; RV32I-NEXT: lw a2, 0(a1)
+; RV32I-NEXT: blt a0, a2, .LBB0_18
+; RV32I-NEXT: # BB#17:
+; RV32I-NEXT: addi a0, a2, 0
+; RV32I-NEXT: .LBB0_18:
+; RV32I-NEXT: lw a1, 0(a1)
+; RV32I-NEXT: bge a1, a0, .LBB0_20
+; RV32I-NEXT: # BB#19:
+; RV32I-NEXT: addi a0, a1, 0
+; RV32I-NEXT: .LBB0_20:
+; RV32I-NEXT: jalr zero, ra, 0
+ %val1 = load volatile i32, i32* %b
+ %tst1 = icmp eq i32 %a, %val1
+ %val2 = select i1 %tst1, i32 %a, i32 %val1
+
+ %val3 = load volatile i32, i32* %b
+ %tst2 = icmp ne i32 %val2, %val3
+ %val4 = select i1 %tst2, i32 %val2, i32 %val3
+
+ %val5 = load volatile i32, i32* %b
+ %tst3 = icmp ugt i32 %val4, %val5
+ %val6 = select i1 %tst3, i32 %val4, i32 %val5
+
+ %val7 = load volatile i32, i32* %b
+ %tst4 = icmp uge i32 %val6, %val7
+ %val8 = select i1 %tst4, i32 %val6, i32 %val7
+
+ %val9 = load volatile i32, i32* %b
+ %tst5 = icmp ult i32 %val8, %val9
+ %val10 = select i1 %tst5, i32 %val8, i32 %val9
+
+ %val11 = load volatile i32, i32* %b
+ %tst6 = icmp ule i32 %val10, %val11
+ %val12 = select i1 %tst6, i32 %val10, i32 %val11
+
+ %val13 = load volatile i32, i32* %b
+ %tst7 = icmp sgt i32 %val12, %val13
+ %val14 = select i1 %tst7, i32 %val12, i32 %val13
+
+ %val15 = load volatile i32, i32* %b
+ %tst8 = icmp sge i32 %val14, %val15
+ %val16 = select i1 %tst8, i32 %val14, i32 %val15
+
+ %val17 = load volatile i32, i32* %b
+ %tst9 = icmp slt i32 %val16, %val17
+ %val18 = select i1 %tst9, i32 %val16, i32 %val17
+
+ %val19 = load volatile i32, i32* %b
+ %tst10 = icmp sle i32 %val18, %val19
+ %val20 = select i1 %tst10, i32 %val18, i32 %val19
+
+ ret i32 %val20
+}
More information about the llvm-commits
mailing list