13d7a057bSTim Northover //===-- SwiftErrorValueTracking.cpp --------------------------------------===//
23d7a057bSTim Northover //
33d7a057bSTim Northover // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
43d7a057bSTim Northover // See https://llvm.org/LICENSE.txt for license information.
53d7a057bSTim Northover // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
63d7a057bSTim Northover //
73d7a057bSTim Northover //===----------------------------------------------------------------------===//
83d7a057bSTim Northover //
93d7a057bSTim Northover // This implements a limited mem2reg-like analysis to promote uses of function
103d7a057bSTim Northover // arguments and allocas marked with swiftalloc from memory into virtual
113d7a057bSTim Northover // registers tracked by this class.
123d7a057bSTim Northover //
133d7a057bSTim Northover //===----------------------------------------------------------------------===//
143d7a057bSTim Northover 
153d7a057bSTim Northover #include "llvm/CodeGen/SwiftErrorValueTracking.h"
16904cd3e0SReid Kleckner #include "llvm/ADT/PostOrderIterator.h"
173d7a057bSTim Northover #include "llvm/ADT/SmallSet.h"
183d7a057bSTim Northover #include "llvm/CodeGen/MachineInstrBuilder.h"
19904cd3e0SReid Kleckner #include "llvm/CodeGen/MachineRegisterInfo.h"
203d7a057bSTim Northover #include "llvm/CodeGen/TargetInstrInfo.h"
213d7a057bSTim Northover #include "llvm/CodeGen/TargetLowering.h"
223d7a057bSTim Northover #include "llvm/IR/Value.h"
233d7a057bSTim Northover 
243d7a057bSTim Northover using namespace llvm;
253d7a057bSTim Northover 
getOrCreateVReg(const MachineBasicBlock * MBB,const Value * Val)26faeaedf8SMatt Arsenault Register SwiftErrorValueTracking::getOrCreateVReg(const MachineBasicBlock *MBB,
273d7a057bSTim Northover                                                   const Value *Val) {
283d7a057bSTim Northover   auto Key = std::make_pair(MBB, Val);
293d7a057bSTim Northover   auto It = VRegDefMap.find(Key);
303d7a057bSTim Northover   // If this is the first use of this swifterror value in this basic block,
313d7a057bSTim Northover   // create a new virtual register.
323d7a057bSTim Northover   // After we processed all basic blocks we will satisfy this "upwards exposed
333d7a057bSTim Northover   // use" by inserting a copy or phi at the beginning of this block.
343d7a057bSTim Northover   if (It == VRegDefMap.end()) {
353d7a057bSTim Northover     auto &DL = MF->getDataLayout();
363d7a057bSTim Northover     const TargetRegisterClass *RC = TLI->getRegClassFor(TLI->getPointerTy(DL));
373d7a057bSTim Northover     auto VReg = MF->getRegInfo().createVirtualRegister(RC);
383d7a057bSTim Northover     VRegDefMap[Key] = VReg;
393d7a057bSTim Northover     VRegUpwardsUse[Key] = VReg;
403d7a057bSTim Northover     return VReg;
413d7a057bSTim Northover   } else
423d7a057bSTim Northover     return It->second;
433d7a057bSTim Northover }
443d7a057bSTim Northover 
setCurrentVReg(const MachineBasicBlock * MBB,const Value * Val,Register VReg)453d7a057bSTim Northover void SwiftErrorValueTracking::setCurrentVReg(const MachineBasicBlock *MBB,
46e3a676e9SMatt Arsenault                                              const Value *Val, Register VReg) {
473d7a057bSTim Northover   VRegDefMap[std::make_pair(MBB, Val)] = VReg;
483d7a057bSTim Northover }
493d7a057bSTim Northover 
getOrCreateVRegDefAt(const Instruction * I,const MachineBasicBlock * MBB,const Value * Val)50faeaedf8SMatt Arsenault Register SwiftErrorValueTracking::getOrCreateVRegDefAt(
513d7a057bSTim Northover     const Instruction *I, const MachineBasicBlock *MBB, const Value *Val) {
523d7a057bSTim Northover   auto Key = PointerIntPair<const Instruction *, 1, bool>(I, true);
533d7a057bSTim Northover   auto It = VRegDefUses.find(Key);
543d7a057bSTim Northover   if (It != VRegDefUses.end())
553d7a057bSTim Northover     return It->second;
563d7a057bSTim Northover 
573d7a057bSTim Northover   auto &DL = MF->getDataLayout();
583d7a057bSTim Northover   const TargetRegisterClass *RC = TLI->getRegClassFor(TLI->getPointerTy(DL));
59faeaedf8SMatt Arsenault   Register VReg = MF->getRegInfo().createVirtualRegister(RC);
603d7a057bSTim Northover   VRegDefUses[Key] = VReg;
613d7a057bSTim Northover   setCurrentVReg(MBB, Val, VReg);
623d7a057bSTim Northover   return VReg;
633d7a057bSTim Northover }
643d7a057bSTim Northover 
getOrCreateVRegUseAt(const Instruction * I,const MachineBasicBlock * MBB,const Value * Val)65faeaedf8SMatt Arsenault Register SwiftErrorValueTracking::getOrCreateVRegUseAt(
663d7a057bSTim Northover     const Instruction *I, const MachineBasicBlock *MBB, const Value *Val) {
673d7a057bSTim Northover   auto Key = PointerIntPair<const Instruction *, 1, bool>(I, false);
683d7a057bSTim Northover   auto It = VRegDefUses.find(Key);
693d7a057bSTim Northover   if (It != VRegDefUses.end())
703d7a057bSTim Northover     return It->second;
713d7a057bSTim Northover 
72faeaedf8SMatt Arsenault   Register VReg = getOrCreateVReg(MBB, Val);
733d7a057bSTim Northover   VRegDefUses[Key] = VReg;
743d7a057bSTim Northover   return VReg;
753d7a057bSTim Northover }
763d7a057bSTim Northover 
773d7a057bSTim Northover /// Set up SwiftErrorVals by going through the function. If the function has
783d7a057bSTim Northover /// swifterror argument, it will be the first entry.
setFunction(MachineFunction & mf)793d7a057bSTim Northover void SwiftErrorValueTracking::setFunction(MachineFunction &mf) {
803d7a057bSTim Northover   MF = &mf;
813d7a057bSTim Northover   Fn = &MF->getFunction();
823d7a057bSTim Northover   TLI = MF->getSubtarget().getTargetLowering();
833d7a057bSTim Northover   TII = MF->getSubtarget().getInstrInfo();
843d7a057bSTim Northover 
853d7a057bSTim Northover   if (!TLI->supportSwiftError())
863d7a057bSTim Northover     return;
873d7a057bSTim Northover 
883d7a057bSTim Northover   SwiftErrorVals.clear();
893d7a057bSTim Northover   VRegDefMap.clear();
903d7a057bSTim Northover   VRegUpwardsUse.clear();
913d7a057bSTim Northover   VRegDefUses.clear();
923d7a057bSTim Northover   SwiftErrorArg = nullptr;
933d7a057bSTim Northover 
943d7a057bSTim Northover   // Check if function has a swifterror argument.
953d7a057bSTim Northover   bool HaveSeenSwiftErrorArg = false;
963d7a057bSTim Northover   for (Function::const_arg_iterator AI = Fn->arg_begin(), AE = Fn->arg_end();
973d7a057bSTim Northover        AI != AE; ++AI)
983d7a057bSTim Northover     if (AI->hasSwiftErrorAttr()) {
993d7a057bSTim Northover       assert(!HaveSeenSwiftErrorArg &&
1003d7a057bSTim Northover              "Must have only one swifterror parameter");
1013d7a057bSTim Northover       (void)HaveSeenSwiftErrorArg; // silence warning.
1023d7a057bSTim Northover       HaveSeenSwiftErrorArg = true;
1033d7a057bSTim Northover       SwiftErrorArg = &*AI;
1043d7a057bSTim Northover       SwiftErrorVals.push_back(&*AI);
1053d7a057bSTim Northover     }
1063d7a057bSTim Northover 
1073d7a057bSTim Northover   for (const auto &LLVMBB : *Fn)
1083d7a057bSTim Northover     for (const auto &Inst : LLVMBB) {
1093d7a057bSTim Northover       if (const AllocaInst *Alloca = dyn_cast<AllocaInst>(&Inst))
1103d7a057bSTim Northover         if (Alloca->isSwiftError())
1113d7a057bSTim Northover           SwiftErrorVals.push_back(Alloca);
1123d7a057bSTim Northover     }
1133d7a057bSTim Northover }
1143d7a057bSTim Northover 
createEntriesInEntryBlock(DebugLoc DbgLoc)1153d7a057bSTim Northover bool SwiftErrorValueTracking::createEntriesInEntryBlock(DebugLoc DbgLoc) {
1163d7a057bSTim Northover   if (!TLI->supportSwiftError())
1173d7a057bSTim Northover     return false;
1183d7a057bSTim Northover 
1193d7a057bSTim Northover   // We only need to do this when we have swifterror parameter or swifterror
1203d7a057bSTim Northover   // alloc.
1213d7a057bSTim Northover   if (SwiftErrorVals.empty())
1223d7a057bSTim Northover     return false;
1233d7a057bSTim Northover 
1243d7a057bSTim Northover   MachineBasicBlock *MBB = &*MF->begin();
1253d7a057bSTim Northover   auto &DL = MF->getDataLayout();
1263d7a057bSTim Northover   auto const *RC = TLI->getRegClassFor(TLI->getPointerTy(DL));
1273d7a057bSTim Northover   bool Inserted = false;
1283d7a057bSTim Northover   for (const auto *SwiftErrorVal : SwiftErrorVals) {
1293d7a057bSTim Northover     // We will always generate a copy from the argument. It is always used at
1303d7a057bSTim Northover     // least by the 'return' of the swifterror.
1313d7a057bSTim Northover     if (SwiftErrorArg && SwiftErrorArg == SwiftErrorVal)
1323d7a057bSTim Northover       continue;
133faeaedf8SMatt Arsenault     Register VReg = MF->getRegInfo().createVirtualRegister(RC);
1343d7a057bSTim Northover     // Assign Undef to Vreg. We construct MI directly to make sure it works
1353d7a057bSTim Northover     // with FastISel.
1363d7a057bSTim Northover     BuildMI(*MBB, MBB->getFirstNonPHI(), DbgLoc,
1373d7a057bSTim Northover             TII->get(TargetOpcode::IMPLICIT_DEF), VReg);
1383d7a057bSTim Northover 
1393d7a057bSTim Northover     setCurrentVReg(MBB, SwiftErrorVal, VReg);
1403d7a057bSTim Northover     Inserted = true;
1413d7a057bSTim Northover   }
1423d7a057bSTim Northover 
1433d7a057bSTim Northover   return Inserted;
1443d7a057bSTim Northover }
1453d7a057bSTim Northover 
1463d7a057bSTim Northover /// Propagate swifterror values through the machine function CFG.
propagateVRegs()1473d7a057bSTim Northover void SwiftErrorValueTracking::propagateVRegs() {
1483d7a057bSTim Northover   if (!TLI->supportSwiftError())
1493d7a057bSTim Northover     return;
1503d7a057bSTim Northover 
1513d7a057bSTim Northover   // We only need to do this when we have swifterror parameter or swifterror
1523d7a057bSTim Northover   // alloc.
1533d7a057bSTim Northover   if (SwiftErrorVals.empty())
1543d7a057bSTim Northover     return;
1553d7a057bSTim Northover 
1563d7a057bSTim Northover   // For each machine basic block in reverse post order.
1573d7a057bSTim Northover   ReversePostOrderTraversal<MachineFunction *> RPOT(MF);
1583d7a057bSTim Northover   for (MachineBasicBlock *MBB : RPOT) {
1593d7a057bSTim Northover     // For each swifterror value in the function.
1603d7a057bSTim Northover     for (const auto *SwiftErrorVal : SwiftErrorVals) {
1613d7a057bSTim Northover       auto Key = std::make_pair(MBB, SwiftErrorVal);
1623d7a057bSTim Northover       auto UUseIt = VRegUpwardsUse.find(Key);
1633d7a057bSTim Northover       auto VRegDefIt = VRegDefMap.find(Key);
1643d7a057bSTim Northover       bool UpwardsUse = UUseIt != VRegUpwardsUse.end();
165e3a676e9SMatt Arsenault       Register UUseVReg = UpwardsUse ? UUseIt->second : Register();
1663d7a057bSTim Northover       bool DownwardDef = VRegDefIt != VRegDefMap.end();
1673d7a057bSTim Northover       assert(!(UpwardsUse && !DownwardDef) &&
1683d7a057bSTim Northover              "We can't have an upwards use but no downwards def");
1693d7a057bSTim Northover 
1703d7a057bSTim Northover       // If there is no upwards exposed use and an entry for the swifterror in
1713d7a057bSTim Northover       // the def map for this value we don't need to do anything: We already
1723d7a057bSTim Northover       // have a downward def for this basic block.
1733d7a057bSTim Northover       if (!UpwardsUse && DownwardDef)
1743d7a057bSTim Northover         continue;
1753d7a057bSTim Northover 
1763d7a057bSTim Northover       // Otherwise we either have an upwards exposed use vreg that we need to
1773d7a057bSTim Northover       // materialize or need to forward the downward def from predecessors.
1783d7a057bSTim Northover 
1793d7a057bSTim Northover       // Check whether we have a single vreg def from all predecessors.
1803d7a057bSTim Northover       // Otherwise we need a phi.
181faeaedf8SMatt Arsenault       SmallVector<std::pair<MachineBasicBlock *, Register>, 4> VRegs;
1823d7a057bSTim Northover       SmallSet<const MachineBasicBlock *, 8> Visited;
1833d7a057bSTim Northover       for (auto *Pred : MBB->predecessors()) {
1843d7a057bSTim Northover         if (!Visited.insert(Pred).second)
1853d7a057bSTim Northover           continue;
1863d7a057bSTim Northover         VRegs.push_back(std::make_pair(
1873d7a057bSTim Northover             Pred, getOrCreateVReg(Pred, SwiftErrorVal)));
1883d7a057bSTim Northover         if (Pred != MBB)
1893d7a057bSTim Northover           continue;
1903d7a057bSTim Northover         // We have a self-edge.
1913d7a057bSTim Northover         // If there was no upwards use in this basic block there is now one: the
1923d7a057bSTim Northover         // phi needs to use it self.
1933d7a057bSTim Northover         if (!UpwardsUse) {
1943d7a057bSTim Northover           UpwardsUse = true;
1953d7a057bSTim Northover           UUseIt = VRegUpwardsUse.find(Key);
1963d7a057bSTim Northover           assert(UUseIt != VRegUpwardsUse.end());
1973d7a057bSTim Northover           UUseVReg = UUseIt->second;
1983d7a057bSTim Northover         }
1993d7a057bSTim Northover       }
2003d7a057bSTim Northover 
2013d7a057bSTim Northover       // We need a phi node if we have more than one predecessor with different
2023d7a057bSTim Northover       // downward defs.
2033d7a057bSTim Northover       bool needPHI =
2043d7a057bSTim Northover           VRegs.size() >= 1 &&
2059850d3b1SKazu Hirata           llvm::find_if(
2069850d3b1SKazu Hirata               VRegs,
207faeaedf8SMatt Arsenault               [&](const std::pair<const MachineBasicBlock *, Register> &V)
2083d7a057bSTim Northover                   -> bool { return V.second != VRegs[0].second; }) !=
2093d7a057bSTim Northover               VRegs.end();
2103d7a057bSTim Northover 
2113d7a057bSTim Northover       // If there is no upwards exposed used and we don't need a phi just
2123d7a057bSTim Northover       // forward the swifterror vreg from the predecessor(s).
2133d7a057bSTim Northover       if (!UpwardsUse && !needPHI) {
2143d7a057bSTim Northover         assert(!VRegs.empty() &&
2153d7a057bSTim Northover                "No predecessors? The entry block should bail out earlier");
2163d7a057bSTim Northover         // Just forward the swifterror vreg from the predecessor(s).
2173d7a057bSTim Northover         setCurrentVReg(MBB, SwiftErrorVal, VRegs[0].second);
2183d7a057bSTim Northover         continue;
2193d7a057bSTim Northover       }
2203d7a057bSTim Northover 
2213d7a057bSTim Northover       auto DLoc = isa<Instruction>(SwiftErrorVal)
2223d7a057bSTim Northover                       ? cast<Instruction>(SwiftErrorVal)->getDebugLoc()
2233d7a057bSTim Northover                       : DebugLoc();
2243d7a057bSTim Northover       const auto *TII = MF->getSubtarget().getInstrInfo();
2253d7a057bSTim Northover 
2263d7a057bSTim Northover       // If we don't need a phi create a copy to the upward exposed vreg.
2273d7a057bSTim Northover       if (!needPHI) {
2283d7a057bSTim Northover         assert(UpwardsUse);
2293d7a057bSTim Northover         assert(!VRegs.empty() &&
2303d7a057bSTim Northover                "No predecessors?  Is the Calling Convention correct?");
231faeaedf8SMatt Arsenault         Register DestReg = UUseVReg;
2323d7a057bSTim Northover         BuildMI(*MBB, MBB->getFirstNonPHI(), DLoc, TII->get(TargetOpcode::COPY),
2333d7a057bSTim Northover                 DestReg)
2343d7a057bSTim Northover             .addReg(VRegs[0].second);
2353d7a057bSTim Northover         continue;
2363d7a057bSTim Northover       }
2373d7a057bSTim Northover 
2383d7a057bSTim Northover       // We need a phi: if there is an upwards exposed use we already have a
2393d7a057bSTim Northover       // destination virtual register number otherwise we generate a new one.
2403d7a057bSTim Northover       auto &DL = MF->getDataLayout();
2413d7a057bSTim Northover       auto const *RC = TLI->getRegClassFor(TLI->getPointerTy(DL));
242e3a676e9SMatt Arsenault       Register PHIVReg =
2433d7a057bSTim Northover           UpwardsUse ? UUseVReg : MF->getRegInfo().createVirtualRegister(RC);
2443d7a057bSTim Northover       MachineInstrBuilder PHI =
2453d7a057bSTim Northover           BuildMI(*MBB, MBB->getFirstNonPHI(), DLoc,
2463d7a057bSTim Northover                   TII->get(TargetOpcode::PHI), PHIVReg);
2473d7a057bSTim Northover       for (auto BBRegPair : VRegs) {
2483d7a057bSTim Northover         PHI.addReg(BBRegPair.second).addMBB(BBRegPair.first);
2493d7a057bSTim Northover       }
2503d7a057bSTim Northover 
2513d7a057bSTim Northover       // We did not have a definition in this block before: store the phi's vreg
2523d7a057bSTim Northover       // as this block downward exposed def.
2533d7a057bSTim Northover       if (!UpwardsUse)
2543d7a057bSTim Northover         setCurrentVReg(MBB, SwiftErrorVal, PHIVReg);
2553d7a057bSTim Northover     }
2563d7a057bSTim Northover   }
2573d7a057bSTim Northover }
2583d7a057bSTim Northover 
preassignVRegs(MachineBasicBlock * MBB,BasicBlock::const_iterator Begin,BasicBlock::const_iterator End)2593d7a057bSTim Northover void SwiftErrorValueTracking::preassignVRegs(
2603d7a057bSTim Northover     MachineBasicBlock *MBB, BasicBlock::const_iterator Begin,
2613d7a057bSTim Northover     BasicBlock::const_iterator End) {
2623d7a057bSTim Northover   if (!TLI->supportSwiftError() || SwiftErrorVals.empty())
2633d7a057bSTim Northover     return;
2643d7a057bSTim Northover 
2653d7a057bSTim Northover   // Iterator over instructions and assign vregs to swifterror defs and uses.
2663d7a057bSTim Northover   for (auto It = Begin; It != End; ++It) {
26742487eafSCraig Topper     if (auto *CB = dyn_cast<CallBase>(&*It)) {
2683d7a057bSTim Northover       // A call-site with a swifterror argument is both use and def.
2693d7a057bSTim Northover       const Value *SwiftErrorAddr = nullptr;
270*9e6d1f4bSKazu Hirata       for (const auto &Arg : CB->args()) {
2713d7a057bSTim Northover         if (!Arg->isSwiftError())
2723d7a057bSTim Northover           continue;
2733d7a057bSTim Northover         // Use of swifterror.
2743d7a057bSTim Northover         assert(!SwiftErrorAddr && "Cannot have multiple swifterror arguments");
2753d7a057bSTim Northover         SwiftErrorAddr = &*Arg;
2763d7a057bSTim Northover         assert(SwiftErrorAddr->isSwiftError() &&
2773d7a057bSTim Northover                "Must have a swifterror value argument");
2783d7a057bSTim Northover         getOrCreateVRegUseAt(&*It, MBB, SwiftErrorAddr);
2793d7a057bSTim Northover       }
2803d7a057bSTim Northover       if (!SwiftErrorAddr)
2813d7a057bSTim Northover         continue;
2823d7a057bSTim Northover 
2833d7a057bSTim Northover       // Def of swifterror.
2843d7a057bSTim Northover       getOrCreateVRegDefAt(&*It, MBB, SwiftErrorAddr);
2853d7a057bSTim Northover 
2863d7a057bSTim Northover       // A load is a use.
2873d7a057bSTim Northover     } else if (const LoadInst *LI = dyn_cast<const LoadInst>(&*It)) {
2883d7a057bSTim Northover       const Value *V = LI->getOperand(0);
2893d7a057bSTim Northover       if (!V->isSwiftError())
2903d7a057bSTim Northover         continue;
2913d7a057bSTim Northover 
2923d7a057bSTim Northover       getOrCreateVRegUseAt(LI, MBB, V);
2933d7a057bSTim Northover 
2943d7a057bSTim Northover       // A store is a def.
2953d7a057bSTim Northover     } else if (const StoreInst *SI = dyn_cast<const StoreInst>(&*It)) {
2963d7a057bSTim Northover       const Value *SwiftErrorAddr = SI->getOperand(1);
2973d7a057bSTim Northover       if (!SwiftErrorAddr->isSwiftError())
2983d7a057bSTim Northover         continue;
2993d7a057bSTim Northover 
3003d7a057bSTim Northover       // Def of swifterror.
3013d7a057bSTim Northover       getOrCreateVRegDefAt(&*It, MBB, SwiftErrorAddr);
3023d7a057bSTim Northover 
3033d7a057bSTim Northover       // A return in a swiferror returning function is a use.
3043d7a057bSTim Northover     } else if (const ReturnInst *R = dyn_cast<const ReturnInst>(&*It)) {
3053d7a057bSTim Northover       const Function *F = R->getParent()->getParent();
3063d7a057bSTim Northover       if (!F->getAttributes().hasAttrSomewhere(Attribute::SwiftError))
3073d7a057bSTim Northover         continue;
3083d7a057bSTim Northover 
3093d7a057bSTim Northover       getOrCreateVRegUseAt(R, MBB, SwiftErrorArg);
3103d7a057bSTim Northover     }
3113d7a057bSTim Northover   }
3123d7a057bSTim Northover }
313