Skip to content

Commit

Permalink
[RISCV] Support lowering FrameIndex
Browse files Browse the repository at this point in the history
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
  • Loading branch information
asb committed Dec 11, 2017
1 parent 775bb74 commit 660bcce
Show file tree
Hide file tree
Showing 18 changed files with 242 additions and 129 deletions.
2 changes: 2 additions & 0 deletions llvm/include/llvm/CodeGen/SelectionDAGISel.h
Original file line number Diff line number Diff line change
Expand Up @@ -276,6 +276,8 @@ class SelectionDAGISel : public MachineFunctionPass {
return false;
}

bool isOrEquivalentToAdd(const SDNode *N) const;

private:

// Calls to these functions are generated by tblgen.
Expand Down
19 changes: 19 additions & 0 deletions llvm/lib/CodeGen/SelectionDAG/SelectionDAGISel.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3761,6 +3761,25 @@ void SelectionDAGISel::SelectCodeCommon(SDNode *NodeToMatch,
}
}

bool SelectionDAGISel::isOrEquivalentToAdd(const SDNode *N) const {
assert(N->getOpcode() == ISD::OR && "Unexpected opcode");
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) && "Unexpected alignment");
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;
}

void SelectionDAGISel::CannotYetSelect(SDNode *N) {
std::string msg;
raw_string_ostream Msg(msg);
Expand Down
20 changes: 0 additions & 20 deletions llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1421,26 +1421,6 @@ bool HexagonDAGToDAGISel::keepsLowBits(const SDValue &Val, unsigned NumBits,
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();
}
Expand Down
1 change: 0 additions & 1 deletion llvm/lib/Target/Hexagon/HexagonISelDAGToDAG.h
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,6 @@ class HexagonDAGToDAGISel : public SelectionDAGISel {
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;
Expand Down
29 changes: 29 additions & 0 deletions llvm/lib/Target/RISCV/RISCVFrameLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,3 +27,32 @@ void RISCVFrameLowering::emitPrologue(MachineFunction &MF,

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;
}
3 changes: 3 additions & 0 deletions llvm/lib/Target/RISCV/RISCVFrameLowering.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,9 @@ class RISCVFrameLowering : public TargetFrameLowering {
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
Expand Down
20 changes: 20 additions & 0 deletions llvm/lib/Target/RISCV/RISCVISelDAGToDAG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -43,6 +44,8 @@ class RISCVDAGToDAGISel final : public SelectionDAGISel {

void Select(SDNode *Node) override;

bool SelectAddrFI(SDValue Addr, SDValue &Base);

// Include the pieces autogenerated from the target description.
#include "RISCVGenDAGISel.inc"
};
Expand Down Expand Up @@ -76,11 +79,28 @@ void RISCVDAGToDAGISel::Select(SDNode *Node) {
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) {
Expand Down
27 changes: 27 additions & 0 deletions llvm/lib/Target/RISCV/RISCVInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -127,6 +127,10 @@ def ixlenimm : Operand<XLenVT>;
// 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, [{
Expand Down Expand Up @@ -347,6 +351,12 @@ class PatGprUimmLog2XLen<SDPatternOperator OpNode, RVInstIShift Inst>
: 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)>;
Expand All @@ -371,6 +381,13 @@ def : PatGprUimmLog2XLen<srl, SRLI>;
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>;
Expand Down Expand Up @@ -451,8 +468,13 @@ def PseudoRET : Pseudo<(outs), (ins), [(RetFlag)]>,

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>;
Expand All @@ -467,8 +489,13 @@ defm : LdPat<zextloadi16, LHU>;

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>;
Expand Down
14 changes: 6 additions & 8 deletions llvm/lib/Target/RISCV/RISCVRegisterInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -57,22 +57,20 @@ const uint32_t *RISCVRegisterInfo::getNoPreservedMask() const {
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)) {
Expand Down
4 changes: 2 additions & 2 deletions llvm/test/CodeGen/RISCV/blockaddress.ll
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
define void @test_blockaddress() nounwind {
; RV32I-LABEL: test_blockaddress:
; RV32I: # %bb.0:
; RV32I-NEXT: sw ra, 0(s0)
; RV32I-NEXT: sw ra, 0(sp)
; RV32I-NEXT: lui a0, %hi(addr)
; RV32I-NEXT: addi a0, a0, %lo(addr)
; RV32I-NEXT: lui a1, %hi(.Ltmp0)
Expand All @@ -17,7 +17,7 @@ define void @test_blockaddress() nounwind {
; RV32I-NEXT: jalr zero, a0, 0
; RV32I-NEXT: .Ltmp0: # Block address taken
; RV32I-NEXT: .LBB0_1: # %block
; RV32I-NEXT: lw ra, 0(s0)
; RV32I-NEXT: lw ra, 0(sp)
; RV32I-NEXT: jalr zero, ra, 0
store volatile i8* blockaddress(@test_blockaddress, %block), i8** @addr
%val = load volatile i8*, i8** @addr
Expand Down
Loading

0 comments on commit 660bcce

Please sign in to comment.