Index: lib/Target/RISCV/RISCVISelDAGToDAG.cpp =================================================================== --- lib/Target/RISCV/RISCVISelDAGToDAG.cpp +++ lib/Target/RISCV/RISCVISelDAGToDAG.cpp @@ -42,6 +42,8 @@ void Select(SDNode *Node) override; + bool SelectADDRii(SDValue Addr, SDValue &Base, SDValue &Offset); + // Include the pieces autogenerated from the target description. #include "RISCVGenDAGISel.inc" }; @@ -85,6 +87,28 @@ SelectCode(Node); } +bool RISCVDAGToDAGISel::SelectADDRii(SDValue Addr, SDValue &Base, + SDValue &Offset) { + + FrameIndexSDNode *FIN = nullptr; + if ((FIN = dyn_cast(Addr))) { + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); + Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32); + return true; + } + if (Addr.getOpcode() == ISD::ADD || Addr.getOpcode() == ISD::OR) { + ConstantSDNode *CN = nullptr; + if ((FIN = dyn_cast(Addr.getOperand(0))) && + (CN = dyn_cast(Addr.getOperand(1)))) { + Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), MVT::i32); + Offset = + CurDAG->getTargetConstant(CN->getSExtValue(), SDLoc(Addr), MVT::i32); + return true; + } + } + return false; +} + // This pass converts a legalized DAG into a RISCV-specific DAG, ready // for instruction scheduling. FunctionPass *llvm::createRISCVISelDag(RISCVTargetMachine &TM) { Index: lib/Target/RISCV/RISCVInstrInfo.cpp =================================================================== --- lib/Target/RISCV/RISCVInstrInfo.cpp +++ lib/Target/RISCV/RISCVInstrInfo.cpp @@ -53,7 +53,7 @@ DL = I->getDebugLoc(); if (RC == &RISCV::GPRRegClass) - BuildMI(MBB, I, DL, get(RISCV::SW)) + BuildMI(MBB, I, DL, get(RISCV::SW_FI)) .addReg(SrcReg, getKillRegState(IsKill)) .addFrameIndex(FI) .addImm(0); @@ -71,7 +71,7 @@ DL = I->getDebugLoc(); if (RC == &RISCV::GPRRegClass) - BuildMI(MBB, I, DL, get(RISCV::LW), DstReg).addFrameIndex(FI).addImm(0); + BuildMI(MBB, I, DL, get(RISCV::LW_FI), DstReg).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 @@ -105,12 +105,20 @@ let DecoderMethod = "decodeSImmOperandAndLsl1<21>"; } -// A parameterized register class alternative to i32imm/i64imm from Target.td. +// A parameterized register class alternative to i32imm/i64imm from Target.td. def ixlenimm : Operand; // Standalone (codegen-only) immleaf patterns. def simm32 : ImmLeaf(Imm);}]>; +// Addressing modes. +def ADDRii : ComplexPattern; + +// Address operands. +def MEMii : Operand { + let MIOperandInfo = (ops ixlenimm, ixlenimm); +} + // Extract least significant 12 bits from an immediate value and sign extend // them. def LO12Sext : SDNodeXForm; def : PatGprUimm5; +// Add with a frameindex, used to legalize frameindex copies and necessary to +// keep tblgen happy +def LEA_FI : Pseudo<(outs GPR:$dst), (ins MEMii:$addr), [(set GPR:$dst, ADDRii:$addr)]>; + /// Setcc def : PatGprGpr; @@ -413,6 +425,10 @@ defm : LdPat; defm : LdPat; +def LW_FI : Pseudo<(outs GPR:$dst), (ins MEMii:$addr), + [(set GPR:$dst, (load ADDRii:$addr))]>; + + /// Stores multiclass StPat { @@ -425,6 +441,9 @@ defm : StPat; defm : StPat; +def SW_FI : Pseudo<(outs), (ins GPR:$src, MEMii:$addr), + [(store GPR:$src, ADDRii:$addr)]>; + /// Other pseudo-instructions // Pessimistically assume the stack pointer will be clobbered Index: lib/Target/RISCV/RISCVRegisterInfo.cpp =================================================================== --- lib/Target/RISCV/RISCVRegisterInfo.cpp +++ lib/Target/RISCV/RISCVRegisterInfo.cpp @@ -57,14 +57,12 @@ void RISCVRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II, int SPAdj, unsigned FIOperandNum, RegScavenger *RS) const { - // 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(); + const TargetInstrInfo *TII = MF.getSubtarget().getInstrInfo(); DebugLoc DL = MI.getDebugLoc(); unsigned FrameReg = getFrameRegister(MF); @@ -72,6 +70,9 @@ int Offset = TFI->getFrameIndexReference(MF, FrameIndex, FrameReg); Offset += MI.getOperand(FIOperandNum + 1).getImm(); + unsigned Reg = MI.getOperand(0).getReg(); + assert(RISCV::GPRRegClass.contains(Reg) && "Unexpected register operand"); + assert(TFI->hasFP(MF) && "eliminateFrameIndex currently requires hasFP"); // Offsets must be directly encoded in a 12-bit immediate field @@ -80,8 +81,30 @@ "Frame offsets outside of the signed 12-bit range not supported"); } - MI.getOperand(FIOperandNum).ChangeToRegister(FrameReg, false); - MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset); + MachineBasicBlock &MBB = *MI.getParent(); + switch (MI.getOpcode()) { + case RISCV::LW_FI: + BuildMI(MBB, II, DL, TII->get(RISCV::LW), Reg) + .addReg(FrameReg) + .addImm(Offset); + break; + case RISCV::SW_FI: + BuildMI(MBB, II, DL, TII->get(RISCV::SW)) + .addReg(Reg, getKillRegState(MI.getOperand(0).isKill())) + .addReg(FrameReg) + .addImm(Offset); + break; + case RISCV::LEA_FI: + BuildMI(MBB, II, DL, TII->get(RISCV::ADDI), Reg) + .addReg(FrameReg) + .addImm(Offset); + break; + default: + llvm_unreachable("Unexpected opcode"); + } + + // Erase old instruction. + MBB.erase(II); return; } Index: test/CodeGen/RISCV/frame.ll =================================================================== --- /dev/null +++ test/CodeGen/RISCV/frame.ll @@ -0,0 +1,37 @@ +; 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 + +%struct.key_t = type { i32, [16 x i8] } + +; FIXME: prologue and epilogue insertion must be implemented to complete this +; test + +define i32 @test() nounwind { +; RV32I-LABEL: test: +; RV32I: # BB#0: +; RV32I-NEXT: sw ra, 28(s0) +; RV32I-NEXT: sw zero, 24(s0) +; RV32I-NEXT: sw zero, 20(s0) +; RV32I-NEXT: sw zero, 16(s0) +; RV32I-NEXT: sw zero, 12(s0) +; RV32I-NEXT: sw zero, 8(s0) +; RV32I-NEXT: addi a0, s0, 8 +; RV32I-NEXT: ori a0, a0, 4 +; RV32I-NEXT: lui a1, %hi(test1) +; RV32I-NEXT: addi a1, a1, %lo(test1) +; RV32I-NEXT: jalr ra, a1, 0 +; RV32I-NEXT: addi a0, zero, 0 +; RV32I-NEXT: lw ra, 28(s0) +; RV32I-NEXT: jalr zero, ra, 0 + %key = alloca %struct.key_t, align 4 + %1 = bitcast %struct.key_t* %key to i8* + call void @llvm.memset.p0i8.i64(i8* %1, i8 0, i64 20, i32 4, i1 false) + %2 = getelementptr inbounds %struct.key_t, %struct.key_t* %key, i64 0, i32 1, i64 0 + call void @test1(i8* %2) #3 + ret i32 0 +} + +declare void @llvm.memset.p0i8.i64(i8* nocapture, i8, i64, i32, i1) + +declare void @test1(i8*)