LLVM 23.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/STLExtras.h"
36#include "llvm/ADT/Statistic.h"
37#include "llvm/CodeGen/Passes.h"
40#include "llvm/Support/Debug.h"
42
43using namespace llvm;
44
45#define DEBUG_TYPE "riscv-qc-relax-marking"
46#define RISCV_QC_RELAX_MARKING_NAME "RISC-V QC Relaxation Marking"
47
48STATISTIC(NumMarked, "Number of Loads/Stores Marked");
49
50namespace {
51
52struct RISCVQCRelaxMarking : public MachineFunctionPass {
53 static char ID;
54
55 bool runOnMachineFunction(MachineFunction &) override;
56
57 RISCVQCRelaxMarking() : MachineFunctionPass(ID) {}
58
59 StringRef getPassName() const override { return RISCV_QC_RELAX_MARKING_NAME; }
60};
61
62} // end namespace
63
64char RISCVQCRelaxMarking::ID = 0;
65
67 false, false)
68
69/// Returns an instance of the Make Compressible Optimization pass.
71 return new RISCVQCRelaxMarking();
72}
73
74static bool isUImm7LSB000(const MachineOperand &MO) {
75 return MO.isImm() && isShiftedUInt<4, 3>(MO.getImm());
76}
77
78static bool isUImm2LSB0(const MachineOperand &MO) {
79 return MO.isImm() && isShiftedUInt<1, 1>(MO.getImm());
80}
81
82static bool isUImm2(const MachineOperand &MO) {
83 return MO.isImm() && isUInt<2>(MO.getImm());
84}
85
86static bool isGPRC(const MachineOperand &MO) {
87 return RISCV::GPRCRegClass.contains(MO.getReg());
88}
89
90static unsigned getQCMarkedOpcode(const MachineInstr &MI,
91 const RISCVSubtarget &STI) {
92 switch (MI.getOpcode()) {
93 case RISCV::LB:
94 // No c.lb
95 return RISCV::PseudoQCAccessLB;
96 case RISCV::LBU:
97 if (STI.hasStdExtZcb() && isGPRC(MI.getOperand(0)) &&
98 isGPRC(MI.getOperand(1)) && isUImm2(MI.getOperand(2)))
99 return RISCV::PseudoQCAccessC_LBU;
100 return RISCV::PseudoQCAccessLBU;
101 case RISCV::LH:
102 if (STI.hasStdExtZcb() && isGPRC(MI.getOperand(0)) &&
103 isGPRC(MI.getOperand(1)) && isUImm2LSB0(MI.getOperand(2)))
104 return RISCV::PseudoQCAccessC_LH;
105 return RISCV::PseudoQCAccessLH;
106 case RISCV::LHU:
107 if (STI.hasStdExtZcb() && isGPRC(MI.getOperand(0)) &&
108 isGPRC(MI.getOperand(1)) && isUImm2LSB0(MI.getOperand(2)))
109 return RISCV::PseudoQCAccessC_LHU;
110 return RISCV::PseudoQCAccessLHU;
111 case RISCV::LW:
112 if (STI.hasStdExtZca() && isGPRC(MI.getOperand(0)) &&
113 isGPRC(MI.getOperand(1)) && isUImm7LSB000(MI.getOperand(2)))
114 return RISCV::PseudoQCAccessC_LW;
115 return RISCV::PseudoQCAccessLW;
116 case RISCV::SB:
117 if (STI.hasStdExtZcb() && isGPRC(MI.getOperand(0)) &&
118 isGPRC(MI.getOperand(1)) && isUImm2(MI.getOperand(2)))
119 return RISCV::PseudoQCAccessC_SB;
120 return RISCV::PseudoQCAccessSB;
121 case RISCV::SH:
122 if (STI.hasStdExtZcb() && isGPRC(MI.getOperand(0)) &&
123 isGPRC(MI.getOperand(1)) && isUImm2LSB0(MI.getOperand(2)))
124 return RISCV::PseudoQCAccessC_SH;
125 return RISCV::PseudoQCAccessSH;
126 case RISCV::SW:
127 if (STI.hasStdExtZca() && isGPRC(MI.getOperand(0)) &&
128 isGPRC(MI.getOperand(1)) && isUImm7LSB000(MI.getOperand(2)))
129 return RISCV::PseudoQCAccessC_SW;
130 return RISCV::PseudoQCAccessSW;
131 default:
133 "Unhandled Opcode: No Corresponding Marked Opcode");
134 }
135}
136
137bool RISCVQCRelaxMarking::runOnMachineFunction(MachineFunction &MF) {
138 if (skipFunction(MF.getFunction()))
139 return false;
140
141 // This is only relevant for QC.E.LI with a symbol, which we only use in the
142 // small code model.
144 return false;
145
146 auto &STI = MF.getSubtarget<RISCVSubtarget>();
147 // We need QC.E.LI instructions to perform this optimisation, which needs
148 // 32-bit and Xqcili. The markers are only needed when linker relaxations are
149 // enabled.
150 if (STI.is64Bit() || !STI.hasVendorXqcili() || !STI.enableLinkerRelax())
151 return false;
152
153 const RISCVInstrInfo *TII = STI.getInstrInfo();
154
155 bool Changed = false;
156 for (MachineBasicBlock &MBB : MF) {
157 for (auto MI = MBB.begin(), E = MBB.end(); MI != E; MI++) {
158 auto NextMI = std::next(MI);
159 if (NextMI == E)
160 break;
161
162 // Looking for QC.E.LI followed by a load or store
163 if (MI->getOpcode() != RISCV::QC_E_LI ||
164 !(RISCVInstrInfo::isBaseLoad(*NextMI) ||
165 RISCVInstrInfo::isBaseStore(*NextMI)))
166 continue;
167
168 LLVM_DEBUG(dbgs() << "Found QC_E_LI " << *MI);
169 LLVM_DEBUG(dbgs() << "Followed by Load/Store " << *NextMI);
170
171 if (MI->getOperand(0).getReg() != NextMI->getOperand(1).getReg())
172 continue;
173 if (!NextMI->getOperand(1).isKill())
174 continue;
175
176 // This is unsafe for stores where the access address is being stored.
177 if (RISCVInstrInfo::isBaseStore(*NextMI) &&
178 MI->getOperand(0).getReg() == NextMI->getOperand(0).getReg())
179 continue;
180
181 MachineOperand &SymOp = MI->getOperand(1);
182 if (!SymOp.isSymbol() && !SymOp.isGlobal() && !SymOp.isMCSymbol() &&
183 !SymOp.isCPI())
184 continue;
185
186 unsigned NewOpc = getQCMarkedOpcode(*NextMI, STI);
187 LLVM_DEBUG(dbgs() << "Load/Store " << TII->getName(NextMI->getOpcode())
188 << " will become " << TII->getName(NewOpc) << "\n");
189 MachineInstrBuilder MIB =
190 BuildMI(MBB, NextMI, NextMI->getDebugLoc(), TII->get(NewOpc))
191 .add(NextMI->getOperand(0))
192 .add(NextMI->getOperand(1))
193 .add(NextMI->getOperand(2))
194 .cloneMemRefs(*NextMI);
195
196 if (SymOp.isSymbol()) {
198 } else if (SymOp.isGlobal()) {
199 MIB.addGlobalAddress(SymOp.getGlobal(), SymOp.getOffset(),
201 } else if (SymOp.isMCSymbol()) {
202 MachineOperand MO = MachineOperand::CreateMCSymbol(
204 MO.setOffset(SymOp.getOffset());
205 MIB.add(MO);
206 } else if (SymOp.isCPI()) {
207 MIB.addConstantPoolIndex(SymOp.getIndex(), SymOp.getOffset(),
209 } else {
210 reportFatalInternalError("Unhandled SymOp Kind");
211 }
212
213 NextMI->removeFromParent();
214 NumMarked++;
215 Changed |= true;
216 }
217 }
218
219 return Changed;
220}
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 isUImm2(const MachineOperand &MO)
static bool isUImm7LSB000(const MachineOperand &MO)
This file declares the machine register scavenger class.
This file contains some templates that are useful if you are working with the STL at all.
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
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
MachineFunctionPass - This class adapts the FunctionPass interface to allow convenient creation of pa...
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.
CodeModel::Model getCodeModel() const
Returns the code model.
Changed
unsigned ID
LLVM IR allows to use arbitrary numbers as calling convention identifiers.
Definition CallingConv.h:24
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.
LLVM_ABI void reportFatalInternalError(Error Err)
Report a fatal error that indicates a bug in LLVM.
Definition Error.cpp:173
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
constexpr bool isUInt(uint64_t x)
Checks if an unsigned integer fits into the given bit width.
Definition MathExtras.h:189
constexpr bool isShiftedUInt(uint64_t x)
Checks if a unsigned integer is an N bit number shifted left by S.
Definition MathExtras.h:198
FunctionPass * createRISCVQCRelaxMarkingPass()