[RISCV] Support lowering FrameIndex
Introduces the AddrFI "addressing mode", which is necessary simply because
it's not possible to write a pattern that directly matches a frameindex.
Ensure callee-saved registers are accessed relative to the stackpointer. This
is necessary as callee-saved register spills are performed before the frame
pointer is set.
Move HexagonDAGToDAGISel::isOrEquivalentToAdd to SelectionDAGISel, so we can
make use of it in the RISC-V backend.
Differential Revision: https://reviews.llvm.org/D39848
llvm-svn: 320353
diff --git a/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp b/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp
index d0cd143..76a7e77 100644
--- a/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp
+++ b/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp
@@ -1421,26 +1421,6 @@
return false;
}
-
-bool HexagonDAGToDAGISel::isOrEquivalentToAdd(const SDNode *N) const {
- assert(N->getOpcode() == ISD::OR);
- auto *C = dyn_cast<ConstantSDNode>(N->getOperand(1));
- if (!C)
- return false;
-
- // Detect when "or" is used to add an offset to a stack object.
- if (auto *FN = dyn_cast<FrameIndexSDNode>(N->getOperand(0))) {
- MachineFrameInfo &MFI = MF->getFrameInfo();
- unsigned A = MFI.getObjectAlignment(FN->getIndex());
- assert(isPowerOf2_32(A));
- int32_t Off = C->getSExtValue();
- // If the alleged offset fits in the zero bits guaranteed by
- // the alignment, then this or is really an add.
- return (Off >= 0) && (((A-1) & Off) == unsigned(Off));
- }
- return false;
-}
-
bool HexagonDAGToDAGISel::isAlignedMemNode(const MemSDNode *N) const {
return N->getAlignment() >= N->getMemoryVT().getStoreSize();
}
diff --git a/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.h b/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.h
index e3e22a3..0028c40 100644
--- a/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.h
+++ b/llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.h
@@ -121,7 +121,6 @@
void SelectHvxRor(SDNode *N);
bool keepsLowBits(const SDValue &Val, unsigned NumBits, SDValue &Src);
- bool isOrEquivalentToAdd(const SDNode *N) const;
bool isAlignedMemNode(const MemSDNode *N) const;
bool isSmallStackStore(const StoreSDNode *N) const;
bool isPositiveHalfWord(const SDNode *N) const;
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
index fd3b258..cd18a10 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
@@ -27,3 +27,32 @@
void RISCVFrameLowering::emitEpilogue(MachineFunction &MF,
MachineBasicBlock &MBB) const {}
+
+int RISCVFrameLowering::getFrameIndexReference(const MachineFunction &MF,
+ int FI,
+ unsigned &FrameReg) const {
+ const MachineFrameInfo &MFI = MF.getFrameInfo();
+ const TargetRegisterInfo *RI = MF.getSubtarget().getRegisterInfo();
+
+ // Callee-saved registers should be referenced relative to the stack
+ // pointer (positive offset), otherwise use the frame pointer (negative
+ // offset).
+ const std::vector<CalleeSavedInfo> &CSI = MFI.getCalleeSavedInfo();
+ int MinCSFI = 0;
+ int MaxCSFI = -1;
+
+ int Offset = MFI.getObjectOffset(FI) - getOffsetOfLocalArea() +
+ MFI.getOffsetAdjustment();
+
+ if (CSI.size()) {
+ MinCSFI = CSI[0].getFrameIdx();
+ MaxCSFI = CSI[CSI.size() - 1].getFrameIdx();
+ }
+
+ FrameReg = RI->getFrameRegister(MF);
+ if (FI >= MinCSFI && FI <= MaxCSFI) {
+ FrameReg = RISCV::X2;
+ Offset += MF.getFrameInfo().getStackSize();
+ }
+ return Offset;
+}
diff --git a/llvm/lib/Target/RISCV/RISCVFrameLowering.h b/llvm/lib/Target/RISCV/RISCVFrameLowering.h
index 0b2c7a4..ba093bb 100644
--- a/llvm/lib/Target/RISCV/RISCVFrameLowering.h
+++ b/llvm/lib/Target/RISCV/RISCVFrameLowering.h
@@ -29,6 +29,9 @@
void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
+ int getFrameIndexReference(const MachineFunction &MF, int FI,
+ unsigned &FrameReg) const override;
+
bool hasFP(const MachineFunction &MF) const override;
MachineBasicBlock::iterator
diff --git a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
index 5b038df..113a45a 100644
--- a/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
+++ b/llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
@@ -14,6 +14,7 @@
#include "RISCV.h"
#include "MCTargetDesc/RISCVMCTargetDesc.h"
#include "RISCVTargetMachine.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/SelectionDAGISel.h"
#include "llvm/Support/Debug.h"
#include "llvm/Support/MathExtras.h"
@@ -43,6 +44,8 @@
void Select(SDNode *Node) override;
+ bool SelectAddrFI(SDValue Addr, SDValue &Base);
+
// Include the pieces autogenerated from the target description.
#include "RISCVGenDAGISel.inc"
};
@@ -76,11 +79,28 @@
return;
}
}
+ if (Opcode == ISD::FrameIndex) {
+ SDLoc DL(Node);
+ SDValue Imm = CurDAG->getTargetConstant(0, DL, XLenVT);
+ int FI = dyn_cast<FrameIndexSDNode>(Node)->getIndex();
+ EVT VT = Node->getValueType(0);
+ SDValue TFI = CurDAG->getTargetFrameIndex(FI, VT);
+ ReplaceNode(Node, CurDAG->getMachineNode(RISCV::ADDI, DL, VT, TFI, Imm));
+ return;
+ }
// Select the default instruction.
SelectCode(Node);
}
+bool RISCVDAGToDAGISel::SelectAddrFI(SDValue Addr, SDValue &Base) {
+ if (auto FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
+ Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), Subtarget->getXLenVT());
+ return true;
+ }
+ return false;
+}
+
// This pass converts a legalized DAG into a RISCV-specific DAG, ready
// for instruction scheduling.
FunctionPass *llvm::createRISCVISelDag(RISCVTargetMachine &TM) {
diff --git a/llvm/lib/Target/RISCV/RISCVInstrInfo.td b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
index b37ab313..9512435 100644
--- a/llvm/lib/Target/RISCV/RISCVInstrInfo.td
+++ b/llvm/lib/Target/RISCV/RISCVInstrInfo.td
@@ -127,6 +127,10 @@
// Standalone (codegen-only) immleaf patterns.
def simm32 : ImmLeaf<XLenVT, [{return isInt<32>(Imm);}]>;
+// Addressing modes.
+// Necessary because a frameindex can't be matched directly in a pattern.
+def AddrFI : ComplexPattern<iPTR, 1, "SelectAddrFI", [frameindex], []>;
+
// Extract least significant 12 bits from an immediate value and sign extend
// them.
def LO12Sext : SDNodeXForm<imm, [{
@@ -347,6 +351,12 @@
: Pat<(OpNode GPR:$rs1, uimmlog2xlen:$shamt),
(Inst GPR:$rs1, uimmlog2xlen:$shamt)>;
+/// Predicates
+
+def IsOrAdd: PatFrag<(ops node:$A, node:$B), (or node:$A, node:$B), [{
+ return isOrEquivalentToAdd(N);
+}]>;
+
/// Immediates
def : Pat<(simm12:$imm), (ADDI X0, simm12:$imm)>;
@@ -371,6 +381,13 @@
def : PatGprGpr<sra, SRA>;
def : PatGprUimmLog2XLen<sra, SRAI>;
+/// FrameIndex calculations
+
+def : Pat<(add (i32 AddrFI:$Rs), simm12:$imm12),
+ (ADDI (i32 AddrFI:$Rs), simm12:$imm12)>;
+def : Pat<(IsOrAdd (i32 AddrFI:$Rs), simm12:$imm12),
+ (ADDI (i32 AddrFI:$Rs), simm12:$imm12)>;
+
/// Setcc
def : PatGprGpr<setlt, SLT>;
@@ -451,8 +468,13 @@
multiclass LdPat<PatFrag LoadOp, RVInst Inst> {
def : Pat<(LoadOp GPR:$rs1), (Inst GPR:$rs1, 0)>;
+ def : Pat<(LoadOp AddrFI:$rs1), (Inst AddrFI:$rs1, 0)>;
def : Pat<(LoadOp (add GPR:$rs1, simm12:$imm12)),
(Inst GPR:$rs1, simm12:$imm12)>;
+ def : Pat<(LoadOp (add AddrFI:$rs1, simm12:$imm12)),
+ (Inst AddrFI:$rs1, simm12:$imm12)>;
+ def : Pat<(LoadOp (IsOrAdd AddrFI:$rs1, simm12:$imm12)),
+ (Inst AddrFI:$rs1, simm12:$imm12)>;
}
defm : LdPat<sextloadi8, LB>;
@@ -467,8 +489,13 @@
multiclass StPat<PatFrag StoreOp, RVInst Inst> {
def : Pat<(StoreOp GPR:$rs2, GPR:$rs1), (Inst GPR:$rs2, GPR:$rs1, 0)>;
+ def : Pat<(StoreOp GPR:$rs2, AddrFI:$rs1), (Inst GPR:$rs2, AddrFI:$rs1, 0)>;
def : Pat<(StoreOp GPR:$rs2, (add GPR:$rs1, simm12:$imm12)),
(Inst GPR:$rs2, GPR:$rs1, simm12:$imm12)>;
+ def : Pat<(StoreOp GPR:$rs2, (add AddrFI:$rs1, simm12:$imm12)),
+ (Inst GPR:$rs2, AddrFI:$rs1, simm12:$imm12)>;
+ def : Pat<(StoreOp GPR:$rs2, (IsOrAdd AddrFI:$rs1, simm12:$imm12)),
+ (Inst GPR:$rs2, AddrFI:$rs1, simm12:$imm12)>;
}
defm : StPat<truncstorei8, SB>;
diff --git a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
index 75b2775..5776a92 100644
--- a/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
+++ b/llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
@@ -57,22 +57,20 @@
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();
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();
+ unsigned FrameReg;
+ int Offset =
+ getFrameLowering(MF)->getFrameIndexReference(MF, FrameIndex, FrameReg) +
+ MI.getOperand(FIOperandNum + 1).getImm();
- assert(TFI->hasFP(MF) && "eliminateFrameIndex currently requires hasFP");
+ assert(MF.getSubtarget().getFrameLowering()->hasFP(MF) &&
+ "eliminateFrameIndex currently requires hasFP");
// Offsets must be directly encoded in a 12-bit immediate field
if (!isInt<12>(Offset)) {