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