[llvm] r317690 - [RISCV] Codegen for conditional branches

Alex Bradbury via llvm-commits llvm-commits at lists.llvm.org
Wed Nov 8 05:31:41 PST 2017


Author: asb
Date: Wed Nov  8 05:31:40 2017
New Revision: 317690

URL: http://llvm.org/viewvc/llvm-project?rev=317690&view=rev
Log:
[RISCV] Codegen for conditional branches

A good portion of this patch is the extra functions that needed to be 
implemented to support the test case. e.g. storeRegToStackSlot, 
loadRegFromStackSlot, eliminateFrameIndex.

Setting ISD::BR_CC to Expand may appear non-obvious on an architecture with 
branch+cmp instructions. However, I found it much easier to deal with matching 
the expanded form.

I had to change simm13_lsb0 and simm21_lsb0 to inherit from the 
Operand<OtherVT> class rather than Operand<i32> in order to keep tablegen 
happy. This isn't a big deal, but it does seem a shame to lose the uniformity 
across immediate types when there's not an obvious benefit (I'm hoping a 
tablegen expert will educate me on what I'm missing here!).

Differential Revision: https://reviews.llvm.org/D29935

Added:
    llvm/trunk/test/CodeGen/RISCV/branch.ll
Modified:
    llvm/trunk/lib/Target/RISCV/RISCVCallingConv.td
    llvm/trunk/lib/Target/RISCV/RISCVISelLowering.cpp
    llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.cpp
    llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.h
    llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td
    llvm/trunk/lib/Target/RISCV/RISCVMCInstLower.cpp
    llvm/trunk/lib/Target/RISCV/RISCVRegisterInfo.cpp
    llvm/trunk/lib/Target/RISCV/RISCVRegisterInfo.h

Modified: llvm/trunk/lib/Target/RISCV/RISCVCallingConv.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/RISCVCallingConv.td?rev=317690&r1=317689&r2=317690&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/RISCVCallingConv.td (original)
+++ llvm/trunk/lib/Target/RISCV/RISCVCallingConv.td Wed Nov  8 05:31:40 2017
@@ -27,3 +27,6 @@ def CC_RISCV32 : CallingConv<[
 ]>;
 
 def CSR : CalleeSavedRegs<(add X1, X3, X4, X8, X9, (sequence "X%u", 18, 27))>;
+
+// Needed for implementation of RISCVRegisterInfo::getNoPreservedMask()
+def CSR_NoRegs : CalleeSavedRegs<(add)>;

Modified: llvm/trunk/lib/Target/RISCV/RISCVISelLowering.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/RISCVISelLowering.cpp?rev=317690&r1=317689&r2=317690&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/RISCVISelLowering.cpp (original)
+++ llvm/trunk/lib/Target/RISCV/RISCVISelLowering.cpp Wed Nov  8 05:31:40 2017
@@ -55,6 +55,7 @@ RISCVTargetLowering::RISCVTargetLowering
   // TODO: add all necessary setOperationAction calls.
   setOperationAction(ISD::GlobalAddress, XLenVT, Custom);
 
+  setOperationAction(ISD::BR_CC, XLenVT, Expand);
   setBooleanContents(ZeroOrOneBooleanContent);
 
   // Function alignments (log2).

Modified: llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.cpp?rev=317690&r1=317689&r2=317690&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.cpp (original)
+++ llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.cpp Wed Nov  8 05:31:40 2017
@@ -41,3 +41,36 @@ void RISCVInstrInfo::copyPhysReg(Machine
       .addReg(SrcReg, getKillRegState(KillSrc))
       .addImm(0);
 }
+
+void RISCVInstrInfo::storeRegToStackSlot(MachineBasicBlock &MBB,
+                                         MachineBasicBlock::iterator I,
+                                         unsigned SrcReg, bool IsKill, int FI,
+                                         const TargetRegisterClass *RC,
+                                         const TargetRegisterInfo *TRI) const {
+  DebugLoc DL;
+  if (I != MBB.end())
+    DL = I->getDebugLoc();
+
+  if (RC == &RISCV::GPRRegClass)
+    BuildMI(MBB, I, DL, get(RISCV::SW))
+        .addReg(SrcReg, getKillRegState(IsKill))
+        .addFrameIndex(FI)
+        .addImm(0);
+  else
+    llvm_unreachable("Can't store this register to stack slot");
+}
+
+void RISCVInstrInfo::loadRegFromStackSlot(MachineBasicBlock &MBB,
+                                          MachineBasicBlock::iterator I,
+                                          unsigned DstReg, int FI,
+                                          const TargetRegisterClass *RC,
+                                          const TargetRegisterInfo *TRI) const {
+  DebugLoc DL;
+  if (I != MBB.end())
+    DL = I->getDebugLoc();
+
+  if (RC == &RISCV::GPRRegClass)
+    BuildMI(MBB, I, DL, get(RISCV::LW), DstReg).addFrameIndex(FI).addImm(0);
+  else
+    llvm_unreachable("Can't load this register from stack slot");
+}

Modified: llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.h?rev=317690&r1=317689&r2=317690&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.h (original)
+++ llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.h Wed Nov  8 05:31:40 2017
@@ -30,7 +30,17 @@ public:
   void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
                    const DebugLoc &DL, unsigned DstReg, unsigned SrcReg,
                    bool KillSrc) const override;
+
+  void storeRegToStackSlot(MachineBasicBlock &MBB,
+                           MachineBasicBlock::iterator MBBI, unsigned SrcReg,
+                           bool IsKill, int FrameIndex,
+                           const TargetRegisterClass *RC,
+                           const TargetRegisterInfo *TRI) const override;
+
+  void loadRegFromStackSlot(MachineBasicBlock &MBB,
+                            MachineBasicBlock::iterator MBBI, unsigned DstReg,
+                            int FrameIndex, const TargetRegisterClass *RC,
+                            const TargetRegisterInfo *TRI) const override;
 };
 }
-
 #endif

Modified: llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td?rev=317690&r1=317689&r2=317690&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td (original)
+++ llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td Wed Nov  8 05:31:40 2017
@@ -67,7 +67,7 @@ def uimm12 : Operand<XLenVT> {
 }
 
 // A 13-bit signed immediate where the least significant bit is zero.
-def simm13_lsb0 : Operand<XLenVT> {
+def simm13_lsb0 : Operand<OtherVT> {
   let ParserMatchClass = SImmAsmOperand<13, "Lsb0">;
   let EncoderMethod = "getImmOpValueAsr1";
   let DecoderMethod = "decodeSImmOperandAndLsl1<13>";
@@ -80,7 +80,7 @@ def uimm20 : Operand<XLenVT> {
 }
 
 // A 21-bit signed immediate where the least significant bit is zero.
-def simm21_lsb0 : Operand<XLenVT> {
+def simm21_lsb0 : Operand<OtherVT> {
   let ParserMatchClass = SImmAsmOperand<21, "Lsb0">;
   let EncoderMethod = "getImmOpValueAsr1";
   let DecoderMethod = "decodeSImmOperandAndLsl1<21>";
@@ -308,6 +308,38 @@ def : PatGprSimm12<setult, SLTIU>;
 
 /// Branches and jumps
 
+// Match `(brcond (CondOp ..), ..)` and lower to the appropriate RISC-V branch
+// instruction.
+class BccPat<PatFrag CondOp, RVInstB Inst>
+    : Pat<(brcond (i32 (CondOp GPR:$rs1, GPR:$rs2)), bb:$imm12),
+          (Inst GPR:$rs1, GPR:$rs2, simm13_lsb0:$imm12)>;
+
+def : BccPat<seteq, BEQ>;
+def : BccPat<setne, BNE>;
+def : BccPat<setlt, BLT>;
+def : BccPat<setge, BGE>;
+def : BccPat<setult, BLTU>;
+def : BccPat<setuge, BGEU>;
+
+class BccSwapPat<PatFrag CondOp, RVInst InstBcc>
+    : Pat<(brcond (i32 (CondOp GPR:$rs1, GPR:$rs2)), bb:$imm12),
+          (InstBcc GPR:$rs2, GPR:$rs1, bb:$imm12)>;
+
+// Condition codes that don't have matching RISC-V branch instructions, but
+// are trivially supported by swapping the two input operands
+def : BccSwapPat<setgt, BLT>;
+def : BccSwapPat<setle, BGE>;
+def : BccSwapPat<setugt, BLTU>;
+def : BccSwapPat<setule, BGEU>;
+
+// An extra pattern is needed for a brcond without a setcc (i.e. where the
+// condition was calculated elsewhere).
+def : Pat<(brcond GPR:$cond, bb:$imm12), (BNE GPR:$cond, X0, bb:$imm12)>;
+
+let isBarrier = 1, isBranch = 1, isTerminator = 1 in
+def PseudoBR : Pseudo<(outs), (ins simm21_lsb0:$imm20), [(br bb:$imm20)]>,
+               PseudoInstExpansion<(JAL X0, simm21_lsb0:$imm20)>;
+
 let isBarrier = 1, isReturn = 1, isTerminator = 1 in
 def PseudoRET : Pseudo<(outs), (ins), [(RetFlag)]>,
                 PseudoInstExpansion<(JALR X0, X1, 0)>;

Modified: llvm/trunk/lib/Target/RISCV/RISCVMCInstLower.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/RISCVMCInstLower.cpp?rev=317690&r1=317689&r2=317690&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/RISCVMCInstLower.cpp (original)
+++ llvm/trunk/lib/Target/RISCV/RISCVMCInstLower.cpp Wed Nov  8 05:31:40 2017
@@ -71,6 +71,10 @@ bool llvm::LowerRISCVMachineOperandToMCO
   case MachineOperand::MO_Immediate:
     MCOp = MCOperand::createImm(MO.getImm());
     break;
+  case MachineOperand::MO_MachineBasicBlock:
+    MCOp = MCOperand::createExpr(
+        MCSymbolRefExpr::create(MO.getMBB()->getSymbol(), AP.OutContext));
+    break;
   case MachineOperand::MO_GlobalAddress:
     MCOp = lowerSymbolOperand(MO, AP.getSymbol(MO.getGlobal()), AP);
     break;

Modified: llvm/trunk/lib/Target/RISCV/RISCVRegisterInfo.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/RISCVRegisterInfo.cpp?rev=317690&r1=317689&r2=317690&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/RISCVRegisterInfo.cpp (original)
+++ llvm/trunk/lib/Target/RISCV/RISCVRegisterInfo.cpp Wed Nov  8 05:31:40 2017
@@ -50,10 +50,39 @@ BitVector RISCVRegisterInfo::getReserved
   return Reserved;
 }
 
+const uint32_t *RISCVRegisterInfo::getNoPreservedMask() const {
+  return CSR_NoRegs_RegMask;
+}
+
 void RISCVRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
                                             int SPAdj, unsigned FIOperandNum,
                                             RegScavenger *RS) const {
-  report_fatal_error("Subroutines not supported yet");
+  // TODO: this implementation is a temporary placeholder which does just
+  // enough to allow other aspects of code generation to be tested
+
+  assert(SPAdj == 0 && "Unexpected non-zero SPAdj value");
+
+  MachineInstr &MI = *II;
+  MachineFunction &MF = *MI.getParent()->getParent();
+  const TargetFrameLowering *TFI = MF.getSubtarget().getFrameLowering();
+  DebugLoc DL = MI.getDebugLoc();
+
+  unsigned FrameReg = getFrameRegister(MF);
+  int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
+  int Offset = TFI->getFrameIndexReference(MF, FrameIndex, FrameReg);
+  Offset += MI.getOperand(FIOperandNum + 1).getImm();
+
+  assert(TFI->hasFP(MF) && "eliminateFrameIndex currently requires hasFP");
+
+  // Offsets must be directly encoded in a 12-bit immediate field
+  if (!isInt<12>(Offset)) {
+    report_fatal_error(
+        "Frame offsets outside of the signed 12-bit range not supported");
+  }
+
+  MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, false);
+  MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset);
+  return;
 }
 
 unsigned RISCVRegisterInfo::getFrameRegister(const MachineFunction &MF) const {

Modified: llvm/trunk/lib/Target/RISCV/RISCVRegisterInfo.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Target/RISCV/RISCVRegisterInfo.h?rev=317690&r1=317689&r2=317690&view=diff
==============================================================================
--- llvm/trunk/lib/Target/RISCV/RISCVRegisterInfo.h (original)
+++ llvm/trunk/lib/Target/RISCV/RISCVRegisterInfo.h Wed Nov  8 05:31:40 2017
@@ -29,6 +29,8 @@ struct RISCVRegisterInfo : public RISCVG
 
   BitVector getReservedRegs(const MachineFunction &MF) const override;
 
+  const uint32_t *getNoPreservedMask() const override;
+
   void eliminateFrameIndex(MachineBasicBlock::iterator MI, int SPAdj,
                            unsigned FIOperandNum,
                            RegScavenger *RS = nullptr) const override;

Added: llvm/trunk/test/CodeGen/RISCV/branch.ll
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/CodeGen/RISCV/branch.ll?rev=317690&view=auto
==============================================================================
--- llvm/trunk/test/CodeGen/RISCV/branch.ll (added)
+++ llvm/trunk/test/CodeGen/RISCV/branch.ll Wed Nov  8 05:31:40 2017
@@ -0,0 +1,121 @@
+; 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 void @foo(i32 %a, i32 *%b, i1 %c) {
+; RV32I-LABEL: foo:
+; RV32I:       # BB#0:
+; RV32I-NEXT:    lw a3, 0(a1)
+; RV32I-NEXT:    beq a3, a0, .LBB0_12
+; RV32I-NEXT:    jal zero, .LBB0_1
+; RV32I-NEXT:  .LBB0_1: # %test2
+; RV32I-NEXT:    lw a3, 0(a1)
+; RV32I-NEXT:    bne a3, a0, .LBB0_12
+; RV32I-NEXT:    jal zero, .LBB0_2
+; RV32I-NEXT:  .LBB0_2: # %test3
+; RV32I-NEXT:    lw a3, 0(a1)
+; RV32I-NEXT:    blt a3, a0, .LBB0_12
+; RV32I-NEXT:    jal zero, .LBB0_3
+; RV32I-NEXT:  .LBB0_3: # %test4
+; RV32I-NEXT:    lw a3, 0(a1)
+; RV32I-NEXT:    bge a3, a0, .LBB0_12
+; RV32I-NEXT:    jal zero, .LBB0_4
+; RV32I-NEXT:  .LBB0_4: # %test5
+; RV32I-NEXT:    lw a3, 0(a1)
+; RV32I-NEXT:    bltu a3, a0, .LBB0_12
+; RV32I-NEXT:    jal zero, .LBB0_5
+; RV32I-NEXT:  .LBB0_5: # %test6
+; RV32I-NEXT:    lw a3, 0(a1)
+; RV32I-NEXT:    bgeu a3, a0, .LBB0_12
+; RV32I-NEXT:    jal zero, .LBB0_6
+; RV32I-NEXT:  .LBB0_6: # %test7
+; RV32I-NEXT:    lw a3, 0(a1)
+; RV32I-NEXT:    blt a0, a3, .LBB0_12
+; RV32I-NEXT:    jal zero, .LBB0_7
+; RV32I-NEXT:  .LBB0_7: # %test8
+; RV32I-NEXT:    lw a3, 0(a1)
+; RV32I-NEXT:    bge a0, a3, .LBB0_12
+; RV32I-NEXT:    jal zero, .LBB0_8
+; RV32I-NEXT:  .LBB0_8: # %test9
+; RV32I-NEXT:    lw a3, 0(a1)
+; RV32I-NEXT:    bltu a0, a3, .LBB0_12
+; RV32I-NEXT:    jal zero, .LBB0_9
+; RV32I-NEXT:  .LBB0_9: # %test10
+; RV32I-NEXT:    lw a3, 0(a1)
+; RV32I-NEXT:    bgeu a0, a3, .LBB0_12
+; RV32I-NEXT:    jal zero, .LBB0_10
+; RV32I-NEXT:  .LBB0_10: # %test11
+; RV32I-NEXT:    lw a0, 0(a1)
+; RV32I-NEXT:    andi a0, a2, 1
+; RV32I-NEXT:    bne a0, zero, .LBB0_12
+; RV32I-NEXT:    jal zero, .LBB0_11
+; RV32I-NEXT:  .LBB0_11: # %test12
+; RV32I-NEXT:    lw a0, 0(a1)
+; RV32I-NEXT:  .LBB0_12: # %end
+; RV32I-NEXT:    jalr zero, ra, 0
+
+  %val1 = load volatile i32, i32* %b
+  %tst1 = icmp eq i32 %val1, %a
+  br i1 %tst1, label %end, label %test2
+
+test2:
+  %val2 = load volatile i32, i32* %b
+  %tst2 = icmp ne i32 %val2, %a
+  br i1 %tst2, label %end, label %test3
+
+test3:
+  %val3 = load volatile i32, i32* %b
+  %tst3 = icmp slt i32 %val3, %a
+  br i1 %tst3, label %end, label %test4
+
+test4:
+  %val4 = load volatile i32, i32* %b
+  %tst4 = icmp sge i32 %val4, %a
+  br i1 %tst4, label %end, label %test5
+
+test5:
+  %val5 = load volatile i32, i32* %b
+  %tst5 = icmp ult i32 %val5, %a
+  br i1 %tst5, label %end, label %test6
+
+test6:
+  %val6 = load volatile i32, i32* %b
+  %tst6 = icmp uge i32 %val6, %a
+  br i1 %tst6, label %end, label %test7
+
+; Check for condition codes that don't have a matching instruction
+
+test7:
+  %val7 = load volatile i32, i32* %b
+  %tst7 = icmp sgt i32 %val7, %a
+  br i1 %tst7, label %end, label %test8
+
+test8:
+  %val8 = load volatile i32, i32* %b
+  %tst8 = icmp sle i32 %val8, %a
+  br i1 %tst8, label %end, label %test9
+
+test9:
+  %val9 = load volatile i32, i32* %b
+  %tst9 = icmp ugt i32 %val9, %a
+  br i1 %tst9, label %end, label %test10
+
+test10:
+  %val10 = load volatile i32, i32* %b
+  %tst10 = icmp ule i32 %val10, %a
+  br i1 %tst10, label %end, label %test11
+
+; Check the case of a branch where the condition was generated in another
+; function
+
+test11:
+  %val11 = load volatile i32, i32* %b
+  br i1 %c, label %end, label %test12
+
+test12:
+  %val12 = load volatile i32, i32* %b
+  br label %end
+
+end:
+  ret void
+}




More information about the llvm-commits mailing list