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 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 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 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 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. 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 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. 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 && 2053d7a057bSTim Northover std::find_if( 2063d7a057bSTim Northover VRegs.begin(), VRegs.end(), 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 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) { 267*42487eafSCraig 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*42487eafSCraig Topper for (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