314 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
			
		
		
	
	
			314 lines
		
	
	
		
			11 KiB
		
	
	
	
		
			C++
		
	
	
	
| //===-- SwiftErrorValueTracking.cpp --------------------------------------===//
 | |
| //
 | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 | |
| // See https://llvm.org/LICENSE.txt for license information.
 | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| //
 | |
| // This implements a limited mem2reg-like analysis to promote uses of function
 | |
| // arguments and allocas marked with swiftalloc from memory into virtual
 | |
| // registers tracked by this class.
 | |
| //
 | |
| //===----------------------------------------------------------------------===//
 | |
| 
 | |
| #include "llvm/CodeGen/SwiftErrorValueTracking.h"
 | |
| #include "llvm/ADT/PostOrderIterator.h"
 | |
| #include "llvm/ADT/SmallSet.h"
 | |
| #include "llvm/CodeGen/MachineInstrBuilder.h"
 | |
| #include "llvm/CodeGen/MachineRegisterInfo.h"
 | |
| #include "llvm/CodeGen/TargetInstrInfo.h"
 | |
| #include "llvm/CodeGen/TargetLowering.h"
 | |
| #include "llvm/IR/Value.h"
 | |
| 
 | |
| using namespace llvm;
 | |
| 
 | |
| Register SwiftErrorValueTracking::getOrCreateVReg(const MachineBasicBlock *MBB,
 | |
|                                                   const Value *Val) {
 | |
|   auto Key = std::make_pair(MBB, Val);
 | |
|   auto It = VRegDefMap.find(Key);
 | |
|   // If this is the first use of this swifterror value in this basic block,
 | |
|   // create a new virtual register.
 | |
|   // After we processed all basic blocks we will satisfy this "upwards exposed
 | |
|   // use" by inserting a copy or phi at the beginning of this block.
 | |
|   if (It == VRegDefMap.end()) {
 | |
|     auto &DL = MF->getDataLayout();
 | |
|     const TargetRegisterClass *RC = TLI->getRegClassFor(TLI->getPointerTy(DL));
 | |
|     auto VReg = MF->getRegInfo().createVirtualRegister(RC);
 | |
|     VRegDefMap[Key] = VReg;
 | |
|     VRegUpwardsUse[Key] = VReg;
 | |
|     return VReg;
 | |
|   } else
 | |
|     return It->second;
 | |
| }
 | |
| 
 | |
| void SwiftErrorValueTracking::setCurrentVReg(const MachineBasicBlock *MBB,
 | |
|                                              const Value *Val, Register VReg) {
 | |
|   VRegDefMap[std::make_pair(MBB, Val)] = VReg;
 | |
| }
 | |
| 
 | |
| Register SwiftErrorValueTracking::getOrCreateVRegDefAt(
 | |
|     const Instruction *I, const MachineBasicBlock *MBB, const Value *Val) {
 | |
|   auto Key = PointerIntPair<const Instruction *, 1, bool>(I, true);
 | |
|   auto It = VRegDefUses.find(Key);
 | |
|   if (It != VRegDefUses.end())
 | |
|     return It->second;
 | |
| 
 | |
|   auto &DL = MF->getDataLayout();
 | |
|   const TargetRegisterClass *RC = TLI->getRegClassFor(TLI->getPointerTy(DL));
 | |
|   Register VReg = MF->getRegInfo().createVirtualRegister(RC);
 | |
|   VRegDefUses[Key] = VReg;
 | |
|   setCurrentVReg(MBB, Val, VReg);
 | |
|   return VReg;
 | |
| }
 | |
| 
 | |
| Register SwiftErrorValueTracking::getOrCreateVRegUseAt(
 | |
|     const Instruction *I, const MachineBasicBlock *MBB, const Value *Val) {
 | |
|   auto Key = PointerIntPair<const Instruction *, 1, bool>(I, false);
 | |
|   auto It = VRegDefUses.find(Key);
 | |
|   if (It != VRegDefUses.end())
 | |
|     return It->second;
 | |
| 
 | |
|   Register VReg = getOrCreateVReg(MBB, Val);
 | |
|   VRegDefUses[Key] = VReg;
 | |
|   return VReg;
 | |
| }
 | |
| 
 | |
| /// Set up SwiftErrorVals by going through the function. If the function has
 | |
| /// swifterror argument, it will be the first entry.
 | |
| void SwiftErrorValueTracking::setFunction(MachineFunction &mf) {
 | |
|   MF = &mf;
 | |
|   Fn = &MF->getFunction();
 | |
|   TLI = MF->getSubtarget().getTargetLowering();
 | |
|   TII = MF->getSubtarget().getInstrInfo();
 | |
| 
 | |
|   if (!TLI->supportSwiftError())
 | |
|     return;
 | |
| 
 | |
|   SwiftErrorVals.clear();
 | |
|   VRegDefMap.clear();
 | |
|   VRegUpwardsUse.clear();
 | |
|   VRegDefUses.clear();
 | |
|   SwiftErrorArg = nullptr;
 | |
| 
 | |
|   // Check if function has a swifterror argument.
 | |
|   bool HaveSeenSwiftErrorArg = false;
 | |
|   for (Function::const_arg_iterator AI = Fn->arg_begin(), AE = Fn->arg_end();
 | |
|        AI != AE; ++AI)
 | |
|     if (AI->hasSwiftErrorAttr()) {
 | |
|       assert(!HaveSeenSwiftErrorArg &&
 | |
|              "Must have only one swifterror parameter");
 | |
|       (void)HaveSeenSwiftErrorArg; // silence warning.
 | |
|       HaveSeenSwiftErrorArg = true;
 | |
|       SwiftErrorArg = &*AI;
 | |
|       SwiftErrorVals.push_back(&*AI);
 | |
|     }
 | |
| 
 | |
|   for (const auto &LLVMBB : *Fn)
 | |
|     for (const auto &Inst : LLVMBB) {
 | |
|       if (const AllocaInst *Alloca = dyn_cast<AllocaInst>(&Inst))
 | |
|         if (Alloca->isSwiftError())
 | |
|           SwiftErrorVals.push_back(Alloca);
 | |
|     }
 | |
| }
 | |
| 
 | |
| bool SwiftErrorValueTracking::createEntriesInEntryBlock(DebugLoc DbgLoc) {
 | |
|   if (!TLI->supportSwiftError())
 | |
|     return false;
 | |
| 
 | |
|   // We only need to do this when we have swifterror parameter or swifterror
 | |
|   // alloc.
 | |
|   if (SwiftErrorVals.empty())
 | |
|     return false;
 | |
| 
 | |
|   MachineBasicBlock *MBB = &*MF->begin();
 | |
|   auto &DL = MF->getDataLayout();
 | |
|   auto const *RC = TLI->getRegClassFor(TLI->getPointerTy(DL));
 | |
|   bool Inserted = false;
 | |
|   for (const auto *SwiftErrorVal : SwiftErrorVals) {
 | |
|     // We will always generate a copy from the argument. It is always used at
 | |
|     // least by the 'return' of the swifterror.
 | |
|     if (SwiftErrorArg && SwiftErrorArg == SwiftErrorVal)
 | |
|       continue;
 | |
|     Register VReg = MF->getRegInfo().createVirtualRegister(RC);
 | |
|     // Assign Undef to Vreg. We construct MI directly to make sure it works
 | |
|     // with FastISel.
 | |
|     BuildMI(*MBB, MBB->getFirstNonPHI(), DbgLoc,
 | |
|             TII->get(TargetOpcode::IMPLICIT_DEF), VReg);
 | |
| 
 | |
|     setCurrentVReg(MBB, SwiftErrorVal, VReg);
 | |
|     Inserted = true;
 | |
|   }
 | |
| 
 | |
|   return Inserted;
 | |
| }
 | |
| 
 | |
| /// Propagate swifterror values through the machine function CFG.
 | |
| void SwiftErrorValueTracking::propagateVRegs() {
 | |
|   if (!TLI->supportSwiftError())
 | |
|     return;
 | |
| 
 | |
|   // We only need to do this when we have swifterror parameter or swifterror
 | |
|   // alloc.
 | |
|   if (SwiftErrorVals.empty())
 | |
|     return;
 | |
| 
 | |
|   // For each machine basic block in reverse post order.
 | |
|   ReversePostOrderTraversal<MachineFunction *> RPOT(MF);
 | |
|   for (MachineBasicBlock *MBB : RPOT) {
 | |
|     // For each swifterror value in the function.
 | |
|     for (const auto *SwiftErrorVal : SwiftErrorVals) {
 | |
|       auto Key = std::make_pair(MBB, SwiftErrorVal);
 | |
|       auto UUseIt = VRegUpwardsUse.find(Key);
 | |
|       auto VRegDefIt = VRegDefMap.find(Key);
 | |
|       bool UpwardsUse = UUseIt != VRegUpwardsUse.end();
 | |
|       Register UUseVReg = UpwardsUse ? UUseIt->second : Register();
 | |
|       bool DownwardDef = VRegDefIt != VRegDefMap.end();
 | |
|       assert(!(UpwardsUse && !DownwardDef) &&
 | |
|              "We can't have an upwards use but no downwards def");
 | |
| 
 | |
|       // If there is no upwards exposed use and an entry for the swifterror in
 | |
|       // the def map for this value we don't need to do anything: We already
 | |
|       // have a downward def for this basic block.
 | |
|       if (!UpwardsUse && DownwardDef)
 | |
|         continue;
 | |
| 
 | |
|       // Otherwise we either have an upwards exposed use vreg that we need to
 | |
|       // materialize or need to forward the downward def from predecessors.
 | |
| 
 | |
|       // Check whether we have a single vreg def from all predecessors.
 | |
|       // Otherwise we need a phi.
 | |
|       SmallVector<std::pair<MachineBasicBlock *, Register>, 4> VRegs;
 | |
|       SmallSet<const MachineBasicBlock *, 8> Visited;
 | |
|       for (auto *Pred : MBB->predecessors()) {
 | |
|         if (!Visited.insert(Pred).second)
 | |
|           continue;
 | |
|         VRegs.push_back(std::make_pair(
 | |
|             Pred, getOrCreateVReg(Pred, SwiftErrorVal)));
 | |
|         if (Pred != MBB)
 | |
|           continue;
 | |
|         // We have a self-edge.
 | |
|         // If there was no upwards use in this basic block there is now one: the
 | |
|         // phi needs to use it self.
 | |
|         if (!UpwardsUse) {
 | |
|           UpwardsUse = true;
 | |
|           UUseIt = VRegUpwardsUse.find(Key);
 | |
|           assert(UUseIt != VRegUpwardsUse.end());
 | |
|           UUseVReg = UUseIt->second;
 | |
|         }
 | |
|       }
 | |
| 
 | |
|       // We need a phi node if we have more than one predecessor with different
 | |
|       // downward defs.
 | |
|       bool needPHI =
 | |
|           VRegs.size() >= 1 &&
 | |
|           std::find_if(
 | |
|               VRegs.begin(), VRegs.end(),
 | |
|               [&](const std::pair<const MachineBasicBlock *, Register> &V)
 | |
|                   -> bool { return V.second != VRegs[0].second; }) !=
 | |
|               VRegs.end();
 | |
| 
 | |
|       // If there is no upwards exposed used and we don't need a phi just
 | |
|       // forward the swifterror vreg from the predecessor(s).
 | |
|       if (!UpwardsUse && !needPHI) {
 | |
|         assert(!VRegs.empty() &&
 | |
|                "No predecessors? The entry block should bail out earlier");
 | |
|         // Just forward the swifterror vreg from the predecessor(s).
 | |
|         setCurrentVReg(MBB, SwiftErrorVal, VRegs[0].second);
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       auto DLoc = isa<Instruction>(SwiftErrorVal)
 | |
|                       ? cast<Instruction>(SwiftErrorVal)->getDebugLoc()
 | |
|                       : DebugLoc();
 | |
|       const auto *TII = MF->getSubtarget().getInstrInfo();
 | |
| 
 | |
|       // If we don't need a phi create a copy to the upward exposed vreg.
 | |
|       if (!needPHI) {
 | |
|         assert(UpwardsUse);
 | |
|         assert(!VRegs.empty() &&
 | |
|                "No predecessors?  Is the Calling Convention correct?");
 | |
|         Register DestReg = UUseVReg;
 | |
|         BuildMI(*MBB, MBB->getFirstNonPHI(), DLoc, TII->get(TargetOpcode::COPY),
 | |
|                 DestReg)
 | |
|             .addReg(VRegs[0].second);
 | |
|         continue;
 | |
|       }
 | |
| 
 | |
|       // We need a phi: if there is an upwards exposed use we already have a
 | |
|       // destination virtual register number otherwise we generate a new one.
 | |
|       auto &DL = MF->getDataLayout();
 | |
|       auto const *RC = TLI->getRegClassFor(TLI->getPointerTy(DL));
 | |
|       Register PHIVReg =
 | |
|           UpwardsUse ? UUseVReg : MF->getRegInfo().createVirtualRegister(RC);
 | |
|       MachineInstrBuilder PHI =
 | |
|           BuildMI(*MBB, MBB->getFirstNonPHI(), DLoc,
 | |
|                   TII->get(TargetOpcode::PHI), PHIVReg);
 | |
|       for (auto BBRegPair : VRegs) {
 | |
|         PHI.addReg(BBRegPair.second).addMBB(BBRegPair.first);
 | |
|       }
 | |
| 
 | |
|       // We did not have a definition in this block before: store the phi's vreg
 | |
|       // as this block downward exposed def.
 | |
|       if (!UpwardsUse)
 | |
|         setCurrentVReg(MBB, SwiftErrorVal, PHIVReg);
 | |
|     }
 | |
|   }
 | |
| }
 | |
| 
 | |
| void SwiftErrorValueTracking::preassignVRegs(
 | |
|     MachineBasicBlock *MBB, BasicBlock::const_iterator Begin,
 | |
|     BasicBlock::const_iterator End) {
 | |
|   if (!TLI->supportSwiftError() || SwiftErrorVals.empty())
 | |
|     return;
 | |
| 
 | |
|   // Iterator over instructions and assign vregs to swifterror defs and uses.
 | |
|   for (auto It = Begin; It != End; ++It) {
 | |
|     ImmutableCallSite CS(&*It);
 | |
|     if (CS) {
 | |
|       // A call-site with a swifterror argument is both use and def.
 | |
|       const Value *SwiftErrorAddr = nullptr;
 | |
|       for (auto &Arg : CS.args()) {
 | |
|         if (!Arg->isSwiftError())
 | |
|           continue;
 | |
|         // Use of swifterror.
 | |
|         assert(!SwiftErrorAddr && "Cannot have multiple swifterror arguments");
 | |
|         SwiftErrorAddr = &*Arg;
 | |
|         assert(SwiftErrorAddr->isSwiftError() &&
 | |
|                "Must have a swifterror value argument");
 | |
|         getOrCreateVRegUseAt(&*It, MBB, SwiftErrorAddr);
 | |
|       }
 | |
|       if (!SwiftErrorAddr)
 | |
|         continue;
 | |
| 
 | |
|       // Def of swifterror.
 | |
|       getOrCreateVRegDefAt(&*It, MBB, SwiftErrorAddr);
 | |
| 
 | |
|       // A load is a use.
 | |
|     } else if (const LoadInst *LI = dyn_cast<const LoadInst>(&*It)) {
 | |
|       const Value *V = LI->getOperand(0);
 | |
|       if (!V->isSwiftError())
 | |
|         continue;
 | |
| 
 | |
|       getOrCreateVRegUseAt(LI, MBB, V);
 | |
| 
 | |
|       // A store is a def.
 | |
|     } else if (const StoreInst *SI = dyn_cast<const StoreInst>(&*It)) {
 | |
|       const Value *SwiftErrorAddr = SI->getOperand(1);
 | |
|       if (!SwiftErrorAddr->isSwiftError())
 | |
|         continue;
 | |
| 
 | |
|       // Def of swifterror.
 | |
|       getOrCreateVRegDefAt(&*It, MBB, SwiftErrorAddr);
 | |
| 
 | |
|       // A return in a swiferror returning function is a use.
 | |
|     } else if (const ReturnInst *R = dyn_cast<const ReturnInst>(&*It)) {
 | |
|       const Function *F = R->getParent()->getParent();
 | |
|       if (!F->getAttributes().hasAttrSomewhere(Attribute::SwiftError))
 | |
|         continue;
 | |
| 
 | |
|       getOrCreateVRegUseAt(R, MBB, SwiftErrorArg);
 | |
|     }
 | |
|   }
 | |
| }
 |