1 //===- NVPTXProxyRegErasure.cpp - NVPTX Proxy Register Instruction Erasure -==// 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 // The pass is needed to remove ProxyReg instructions and restore related 10 // registers. The instructions were needed at instruction selection stage to 11 // make sure that callseq_end nodes won't be removed as "dead nodes". This can 12 // happen when we expand instructions into libcalls and the call site doesn't 13 // care about the libcall chain. Call site cares about data flow only, and the 14 // latest data flow node happens to be before callseq_end. Therefore the node 15 // becomes dangling and "dead". The ProxyReg acts like an additional data flow 16 // node *after* the callseq_end in the chain and ensures that everything will be 17 // preserved. 18 // 19 //===----------------------------------------------------------------------===// 20 21 #include "NVPTX.h" 22 #include "llvm/CodeGen/MachineFunctionPass.h" 23 #include "llvm/CodeGen/TargetRegisterInfo.h" 24 25 using namespace llvm; 26 27 namespace llvm { 28 void initializeNVPTXProxyRegErasurePass(PassRegistry &); 29 } 30 31 namespace { 32 33 struct NVPTXProxyRegErasure : public MachineFunctionPass { 34 static char ID; 35 NVPTXProxyRegErasure() : MachineFunctionPass(ID) { 36 initializeNVPTXProxyRegErasurePass(*PassRegistry::getPassRegistry()); 37 } 38 39 bool runOnMachineFunction(MachineFunction &MF) override; 40 41 StringRef getPassName() const override { 42 return "NVPTX Proxy Register Instruction Erasure"; 43 } 44 45 void getAnalysisUsage(AnalysisUsage &AU) const override { 46 MachineFunctionPass::getAnalysisUsage(AU); 47 } 48 }; 49 50 } // namespace 51 52 char NVPTXProxyRegErasure::ID = 0; 53 54 INITIALIZE_PASS(NVPTXProxyRegErasure, "nvptx-proxyreg-erasure", 55 "NVPTX ProxyReg Erasure", false, false) 56 57 bool NVPTXProxyRegErasure::runOnMachineFunction(MachineFunction &MF) { 58 SmallVector<MachineInstr *, 16> RemoveList; 59 60 // ProxyReg instructions forward a register as another: `%dst = mov.iN %src`. 61 // Bulk RAUW the `%dst` registers in two passes over the machine function. 62 DenseMap<Register, Register> RAUWBatch; 63 64 for (auto &BB : MF) { 65 for (auto &MI : BB) { 66 switch (MI.getOpcode()) { 67 case NVPTX::ProxyRegI1: 68 case NVPTX::ProxyRegI16: 69 case NVPTX::ProxyRegI32: 70 case NVPTX::ProxyRegI64: 71 case NVPTX::ProxyRegF32: 72 case NVPTX::ProxyRegF64: { 73 auto &InOp = *MI.uses().begin(); 74 auto &OutOp = *MI.defs().begin(); 75 assert(InOp.isReg() && "ProxyReg input should be a register."); 76 assert(OutOp.isReg() && "ProxyReg output should be a register."); 77 RemoveList.push_back(&MI); 78 Register replacement = InOp.getReg(); 79 // Check if the replacement itself has been replaced. 80 if (auto it = RAUWBatch.find(replacement); it != RAUWBatch.end()) 81 replacement = it->second; 82 RAUWBatch.try_emplace(OutOp.getReg(), replacement); 83 break; 84 } 85 } 86 } 87 } 88 89 // If there were no proxy instructions, exit early. 90 if (RemoveList.empty()) 91 return false; 92 93 // Erase the proxy instructions first. 94 for (auto *MI : RemoveList) { 95 MI->eraseFromParent(); 96 } 97 98 // Now go replace the registers. 99 for (auto &BB : MF) { 100 for (auto &MI : BB) { 101 for (auto &Op : MI.uses()) { 102 if (!Op.isReg()) 103 continue; 104 auto it = RAUWBatch.find(Op.getReg()); 105 if (it != RAUWBatch.end()) 106 Op.setReg(it->second); 107 } 108 } 109 } 110 111 return true; 112 } 113 114 MachineFunctionPass *llvm::createNVPTXProxyRegErasurePass() { 115 return new NVPTXProxyRegErasure(); 116 } 117