brintos

brintos / llvm-project-archived public Read only

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