LLVM 24.0.0git
HexagonHVXSaveRemark.cpp
Go to the documentation of this file.
1//===- HexagonHVXSaveRemark.cpp - Remark on HVX saves around calls --------===//
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// Diagnostic pass that emits optimization remarks when HVX vector registers
10// are live across function calls. All HVX registers are caller-saved
11// (Section 5.3 of the Hexagon ABI), so every HVX value that is live across a
12// call requires a save/restore pair on the stack. Each HVX vector is 64 or
13// 128 bytes (depending on the mode), making this overhead expensive. The
14// remarks help programmers identify call sites where inlining, hoisting, or
15// sinking the call could reduce the save/restore cost.
16//
17// The pass runs before register allocation while values are still in virtual
18// registers. A backward liveness scan over each basic block counts the HVX
19// virtual registers (and their corresponding byte cost) live at each call
20// instruction.
21//
22//===----------------------------------------------------------------------===//
23
24#include "HexagonSubtarget.h"
25#include "llvm/ADT/SmallSet.h"
32#include "llvm/Pass.h"
34#include "llvm/Support/Debug.h"
35
36using namespace llvm;
37
38#define DEBUG_TYPE "hexagon-hvx-save"
39
41 "hexagon-hvx-save-threshold", cl::Hidden, cl::init(128 * 8),
42 cl::desc("Minimum number of bytes of HVX caller-saved register data live "
43 "across a call to trigger a remark (default: 8 x 128-byte "
44 "vectors)"));
45
46namespace {
47
48struct HexagonHVXSaveRemark : public MachineFunctionPass {
49 static char ID;
50
51 HexagonHVXSaveRemark() : MachineFunctionPass(ID) {}
52
53 // Returns the number of HVX vectors represented by VReg: 2 for HvxWR
54 // (vector pair), 1 for HvxVR (single vector), 0 for non-HVX registers.
55 static unsigned hvxVecCount(Register VReg, const MachineRegisterInfo &MRI) {
56 const TargetRegisterClass *RC = MRI.getRegClass(VReg);
57 if (RC == &Hexagon::HvxWRRegClass)
58 return 2;
59 if (RC == &Hexagon::HvxVRRegClass)
60 return 1;
61 return 0;
62 }
63
64 bool runOnMachineFunction(MachineFunction &MF) override {
65 auto &MORE = getAnalysis<MachineOptimizationRemarkEmitterPass>().getORE();
66 if (!MORE.allowExtraAnalysis(DEBUG_TYPE))
67 return false;
68
69 const HexagonSubtarget &HST = MF.getSubtarget<HexagonSubtarget>();
70 if (!HST.useHVXOps())
71 return false;
72
73 const MachineRegisterInfo &MRI = MF.getRegInfo();
74 unsigned HVXLen = HST.getVectorLength();
75
76 // Compute LiveOut[B] for each block: the set of HVX virtual registers
77 // that are live on exit from B. We use a standard backward dataflow
78 // fixed-point:
79 //
80 // LiveIn[B] = UEVar[B] union (LiveOut[B] - Def[B])
81 // LiveOut[B] = union over successors S of LiveIn[S]
82 //
83 // where UEVar[B] is the set of HVX vregs that are used in B before any
84 // definition of that vreg in B (upward-exposed uses), and Def[B] is the
85 // set of HVX vregs defined in B.
86 //
87 // Because MachineBasicBlock::liveins() only contains physical registers,
88 // we cannot seed cross-block virtual register liveness from successor
89 // liveins -- we must compute it ourselves.
90
91 unsigned NumBlocks = MF.getNumBlockIDs();
92 using VRegSet = SmallSet<Register, 8>;
93
94 // Per-block UEVar and Def sets (HVX vregs only).
95 SmallVector<VRegSet, 16> UEVar(NumBlocks), BlockDef(NumBlocks);
96
97 for (const MachineBasicBlock &MBB : MF) {
98 unsigned BN = MBB.getNumber();
99 VRegSet Defs;
100 for (const MachineInstr &MI : MBB) {
101 for (const MachineOperand &MO : MI.operands()) {
102 if (!MO.isReg())
103 continue;
104 Register R = MO.getReg();
105 if (!R.isVirtual() || !hvxVecCount(R, MRI))
106 continue;
107 if (MO.isDef()) {
108 Defs.insert(R);
109 } else if (MO.isUse() && !Defs.count(R)) {
110 UEVar[BN].insert(R); // upward-exposed use
111 }
112 }
113 }
114 BlockDef[BN] = Defs;
115 }
116
117 // LiveOut[B] and LiveIn[B] maps.
118 SmallVector<VRegSet, 16> LiveOut(NumBlocks), LiveIn(NumBlocks);
119
120 // Seed LiveIn from UEVar and iterate until stable.
121 for (unsigned I = 0; I < NumBlocks; ++I)
122 LiveIn[I] = UEVar[I];
123
124 bool Changed = true;
125 while (Changed) {
126 Changed = false;
127 for (const MachineBasicBlock &MBB : MF) {
128 unsigned BN = MBB.getNumber();
129
130 // LiveOut[B] = union of LiveIn[S] for each successor S.
131 VRegSet NewLiveOut;
132 for (const MachineBasicBlock *Succ : MBB.successors())
133 for (Register R : LiveIn[Succ->getNumber()])
134 NewLiveOut.insert(R);
135
136 if (NewLiveOut != LiveOut[BN]) {
137 LiveOut[BN] = NewLiveOut;
138 Changed = true;
139 }
140
141 // LiveIn[B] = UEVar[B] union (LiveOut[B] - Def[B]).
142 VRegSet NewLiveIn = UEVar[BN];
143 for (Register R : LiveOut[BN])
144 if (!BlockDef[BN].count(R))
145 NewLiveIn.insert(R);
146
147 if (NewLiveIn != LiveIn[BN]) {
148 LiveIn[BN] = NewLiveIn;
149 Changed = true;
150 }
151 }
152 }
153
154 // Now do the backward scan over each block, seeded from LiveOut[B].
155 for (const MachineBasicBlock &MBB : MF) {
156 // Backward liveness scan over virtual registers. We track which
157 // virtual registers are live at each point, then at call instructions
158 // count those with HVX register classes.
159 //
160 // When walking backwards:
161 // - a def removes a vreg from the live set
162 // - a use adds a vreg to the live set
163 // At each call, the live set holds vregs live after the call (i.e., the
164 // values that must survive across it and therefore need save/restore).
165 VRegSet LiveVRegs = LiveOut[MBB.getNumber()];
166
167 for (const MachineInstr &MI : llvm::reverse(MBB)) {
168 if (MI.isCall()) {
169 // Count HVX virtual registers live after (and thus across) this
170 // call. HvxVR holds one vector (HVXLen bytes); HvxWR holds two
171 // (2 * HVXLen bytes).
172 unsigned NumVecs = 0;
173 for (Register VReg : LiveVRegs)
174 NumVecs += hvxVecCount(VReg, MRI);
175 unsigned TotalBytes = NumVecs * HVXLen;
176
177 LLVM_DEBUG(dbgs() << "HVXSaveRemark: call in " << MF.getName()
178 << " has " << NumVecs << " HVX vector(s) live ("
179 << TotalBytes << " bytes)\n");
180
181 if (TotalBytes >= HVXSaveThreshold) {
182 MORE.emit([&]() {
183 MachineOptimizationRemarkAnalysis R(
184 DEBUG_TYPE, "HVXSaveAroundCall", MI.getDebugLoc(), &MBB);
185 R << ore::NV("NumVecs", NumVecs)
186 << " HVX caller-saved register(s) ("
187 << ore::NV("TotalBytes", TotalBytes)
188 << " bytes) live across call";
189 return R;
190 });
191 }
192 }
193
194 // Update liveness: defs kill vregs, uses add them.
195 for (const MachineOperand &MO : MI.operands()) {
196 if (!MO.isReg() || !MO.getReg().isVirtual())
197 continue;
198 if (MO.isDef())
199 LiveVRegs.erase(MO.getReg());
200 else if (MO.isUse())
201 LiveVRegs.insert(MO.getReg());
202 }
203 }
204 }
205
206 return false;
207 }
208
209 StringRef getPassName() const override { return "Hexagon HVX Save Remarks"; }
210
211 void getAnalysisUsage(AnalysisUsage &AU) const override {
212 AU.addRequired<MachineOptimizationRemarkEmitterPass>();
213 AU.setPreservesAll();
215 }
216};
217
218char HexagonHVXSaveRemark::ID = 0;
219
220} // end anonymous namespace
221
222INITIALIZE_PASS(HexagonHVXSaveRemark, DEBUG_TYPE, "Hexagon HVX Save Remarks",
223 false, false)
224
226 return new HexagonHVXSaveRemark();
227}
MachineBasicBlock & MBB
#define DEBUG_TYPE
static cl::opt< unsigned > HVXSaveThreshold("hexagon-hvx-save-threshold", cl::Hidden, cl::init(128 *8), cl::desc("Minimum number of bytes of HVX caller-saved register data live " "across a call to trigger a remark (default: 8 x 128-byte " "vectors)"))
#define DEBUG_TYPE
IRTranslator LLVM IR MI
#define I(x, y, z)
Definition MD5.cpp:57
===- MachineOptimizationRemarkEmitter.h - Opt Diagnostics -*- C++ -*-—===//
Promote Memory to Register
Definition Mem2Reg.cpp:110
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
Definition PassSupport.h:56
This file defines the SmallSet class.
This file defines the SmallVector class.
#define LLVM_DEBUG(...)
Definition Debug.h:119
AnalysisUsage & addRequired()
void setPreservesAll()
Set by analyses that do not transform their input at all.
FunctionPass class - This class is used to implement most global optimizations.
Definition Pass.h:314
unsigned getVectorLength() const
int getNumber() const
MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a MachineFuncti...
iterator_range< succ_iterator > successors()
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.
MachineRegisterInfo & getRegInfo()
getRegInfo - Return information about the registers currently in use.
unsigned getNumBlockIDs() const
getNumBlockIDs - Return the number of MBB ID's allocated.
const TargetRegisterClass * getRegClass(Register Reg) const
Return the register class of the specified virtual register.
Changed
initializer< Ty > init(const Ty &Val)
DiagnosticInfoOptimizationBase::Argument NV
This is an optimization pass for GlobalISel generic memory operations.
auto reverse(ContainerTy &&C)
Definition STLExtras.h:407
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
Definition Debug.cpp:209
class LLVM_GSL_OWNER SmallVector
Forward declaration of SmallVector so that calculateSmallVectorDefaultInlinedElements can reference s...
auto count(R &&Range, const E &Element)
Wrapper function around std::count to count the number of times an element Element occurs in the give...
Definition STLExtras.h:2012
FunctionPass * createHexagonHVXSaveRemark()
MCRegisterClass TargetRegisterClass
Definition FastISel.h:58
#define MORE()
Definition regcomp.c:246