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