Skip to content

Commit da20f5c

Browse files
committed
[RISCV] Generate address sequences suitable for mcmodel=medium
This patch adds an implementation of a PC-relative addressing sequence to be used when -mcmodel=medium is specified. With absolute addressing, a 'medium' codemodel may cause addresses to be out of range. This is because while 'medium' implies a 2 GiB addressing range, this 2 GiB can be at any offset as opposed to 'small', which implies the first 2 GiB only. Note that LLVM/Clang currently specifies code models differently to GCC, where small and medium imply the same functionality as GCC's medlow and medany respectively. Differential Revision: https://reviews.llvm.org/D54143 Patch by Lewis Revill. llvm-svn: 357393
1 parent efe376a commit da20f5c

File tree

9 files changed

+205
-36
lines changed

9 files changed

+205
-36
lines changed

llvm/include/llvm/CodeGen/MachineBasicBlock.h

+11
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,10 @@ class MachineBasicBlock
114114
/// branch.
115115
bool AddressTaken = false;
116116

117+
/// Indicate that this basic block needs its symbol be emitted regardless of
118+
/// whether the flow just falls-through to it.
119+
bool LabelMustBeEmitted = false;
120+
117121
/// Indicate that this basic block is the entry block of an EH scope, i.e.,
118122
/// the block that used to have a catchpad or cleanuppad instruction in the
119123
/// LLVM IR.
@@ -158,6 +162,13 @@ class MachineBasicBlock
158162
/// branch.
159163
void setHasAddressTaken() { AddressTaken = true; }
160164

165+
/// Test whether this block must have its label emitted.
166+
bool hasLabelMustBeEmitted() const { return LabelMustBeEmitted; }
167+
168+
/// Set this block to reflect that, regardless how we flow to it, we need
169+
/// its label be emitted.
170+
void setLabelMustBeEmitted() { LabelMustBeEmitted = true; }
171+
161172
/// Return the MachineFunction containing this basic block.
162173
const MachineFunction *getParent() const { return xParent; }
163174
MachineFunction *getParent() { return xParent; }

llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -2925,13 +2925,16 @@ void AsmPrinter::EmitBasicBlockStart(const MachineBasicBlock &MBB) const {
29252925

29262926
// Print the main label for the block.
29272927
if (MBB.pred_empty() ||
2928-
(isBlockOnlyReachableByFallthrough(&MBB) && !MBB.isEHFuncletEntry())) {
2928+
(isBlockOnlyReachableByFallthrough(&MBB) && !MBB.isEHFuncletEntry() &&
2929+
!MBB.hasLabelMustBeEmitted())) {
29292930
if (isVerbose()) {
29302931
// NOTE: Want this comment at start of line, don't emit with AddComment.
29312932
OutStreamer->emitRawComment(" %bb." + Twine(MBB.getNumber()) + ":",
29322933
false);
29332934
}
29342935
} else {
2936+
if (isVerbose() && MBB.hasLabelMustBeEmitted())
2937+
OutStreamer->AddComment("Label of block must be emitted");
29352938
OutStreamer->EmitLabel(MBB.getSymbol());
29362939
}
29372940
}

llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp

+45
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,9 @@ class RISCVExpandPseudo : public MachineFunctionPass {
5454
bool expandAtomicCmpXchg(MachineBasicBlock &MBB,
5555
MachineBasicBlock::iterator MBBI, bool IsMasked,
5656
int Width, MachineBasicBlock::iterator &NextMBBI);
57+
bool expandLoadLocalAddress(MachineBasicBlock &MBB,
58+
MachineBasicBlock::iterator MBBI,
59+
MachineBasicBlock::iterator &NextMBBI);
5760
};
5861

5962
char RISCVExpandPseudo::ID = 0;
@@ -117,6 +120,8 @@ bool RISCVExpandPseudo::expandMI(MachineBasicBlock &MBB,
117120
return expandAtomicCmpXchg(MBB, MBBI, false, 64, NextMBBI);
118121
case RISCV::PseudoMaskedCmpXchg32:
119122
return expandAtomicCmpXchg(MBB, MBBI, true, 32, NextMBBI);
123+
case RISCV::PseudoLLA:
124+
return expandLoadLocalAddress(MBB, MBBI, NextMBBI);
120125
}
121126

122127
return false;
@@ -597,6 +602,46 @@ bool RISCVExpandPseudo::expandAtomicCmpXchg(
597602
return true;
598603
}
599604

605+
bool RISCVExpandPseudo::expandLoadLocalAddress(
606+
MachineBasicBlock &MBB, MachineBasicBlock::iterator MBBI,
607+
MachineBasicBlock::iterator &NextMBBI) {
608+
MachineFunction *MF = MBB.getParent();
609+
MachineInstr &MI = *MBBI;
610+
DebugLoc DL = MI.getDebugLoc();
611+
612+
unsigned DestReg = MI.getOperand(0).getReg();
613+
const MachineOperand &Symbol = MI.getOperand(1);
614+
615+
MachineBasicBlock *NewMBB = MF->CreateMachineBasicBlock(MBB.getBasicBlock());
616+
617+
// Tell AsmPrinter that we unconditionally want the symbol of this label to be
618+
// emitted.
619+
NewMBB->setLabelMustBeEmitted();
620+
621+
MF->insert(++MBB.getIterator(), NewMBB);
622+
623+
BuildMI(NewMBB, DL, TII->get(RISCV::AUIPC), DestReg)
624+
.addDisp(Symbol, 0, RISCVII::MO_PCREL_HI);
625+
BuildMI(NewMBB, DL, TII->get(RISCV::ADDI), DestReg)
626+
.addReg(DestReg)
627+
.addMBB(NewMBB, RISCVII::MO_PCREL_LO);
628+
629+
// Move all the rest of the instructions to NewMBB.
630+
NewMBB->splice(NewMBB->end(), &MBB, std::next(MBBI), MBB.end());
631+
// Update machine-CFG edges.
632+
NewMBB->transferSuccessorsAndUpdatePHIs(&MBB);
633+
// Make the original basic block fall-through to the new.
634+
MBB.addSuccessor(NewMBB);
635+
636+
// Make sure live-ins are correctly attached to this new basic block.
637+
LivePhysRegs LiveRegs;
638+
computeAndAddLiveIns(LiveRegs, *NewMBB);
639+
640+
NextMBBI = MBB.end();
641+
MI.eraseFromParent();
642+
return true;
643+
}
644+
600645
} // end of anonymous namespace
601646

602647
INITIALIZE_PASS(RISCVExpandPseudo, "riscv-expand-pseudo",

llvm/lib/Target/RISCV/RISCVISelLowering.cpp

+53-35
Original file line numberDiff line numberDiff line change
@@ -374,72 +374,90 @@ SDValue RISCVTargetLowering::LowerOperation(SDValue Op,
374374
}
375375
}
376376

377+
static SDValue getTargetNode(GlobalAddressSDNode *N, SDLoc DL, EVT Ty,
378+
SelectionDAG &DAG, unsigned Flags) {
379+
return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags);
380+
}
381+
382+
static SDValue getTargetNode(BlockAddressSDNode *N, SDLoc DL, EVT Ty,
383+
SelectionDAG &DAG, unsigned Flags) {
384+
return DAG.getTargetBlockAddress(N->getBlockAddress(), Ty, N->getOffset(),
385+
Flags);
386+
}
387+
388+
static SDValue getTargetNode(ConstantPoolSDNode *N, SDLoc DL, EVT Ty,
389+
SelectionDAG &DAG, unsigned Flags) {
390+
return DAG.getTargetConstantPool(N->getConstVal(), Ty, N->getAlignment(),
391+
N->getOffset(), Flags);
392+
}
393+
394+
template <class NodeTy>
395+
SDValue RISCVTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG) const {
396+
SDLoc DL(N);
397+
EVT Ty = getPointerTy(DAG.getDataLayout());
398+
399+
switch (getTargetMachine().getCodeModel()) {
400+
default:
401+
report_fatal_error("Unsupported code model for lowering");
402+
case CodeModel::Small: {
403+
// Generate a sequence for accessing addresses within the first 2 GiB of
404+
// address space. This generates the pattern (addi (lui %hi(sym)) %lo(sym)).
405+
SDValue AddrHi = getTargetNode(N, DL, Ty, DAG, RISCVII::MO_HI);
406+
SDValue AddrLo = getTargetNode(N, DL, Ty, DAG, RISCVII::MO_LO);
407+
SDValue MNHi = SDValue(DAG.getMachineNode(RISCV::LUI, DL, Ty, AddrHi), 0);
408+
return SDValue(DAG.getMachineNode(RISCV::ADDI, DL, Ty, MNHi, AddrLo), 0);
409+
}
410+
case CodeModel::Medium: {
411+
// Generate a sequence for accessing addresses within any 2GiB range within
412+
// the address space. This generates the pattern (PseudoLLA sym), which
413+
// expands to (addi (auipc %pcrel_hi(sym)) %pcrel_lo(auipc)).
414+
SDValue Addr = getTargetNode(N, DL, Ty, DAG, 0);
415+
return SDValue(DAG.getMachineNode(RISCV::PseudoLLA, DL, Ty, Addr), 0);
416+
}
417+
}
418+
}
419+
377420
SDValue RISCVTargetLowering::lowerGlobalAddress(SDValue Op,
378421
SelectionDAG &DAG) const {
379422
SDLoc DL(Op);
380423
EVT Ty = Op.getValueType();
381424
GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
382-
const GlobalValue *GV = N->getGlobal();
383425
int64_t Offset = N->getOffset();
384426
MVT XLenVT = Subtarget.getXLenVT();
385427

386428
if (isPositionIndependent())
387429
report_fatal_error("Unable to lowerGlobalAddress");
430+
431+
SDValue Addr = getAddr(N, DAG);
432+
388433
// In order to maximise the opportunity for common subexpression elimination,
389434
// emit a separate ADD node for the global address offset instead of folding
390435
// it in the global address node. Later peephole optimisations may choose to
391436
// fold it back in when profitable.
392-
SDValue GAHi = DAG.getTargetGlobalAddress(GV, DL, Ty, 0, RISCVII::MO_HI);
393-
SDValue GALo = DAG.getTargetGlobalAddress(GV, DL, Ty, 0, RISCVII::MO_LO);
394-
SDValue MNHi = SDValue(DAG.getMachineNode(RISCV::LUI, DL, Ty, GAHi), 0);
395-
SDValue MNLo =
396-
SDValue(DAG.getMachineNode(RISCV::ADDI, DL, Ty, MNHi, GALo), 0);
397437
if (Offset != 0)
398-
return DAG.getNode(ISD::ADD, DL, Ty, MNLo,
438+
return DAG.getNode(ISD::ADD, DL, Ty, Addr,
399439
DAG.getConstant(Offset, DL, XLenVT));
400-
return MNLo;
440+
return Addr;
401441
}
402442

403443
SDValue RISCVTargetLowering::lowerBlockAddress(SDValue Op,
404444
SelectionDAG &DAG) const {
405-
SDLoc DL(Op);
406-
EVT Ty = Op.getValueType();
407445
BlockAddressSDNode *N = cast<BlockAddressSDNode>(Op);
408-
const BlockAddress *BA = N->getBlockAddress();
409-
int64_t Offset = N->getOffset();
410446

411447
if (isPositionIndependent())
412448
report_fatal_error("Unable to lowerBlockAddress");
413449

414-
SDValue BAHi = DAG.getTargetBlockAddress(BA, Ty, Offset, RISCVII::MO_HI);
415-
SDValue BALo = DAG.getTargetBlockAddress(BA, Ty, Offset, RISCVII::MO_LO);
416-
SDValue MNHi = SDValue(DAG.getMachineNode(RISCV::LUI, DL, Ty, BAHi), 0);
417-
SDValue MNLo =
418-
SDValue(DAG.getMachineNode(RISCV::ADDI, DL, Ty, MNHi, BALo), 0);
419-
return MNLo;
450+
return getAddr(N, DAG);
420451
}
421452

422453
SDValue RISCVTargetLowering::lowerConstantPool(SDValue Op,
423454
SelectionDAG &DAG) const {
424-
SDLoc DL(Op);
425-
EVT Ty = Op.getValueType();
426455
ConstantPoolSDNode *N = cast<ConstantPoolSDNode>(Op);
427-
const Constant *CPA = N->getConstVal();
428-
int64_t Offset = N->getOffset();
429-
unsigned Alignment = N->getAlignment();
430-
431-
if (!isPositionIndependent()) {
432-
SDValue CPAHi =
433-
DAG.getTargetConstantPool(CPA, Ty, Alignment, Offset, RISCVII::MO_HI);
434-
SDValue CPALo =
435-
DAG.getTargetConstantPool(CPA, Ty, Alignment, Offset, RISCVII::MO_LO);
436-
SDValue MNHi = SDValue(DAG.getMachineNode(RISCV::LUI, DL, Ty, CPAHi), 0);
437-
SDValue MNLo =
438-
SDValue(DAG.getMachineNode(RISCV::ADDI, DL, Ty, MNHi, CPALo), 0);
439-
return MNLo;
440-
} else {
456+
457+
if (isPositionIndependent())
441458
report_fatal_error("Unable to lowerConstantPool");
442-
}
459+
460+
return getAddr(N, DAG);
443461
}
444462

445463
SDValue RISCVTargetLowering::lowerSELECT(SDValue Op, SelectionDAG &DAG) const {

llvm/lib/Target/RISCV/RISCVISelLowering.h

+4
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,10 @@ class RISCVTargetLowering : public TargetLowering {
141141
Type *Ty) const override {
142142
return true;
143143
}
144+
145+
template <class NodeTy>
146+
SDValue getAddr(NodeTy *N, SelectionDAG &DAG) const;
147+
144148
SDValue lowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
145149
SDValue lowerBlockAddress(SDValue Op, SelectionDAG &DAG) const;
146150
SDValue lowerConstantPool(SDValue Op, SelectionDAG &DAG) const;

llvm/lib/Target/RISCV/RISCVInstrInfo.cpp

+1
Original file line numberDiff line numberDiff line change
@@ -438,6 +438,7 @@ unsigned RISCVInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
438438
return 0;
439439
case RISCV::PseudoCALL:
440440
case RISCV::PseudoTAIL:
441+
case RISCV::PseudoLLA:
441442
return 8;
442443
case TargetOpcode::INLINEASM:
443444
case TargetOpcode::INLINEASM_BR: {

llvm/lib/Target/RISCV/RISCVMCInstLower.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,12 @@ static MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym,
4242
case RISCVII::MO_HI:
4343
Kind = RISCVMCExpr::VK_RISCV_HI;
4444
break;
45+
case RISCVII::MO_PCREL_LO:
46+
Kind = RISCVMCExpr::VK_RISCV_PCREL_LO;
47+
break;
48+
case RISCVII::MO_PCREL_HI:
49+
Kind = RISCVMCExpr::VK_RISCV_PCREL_HI;
50+
break;
4551
}
4652

4753
const MCExpr *ME =

llvm/lib/Target/RISCV/Utils/RISCVBaseInfo.h

+1
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,7 @@ enum {
5050
MO_None,
5151
MO_LO,
5252
MO_HI,
53+
MO_PCREL_LO,
5354
MO_PCREL_HI,
5455
};
5556
} // namespace RISCVII
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
2+
; RUN: llc -mtriple=riscv32 -mattr=+f -code-model=small -verify-machineinstrs < %s \
3+
; RUN: | FileCheck %s -check-prefix=RV32I-SMALL
4+
; RUN: llc -mtriple=riscv32 -mattr=+f -code-model=medium -verify-machineinstrs < %s \
5+
; RUN: | FileCheck %s -check-prefix=RV32I-MEDIUM
6+
7+
; Check lowering of globals
8+
@G = global i32 0
9+
10+
define i32 @lower_global(i32 %a) nounwind {
11+
; RV32I-SMALL-LABEL: lower_global:
12+
; RV32I-SMALL: # %bb.0:
13+
; RV32I-SMALL-NEXT: lui a0, %hi(G)
14+
; RV32I-SMALL-NEXT: lw a0, %lo(G)(a0)
15+
; RV32I-SMALL-NEXT: ret
16+
;
17+
; RV32I-MEDIUM-LABEL: lower_global:
18+
; RV32I-MEDIUM: # %bb.0:
19+
; RV32I-MEDIUM-NEXT: .LBB0_1: # Label of block must be emitted
20+
; RV32I-MEDIUM-NEXT: auipc a0, %pcrel_hi(G)
21+
; RV32I-MEDIUM-NEXT: addi a0, a0, %pcrel_lo(.LBB0_1)
22+
; RV32I-MEDIUM-NEXT: lw a0, 0(a0)
23+
; RV32I-MEDIUM-NEXT: ret
24+
%1 = load volatile i32, i32* @G
25+
ret i32 %1
26+
}
27+
28+
; Check lowering of blockaddresses
29+
30+
@addr = global i8* null
31+
32+
define void @lower_blockaddress() nounwind {
33+
; RV32I-SMALL-LABEL: lower_blockaddress:
34+
; RV32I-SMALL: # %bb.0:
35+
; RV32I-SMALL-NEXT: lui a0, %hi(addr)
36+
; RV32I-SMALL-NEXT: addi a1, zero, 1
37+
; RV32I-SMALL-NEXT: sw a1, %lo(addr)(a0)
38+
; RV32I-SMALL-NEXT: ret
39+
;
40+
; RV32I-MEDIUM-LABEL: lower_blockaddress:
41+
; RV32I-MEDIUM: # %bb.0:
42+
; RV32I-MEDIUM-NEXT: .LBB1_1: # Label of block must be emitted
43+
; RV32I-MEDIUM-NEXT: auipc a0, %pcrel_hi(addr)
44+
; RV32I-MEDIUM-NEXT: addi a0, a0, %pcrel_lo(.LBB1_1)
45+
; RV32I-MEDIUM-NEXT: addi a1, zero, 1
46+
; RV32I-MEDIUM-NEXT: sw a1, 0(a0)
47+
; RV32I-MEDIUM-NEXT: ret
48+
store volatile i8* blockaddress(@lower_blockaddress, %block), i8** @addr
49+
ret void
50+
51+
block:
52+
unreachable
53+
}
54+
55+
; Check lowering of constantpools
56+
57+
define float @lower_constantpool(float %a) nounwind {
58+
; RV32I-SMALL-LABEL: lower_constantpool:
59+
; RV32I-SMALL: # %bb.0:
60+
; RV32I-SMALL-NEXT: fmv.w.x ft0, a0
61+
; RV32I-SMALL-NEXT: lui a0, %hi(.LCPI2_0)
62+
; RV32I-SMALL-NEXT: addi a0, a0, %lo(.LCPI2_0)
63+
; RV32I-SMALL-NEXT: flw ft1, 0(a0)
64+
; RV32I-SMALL-NEXT: fadd.s ft0, ft0, ft1
65+
; RV32I-SMALL-NEXT: fmv.x.w a0, ft0
66+
; RV32I-SMALL-NEXT: ret
67+
;
68+
; RV32I-MEDIUM-LABEL: lower_constantpool:
69+
; RV32I-MEDIUM: # %bb.0:
70+
; RV32I-MEDIUM-NEXT: .LBB2_1: # Label of block must be emitted
71+
; RV32I-MEDIUM-NEXT: auipc a1, %pcrel_hi(.LCPI2_0)
72+
; RV32I-MEDIUM-NEXT: addi a1, a1, %pcrel_lo(.LBB2_1)
73+
; RV32I-MEDIUM-NEXT: flw ft0, 0(a1)
74+
; RV32I-MEDIUM-NEXT: fmv.w.x ft1, a0
75+
; RV32I-MEDIUM-NEXT: fadd.s ft0, ft1, ft0
76+
; RV32I-MEDIUM-NEXT: fmv.x.w a0, ft0
77+
; RV32I-MEDIUM-NEXT: ret
78+
%1 = fadd float %a, 1.0
79+
ret float %1
80+
}

0 commit comments

Comments
 (0)