LLVM 24.0.0git
RISCVQCRelaxMarking.cpp
Go to the documentation of this file.
1//===-- RISCVQCRelaxMarking.cpp - Mark Instructions for QC Relaxations ----===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This pass adds access tags to some instructions which are used by the
10// assembler to emit marker relocations, which enable some code-size relaxations
11// for Xqcilo/Xqcili.
12//
13// The pass is looking for the following sequences:
14//
15// $dst1 = QC_E_LI sym
16// $dst2 = Load killed $dst1, 0
17//
18// $dst1 = QC_E_LI sym
19// Store $dst2, killed $dst1, 0
20//
21// In either case, the Load/Store is modified to become a
22// PseudoQCAccess<Load/Store>, with an additional operand that represents the
23// accessed symbolic address, which will become the contents of a
24// `R_RISCV_QC_ACCESS_*` relocation on the emitted instruction.
25//
26// FIXME: The intention is this pass does not change the size of any
27// instructions, but right now it has to do instruction compression as the
28// CompressPat infrastructure cannot handle compressing the `%qc.access(...)`
29// operand. Symbolic operands are not usually compressible, but this one is as
30// we have relocations for both 32-bit and 16-bit instructions (and the
31// relocation does not care about the fields of the instruction).
32
33#include "RISCV.h"
34#include "RISCVSubtarget.h"
35#include "llvm/ADT/Statistic.h"
38#include "llvm/CodeGen/Passes.h"
40#include "llvm/IR/Analysis.h"
42#include "llvm/Pass.h"
43#include "llvm/Support/Debug.h"
45
46using namespace llvm;
47
48#define DEBUG_TYPE "riscv-qc-relax-marking"
49#define RISCV_QC_RELAX_MARKING_NAME "RISC-V QC Relaxation Marking"
50
51STATISTIC(NumMarked, "Number of Loads/Stores Marked");
52
53namespace {
54
55struct RISCVQCRelaxMarkingLegacy : public MachineFunctionPass {
56 static char ID;
57
58 bool runOnMachineFunction(MachineFunction &) override;
59
60 RISCVQCRelaxMarkingLegacy() : MachineFunctionPass(ID) {}
61
62 StringRef getPassName() const override { return RISCV_QC_RELAX_MARKING_NAME; }
63
64 void getAnalysisUsage(AnalysisUsage &AU) const override {
65 AU.setPreservesCFG();
67 }
68};
69
70} // end namespace
71
72char RISCVQCRelaxMarkingLegacy::ID = 0;
73
74INITIALIZE_PASS(RISCVQCRelaxMarkingLegacy, DEBUG_TYPE,
75 RISCV_QC_RELAX_MARKING_NAME, false, false)
76
77/// Returns an instance of the Make Compressible Optimization pass.
79 return new RISCVQCRelaxMarkingLegacy();
80}
81
82static bool isUImm7LSB000(const MachineOperand &MO) {
83 return MO.isImm() && isShiftedUInt<4, 3>(MO.getImm());
84}
85
86static bool isUImm2LSB0(const MachineOperand &MO) {
87 return MO.isImm() && isShiftedUInt<1, 1>(MO.getImm());
88}
89
90static bool isUImm2(const MachineOperand &MO) {
91 return MO.isImm() && isUInt<2>(MO.getImm());
92}
93
94static bool isGPRC(const MachineOperand &MO) {
95 return RISCV::GPRCRegClass.contains(MO.getReg());
96}
97
98static unsigned getQCMarkedOpcode(const MachineInstr &MI,
99 const RISCVSubtarget &STI) {
100 switch (MI.getOpcode()) {
101 case RISCV::LB:
102 // No c.lb
103 return RISCV::PseudoQCAccessLB;
104 case RISCV::LBU:
105 if (STI.hasStdExtZcb() && isGPRC(MI.getOperand(0)) &&
106 isGPRC(MI.getOperand(1)) && isUImm2(MI.getOperand(2)))
107 return RISCV::PseudoQCAccessC_LBU;
108 return RISCV::PseudoQCAccessLBU;
109 case RISCV::LH:
110 if (STI.hasStdExtZcb() && isGPRC(MI.getOperand(0)) &&
111 isGPRC(MI.getOperand(1)) && isUImm2LSB0(MI.getOperand(2)))
112 return RISCV::PseudoQCAccessC_LH;
113 return RISCV::PseudoQCAccessLH;
114 case RISCV::LHU:
115 if (STI.hasStdExtZcb() && isGPRC(MI.getOperand(0)) &&
116 isGPRC(MI.getOperand(1)) && isUImm2LSB0(MI.getOperand(2)))
117 return RISCV::PseudoQCAccessC_LHU;
118 return RISCV::PseudoQCAccessLHU;
119 case RISCV::LW:
120 if (STI.hasStdExtZca() && isGPRC(MI.getOperand(0)) &&
121 isGPRC(MI.getOperand(1)) && isUImm7LSB000(MI.getOperand(2)))
122 return RISCV::PseudoQCAccessC_LW;
123 return RISCV::PseudoQCAccessLW;
124 case RISCV::SB:
125 if (STI.hasStdExtZcb() && isGPRC(MI.getOperand(0)) &&
126 isGPRC(MI.getOperand(1)) && isUImm2(MI.getOperand(2)))
127 return RISCV::PseudoQCAccessC_SB;
128 return RISCV::PseudoQCAccessSB;
129 case RISCV::SH:
130 if (STI.hasStdExtZcb() && isGPRC(MI.getOperand(0)) &&
131 isGPRC(MI.getOperand(1)) && isUImm2LSB0(MI.getOperand(2)))
132 return RISCV::PseudoQCAccessC_SH;
133 return RISCV::PseudoQCAccessSH;
134 case RISCV::SW:
135 if (STI.hasStdExtZca() && isGPRC(MI.getOperand(0)) &&
136 isGPRC(MI.getOperand(1)) && isUImm7LSB000(MI.getOperand(2)))
137 return RISCV::PseudoQCAccessC_SW;
138 return RISCV::PseudoQCAccessSW;
139 default:
141 "Unhandled Opcode: No Corresponding Marked Opcode");
142 }
143}
144
146 // This is only relevant for QC.E.LI with a symbol, which we only use in the
147 // small code model.
149 return false;
150
151 auto &STI = MF.getSubtarget<RISCVSubtarget>();
152 // We need QC.E.LI instructions to perform this optimisation, which needs
153 // 32-bit and Xqcili. The markers are only needed when linker relaxations are
154 // enabled.
155 if (STI.is64Bit() || !STI.hasVendorXqcili() || !STI.enableLinkerRelax())
156 return false;
157
158 const RISCVInstrInfo *TII = STI.getInstrInfo();
159
160 bool Changed = false;
161 for (MachineBasicBlock &MBB : MF) {
162 for (auto MI = MBB.begin(), E = MBB.end(); MI != E; MI++) {
163 auto NextMI = std::next(MI);
164 if (NextMI == E)
165 break;
166
167 // Looking for QC.E.LI followed by a load or store
168 if (MI->getOpcode() != RISCV::QC_E_LI ||
169 !(RISCVInstrInfo::isBaseLoad(*NextMI) ||
170 RISCVInstrInfo::isBaseStore(*NextMI)))
171 continue;
172
173 LLVM_DEBUG(dbgs() << "Found QC_E_LI " << *MI);
174 LLVM_DEBUG(dbgs() << "Followed by Load/Store " << *NextMI);
175
176 if (MI->getOperand(0).getReg() != NextMI->getOperand(1).getReg())
177 continue;
178 if (!NextMI->getOperand(1).isKill())
179 continue;
180
181 // This is unsafe for stores where the access address is being stored.
182 if (RISCVInstrInfo::isBaseStore(*NextMI) &&
183 MI->getOperand(0).getReg() == NextMI->getOperand(0).getReg())
184 continue;
185
186 MachineOperand &SymOp = MI->getOperand(1);
187 if (!SymOp.isSymbol() && !SymOp.isGlobal() && !SymOp.isMCSymbol() &&
188 !SymOp.isCPI())
189 continue;
190
191 unsigned NewOpc = getQCMarkedOpcode(*NextMI, STI);
192 LLVM_DEBUG(dbgs() << "Load/Store " << TII->getName(NextMI->getOpcode())
193 << " will become " << TII->getName(NewOpc) << "\n");
195 BuildMI(MBB, NextMI, NextMI->getDebugLoc(), TII->get(NewOpc))
196 .add(NextMI->getOperand(0))
197 .add(NextMI->getOperand(1))
198 .add(NextMI->getOperand(2))
199 .cloneMemRefs(*NextMI);
200
201 if (SymOp.isSymbol()) {
203 } else if (SymOp.isGlobal()) {
204 MIB.addGlobalAddress(SymOp.getGlobal(), SymOp.getOffset(),
206 } else if (SymOp.isMCSymbol()) {
209 MO.setOffset(SymOp.getOffset());
210 MIB.add(MO);
211 } else if (SymOp.isCPI()) {
212 MIB.addConstantPoolIndex(SymOp.getIndex(), SymOp.getOffset(),
214 } else {
215 reportFatalInternalError("Unhandled SymOp Kind");
216 }
217
218 NextMI->removeFromParent();
219 NumMarked++;
220 Changed |= true;
221 }
222 }
223
224 return Changed;
225}
226
227bool RISCVQCRelaxMarkingLegacy::runOnMachineFunction(MachineFunction &MF) {
228 if (skipFunction(MF.getFunction()))
229 return false;
230 return runQCRelaxMarking(MF);
231}
232
233PreservedAnalyses
MachineBasicBlock & MBB
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
#define DEBUG_TYPE
const HexagonInstrInfo * TII
IRTranslator LLVM IR MI
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
static bool isGPRC(const MachineOperand &MO)
static unsigned getQCMarkedOpcode(const MachineInstr &MI, const RISCVSubtarget &STI)
#define RISCV_QC_RELAX_MARKING_NAME
static bool isUImm2LSB0(const MachineOperand &MO)
static bool runQCRelaxMarking(MachineFunction &MF)
static bool isUImm2(const MachineOperand &MO)
static bool isUImm7LSB000(const MachineOperand &MO)
This file declares the machine register scavenger class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
Definition Statistic.h:171
#define LLVM_DEBUG(...)
Definition Debug.h:119
LLVM_ABI void setPreservesCFG()
This function should be called by the pass, iff they do not:
Definition Pass.cpp:280
Represents analyses that only rely on functions' control flow.
Definition Analysis.h:73
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:312
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
void getAnalysisUsage(AnalysisUsage &AU) const override
getAnalysisUsage - Subclasses that override getAnalysisUsage must call this.
const TargetSubtargetInfo & getSubtarget() const
getSubtarget - Return the subtarget for which this machine code is being compiled.
Function & getFunction()
Return the LLVM function that this machine code represents.
const TargetMachine & getTarget() const
getTarget - Return the target machine this machine code is compiled with
const MachineInstrBuilder & addExternalSymbol(const char *FnName, unsigned TargetFlags=0) const
const MachineInstrBuilder & add(const MachineOperand &MO) const
const MachineInstrBuilder & addConstantPoolIndex(unsigned Idx, int Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & addGlobalAddress(const GlobalValue *GV, int64_t Offset=0, unsigned TargetFlags=0) const
const MachineInstrBuilder & cloneMemRefs(const MachineInstr &OtherMI) const
Representation of each machine instruction.
LLVM_ABI MachineInstr * removeFromParent()
Unlink 'this' from the containing basic block, and return it without deleting it.
MachineOperand class - Representation of each machine instruction operand.
static MachineOperand CreateMCSymbol(MCSymbol *Sym, unsigned TargetFlags=0)
const GlobalValue * getGlobal() const
int64_t getImm() const
bool isCPI() const
isCPI - Tests if this is a MO_ConstantPoolIndex operand.
bool isImm() const
isImm - Tests if this is a MO_Immediate operand.
bool isSymbol() const
isSymbol - Tests if this is a MO_ExternalSymbol operand.
void setOffset(int64_t Offset)
bool isGlobal() const
isGlobal - Tests if this is a MO_GlobalAddress operand.
const char * getSymbolName() const
Register getReg() const
getReg - Returns the register number.
MCSymbol * getMCSymbol() const
int64_t getOffset() const
Return the offset from the symbol in this operand.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
Definition Analysis.h:118
PreservedAnalyses & preserveSet()
Mark an analysis set as preserved.
Definition Analysis.h:151
PreservedAnalyses run(MachineFunction &MF, MachineFunctionAnalysisManager &MFAM)
CodeModel::Model getCodeModel() const
Returns the code model.
Pass manager infrastructure for declaring and invalidating analyses.
This is an optimization pass for GlobalISel generic memory operations.
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
AnalysisManager< MachineFunction > MachineFunctionAnalysisManager
LLVM_ABI void reportFatalInternalError(Error Err)
Report a fatal error that indicates a bug in LLVM.
Definition Error.cpp:173
LLVM_ABI PreservedAnalyses getMachineFunctionPassPreservedAnalyses()
Returns the minimum set of Analyses that all machine function passes must preserve.
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
FunctionPass * createRISCVQCRelaxMarkingLegacyPass()
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
Definition MathExtras.h:190
constexpr bool isShiftedUInt(uint64_t x)
Checks if a unsigned integer is an N bit number shifted left by S.
Definition MathExtras.h:199