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