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