1*3d7a057bSTim Northover //===-- SwiftErrorValueTracking.cpp --------------------------------------===//
2*3d7a057bSTim Northover //
3*3d7a057bSTim Northover // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*3d7a057bSTim Northover // See https://llvm.org/LICENSE.txt for license information.
5*3d7a057bSTim Northover // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*3d7a057bSTim Northover //
7*3d7a057bSTim Northover //===----------------------------------------------------------------------===//
8*3d7a057bSTim Northover //
9*3d7a057bSTim Northover // This implements a limited mem2reg-like analysis to promote uses of function
10*3d7a057bSTim Northover // arguments and allocas marked with swiftalloc from memory into virtual
11*3d7a057bSTim Northover // registers tracked by this class.
12*3d7a057bSTim Northover //
13*3d7a057bSTim Northover //===----------------------------------------------------------------------===//
14*3d7a057bSTim Northover 
15*3d7a057bSTim Northover #include "llvm/CodeGen/SwiftErrorValueTracking.h"
16*3d7a057bSTim Northover #include "llvm/ADT/SmallSet.h"
17*3d7a057bSTim Northover #include "llvm/CodeGen/MachineRegisterInfo.h"
18*3d7a057bSTim Northover #include "llvm/CodeGen/MachineInstrBuilder.h"
19*3d7a057bSTim Northover #include "llvm/CodeGen/TargetInstrInfo.h"
20*3d7a057bSTim Northover #include "llvm/CodeGen/TargetLowering.h"
21*3d7a057bSTim Northover #include "llvm/IR/Value.h"
22*3d7a057bSTim Northover 
23*3d7a057bSTim Northover using namespace llvm;
24*3d7a057bSTim Northover 
25*3d7a057bSTim Northover unsigned SwiftErrorValueTracking::getOrCreateVReg(const MachineBasicBlock *MBB,
26*3d7a057bSTim Northover                                                   const Value *Val) {
27*3d7a057bSTim Northover   auto Key = std::make_pair(MBB, Val);
28*3d7a057bSTim Northover   auto It = VRegDefMap.find(Key);
29*3d7a057bSTim Northover   // If this is the first use of this swifterror value in this basic block,
30*3d7a057bSTim Northover   // create a new virtual register.
31*3d7a057bSTim Northover   // After we processed all basic blocks we will satisfy this "upwards exposed
32*3d7a057bSTim Northover   // use" by inserting a copy or phi at the beginning of this block.
33*3d7a057bSTim Northover   if (It == VRegDefMap.end()) {
34*3d7a057bSTim Northover     auto &DL = MF->getDataLayout();
35*3d7a057bSTim Northover     const TargetRegisterClass *RC = TLI->getRegClassFor(TLI->getPointerTy(DL));
36*3d7a057bSTim Northover     auto VReg = MF->getRegInfo().createVirtualRegister(RC);
37*3d7a057bSTim Northover     VRegDefMap[Key] = VReg;
38*3d7a057bSTim Northover     VRegUpwardsUse[Key] = VReg;
39*3d7a057bSTim Northover     return VReg;
40*3d7a057bSTim Northover   } else
41*3d7a057bSTim Northover     return It->second;
42*3d7a057bSTim Northover }
43*3d7a057bSTim Northover 
44*3d7a057bSTim Northover void SwiftErrorValueTracking::setCurrentVReg(const MachineBasicBlock *MBB,
45*3d7a057bSTim Northover                                              const Value *Val, unsigned VReg) {
46*3d7a057bSTim Northover   VRegDefMap[std::make_pair(MBB, Val)] = VReg;
47*3d7a057bSTim Northover }
48*3d7a057bSTim Northover 
49*3d7a057bSTim Northover unsigned SwiftErrorValueTracking::getOrCreateVRegDefAt(
50*3d7a057bSTim Northover     const Instruction *I, const MachineBasicBlock *MBB, const Value *Val) {
51*3d7a057bSTim Northover   auto Key = PointerIntPair<const Instruction *, 1, bool>(I, true);
52*3d7a057bSTim Northover   auto It = VRegDefUses.find(Key);
53*3d7a057bSTim Northover   if (It != VRegDefUses.end())
54*3d7a057bSTim Northover     return It->second;
55*3d7a057bSTim Northover 
56*3d7a057bSTim Northover   auto &DL = MF->getDataLayout();
57*3d7a057bSTim Northover   const TargetRegisterClass *RC = TLI->getRegClassFor(TLI->getPointerTy(DL));
58*3d7a057bSTim Northover   unsigned VReg = MF->getRegInfo().createVirtualRegister(RC);
59*3d7a057bSTim Northover   VRegDefUses[Key] = VReg;
60*3d7a057bSTim Northover   setCurrentVReg(MBB, Val, VReg);
61*3d7a057bSTim Northover   return VReg;
62*3d7a057bSTim Northover }
63*3d7a057bSTim Northover 
64*3d7a057bSTim Northover unsigned SwiftErrorValueTracking::getOrCreateVRegUseAt(
65*3d7a057bSTim Northover     const Instruction *I, const MachineBasicBlock *MBB, const Value *Val) {
66*3d7a057bSTim Northover   auto Key = PointerIntPair<const Instruction *, 1, bool>(I, false);
67*3d7a057bSTim Northover   auto It = VRegDefUses.find(Key);
68*3d7a057bSTim Northover   if (It != VRegDefUses.end())
69*3d7a057bSTim Northover     return It->second;
70*3d7a057bSTim Northover 
71*3d7a057bSTim Northover   unsigned VReg = getOrCreateVReg(MBB, Val);
72*3d7a057bSTim Northover   VRegDefUses[Key] = VReg;
73*3d7a057bSTim Northover   return VReg;
74*3d7a057bSTim Northover }
75*3d7a057bSTim Northover 
76*3d7a057bSTim Northover /// Set up SwiftErrorVals by going through the function. If the function has
77*3d7a057bSTim Northover /// swifterror argument, it will be the first entry.
78*3d7a057bSTim Northover void SwiftErrorValueTracking::setFunction(MachineFunction &mf) {
79*3d7a057bSTim Northover   MF = &mf;
80*3d7a057bSTim Northover   Fn = &MF->getFunction();
81*3d7a057bSTim Northover   TLI = MF->getSubtarget().getTargetLowering();
82*3d7a057bSTim Northover   TII = MF->getSubtarget().getInstrInfo();
83*3d7a057bSTim Northover 
84*3d7a057bSTim Northover   if (!TLI->supportSwiftError())
85*3d7a057bSTim Northover     return;
86*3d7a057bSTim Northover 
87*3d7a057bSTim Northover   SwiftErrorVals.clear();
88*3d7a057bSTim Northover   VRegDefMap.clear();
89*3d7a057bSTim Northover   VRegUpwardsUse.clear();
90*3d7a057bSTim Northover   VRegDefUses.clear();
91*3d7a057bSTim Northover   SwiftErrorArg = nullptr;
92*3d7a057bSTim Northover 
93*3d7a057bSTim Northover   // Check if function has a swifterror argument.
94*3d7a057bSTim Northover   bool HaveSeenSwiftErrorArg = false;
95*3d7a057bSTim Northover   for (Function::const_arg_iterator AI = Fn->arg_begin(), AE = Fn->arg_end();
96*3d7a057bSTim Northover        AI != AE; ++AI)
97*3d7a057bSTim Northover     if (AI->hasSwiftErrorAttr()) {
98*3d7a057bSTim Northover       assert(!HaveSeenSwiftErrorArg &&
99*3d7a057bSTim Northover              "Must have only one swifterror parameter");
100*3d7a057bSTim Northover       (void)HaveSeenSwiftErrorArg; // silence warning.
101*3d7a057bSTim Northover       HaveSeenSwiftErrorArg = true;
102*3d7a057bSTim Northover       SwiftErrorArg = &*AI;
103*3d7a057bSTim Northover       SwiftErrorVals.push_back(&*AI);
104*3d7a057bSTim Northover     }
105*3d7a057bSTim Northover 
106*3d7a057bSTim Northover   for (const auto &LLVMBB : *Fn)
107*3d7a057bSTim Northover     for (const auto &Inst : LLVMBB) {
108*3d7a057bSTim Northover       if (const AllocaInst *Alloca = dyn_cast<AllocaInst>(&Inst))
109*3d7a057bSTim Northover         if (Alloca->isSwiftError())
110*3d7a057bSTim Northover           SwiftErrorVals.push_back(Alloca);
111*3d7a057bSTim Northover     }
112*3d7a057bSTim Northover }
113*3d7a057bSTim Northover 
114*3d7a057bSTim Northover bool SwiftErrorValueTracking::createEntriesInEntryBlock(DebugLoc DbgLoc) {
115*3d7a057bSTim Northover   if (!TLI->supportSwiftError())
116*3d7a057bSTim Northover     return false;
117*3d7a057bSTim Northover 
118*3d7a057bSTim Northover   // We only need to do this when we have swifterror parameter or swifterror
119*3d7a057bSTim Northover   // alloc.
120*3d7a057bSTim Northover   if (SwiftErrorVals.empty())
121*3d7a057bSTim Northover     return false;
122*3d7a057bSTim Northover 
123*3d7a057bSTim Northover   MachineBasicBlock *MBB = &*MF->begin();
124*3d7a057bSTim Northover   auto &DL = MF->getDataLayout();
125*3d7a057bSTim Northover   auto const *RC = TLI->getRegClassFor(TLI->getPointerTy(DL));
126*3d7a057bSTim Northover   bool Inserted = false;
127*3d7a057bSTim Northover   for (const auto *SwiftErrorVal : SwiftErrorVals) {
128*3d7a057bSTim Northover     // We will always generate a copy from the argument. It is always used at
129*3d7a057bSTim Northover     // least by the 'return' of the swifterror.
130*3d7a057bSTim Northover     if (SwiftErrorArg && SwiftErrorArg == SwiftErrorVal)
131*3d7a057bSTim Northover       continue;
132*3d7a057bSTim Northover     unsigned VReg = MF->getRegInfo().createVirtualRegister(RC);
133*3d7a057bSTim Northover     // Assign Undef to Vreg. We construct MI directly to make sure it works
134*3d7a057bSTim Northover     // with FastISel.
135*3d7a057bSTim Northover     BuildMI(*MBB, MBB->getFirstNonPHI(), DbgLoc,
136*3d7a057bSTim Northover             TII->get(TargetOpcode::IMPLICIT_DEF), VReg);
137*3d7a057bSTim Northover 
138*3d7a057bSTim Northover     setCurrentVReg(MBB, SwiftErrorVal, VReg);
139*3d7a057bSTim Northover     Inserted = true;
140*3d7a057bSTim Northover   }
141*3d7a057bSTim Northover 
142*3d7a057bSTim Northover   return Inserted;
143*3d7a057bSTim Northover }
144*3d7a057bSTim Northover 
145*3d7a057bSTim Northover /// Propagate swifterror values through the machine function CFG.
146*3d7a057bSTim Northover void SwiftErrorValueTracking::propagateVRegs() {
147*3d7a057bSTim Northover   if (!TLI->supportSwiftError())
148*3d7a057bSTim Northover     return;
149*3d7a057bSTim Northover 
150*3d7a057bSTim Northover   // We only need to do this when we have swifterror parameter or swifterror
151*3d7a057bSTim Northover   // alloc.
152*3d7a057bSTim Northover   if (SwiftErrorVals.empty())
153*3d7a057bSTim Northover     return;
154*3d7a057bSTim Northover 
155*3d7a057bSTim Northover   // For each machine basic block in reverse post order.
156*3d7a057bSTim Northover   ReversePostOrderTraversal<MachineFunction *> RPOT(MF);
157*3d7a057bSTim Northover   for (MachineBasicBlock *MBB : RPOT) {
158*3d7a057bSTim Northover     // For each swifterror value in the function.
159*3d7a057bSTim Northover     for (const auto *SwiftErrorVal : SwiftErrorVals) {
160*3d7a057bSTim Northover       auto Key = std::make_pair(MBB, SwiftErrorVal);
161*3d7a057bSTim Northover       auto UUseIt = VRegUpwardsUse.find(Key);
162*3d7a057bSTim Northover       auto VRegDefIt = VRegDefMap.find(Key);
163*3d7a057bSTim Northover       bool UpwardsUse = UUseIt != VRegUpwardsUse.end();
164*3d7a057bSTim Northover       unsigned UUseVReg = UpwardsUse ? UUseIt->second : 0;
165*3d7a057bSTim Northover       bool DownwardDef = VRegDefIt != VRegDefMap.end();
166*3d7a057bSTim Northover       assert(!(UpwardsUse && !DownwardDef) &&
167*3d7a057bSTim Northover              "We can't have an upwards use but no downwards def");
168*3d7a057bSTim Northover 
169*3d7a057bSTim Northover       // If there is no upwards exposed use and an entry for the swifterror in
170*3d7a057bSTim Northover       // the def map for this value we don't need to do anything: We already
171*3d7a057bSTim Northover       // have a downward def for this basic block.
172*3d7a057bSTim Northover       if (!UpwardsUse && DownwardDef)
173*3d7a057bSTim Northover         continue;
174*3d7a057bSTim Northover 
175*3d7a057bSTim Northover       // Otherwise we either have an upwards exposed use vreg that we need to
176*3d7a057bSTim Northover       // materialize or need to forward the downward def from predecessors.
177*3d7a057bSTim Northover 
178*3d7a057bSTim Northover       // Check whether we have a single vreg def from all predecessors.
179*3d7a057bSTim Northover       // Otherwise we need a phi.
180*3d7a057bSTim Northover       SmallVector<std::pair<MachineBasicBlock *, unsigned>, 4> VRegs;
181*3d7a057bSTim Northover       SmallSet<const MachineBasicBlock *, 8> Visited;
182*3d7a057bSTim Northover       for (auto *Pred : MBB->predecessors()) {
183*3d7a057bSTim Northover         if (!Visited.insert(Pred).second)
184*3d7a057bSTim Northover           continue;
185*3d7a057bSTim Northover         VRegs.push_back(std::make_pair(
186*3d7a057bSTim Northover             Pred, getOrCreateVReg(Pred, SwiftErrorVal)));
187*3d7a057bSTim Northover         if (Pred != MBB)
188*3d7a057bSTim Northover           continue;
189*3d7a057bSTim Northover         // We have a self-edge.
190*3d7a057bSTim Northover         // If there was no upwards use in this basic block there is now one: the
191*3d7a057bSTim Northover         // phi needs to use it self.
192*3d7a057bSTim Northover         if (!UpwardsUse) {
193*3d7a057bSTim Northover           UpwardsUse = true;
194*3d7a057bSTim Northover           UUseIt = VRegUpwardsUse.find(Key);
195*3d7a057bSTim Northover           assert(UUseIt != VRegUpwardsUse.end());
196*3d7a057bSTim Northover           UUseVReg = UUseIt->second;
197*3d7a057bSTim Northover         }
198*3d7a057bSTim Northover       }
199*3d7a057bSTim Northover 
200*3d7a057bSTim Northover       // We need a phi node if we have more than one predecessor with different
201*3d7a057bSTim Northover       // downward defs.
202*3d7a057bSTim Northover       bool needPHI =
203*3d7a057bSTim Northover           VRegs.size() >= 1 &&
204*3d7a057bSTim Northover           std::find_if(
205*3d7a057bSTim Northover               VRegs.begin(), VRegs.end(),
206*3d7a057bSTim Northover               [&](const std::pair<const MachineBasicBlock *, unsigned> &V)
207*3d7a057bSTim Northover                   -> bool { return V.second != VRegs[0].second; }) !=
208*3d7a057bSTim Northover               VRegs.end();
209*3d7a057bSTim Northover 
210*3d7a057bSTim Northover       // If there is no upwards exposed used and we don't need a phi just
211*3d7a057bSTim Northover       // forward the swifterror vreg from the predecessor(s).
212*3d7a057bSTim Northover       if (!UpwardsUse && !needPHI) {
213*3d7a057bSTim Northover         assert(!VRegs.empty() &&
214*3d7a057bSTim Northover                "No predecessors? The entry block should bail out earlier");
215*3d7a057bSTim Northover         // Just forward the swifterror vreg from the predecessor(s).
216*3d7a057bSTim Northover         setCurrentVReg(MBB, SwiftErrorVal, VRegs[0].second);
217*3d7a057bSTim Northover         continue;
218*3d7a057bSTim Northover       }
219*3d7a057bSTim Northover 
220*3d7a057bSTim Northover       auto DLoc = isa<Instruction>(SwiftErrorVal)
221*3d7a057bSTim Northover                       ? cast<Instruction>(SwiftErrorVal)->getDebugLoc()
222*3d7a057bSTim Northover                       : DebugLoc();
223*3d7a057bSTim Northover       const auto *TII = MF->getSubtarget().getInstrInfo();
224*3d7a057bSTim Northover 
225*3d7a057bSTim Northover       // If we don't need a phi create a copy to the upward exposed vreg.
226*3d7a057bSTim Northover       if (!needPHI) {
227*3d7a057bSTim Northover         assert(UpwardsUse);
228*3d7a057bSTim Northover         assert(!VRegs.empty() &&
229*3d7a057bSTim Northover                "No predecessors?  Is the Calling Convention correct?");
230*3d7a057bSTim Northover         unsigned DestReg = UUseVReg;
231*3d7a057bSTim Northover         BuildMI(*MBB, MBB->getFirstNonPHI(), DLoc, TII->get(TargetOpcode::COPY),
232*3d7a057bSTim Northover                 DestReg)
233*3d7a057bSTim Northover             .addReg(VRegs[0].second);
234*3d7a057bSTim Northover         continue;
235*3d7a057bSTim Northover       }
236*3d7a057bSTim Northover 
237*3d7a057bSTim Northover       // We need a phi: if there is an upwards exposed use we already have a
238*3d7a057bSTim Northover       // destination virtual register number otherwise we generate a new one.
239*3d7a057bSTim Northover       auto &DL = MF->getDataLayout();
240*3d7a057bSTim Northover       auto const *RC = TLI->getRegClassFor(TLI->getPointerTy(DL));
241*3d7a057bSTim Northover       unsigned PHIVReg =
242*3d7a057bSTim Northover           UpwardsUse ? UUseVReg : MF->getRegInfo().createVirtualRegister(RC);
243*3d7a057bSTim Northover       MachineInstrBuilder PHI =
244*3d7a057bSTim Northover           BuildMI(*MBB, MBB->getFirstNonPHI(), DLoc,
245*3d7a057bSTim Northover                   TII->get(TargetOpcode::PHI), PHIVReg);
246*3d7a057bSTim Northover       for (auto BBRegPair : VRegs) {
247*3d7a057bSTim Northover         PHI.addReg(BBRegPair.second).addMBB(BBRegPair.first);
248*3d7a057bSTim Northover       }
249*3d7a057bSTim Northover 
250*3d7a057bSTim Northover       // We did not have a definition in this block before: store the phi's vreg
251*3d7a057bSTim Northover       // as this block downward exposed def.
252*3d7a057bSTim Northover       if (!UpwardsUse)
253*3d7a057bSTim Northover         setCurrentVReg(MBB, SwiftErrorVal, PHIVReg);
254*3d7a057bSTim Northover     }
255*3d7a057bSTim Northover   }
256*3d7a057bSTim Northover }
257*3d7a057bSTim Northover 
258*3d7a057bSTim Northover void SwiftErrorValueTracking::preassignVRegs(
259*3d7a057bSTim Northover     MachineBasicBlock *MBB, BasicBlock::const_iterator Begin,
260*3d7a057bSTim Northover     BasicBlock::const_iterator End) {
261*3d7a057bSTim Northover   if (!TLI->supportSwiftError() || SwiftErrorVals.empty())
262*3d7a057bSTim Northover     return;
263*3d7a057bSTim Northover 
264*3d7a057bSTim Northover   // Iterator over instructions and assign vregs to swifterror defs and uses.
265*3d7a057bSTim Northover   for (auto It = Begin; It != End; ++It) {
266*3d7a057bSTim Northover     ImmutableCallSite CS(&*It);
267*3d7a057bSTim Northover     if (CS) {
268*3d7a057bSTim Northover       // A call-site with a swifterror argument is both use and def.
269*3d7a057bSTim Northover       const Value *SwiftErrorAddr = nullptr;
270*3d7a057bSTim Northover       for (auto &Arg : CS.args()) {
271*3d7a057bSTim Northover         if (!Arg->isSwiftError())
272*3d7a057bSTim Northover           continue;
273*3d7a057bSTim Northover         // Use of swifterror.
274*3d7a057bSTim Northover         assert(!SwiftErrorAddr && "Cannot have multiple swifterror arguments");
275*3d7a057bSTim Northover         SwiftErrorAddr = &*Arg;
276*3d7a057bSTim Northover         assert(SwiftErrorAddr->isSwiftError() &&
277*3d7a057bSTim Northover                "Must have a swifterror value argument");
278*3d7a057bSTim Northover         getOrCreateVRegUseAt(&*It, MBB, SwiftErrorAddr);
279*3d7a057bSTim Northover       }
280*3d7a057bSTim Northover       if (!SwiftErrorAddr)
281*3d7a057bSTim Northover         continue;
282*3d7a057bSTim Northover 
283*3d7a057bSTim Northover       // Def of swifterror.
284*3d7a057bSTim Northover       getOrCreateVRegDefAt(&*It, MBB, SwiftErrorAddr);
285*3d7a057bSTim Northover 
286*3d7a057bSTim Northover       // A load is a use.
287*3d7a057bSTim Northover     } else if (const LoadInst *LI = dyn_cast<const LoadInst>(&*It)) {
288*3d7a057bSTim Northover       const Value *V = LI->getOperand(0);
289*3d7a057bSTim Northover       if (!V->isSwiftError())
290*3d7a057bSTim Northover         continue;
291*3d7a057bSTim Northover 
292*3d7a057bSTim Northover       getOrCreateVRegUseAt(LI, MBB, V);
293*3d7a057bSTim Northover 
294*3d7a057bSTim Northover       // A store is a def.
295*3d7a057bSTim Northover     } else if (const StoreInst *SI = dyn_cast<const StoreInst>(&*It)) {
296*3d7a057bSTim Northover       const Value *SwiftErrorAddr = SI->getOperand(1);
297*3d7a057bSTim Northover       if (!SwiftErrorAddr->isSwiftError())
298*3d7a057bSTim Northover         continue;
299*3d7a057bSTim Northover 
300*3d7a057bSTim Northover       // Def of swifterror.
301*3d7a057bSTim Northover       getOrCreateVRegDefAt(&*It, MBB, SwiftErrorAddr);
302*3d7a057bSTim Northover 
303*3d7a057bSTim Northover       // A return in a swiferror returning function is a use.
304*3d7a057bSTim Northover     } else if (const ReturnInst *R = dyn_cast<const ReturnInst>(&*It)) {
305*3d7a057bSTim Northover       const Function *F = R->getParent()->getParent();
306*3d7a057bSTim Northover       if (!F->getAttributes().hasAttrSomewhere(Attribute::SwiftError))
307*3d7a057bSTim Northover         continue;
308*3d7a057bSTim Northover 
309*3d7a057bSTim Northover       getOrCreateVRegUseAt(R, MBB, SwiftErrorArg);
310*3d7a057bSTim Northover     }
311*3d7a057bSTim Northover   }
312*3d7a057bSTim Northover }
313