1*0fca6ea1SDimitry Andric //===------- HexagonTfrCleanup.cpp - Hexagon Transfer Cleanup Pass -------===// 2*0fca6ea1SDimitry Andric // 3*0fca6ea1SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4*0fca6ea1SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5*0fca6ea1SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6*0fca6ea1SDimitry Andric // 7*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 8*0fca6ea1SDimitry Andric // This pass is to address a situation that appears after register allocaion 9*0fca6ea1SDimitry Andric // evey now and then, namely a register copy from a source that was defined 10*0fca6ea1SDimitry Andric // as an immediate value in the same block (usually just before the copy). 11*0fca6ea1SDimitry Andric // 12*0fca6ea1SDimitry Andric // Here is an example of actual code emitted that shows this problem: 13*0fca6ea1SDimitry Andric // 14*0fca6ea1SDimitry Andric // .LBB0_5: 15*0fca6ea1SDimitry Andric // { 16*0fca6ea1SDimitry Andric // r5 = zxtb(r8) 17*0fca6ea1SDimitry Andric // r6 = or(r6, ##12345) 18*0fca6ea1SDimitry Andric // } 19*0fca6ea1SDimitry Andric // { 20*0fca6ea1SDimitry Andric // r3 = xor(r1, r2) 21*0fca6ea1SDimitry Andric // r1 = #0 <-- r1 set to #0 22*0fca6ea1SDimitry Andric // } 23*0fca6ea1SDimitry Andric // { 24*0fca6ea1SDimitry Andric // r7 = r1 <-- r7 set to r1 25*0fca6ea1SDimitry Andric // r0 = zxtb(r3) 26*0fca6ea1SDimitry Andric // } 27*0fca6ea1SDimitry Andric 28*0fca6ea1SDimitry Andric #define DEBUG_TYPE "tfr-cleanup" 29*0fca6ea1SDimitry Andric #include "HexagonTargetMachine.h" 30*0fca6ea1SDimitry Andric 31*0fca6ea1SDimitry Andric #include "llvm/CodeGen/LiveInterval.h" 32*0fca6ea1SDimitry Andric #include "llvm/CodeGen/LiveIntervals.h" 33*0fca6ea1SDimitry Andric #include "llvm/CodeGen/MachineFunction.h" 34*0fca6ea1SDimitry Andric #include "llvm/CodeGen/MachineInstrBuilder.h" 35*0fca6ea1SDimitry Andric #include "llvm/CodeGen/MachineRegisterInfo.h" 36*0fca6ea1SDimitry Andric #include "llvm/CodeGen/Passes.h" 37*0fca6ea1SDimitry Andric #include "llvm/CodeGen/TargetInstrInfo.h" 38*0fca6ea1SDimitry Andric #include "llvm/CodeGen/TargetRegisterInfo.h" 39*0fca6ea1SDimitry Andric #include "llvm/Support/CommandLine.h" 40*0fca6ea1SDimitry Andric #include "llvm/Support/Debug.h" 41*0fca6ea1SDimitry Andric #include "llvm/Support/raw_ostream.h" 42*0fca6ea1SDimitry Andric #include "llvm/Target/TargetMachine.h" 43*0fca6ea1SDimitry Andric 44*0fca6ea1SDimitry Andric using namespace llvm; 45*0fca6ea1SDimitry Andric 46*0fca6ea1SDimitry Andric namespace llvm { 47*0fca6ea1SDimitry Andric FunctionPass *createHexagonTfrCleanup(); 48*0fca6ea1SDimitry Andric void initializeHexagonTfrCleanupPass(PassRegistry &); 49*0fca6ea1SDimitry Andric } // namespace llvm 50*0fca6ea1SDimitry Andric 51*0fca6ea1SDimitry Andric namespace { 52*0fca6ea1SDimitry Andric class HexagonTfrCleanup : public MachineFunctionPass { 53*0fca6ea1SDimitry Andric public: 54*0fca6ea1SDimitry Andric static char ID; 55*0fca6ea1SDimitry Andric HexagonTfrCleanup() : MachineFunctionPass(ID), HII(0), TRI(0) { 56*0fca6ea1SDimitry Andric PassRegistry &R = *PassRegistry::getPassRegistry(); 57*0fca6ea1SDimitry Andric initializeHexagonTfrCleanupPass(R); 58*0fca6ea1SDimitry Andric } 59*0fca6ea1SDimitry Andric StringRef getPassName() const override { return "Hexagon TFR Cleanup"; } 60*0fca6ea1SDimitry Andric void getAnalysisUsage(AnalysisUsage &AU) const override { 61*0fca6ea1SDimitry Andric AU.setPreservesAll(); 62*0fca6ea1SDimitry Andric MachineFunctionPass::getAnalysisUsage(AU); 63*0fca6ea1SDimitry Andric } 64*0fca6ea1SDimitry Andric bool runOnMachineFunction(MachineFunction &MF) override; 65*0fca6ea1SDimitry Andric 66*0fca6ea1SDimitry Andric private: 67*0fca6ea1SDimitry Andric const HexagonInstrInfo *HII; 68*0fca6ea1SDimitry Andric const TargetRegisterInfo *TRI; 69*0fca6ea1SDimitry Andric 70*0fca6ea1SDimitry Andric typedef DenseMap<unsigned, uint64_t> ImmediateMap; 71*0fca6ea1SDimitry Andric 72*0fca6ea1SDimitry Andric bool isIntReg(unsigned Reg, bool &Is32); 73*0fca6ea1SDimitry Andric void setReg(unsigned R32, uint32_t V32, ImmediateMap &IMap); 74*0fca6ea1SDimitry Andric bool getReg(unsigned Reg, uint64_t &Val, ImmediateMap &IMap); 75*0fca6ea1SDimitry Andric bool updateImmMap(MachineInstr *MI, ImmediateMap &IMap); 76*0fca6ea1SDimitry Andric bool rewriteIfImm(MachineInstr *MI, ImmediateMap &IMap, SlotIndexes *Indexes); 77*0fca6ea1SDimitry Andric bool eraseIfRedundant(MachineInstr *MI, SlotIndexes *Indexes); 78*0fca6ea1SDimitry Andric }; 79*0fca6ea1SDimitry Andric } // namespace 80*0fca6ea1SDimitry Andric 81*0fca6ea1SDimitry Andric char HexagonTfrCleanup::ID = 0; 82*0fca6ea1SDimitry Andric 83*0fca6ea1SDimitry Andric namespace llvm { 84*0fca6ea1SDimitry Andric char &HexagonTfrCleanupID = HexagonTfrCleanup::ID; 85*0fca6ea1SDimitry Andric } 86*0fca6ea1SDimitry Andric 87*0fca6ea1SDimitry Andric bool HexagonTfrCleanup::isIntReg(unsigned Reg, bool &Is32) { 88*0fca6ea1SDimitry Andric Is32 = Hexagon::IntRegsRegClass.contains(Reg); 89*0fca6ea1SDimitry Andric return Is32 || Hexagon::DoubleRegsRegClass.contains(Reg); 90*0fca6ea1SDimitry Andric } 91*0fca6ea1SDimitry Andric 92*0fca6ea1SDimitry Andric // Assign given value V32 to the specified the register R32 in the map. Only 93*0fca6ea1SDimitry Andric // 32-bit registers are valid arguments. 94*0fca6ea1SDimitry Andric void HexagonTfrCleanup::setReg(unsigned R32, uint32_t V32, ImmediateMap &IMap) { 95*0fca6ea1SDimitry Andric ImmediateMap::iterator F = IMap.find(R32); 96*0fca6ea1SDimitry Andric if (F == IMap.end()) 97*0fca6ea1SDimitry Andric IMap.insert(std::make_pair(R32, V32)); 98*0fca6ea1SDimitry Andric else 99*0fca6ea1SDimitry Andric F->second = V32; 100*0fca6ea1SDimitry Andric } 101*0fca6ea1SDimitry Andric 102*0fca6ea1SDimitry Andric // Retrieve a value of the provided register Reg and store it into Val. 103*0fca6ea1SDimitry Andric // Return "true" if a value was found, "false" otherwise. 104*0fca6ea1SDimitry Andric bool HexagonTfrCleanup::getReg(unsigned Reg, uint64_t &Val, 105*0fca6ea1SDimitry Andric ImmediateMap &IMap) { 106*0fca6ea1SDimitry Andric bool Is32; 107*0fca6ea1SDimitry Andric if (!isIntReg(Reg, Is32)) 108*0fca6ea1SDimitry Andric return false; 109*0fca6ea1SDimitry Andric 110*0fca6ea1SDimitry Andric if (Is32) { 111*0fca6ea1SDimitry Andric ImmediateMap::iterator F = IMap.find(Reg); 112*0fca6ea1SDimitry Andric if (F == IMap.end()) 113*0fca6ea1SDimitry Andric return false; 114*0fca6ea1SDimitry Andric Val = F->second; 115*0fca6ea1SDimitry Andric return true; 116*0fca6ea1SDimitry Andric } 117*0fca6ea1SDimitry Andric 118*0fca6ea1SDimitry Andric // For 64-bit registers, compose the value from the values of its 119*0fca6ea1SDimitry Andric // subregisters. 120*0fca6ea1SDimitry Andric unsigned SubL = TRI->getSubReg(Reg, Hexagon::isub_lo); 121*0fca6ea1SDimitry Andric unsigned SubH = TRI->getSubReg(Reg, Hexagon::isub_hi); 122*0fca6ea1SDimitry Andric ImmediateMap::iterator FL = IMap.find(SubL), FH = IMap.find(SubH); 123*0fca6ea1SDimitry Andric if (FL == IMap.end() || FH == IMap.end()) 124*0fca6ea1SDimitry Andric return false; 125*0fca6ea1SDimitry Andric Val = (FH->second << 32) | FL->second; 126*0fca6ea1SDimitry Andric return true; 127*0fca6ea1SDimitry Andric } 128*0fca6ea1SDimitry Andric 129*0fca6ea1SDimitry Andric // Process an instruction and record the relevant information in the imme- 130*0fca6ea1SDimitry Andric // diate map. 131*0fca6ea1SDimitry Andric bool HexagonTfrCleanup::updateImmMap(MachineInstr *MI, ImmediateMap &IMap) { 132*0fca6ea1SDimitry Andric using namespace Hexagon; 133*0fca6ea1SDimitry Andric 134*0fca6ea1SDimitry Andric if (MI->isCall()) { 135*0fca6ea1SDimitry Andric IMap.clear(); 136*0fca6ea1SDimitry Andric return true; 137*0fca6ea1SDimitry Andric } 138*0fca6ea1SDimitry Andric 139*0fca6ea1SDimitry Andric // If this is an instruction that loads a constant into a register, 140*0fca6ea1SDimitry Andric // record this information in IMap. 141*0fca6ea1SDimitry Andric unsigned Opc = MI->getOpcode(); 142*0fca6ea1SDimitry Andric if (Opc == A2_tfrsi || Opc == A2_tfrpi) { 143*0fca6ea1SDimitry Andric unsigned DefR = MI->getOperand(0).getReg(); 144*0fca6ea1SDimitry Andric bool Is32; 145*0fca6ea1SDimitry Andric if (!isIntReg(DefR, Is32)) 146*0fca6ea1SDimitry Andric return false; 147*0fca6ea1SDimitry Andric if (!MI->getOperand(1).isImm()) { 148*0fca6ea1SDimitry Andric if (!Is32) { 149*0fca6ea1SDimitry Andric IMap.erase(TRI->getSubReg(DefR, isub_lo)); 150*0fca6ea1SDimitry Andric IMap.erase(TRI->getSubReg(DefR, isub_hi)); 151*0fca6ea1SDimitry Andric } else { 152*0fca6ea1SDimitry Andric IMap.erase(DefR); 153*0fca6ea1SDimitry Andric } 154*0fca6ea1SDimitry Andric return false; 155*0fca6ea1SDimitry Andric } 156*0fca6ea1SDimitry Andric uint64_t Val = MI->getOperand(1).getImm(); 157*0fca6ea1SDimitry Andric // If it's a 64-bit register, break it up into subregisters. 158*0fca6ea1SDimitry Andric if (!Is32) { 159*0fca6ea1SDimitry Andric uint32_t VH = (Val >> 32), VL = (Val & 0xFFFFFFFFU); 160*0fca6ea1SDimitry Andric setReg(TRI->getSubReg(DefR, isub_lo), VL, IMap); 161*0fca6ea1SDimitry Andric setReg(TRI->getSubReg(DefR, isub_hi), VH, IMap); 162*0fca6ea1SDimitry Andric } else { 163*0fca6ea1SDimitry Andric setReg(DefR, Val, IMap); 164*0fca6ea1SDimitry Andric } 165*0fca6ea1SDimitry Andric return true; 166*0fca6ea1SDimitry Andric } 167*0fca6ea1SDimitry Andric 168*0fca6ea1SDimitry Andric // Not a A2_tfr[sp]i. Invalidate all modified registers in IMap. 169*0fca6ea1SDimitry Andric for (MachineInstr::mop_iterator Mo = MI->operands_begin(), 170*0fca6ea1SDimitry Andric E = MI->operands_end(); 171*0fca6ea1SDimitry Andric Mo != E; ++Mo) { 172*0fca6ea1SDimitry Andric if (Mo->isRegMask()) { 173*0fca6ea1SDimitry Andric IMap.clear(); 174*0fca6ea1SDimitry Andric return true; 175*0fca6ea1SDimitry Andric } 176*0fca6ea1SDimitry Andric if (!Mo->isReg() || !Mo->isDef()) 177*0fca6ea1SDimitry Andric continue; 178*0fca6ea1SDimitry Andric unsigned R = Mo->getReg(); 179*0fca6ea1SDimitry Andric for (MCRegAliasIterator AR(R, TRI, true); AR.isValid(); ++AR) { 180*0fca6ea1SDimitry Andric ImmediateMap::iterator F = IMap.find(*AR); 181*0fca6ea1SDimitry Andric if (F != IMap.end()) 182*0fca6ea1SDimitry Andric IMap.erase(F); 183*0fca6ea1SDimitry Andric } 184*0fca6ea1SDimitry Andric } 185*0fca6ea1SDimitry Andric return true; 186*0fca6ea1SDimitry Andric } 187*0fca6ea1SDimitry Andric 188*0fca6ea1SDimitry Andric // Rewrite the instruction as A2_tfrsi/A2_tfrpi, it is a copy of a source that 189*0fca6ea1SDimitry Andric // has a known constant value. 190*0fca6ea1SDimitry Andric bool HexagonTfrCleanup::rewriteIfImm(MachineInstr *MI, ImmediateMap &IMap, 191*0fca6ea1SDimitry Andric SlotIndexes *Indexes) { 192*0fca6ea1SDimitry Andric using namespace Hexagon; 193*0fca6ea1SDimitry Andric unsigned Opc = MI->getOpcode(); 194*0fca6ea1SDimitry Andric switch (Opc) { 195*0fca6ea1SDimitry Andric case A2_tfr: 196*0fca6ea1SDimitry Andric case A2_tfrp: 197*0fca6ea1SDimitry Andric case COPY: 198*0fca6ea1SDimitry Andric break; 199*0fca6ea1SDimitry Andric default: 200*0fca6ea1SDimitry Andric return false; 201*0fca6ea1SDimitry Andric } 202*0fca6ea1SDimitry Andric 203*0fca6ea1SDimitry Andric unsigned DstR = MI->getOperand(0).getReg(); 204*0fca6ea1SDimitry Andric unsigned SrcR = MI->getOperand(1).getReg(); 205*0fca6ea1SDimitry Andric bool Tmp, Is32; 206*0fca6ea1SDimitry Andric if (!isIntReg(DstR, Is32) || !isIntReg(SrcR, Tmp)) 207*0fca6ea1SDimitry Andric return false; 208*0fca6ea1SDimitry Andric assert(Tmp == Is32 && "Register size mismatch"); 209*0fca6ea1SDimitry Andric uint64_t Val; 210*0fca6ea1SDimitry Andric bool Found = getReg(SrcR, Val, IMap); 211*0fca6ea1SDimitry Andric if (!Found) 212*0fca6ea1SDimitry Andric return false; 213*0fca6ea1SDimitry Andric 214*0fca6ea1SDimitry Andric MachineBasicBlock &B = *MI->getParent(); 215*0fca6ea1SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 216*0fca6ea1SDimitry Andric int64_t SVal = Is32 ? int32_t(Val) : Val; 217*0fca6ea1SDimitry Andric auto &HST = B.getParent()->getSubtarget<HexagonSubtarget>(); 218*0fca6ea1SDimitry Andric MachineInstr *NewMI; 219*0fca6ea1SDimitry Andric if (Is32) 220*0fca6ea1SDimitry Andric NewMI = BuildMI(B, MI, DL, HII->get(A2_tfrsi), DstR).addImm(SVal); 221*0fca6ea1SDimitry Andric else if (isInt<8>(SVal)) 222*0fca6ea1SDimitry Andric NewMI = BuildMI(B, MI, DL, HII->get(A2_tfrpi), DstR).addImm(SVal); 223*0fca6ea1SDimitry Andric else if (isInt<8>(SVal >> 32) && isInt<8>(int32_t(Val & 0xFFFFFFFFLL))) 224*0fca6ea1SDimitry Andric NewMI = BuildMI(B, MI, DL, HII->get(A2_combineii), DstR) 225*0fca6ea1SDimitry Andric .addImm(int32_t(SVal >> 32)) 226*0fca6ea1SDimitry Andric .addImm(int32_t(Val & 0xFFFFFFFFLL)); 227*0fca6ea1SDimitry Andric else if (HST.isTinyCore()) 228*0fca6ea1SDimitry Andric // Disable generating CONST64 since it requires load resource. 229*0fca6ea1SDimitry Andric return false; 230*0fca6ea1SDimitry Andric else 231*0fca6ea1SDimitry Andric NewMI = BuildMI(B, MI, DL, HII->get(CONST64), DstR).addImm(Val); 232*0fca6ea1SDimitry Andric 233*0fca6ea1SDimitry Andric // Replace the MI to reuse the same slot index 234*0fca6ea1SDimitry Andric if (Indexes) 235*0fca6ea1SDimitry Andric Indexes->replaceMachineInstrInMaps(*MI, *NewMI); 236*0fca6ea1SDimitry Andric MI->eraseFromParent(); 237*0fca6ea1SDimitry Andric return true; 238*0fca6ea1SDimitry Andric } 239*0fca6ea1SDimitry Andric 240*0fca6ea1SDimitry Andric // Remove the instruction if it is a self-assignment. 241*0fca6ea1SDimitry Andric bool HexagonTfrCleanup::eraseIfRedundant(MachineInstr *MI, 242*0fca6ea1SDimitry Andric SlotIndexes *Indexes) { 243*0fca6ea1SDimitry Andric unsigned Opc = MI->getOpcode(); 244*0fca6ea1SDimitry Andric unsigned DefR, SrcR; 245*0fca6ea1SDimitry Andric bool IsUndef = false; 246*0fca6ea1SDimitry Andric switch (Opc) { 247*0fca6ea1SDimitry Andric case Hexagon::A2_tfr: 248*0fca6ea1SDimitry Andric // Rd = Rd 249*0fca6ea1SDimitry Andric DefR = MI->getOperand(0).getReg(); 250*0fca6ea1SDimitry Andric SrcR = MI->getOperand(1).getReg(); 251*0fca6ea1SDimitry Andric IsUndef = MI->getOperand(1).isUndef(); 252*0fca6ea1SDimitry Andric break; 253*0fca6ea1SDimitry Andric case Hexagon::A2_tfrt: 254*0fca6ea1SDimitry Andric case Hexagon::A2_tfrf: 255*0fca6ea1SDimitry Andric // if ([!]Pu) Rd = Rd 256*0fca6ea1SDimitry Andric DefR = MI->getOperand(0).getReg(); 257*0fca6ea1SDimitry Andric SrcR = MI->getOperand(2).getReg(); 258*0fca6ea1SDimitry Andric IsUndef = MI->getOperand(2).isUndef(); 259*0fca6ea1SDimitry Andric break; 260*0fca6ea1SDimitry Andric default: 261*0fca6ea1SDimitry Andric return false; 262*0fca6ea1SDimitry Andric } 263*0fca6ea1SDimitry Andric if (DefR != SrcR) 264*0fca6ea1SDimitry Andric return false; 265*0fca6ea1SDimitry Andric if (IsUndef) { 266*0fca6ea1SDimitry Andric MachineBasicBlock &B = *MI->getParent(); 267*0fca6ea1SDimitry Andric DebugLoc DL = MI->getDebugLoc(); 268*0fca6ea1SDimitry Andric auto DefI = BuildMI(B, MI, DL, HII->get(TargetOpcode::IMPLICIT_DEF), DefR); 269*0fca6ea1SDimitry Andric for (auto &Op : MI->operands()) 270*0fca6ea1SDimitry Andric if (Op.isReg() && Op.isDef() && Op.isImplicit()) 271*0fca6ea1SDimitry Andric DefI->addOperand(Op); 272*0fca6ea1SDimitry Andric } 273*0fca6ea1SDimitry Andric 274*0fca6ea1SDimitry Andric if (Indexes) 275*0fca6ea1SDimitry Andric Indexes->removeMachineInstrFromMaps(*MI); 276*0fca6ea1SDimitry Andric MI->eraseFromParent(); 277*0fca6ea1SDimitry Andric return true; 278*0fca6ea1SDimitry Andric } 279*0fca6ea1SDimitry Andric 280*0fca6ea1SDimitry Andric bool HexagonTfrCleanup::runOnMachineFunction(MachineFunction &MF) { 281*0fca6ea1SDimitry Andric bool Changed = false; 282*0fca6ea1SDimitry Andric // Map: 32-bit register -> immediate value. 283*0fca6ea1SDimitry Andric // 64-bit registers are stored through their subregisters. 284*0fca6ea1SDimitry Andric ImmediateMap IMap; 285*0fca6ea1SDimitry Andric auto *SIWrapper = getAnalysisIfAvailable<SlotIndexesWrapperPass>(); 286*0fca6ea1SDimitry Andric SlotIndexes *Indexes = SIWrapper ? &SIWrapper->getSI() : nullptr; 287*0fca6ea1SDimitry Andric 288*0fca6ea1SDimitry Andric auto &HST = MF.getSubtarget<HexagonSubtarget>(); 289*0fca6ea1SDimitry Andric HII = HST.getInstrInfo(); 290*0fca6ea1SDimitry Andric TRI = HST.getRegisterInfo(); 291*0fca6ea1SDimitry Andric 292*0fca6ea1SDimitry Andric for (MachineBasicBlock &B : MF) { 293*0fca6ea1SDimitry Andric MachineBasicBlock::iterator J, F, NextJ; 294*0fca6ea1SDimitry Andric IMap.clear(); 295*0fca6ea1SDimitry Andric bool Inserted = false, Erased = false; 296*0fca6ea1SDimitry Andric for (J = B.begin(), F = B.end(); J != F; J = NextJ) { 297*0fca6ea1SDimitry Andric NextJ = std::next(J); 298*0fca6ea1SDimitry Andric MachineInstr *MI = &*J; 299*0fca6ea1SDimitry Andric bool E = eraseIfRedundant(MI, Indexes); 300*0fca6ea1SDimitry Andric Erased |= E; 301*0fca6ea1SDimitry Andric if (E) 302*0fca6ea1SDimitry Andric continue; 303*0fca6ea1SDimitry Andric Inserted |= rewriteIfImm(MI, IMap, Indexes); 304*0fca6ea1SDimitry Andric MachineBasicBlock::iterator NewJ = std::prev(NextJ); 305*0fca6ea1SDimitry Andric updateImmMap(&*NewJ, IMap); 306*0fca6ea1SDimitry Andric } 307*0fca6ea1SDimitry Andric bool BlockC = Inserted | Erased; 308*0fca6ea1SDimitry Andric Changed |= BlockC; 309*0fca6ea1SDimitry Andric if (BlockC && Indexes) 310*0fca6ea1SDimitry Andric Indexes->repairIndexesInRange(&B, B.begin(), B.end()); 311*0fca6ea1SDimitry Andric } 312*0fca6ea1SDimitry Andric 313*0fca6ea1SDimitry Andric return Changed; 314*0fca6ea1SDimitry Andric } 315*0fca6ea1SDimitry Andric 316*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 317*0fca6ea1SDimitry Andric // Public Constructor Functions 318*0fca6ea1SDimitry Andric //===----------------------------------------------------------------------===// 319*0fca6ea1SDimitry Andric INITIALIZE_PASS(HexagonTfrCleanup, "tfr-cleanup", "Hexagon TFR Cleanup", false, 320*0fca6ea1SDimitry Andric false) 321*0fca6ea1SDimitry Andric 322*0fca6ea1SDimitry Andric FunctionPass *llvm::createHexagonTfrCleanup() { 323*0fca6ea1SDimitry Andric return new HexagonTfrCleanup(); 324*0fca6ea1SDimitry Andric } 325