Skip to content

Commit 338c74c

Browse files
asbDisasm
authored andcommitted
[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 ff06710 commit 338c74c

File tree

9 files changed

+205
-36
lines changed

9 files changed

+205
-36
lines changed

llvm/include/llvm/CodeGen/MachineBasicBlock.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,10 @@ class MachineBasicBlock
115115
/// branch.
116116
bool AddressTaken = false;
117117

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

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

llvm/lib/CodeGen/AsmPrinter/AsmPrinter.cpp

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2922,13 +2922,16 @@ void AsmPrinter::EmitBasicBlockStart(const MachineBasicBlock &MBB) const {
29222922

29232923
// Print the main label for the block.
29242924
if (MBB.pred_empty() ||
2925-
(isBlockOnlyReachableByFallthrough(&MBB) && !MBB.isEHFuncletEntry())) {
2925+
(isBlockOnlyReachableByFallthrough(&MBB) && !MBB.isEHFuncletEntry() &&
2926+
!MBB.hasLabelMustBeEmitted())) {
29262927
if (isVerbose()) {
29272928
// NOTE: Want this comment at start of line, don't emit with AddComment.
29282929
OutStreamer->emitRawComment(" %bb." + Twine(MBB.getNumber()) + ":",
29292930
false);
29302931
}
29312932
} else {
2933+
if (isVerbose() && MBB.hasLabelMustBeEmitted())
2934+
OutStreamer->AddComment("Label of block must be emitted");
29322935
OutStreamer->EmitLabel(MBB.getSymbol());
29332936
}
29342937
}

llvm/lib/Target/RISCV/RISCVExpandPseudoInsts.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,9 @@ class RISCVExpandPseudo : public MachineFunctionPass {
5555
bool expandAtomicCmpXchg(MachineBasicBlock &MBB,
5656
MachineBasicBlock::iterator MBBI, bool IsMasked,
5757
int Width, MachineBasicBlock::iterator &NextMBBI);
58+
bool expandLoadLocalAddress(MachineBasicBlock &MBB,
59+
MachineBasicBlock::iterator MBBI,
60+
MachineBasicBlock::iterator &NextMBBI);
5861
};
5962

6063
char RISCVExpandPseudo::ID = 0;
@@ -118,6 +121,8 @@ bool RISCVExpandPseudo::expandMI(MachineBasicBlock &MBB,
118121
return expandAtomicCmpXchg(MBB, MBBI, false, 64, NextMBBI);
119122
case RISCV::PseudoMaskedCmpXchg32:
120123
return expandAtomicCmpXchg(MBB, MBBI, true, 32, NextMBBI);
124+
case RISCV::PseudoLLA:
125+
return expandLoadLocalAddress(MBB, MBBI, NextMBBI);
121126
}
122127

123128
return false;
@@ -598,6 +603,46 @@ bool RISCVExpandPseudo::expandAtomicCmpXchg(
598603
return true;
599604
}
600605

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

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

llvm/lib/Target/RISCV/RISCVISelLowering.cpp

Lines changed: 53 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -356,72 +356,90 @@ SDValue RISCVTargetLowering::LowerOperation(SDValue Op,
356356
}
357357
}
358358

359+
static SDValue getTargetNode(GlobalAddressSDNode *N, SDLoc DL, EVT Ty,
360+
SelectionDAG &DAG, unsigned Flags) {
361+
return DAG.getTargetGlobalAddress(N->getGlobal(), DL, Ty, 0, Flags);
362+
}
363+
364+
static SDValue getTargetNode(BlockAddressSDNode *N, SDLoc DL, EVT Ty,
365+
SelectionDAG &DAG, unsigned Flags) {
366+
return DAG.getTargetBlockAddress(N->getBlockAddress(), Ty, N->getOffset(),
367+
Flags);
368+
}
369+
370+
static SDValue getTargetNode(ConstantPoolSDNode *N, SDLoc DL, EVT Ty,
371+
SelectionDAG &DAG, unsigned Flags) {
372+
return DAG.getTargetConstantPool(N->getConstVal(), Ty, N->getAlignment(),
373+
N->getOffset(), Flags);
374+
}
375+
376+
template <class NodeTy>
377+
SDValue RISCVTargetLowering::getAddr(NodeTy *N, SelectionDAG &DAG) const {
378+
SDLoc DL(N);
379+
EVT Ty = getPointerTy(DAG.getDataLayout());
380+
381+
switch (getTargetMachine().getCodeModel()) {
382+
default:
383+
report_fatal_error("Unsupported code model for lowering");
384+
case CodeModel::Small: {
385+
// Generate a sequence for accessing addresses within the first 2 GiB of
386+
// address space. This generates the pattern (addi (lui %hi(sym)) %lo(sym)).
387+
SDValue AddrHi = getTargetNode(N, DL, Ty, DAG, RISCVII::MO_HI);
388+
SDValue AddrLo = getTargetNode(N, DL, Ty, DAG, RISCVII::MO_LO);
389+
SDValue MNHi = SDValue(DAG.getMachineNode(RISCV::LUI, DL, Ty, AddrHi), 0);
390+
return SDValue(DAG.getMachineNode(RISCV::ADDI, DL, Ty, MNHi, AddrLo), 0);
391+
}
392+
case CodeModel::Medium: {
393+
// Generate a sequence for accessing addresses within any 2GiB range within
394+
// the address space. This generates the pattern (PseudoLLA sym), which
395+
// expands to (addi (auipc %pcrel_hi(sym)) %pcrel_lo(auipc)).
396+
SDValue Addr = getTargetNode(N, DL, Ty, DAG, 0);
397+
return SDValue(DAG.getMachineNode(RISCV::PseudoLLA, DL, Ty, Addr), 0);
398+
}
399+
}
400+
}
401+
359402
SDValue RISCVTargetLowering::lowerGlobalAddress(SDValue Op,
360403
SelectionDAG &DAG) const {
361404
SDLoc DL(Op);
362405
EVT Ty = Op.getValueType();
363406
GlobalAddressSDNode *N = cast<GlobalAddressSDNode>(Op);
364-
const GlobalValue *GV = N->getGlobal();
365407
int64_t Offset = N->getOffset();
366408
MVT XLenVT = Subtarget.getXLenVT();
367409

368410
if (isPositionIndependent())
369411
report_fatal_error("Unable to lowerGlobalAddress");
412+
413+
SDValue Addr = getAddr(N, DAG);
414+
370415
// In order to maximise the opportunity for common subexpression elimination,
371416
// emit a separate ADD node for the global address offset instead of folding
372417
// it in the global address node. Later peephole optimisations may choose to
373418
// fold it back in when profitable.
374-
SDValue GAHi = DAG.getTargetGlobalAddress(GV, DL, Ty, 0, RISCVII::MO_HI);
375-
SDValue GALo = DAG.getTargetGlobalAddress(GV, DL, Ty, 0, RISCVII::MO_LO);
376-
SDValue MNHi = SDValue(DAG.getMachineNode(RISCV::LUI, DL, Ty, GAHi), 0);
377-
SDValue MNLo =
378-
SDValue(DAG.getMachineNode(RISCV::ADDI, DL, Ty, MNHi, GALo), 0);
379419
if (Offset != 0)
380-
return DAG.getNode(ISD::ADD, DL, Ty, MNLo,
420+
return DAG.getNode(ISD::ADD, DL, Ty, Addr,
381421
DAG.getConstant(Offset, DL, XLenVT));
382-
return MNLo;
422+
return Addr;
383423
}
384424

385425
SDValue RISCVTargetLowering::lowerBlockAddress(SDValue Op,
386426
SelectionDAG &DAG) const {
387-
SDLoc DL(Op);
388-
EVT Ty = Op.getValueType();
389427
BlockAddressSDNode *N = cast<BlockAddressSDNode>(Op);
390-
const BlockAddress *BA = N->getBlockAddress();
391-
int64_t Offset = N->getOffset();
392428

393429
if (isPositionIndependent())
394430
report_fatal_error("Unable to lowerBlockAddress");
395431

396-
SDValue BAHi = DAG.getTargetBlockAddress(BA, Ty, Offset, RISCVII::MO_HI);
397-
SDValue BALo = DAG.getTargetBlockAddress(BA, Ty, Offset, RISCVII::MO_LO);
398-
SDValue MNHi = SDValue(DAG.getMachineNode(RISCV::LUI, DL, Ty, BAHi), 0);
399-
SDValue MNLo =
400-
SDValue(DAG.getMachineNode(RISCV::ADDI, DL, Ty, MNHi, BALo), 0);
401-
return MNLo;
432+
return getAddr(N, DAG);
402433
}
403434

404435
SDValue RISCVTargetLowering::lowerConstantPool(SDValue Op,
405436
SelectionDAG &DAG) const {
406-
SDLoc DL(Op);
407-
EVT Ty = Op.getValueType();
408437
ConstantPoolSDNode *N = cast<ConstantPoolSDNode>(Op);
409-
const Constant *CPA = N->getConstVal();
410-
int64_t Offset = N->getOffset();
411-
unsigned Alignment = N->getAlignment();
412-
413-
if (!isPositionIndependent()) {
414-
SDValue CPAHi =
415-
DAG.getTargetConstantPool(CPA, Ty, Alignment, Offset, RISCVII::MO_HI);
416-
SDValue CPALo =
417-
DAG.getTargetConstantPool(CPA, Ty, Alignment, Offset, RISCVII::MO_LO);
418-
SDValue MNHi = SDValue(DAG.getMachineNode(RISCV::LUI, DL, Ty, CPAHi), 0);
419-
SDValue MNLo =
420-
SDValue(DAG.getMachineNode(RISCV::ADDI, DL, Ty, MNHi, CPALo), 0);
421-
return MNLo;
422-
} else {
438+
439+
if (isPositionIndependent())
423440
report_fatal_error("Unable to lowerConstantPool");
424-
}
441+
442+
return getAddr(N, DAG);
425443
}
426444

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

llvm/lib/Target/RISCV/RISCVISelLowering.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,10 @@ class RISCVTargetLowering : public TargetLowering {
134134
Type *Ty) const override {
135135
return true;
136136
}
137+
138+
template <class NodeTy>
139+
SDValue getAddr(NodeTy *N, SelectionDAG &DAG) const;
140+
137141
SDValue lowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const;
138142
SDValue lowerBlockAddress(SDValue Op, SelectionDAG &DAG) const;
139143
SDValue lowerConstantPool(SDValue Op, SelectionDAG &DAG) const;

llvm/lib/Target/RISCV/RISCVInstrInfo.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -439,6 +439,7 @@ unsigned RISCVInstrInfo::getInstSizeInBytes(const MachineInstr &MI) const {
439439
return 0;
440440
case RISCV::PseudoCALL:
441441
case RISCV::PseudoTAIL:
442+
case RISCV::PseudoLLA:
442443
return 8;
443444
case TargetOpcode::INLINEASM: {
444445
const MachineFunction &MF = *MI.getParent()->getParent();

llvm/lib/Target/RISCV/RISCVMCInstLower.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,12 @@ static MCOperand lowerSymbolOperand(const MachineOperand &MO, MCSymbol *Sym,
4343
case RISCVII::MO_HI:
4444
Kind = RISCVMCExpr::VK_RISCV_HI;
4545
break;
46+
case RISCVII::MO_PCREL_LO:
47+
Kind = RISCVMCExpr::VK_RISCV_PCREL_LO;
48+
break;
49+
case RISCVII::MO_PCREL_HI:
50+
Kind = RISCVMCExpr::VK_RISCV_PCREL_HI;
51+
break;
4652
}
4753

4854
const MCExpr *ME =

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,7 @@ enum {
5151
MO_None,
5252
MO_LO,
5353
MO_HI,
54+
MO_PCREL_LO,
5455
MO_PCREL_HI,
5556
};
5657
} // namespace RISCVII
Lines changed: 80 additions & 0 deletions
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)