LLVM 20.0.0git
SwiftErrorValueTracking.cpp
Go to the documentation of this file.
1//===-- SwiftErrorValueTracking.cpp --------------------------------------===//
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 implements a limited mem2reg-like analysis to promote uses of function
10// arguments and allocas marked with swiftalloc from memory into virtual
11// registers tracked by this class.
12//
13//===----------------------------------------------------------------------===//
14
17#include "llvm/ADT/SmallSet.h"
22#include "llvm/IR/Value.h"
23
24using namespace llvm;
25
27 const Value *Val) {
28 auto Key = std::make_pair(MBB, Val);
29 auto It = VRegDefMap.find(Key);
30 // If this is the first use of this swifterror value in this basic block,
31 // create a new virtual register.
32 // After we processed all basic blocks we will satisfy this "upwards exposed
33 // use" by inserting a copy or phi at the beginning of this block.
34 if (It == VRegDefMap.end()) {
35 auto &DL = MF->getDataLayout();
36 const TargetRegisterClass *RC = TLI->getRegClassFor(TLI->getPointerTy(DL));
37 auto VReg = MF->getRegInfo().createVirtualRegister(RC);
38 VRegDefMap[Key] = VReg;
39 VRegUpwardsUse[Key] = VReg;
40 return VReg;
41 } else
42 return It->second;
43}
44
46 const Value *Val, Register VReg) {
47 VRegDefMap[std::make_pair(MBB, Val)] = VReg;
48}
49
51 const Instruction *I, const MachineBasicBlock *MBB, const Value *Val) {
53 auto It = VRegDefUses.find(Key);
54 if (It != VRegDefUses.end())
55 return It->second;
56
57 auto &DL = MF->getDataLayout();
58 const TargetRegisterClass *RC = TLI->getRegClassFor(TLI->getPointerTy(DL));
60 VRegDefUses[Key] = VReg;
61 setCurrentVReg(MBB, Val, VReg);
62 return VReg;
63}
64
66 const Instruction *I, const MachineBasicBlock *MBB, const Value *Val) {
68 auto It = VRegDefUses.find(Key);
69 if (It != VRegDefUses.end())
70 return It->second;
71
72 Register VReg = getOrCreateVReg(MBB, Val);
73 VRegDefUses[Key] = VReg;
74 return VReg;
75}
76
77/// Set up SwiftErrorVals by going through the function. If the function has
78/// swifterror argument, it will be the first entry.
80 MF = &mf;
81 Fn = &MF->getFunction();
82 TLI = MF->getSubtarget().getTargetLowering();
83 TII = MF->getSubtarget().getInstrInfo();
84
85 if (!TLI->supportSwiftError())
86 return;
87
88 SwiftErrorVals.clear();
89 VRegDefMap.clear();
90 VRegUpwardsUse.clear();
91 VRegDefUses.clear();
92 SwiftErrorArg = nullptr;
93
94 // Check if function has a swifterror argument.
95 bool HaveSeenSwiftErrorArg = false;
96 for (Function::const_arg_iterator AI = Fn->arg_begin(), AE = Fn->arg_end();
97 AI != AE; ++AI)
98 if (AI->hasSwiftErrorAttr()) {
99 assert(!HaveSeenSwiftErrorArg &&
100 "Must have only one swifterror parameter");
101 (void)HaveSeenSwiftErrorArg; // silence warning.
102 HaveSeenSwiftErrorArg = true;
103 SwiftErrorArg = &*AI;
104 SwiftErrorVals.push_back(&*AI);
105 }
106
107 for (const auto &LLVMBB : *Fn)
108 for (const auto &Inst : LLVMBB) {
109 if (const AllocaInst *Alloca = dyn_cast<AllocaInst>(&Inst))
110 if (Alloca->isSwiftError())
111 SwiftErrorVals.push_back(Alloca);
112 }
113}
114
116 if (!TLI->supportSwiftError())
117 return false;
118
119 // We only need to do this when we have swifterror parameter or swifterror
120 // alloc.
121 if (SwiftErrorVals.empty())
122 return false;
123
124 MachineBasicBlock *MBB = &*MF->begin();
125 auto &DL = MF->getDataLayout();
126 auto const *RC = TLI->getRegClassFor(TLI->getPointerTy(DL));
127 bool Inserted = false;
128 for (const auto *SwiftErrorVal : SwiftErrorVals) {
129 // We will always generate a copy from the argument. It is always used at
130 // least by the 'return' of the swifterror.
131 if (SwiftErrorArg && SwiftErrorArg == SwiftErrorVal)
132 continue;
134 // Assign Undef to Vreg. We construct MI directly to make sure it works
135 // with FastISel.
136 BuildMI(*MBB, MBB->getFirstNonPHI(), DbgLoc,
137 TII->get(TargetOpcode::IMPLICIT_DEF), VReg);
138
139 setCurrentVReg(MBB, SwiftErrorVal, VReg);
140 Inserted = true;
141 }
142
143 return Inserted;
144}
145
146/// Propagate swifterror values through the machine function CFG.
148 if (!TLI->supportSwiftError())
149 return;
150
151 // We only need to do this when we have swifterror parameter or swifterror
152 // alloc.
153 if (SwiftErrorVals.empty())
154 return;
155
156 // For each machine basic block in reverse post order.
158 for (MachineBasicBlock *MBB : RPOT) {
159 // For each swifterror value in the function.
160 for (const auto *SwiftErrorVal : SwiftErrorVals) {
161 auto Key = std::make_pair(MBB, SwiftErrorVal);
162 auto UUseIt = VRegUpwardsUse.find(Key);
163 auto VRegDefIt = VRegDefMap.find(Key);
164 bool UpwardsUse = UUseIt != VRegUpwardsUse.end();
165 Register UUseVReg = UpwardsUse ? UUseIt->second : Register();
166 bool DownwardDef = VRegDefIt != VRegDefMap.end();
167 assert(!(UpwardsUse && !DownwardDef) &&
168 "We can't have an upwards use but no downwards def");
169
170 // If there is no upwards exposed use and an entry for the swifterror in
171 // the def map for this value we don't need to do anything: We already
172 // have a downward def for this basic block.
173 if (!UpwardsUse && DownwardDef)
174 continue;
175
176 // Otherwise we either have an upwards exposed use vreg that we need to
177 // materialize or need to forward the downward def from predecessors.
178
179 // Check whether we have a single vreg def from all predecessors.
180 // Otherwise we need a phi.
183 for (auto *Pred : MBB->predecessors()) {
184 if (!Visited.insert(Pred).second)
185 continue;
186 VRegs.push_back(std::make_pair(
187 Pred, getOrCreateVReg(Pred, SwiftErrorVal)));
188 if (Pred != MBB)
189 continue;
190 // We have a self-edge.
191 // If there was no upwards use in this basic block there is now one: the
192 // phi needs to use it self.
193 if (!UpwardsUse) {
194 UpwardsUse = true;
195 UUseIt = VRegUpwardsUse.find(Key);
196 assert(UUseIt != VRegUpwardsUse.end());
197 UUseVReg = UUseIt->second;
198 }
199 }
200
201 // We need a phi node if we have more than one predecessor with different
202 // downward defs.
203 bool needPHI =
204 VRegs.size() >= 1 &&
206 VRegs,
207 [&](const std::pair<const MachineBasicBlock *, Register> &V)
208 -> bool { return V.second != VRegs[0].second; });
209
210 // If there is no upwards exposed used and we don't need a phi just
211 // forward the swifterror vreg from the predecessor(s).
212 if (!UpwardsUse && !needPHI) {
213 assert(!VRegs.empty() &&
214 "No predecessors? The entry block should bail out earlier");
215 // Just forward the swifterror vreg from the predecessor(s).
216 setCurrentVReg(MBB, SwiftErrorVal, VRegs[0].second);
217 continue;
218 }
219
220 auto DLoc = isa<Instruction>(SwiftErrorVal)
221 ? cast<Instruction>(SwiftErrorVal)->getDebugLoc()
222 : DebugLoc();
223 const auto *TII = MF->getSubtarget().getInstrInfo();
224
225 // If we don't need a phi create a copy to the upward exposed vreg.
226 if (!needPHI) {
227 assert(UpwardsUse);
228 assert(!VRegs.empty() &&
229 "No predecessors? Is the Calling Convention correct?");
230 Register DestReg = UUseVReg;
231 BuildMI(*MBB, MBB->getFirstNonPHI(), DLoc, TII->get(TargetOpcode::COPY),
232 DestReg)
233 .addReg(VRegs[0].second);
234 continue;
235 }
236
237 // We need a phi: if there is an upwards exposed use we already have a
238 // destination virtual register number otherwise we generate a new one.
239 auto &DL = MF->getDataLayout();
240 auto const *RC = TLI->getRegClassFor(TLI->getPointerTy(DL));
241 Register PHIVReg =
242 UpwardsUse ? UUseVReg : MF->getRegInfo().createVirtualRegister(RC);
244 BuildMI(*MBB, MBB->getFirstNonPHI(), DLoc,
245 TII->get(TargetOpcode::PHI), PHIVReg);
246 for (auto BBRegPair : VRegs) {
247 PHI.addReg(BBRegPair.second).addMBB(BBRegPair.first);
248 }
249
250 // We did not have a definition in this block before: store the phi's vreg
251 // as this block downward exposed def.
252 if (!UpwardsUse)
253 setCurrentVReg(MBB, SwiftErrorVal, PHIVReg);
254 }
255 }
256
257 // Create implicit defs for upward uses from unreachable blocks
259 for (const auto &Use : VRegUpwardsUse) {
260 const MachineBasicBlock *UseBB = Use.first.first;
261 Register VReg = Use.second;
262 if (!MRI.def_begin(VReg).atEnd())
263 continue;
264
265#ifdef EXPENSIVE_CHECKS
266 assert(std::find(RPOT.begin(), RPOT.end(), UseBB) == RPOT.end() &&
267 "Reachable block has VReg upward use without definition.");
268#endif
269
270 MachineBasicBlock *UseBBMut = MF->getBlockNumbered(UseBB->getNumber());
271
272 BuildMI(*UseBBMut, UseBBMut->getFirstNonPHI(), DebugLoc(),
273 TII->get(TargetOpcode::IMPLICIT_DEF), VReg);
274 }
275}
276
280 if (!TLI->supportSwiftError() || SwiftErrorVals.empty())
281 return;
282
283 // Iterator over instructions and assign vregs to swifterror defs and uses.
284 for (auto It = Begin; It != End; ++It) {
285 if (auto *CB = dyn_cast<CallBase>(&*It)) {
286 // A call-site with a swifterror argument is both use and def.
287 const Value *SwiftErrorAddr = nullptr;
288 for (const auto &Arg : CB->args()) {
289 if (!Arg->isSwiftError())
290 continue;
291 // Use of swifterror.
292 assert(!SwiftErrorAddr && "Cannot have multiple swifterror arguments");
293 SwiftErrorAddr = &*Arg;
294 assert(SwiftErrorAddr->isSwiftError() &&
295 "Must have a swifterror value argument");
296 getOrCreateVRegUseAt(&*It, MBB, SwiftErrorAddr);
297 }
298 if (!SwiftErrorAddr)
299 continue;
300
301 // Def of swifterror.
302 getOrCreateVRegDefAt(&*It, MBB, SwiftErrorAddr);
303
304 // A load is a use.
305 } else if (const LoadInst *LI = dyn_cast<const LoadInst>(&*It)) {
306 const Value *V = LI->getOperand(0);
307 if (!V->isSwiftError())
308 continue;
309
311
312 // A store is a def.
313 } else if (const StoreInst *SI = dyn_cast<const StoreInst>(&*It)) {
314 const Value *SwiftErrorAddr = SI->getOperand(1);
315 if (!SwiftErrorAddr->isSwiftError())
316 continue;
317
318 // Def of swifterror.
319 getOrCreateVRegDefAt(&*It, MBB, SwiftErrorAddr);
320
321 // A return in a swiferror returning function is a use.
322 } else if (const ReturnInst *R = dyn_cast<const ReturnInst>(&*It)) {
323 const Function *F = R->getParent()->getParent();
324 if (!F->getAttributes().hasAttrSomewhere(Attribute::SwiftError))
325 continue;
326
327 getOrCreateVRegUseAt(R, MBB, SwiftErrorArg);
328 }
329 }
330}
unsigned const MachineRegisterInfo * MRI
Rewrite undef for PHI
MachineBasicBlock & MBB
MachineBasicBlock MachineBasicBlock::iterator DebugLoc DL
bool End
Definition: ELF_riscv.cpp:480
#define F(x, y, z)
Definition: MD5.cpp:55
#define I(x, y, z)
Definition: MD5.cpp:58
This file builds on the ADT/GraphTraits.h file to build a generic graph post order iterator.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
This file defines the SmallSet class.
This file describes how to lower LLVM code to machine code.
an instruction to allocate memory on the stack
Definition: Instructions.h:63
This class represents an incoming formal argument to a Function.
Definition: Argument.h:31
InstListType::const_iterator const_iterator
Definition: BasicBlock.h:178
A debug info location.
Definition: DebugLoc.h:33
arg_iterator arg_end()
Definition: Function.h:877
arg_iterator arg_begin()
Definition: Function.h:868
An instruction for reading from memory.
Definition: Instructions.h:176
const MCInstrDesc & get(unsigned Opcode) const
Return the machine instruction descriptor that corresponds to the specified instruction opcode.
Definition: MCInstrInfo.h:63
int getNumber() const
MachineBasicBlocks are uniquely numbered at the function level, unless they're not in a MachineFuncti...
iterator getFirstNonPHI()
Returns a pointer to the first instruction in this block that is not a PHINode instruction.
iterator_range< pred_iterator > predecessors()
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.
MachineBasicBlock * getBlockNumbered(unsigned N) const
getBlockNumbered - MachineBasicBlocks are automatically numbered when they are inserted into the mach...
const DataLayout & getDataLayout() const
Return the DataLayout attached to the Module associated to this MF.
Function & getFunction()
Return the LLVM function that this machine code represents.
const MachineInstrBuilder & addReg(Register RegNo, unsigned flags=0, unsigned SubReg=0) const
Add a new virtual register operand.
MachineRegisterInfo - Keep track of information for virtual and physical registers,...
Register createVirtualRegister(const TargetRegisterClass *RegClass, StringRef Name="")
createVirtualRegister - Create and return a new virtual register in the function with the specified r...
PointerIntPair - This class implements a pair of a pointer and small integer.
Wrapper class representing virtual and physical registers.
Definition: Register.h:19
Return a value (possibly void), from a function.
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
Definition: SmallSet.h:132
std::pair< const_iterator, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
Definition: SmallSet.h:181
bool empty() const
Definition: SmallVector.h:81
size_t size() const
Definition: SmallVector.h:78
void push_back(const T &Elt)
Definition: SmallVector.h:413
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
Definition: SmallVector.h:1196
An instruction for storing to memory.
Definition: Instructions.h:292
bool createEntriesInEntryBlock(DebugLoc DbgLoc)
Create initial definitions of swifterror values in the entry block of the current function.
void setFunction(MachineFunction &MF)
Initialize data structures for specified new function.
Register getOrCreateVReg(const MachineBasicBlock *, const Value *)
Get or create the swifterror value virtual register in VRegDefMap for this basic block.
void setCurrentVReg(const MachineBasicBlock *MBB, const Value *, Register)
Set the swifterror virtual register in the VRegDefMap for this basic block.
Register getOrCreateVRegUseAt(const Instruction *, const MachineBasicBlock *, const Value *)
Get or create the swifterror value virtual register for a use of a swifterror by an instruction.
void preassignVRegs(MachineBasicBlock *MBB, BasicBlock::const_iterator Begin, BasicBlock::const_iterator End)
Register getOrCreateVRegDefAt(const Instruction *, const MachineBasicBlock *, const Value *)
Get or create the swifterror value virtual register for a def of a swifterror by an instruction.
void propagateVRegs()
Propagate assigned swifterror vregs through a function, synthesizing PHI nodes when needed to maintai...
virtual const TargetRegisterClass * getRegClassFor(MVT VT, bool isDivergent=false) const
Return the register class that should be used for the specified value type.
virtual MVT getPointerTy(const DataLayout &DL, uint32_t AS=0) const
Return the pointer type for the given address space, defaults to the pointer type from the data layou...
virtual bool supportSwiftError() const
Return true if the target supports swifterror attribute.
virtual const TargetInstrInfo * getInstrInfo() const
virtual const TargetLowering * getTargetLowering() const
A Use represents the edge between a Value definition and its users.
Definition: Use.h:43
LLVM Value Representation.
Definition: Value.h:74
bool isSwiftError() const
Return true if this value is a swifterror value.
Definition: Value.cpp:1096
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:18
MachineInstrBuilder BuildMI(MachineFunction &MF, const MIMetadata &MIMD, const MCInstrDesc &MCID)
Builder interface. Specify how to create the initial instruction itself.
bool any_of(R &&range, UnaryPredicate P)
Provide wrappers to std::any_of which take ranges instead of having to pass begin/end explicitly.
Definition: STLExtras.h:1746