Index: lib/Target/RISCV/RISCV.h =================================================================== --- lib/Target/RISCV/RISCV.h +++ lib/Target/RISCV/RISCV.h @@ -24,8 +24,11 @@ namespace llvm { class RISCVTargetMachine; class AsmPrinter; +class MCContext; class MCInst; +class MCOperand; class MachineInstr; +class MachineOperand; void LowerRISCVMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI, const AsmPrinter &AP); Index: lib/Target/RISCV/RISCVCallingConv.td =================================================================== --- lib/Target/RISCV/RISCVCallingConv.td +++ lib/Target/RISCV/RISCVCallingConv.td @@ -29,3 +29,6 @@ def CSR : CalleeSavedRegs<(add X1_32, X3_32, X4_32, X8_32, X9_32, (sequence "X%u_32", 18, 27))>; + +// Needed for implementation of RISCVRegisterInfo::getNoPreservedMask() +def CSR_NoRegs : CalleeSavedRegs<(add)>; Index: lib/Target/RISCV/RISCVISelLowering.cpp =================================================================== --- lib/Target/RISCV/RISCVISelLowering.cpp +++ lib/Target/RISCV/RISCVISelLowering.cpp @@ -49,6 +49,7 @@ // TODO: add all necessary setOperationAction calls + setOperationAction(ISD::BR_CC, MVT::i32, Expand); setBooleanContents(ZeroOrOneBooleanContent); setOperationAction(ISD::GlobalAddress, MVT::i32, Custom); Index: lib/Target/RISCV/RISCVInstrInfo.h =================================================================== --- lib/Target/RISCV/RISCVInstrInfo.h +++ lib/Target/RISCV/RISCVInstrInfo.h @@ -33,6 +33,17 @@ void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator Position, const DebugLoc &DL, unsigned DestinationRegister, unsigned SourceRegister, bool KillSource) 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 DestReg, + int FrameIndex, const TargetRegisterClass *RC, + const TargetRegisterInfo *TRI) const override; }; } Index: lib/Target/RISCV/RISCVInstrInfo.cpp =================================================================== --- lib/Target/RISCV/RISCVInstrInfo.cpp +++ lib/Target/RISCV/RISCVInstrInfo.cpp @@ -44,3 +44,36 @@ .addReg(SourceRegister, getKillRegState(KillSource)) .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 DestReg, 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), DestReg).addFrameIndex(FI).addImm(0); + else + llvm_unreachable("Can't load this register from stack slot"); +} Index: lib/Target/RISCV/RISCVInstrInfo.td =================================================================== --- lib/Target/RISCV/RISCVInstrInfo.td +++ lib/Target/RISCV/RISCVInstrInfo.td @@ -60,7 +60,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>"; @@ -73,7 +73,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>"; @@ -120,7 +120,10 @@ let hasSideEffects = 0, mayLoad = 0, mayStore = 0 in class Bcc funct3, string OpcodeStr> : FSB; + OpcodeStr#"\t$rs1, $rs2, $imm12", []> { + let isBranch = 1; + let isTerminator = 1; +} def BEQ : Bcc<0b000, "beq">; def BNE : Bcc<0b001, "bne">; @@ -283,6 +286,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_32, bb:$imm12)>; + +let isBarrier = 1, isTerminator = 1 in +def PseudoBR : Pseudo<(outs), (ins simm21_lsb0:$imm20), [(br bb:$imm20)]>, + PseudoInstExpansion<(JAL X0_32, simm21_lsb0:$imm20)>; + let isBarrier = 1, isReturn = 1, isTerminator = 1 in def PseudoRET : Pseudo<(outs), (ins), [(RetFlag)]>, PseudoInstExpansion<(JALR X0_32, X1_32, 0)>; Index: lib/Target/RISCV/RISCVRegisterInfo.h =================================================================== --- lib/Target/RISCV/RISCVRegisterInfo.h +++ 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: lib/Target/RISCV/RISCVRegisterInfo.cpp =================================================================== --- lib/Target/RISCV/RISCVRegisterInfo.cpp +++ lib/Target/RISCV/RISCVRegisterInfo.cpp @@ -49,10 +49,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: test/CodeGen/RISCV/branch.ll =================================================================== --- /dev/null +++ test/CodeGen/RISCV/branch.ll @@ -0,0 +1,83 @@ +; RUN: llc -mtriple=riscv32 -verify-machineinstrs < %s | FileCheck %s + +define void @foo(i32 %a, i32 *%b, i1 %c) { +; CHECK-LABEL: foo: + + %val1 = load volatile i32, i32* %b + %tst1 = icmp eq i32 %val1, %a + br i1 %tst1, label %end, label %test2 +; CHECK: beq {{[a-z0-9]+}}, {{[a-z0-9]+}}, .LBB + +test2: + %val2 = load volatile i32, i32* %b + %tst2 = icmp ne i32 %val2, %a + br i1 %tst2, label %end, label %test3 +; CHECK: bne {{[a-z0-9]+}}, {{[a-z0-9]+}}, .LBB + +test3: + %val3 = load volatile i32, i32* %b + %tst3 = icmp slt i32 %val3, %a + br i1 %tst3, label %end, label %test4 +; CHECK: blt {{[a-z0-9]+}}, {{[a-z0-9]+}}, .LBB + +test4: + %val4 = load volatile i32, i32* %b + %tst4 = icmp sge i32 %val4, %a + br i1 %tst4, label %end, label %test5 +; CHECK: bge {{[a-z0-9]+}}, {{[a-z0-9]+}}, .LBB + +test5: + %val5 = load volatile i32, i32* %b + %tst5 = icmp ult i32 %val5, %a + br i1 %tst5, label %end, label %test6 +; CHECK: bltu {{[a-z0-9]+}}, {{[a-z0-9]+}}, .LBB + +test6: + %val6 = load volatile i32, i32* %b + %tst6 = icmp uge i32 %val6, %a + br i1 %tst6, label %end, label %test7 +; CHECK: bgeu {{[a-z0-9]+}}, {{[a-z0-9]+}}, .LBB + +; 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 +; CHECK: blt {{[a-z0-9]+}}, {{[a-z0-9]+}}, .LBB + +test8: + %val8 = load volatile i32, i32* %b + %tst8 = icmp sle i32 %val8, %a + br i1 %tst8, label %end, label %test9 +; CHECK: bge {{[a-z0-9]+}}, {{[a-z0-9]+}}, .LBB + +test9: + %val9 = load volatile i32, i32* %b + %tst9 = icmp ugt i32 %val9, %a + br i1 %tst9, label %end, label %test10 +; CHECK: bltu {{[a-z0-9]+}}, {{[a-z0-9]+}}, .LBB + +test10: + %val10 = load volatile i32, i32* %b + %tst10 = icmp ule i32 %val10, %a + br i1 %tst10, label %end, label %test11 +; CHECK: bgeu {{[a-z0-9]+}}, {{[a-z0-9]+}}, .LBB + +; Check the case of a branch where the condition was generated in another +; function + +test11: +; CHECK: andi {{[a-z0-9]+}}, {{[a-z0-9]+}}, 1 +; CHECK: bne {{[a-z0-9]+}}, zero, .LBB + %val11 = load volatile i32, i32* %b + br i1 %c, label %end, label %test12 + +test12: + %val12 = load volatile i32, i32* %b +; CHECK: jalr zero, ra, 0 + br label %end + +end: + ret void +}