Index: llvm/trunk/lib/Target/RISCV/RISCVCallingConv.td =================================================================== --- llvm/trunk/lib/Target/RISCV/RISCVCallingConv.td +++ llvm/trunk/lib/Target/RISCV/RISCVCallingConv.td @@ -27,3 +27,6 @@ ]>; 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)>; Index: llvm/trunk/lib/Target/RISCV/RISCVISelLowering.cpp =================================================================== --- llvm/trunk/lib/Target/RISCV/RISCVISelLowering.cpp +++ llvm/trunk/lib/Target/RISCV/RISCVISelLowering.cpp @@ -55,6 +55,7 @@ // TODO: add all necessary setOperationAction calls. setOperationAction(ISD::GlobalAddress, XLenVT, Custom); + setOperationAction(ISD::BR_CC, XLenVT, Expand); setBooleanContents(ZeroOrOneBooleanContent); // Function alignments (log2). Index: llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.h =================================================================== --- llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.h +++ llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.h @@ -30,7 +30,17 @@ 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 Index: llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.cpp =================================================================== --- llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.cpp +++ llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.cpp @@ -41,3 +41,36 @@ .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"); +} Index: llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td =================================================================== --- llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td +++ llvm/trunk/lib/Target/RISCV/RISCVInstrInfo.td @@ -67,7 +67,7 @@ } // A 13-bit signed immediate where the least significant bit is zero. -def simm13_lsb0 : Operand { +def simm13_lsb0 : Operand { let ParserMatchClass = SImmAsmOperand<13, "Lsb0">; let EncoderMethod = "getImmOpValueAsr1"; let DecoderMethod = "decodeSImmOperandAndLsl1<13>"; @@ -80,7 +80,7 @@ } // A 21-bit signed immediate where the least significant bit is zero. -def simm21_lsb0 : Operand { +def simm21_lsb0 : Operand { let ParserMatchClass = SImmAsmOperand<21, "Lsb0">; let EncoderMethod = "getImmOpValueAsr1"; let DecoderMethod = "decodeSImmOperandAndLsl1<21>"; @@ -308,6 +308,38 @@ /// Branches and jumps +// Match `(brcond (CondOp ..), ..)` and lower to the appropriate RISC-V branch +// instruction. +class BccPat + : Pat<(brcond (i32 (CondOp GPR:$rs1, GPR:$rs2)), bb:$imm12), + (Inst GPR:$rs1, GPR:$rs2, simm13_lsb0:$imm12)>; + +def : BccPat; +def : BccPat; +def : BccPat; +def : BccPat; +def : BccPat; +def : BccPat; + +class BccSwapPat + : 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; +def : BccSwapPat; +def : BccSwapPat; +def : BccSwapPat; + +// 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)>; Index: llvm/trunk/lib/Target/RISCV/RISCVMCInstLower.cpp =================================================================== --- llvm/trunk/lib/Target/RISCV/RISCVMCInstLower.cpp +++ llvm/trunk/lib/Target/RISCV/RISCVMCInstLower.cpp @@ -71,6 +71,10 @@ 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; Index: llvm/trunk/lib/Target/RISCV/RISCVRegisterInfo.h =================================================================== --- llvm/trunk/lib/Target/RISCV/RISCVRegisterInfo.h +++ llvm/trunk/lib/Target/RISCV/RISCVRegisterInfo.h @@ -29,6 +29,8 @@ 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; Index: llvm/trunk/lib/Target/RISCV/RISCVRegisterInfo.cpp =================================================================== --- llvm/trunk/lib/Target/RISCV/RISCVRegisterInfo.cpp +++ llvm/trunk/lib/Target/RISCV/RISCVRegisterInfo.cpp @@ -50,10 +50,39 @@ 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 { Index: llvm/trunk/test/CodeGen/RISCV/branch.ll =================================================================== --- llvm/trunk/test/CodeGen/RISCV/branch.ll +++ llvm/trunk/test/CodeGen/RISCV/branch.ll @@ -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 +}