1*62c7b5bfSEvan Cheng //===-- MLxExpansionPass.cpp - Expand MLx instrs to avoid hazards ----------=// 2*62c7b5bfSEvan Cheng // 3*62c7b5bfSEvan Cheng // The LLVM Compiler Infrastructure 4*62c7b5bfSEvan Cheng // 5*62c7b5bfSEvan Cheng // This file is distributed under the University of Illinois Open Source 6*62c7b5bfSEvan Cheng // License. See LICENSE.TXT for details. 7*62c7b5bfSEvan Cheng // 8*62c7b5bfSEvan Cheng //===----------------------------------------------------------------------===// 9*62c7b5bfSEvan Cheng // 10*62c7b5bfSEvan Cheng // Expand VFP / NEON floating point MLA / MLS instructions (each to a pair of 11*62c7b5bfSEvan Cheng // multiple and add / sub instructions) when special VMLx hazards are detected. 12*62c7b5bfSEvan Cheng // 13*62c7b5bfSEvan Cheng //===----------------------------------------------------------------------===// 14*62c7b5bfSEvan Cheng 15*62c7b5bfSEvan Cheng #define DEBUG_TYPE "mlx-expansion" 16*62c7b5bfSEvan Cheng #include "ARM.h" 17*62c7b5bfSEvan Cheng #include "ARMBaseInstrInfo.h" 18*62c7b5bfSEvan Cheng #include "llvm/CodeGen/MachineInstr.h" 19*62c7b5bfSEvan Cheng #include "llvm/CodeGen/MachineInstrBuilder.h" 20*62c7b5bfSEvan Cheng #include "llvm/CodeGen/MachineFunctionPass.h" 21*62c7b5bfSEvan Cheng #include "llvm/CodeGen/MachineRegisterInfo.h" 22*62c7b5bfSEvan Cheng #include "llvm/Target/TargetRegisterInfo.h" 23*62c7b5bfSEvan Cheng #include "llvm/ADT/DenseMap.h" 24*62c7b5bfSEvan Cheng #include "llvm/ADT/SmallSet.h" 25*62c7b5bfSEvan Cheng #include "llvm/ADT/Statistic.h" 26*62c7b5bfSEvan Cheng #include "llvm/Support/CommandLine.h" 27*62c7b5bfSEvan Cheng #include "llvm/Support/Debug.h" 28*62c7b5bfSEvan Cheng #include "llvm/Support/raw_ostream.h" 29*62c7b5bfSEvan Cheng using namespace llvm; 30*62c7b5bfSEvan Cheng 31*62c7b5bfSEvan Cheng static cl::opt<bool> 32*62c7b5bfSEvan Cheng ForceExapnd("expand-all-fp-mlx", cl::init(false), cl::Hidden); 33*62c7b5bfSEvan Cheng static cl::opt<unsigned> 34*62c7b5bfSEvan Cheng ExpandLimit("expand-limit", cl::init(~0U), cl::Hidden); 35*62c7b5bfSEvan Cheng 36*62c7b5bfSEvan Cheng STATISTIC(NumExpand, "Number of fp MLA / MLS instructions expanded"); 37*62c7b5bfSEvan Cheng 38*62c7b5bfSEvan Cheng namespace { 39*62c7b5bfSEvan Cheng struct MLxExpansion : public MachineFunctionPass { 40*62c7b5bfSEvan Cheng static char ID; 41*62c7b5bfSEvan Cheng MLxExpansion() : MachineFunctionPass(ID) {} 42*62c7b5bfSEvan Cheng 43*62c7b5bfSEvan Cheng virtual bool runOnMachineFunction(MachineFunction &Fn); 44*62c7b5bfSEvan Cheng 45*62c7b5bfSEvan Cheng virtual const char *getPassName() const { 46*62c7b5bfSEvan Cheng return "ARM MLA / MLS expansion pass"; 47*62c7b5bfSEvan Cheng } 48*62c7b5bfSEvan Cheng 49*62c7b5bfSEvan Cheng private: 50*62c7b5bfSEvan Cheng const ARMBaseInstrInfo *TII; 51*62c7b5bfSEvan Cheng const TargetRegisterInfo *TRI; 52*62c7b5bfSEvan Cheng MachineRegisterInfo *MRI; 53*62c7b5bfSEvan Cheng 54*62c7b5bfSEvan Cheng unsigned HazardLimit; 55*62c7b5bfSEvan Cheng unsigned MIIdx; 56*62c7b5bfSEvan Cheng MachineInstr* LastMIs[4]; 57*62c7b5bfSEvan Cheng 58*62c7b5bfSEvan Cheng void clearStack(); 59*62c7b5bfSEvan Cheng void pushStack(MachineInstr *MI); 60*62c7b5bfSEvan Cheng MachineInstr *getAccDefMI(MachineInstr *MI) const; 61*62c7b5bfSEvan Cheng unsigned getDefReg(MachineInstr *MI) const; 62*62c7b5bfSEvan Cheng bool hasRAWHazard(unsigned Reg, MachineInstr *MI) const; 63*62c7b5bfSEvan Cheng bool FindMLxHazard(MachineInstr *MI) const; 64*62c7b5bfSEvan Cheng void ExpandFPMLxInstruction(MachineBasicBlock &MBB, MachineInstr *MI, 65*62c7b5bfSEvan Cheng unsigned MulOpc, unsigned AddSubOpc, 66*62c7b5bfSEvan Cheng bool NegAcc, bool HasLane); 67*62c7b5bfSEvan Cheng bool ExpandFPMLxInstructions(MachineBasicBlock &MBB); 68*62c7b5bfSEvan Cheng }; 69*62c7b5bfSEvan Cheng char MLxExpansion::ID = 0; 70*62c7b5bfSEvan Cheng } 71*62c7b5bfSEvan Cheng 72*62c7b5bfSEvan Cheng void MLxExpansion::clearStack() { 73*62c7b5bfSEvan Cheng std::fill(LastMIs, LastMIs + 4, (MachineInstr*)0); 74*62c7b5bfSEvan Cheng MIIdx = 0; 75*62c7b5bfSEvan Cheng } 76*62c7b5bfSEvan Cheng 77*62c7b5bfSEvan Cheng void MLxExpansion::pushStack(MachineInstr *MI) { 78*62c7b5bfSEvan Cheng LastMIs[MIIdx] = MI; 79*62c7b5bfSEvan Cheng if (++MIIdx == 4) 80*62c7b5bfSEvan Cheng MIIdx = 0; 81*62c7b5bfSEvan Cheng } 82*62c7b5bfSEvan Cheng 83*62c7b5bfSEvan Cheng MachineInstr *MLxExpansion::getAccDefMI(MachineInstr *MI) const { 84*62c7b5bfSEvan Cheng // Look past COPY and INSERT_SUBREG instructions to find the 85*62c7b5bfSEvan Cheng // real definition MI. This is important for _sfp instructions. 86*62c7b5bfSEvan Cheng unsigned Reg = MI->getOperand(1).getReg(); 87*62c7b5bfSEvan Cheng if (TargetRegisterInfo::isPhysicalRegister(Reg)) 88*62c7b5bfSEvan Cheng return 0; 89*62c7b5bfSEvan Cheng 90*62c7b5bfSEvan Cheng MachineBasicBlock *MBB = MI->getParent(); 91*62c7b5bfSEvan Cheng MachineInstr *DefMI = MRI->getVRegDef(Reg); 92*62c7b5bfSEvan Cheng while (true) { 93*62c7b5bfSEvan Cheng if (DefMI->getParent() != MBB) 94*62c7b5bfSEvan Cheng break; 95*62c7b5bfSEvan Cheng if (DefMI->isCopyLike()) { 96*62c7b5bfSEvan Cheng Reg = DefMI->getOperand(1).getReg(); 97*62c7b5bfSEvan Cheng if (TargetRegisterInfo::isVirtualRegister(Reg)) { 98*62c7b5bfSEvan Cheng DefMI = MRI->getVRegDef(Reg); 99*62c7b5bfSEvan Cheng continue; 100*62c7b5bfSEvan Cheng } 101*62c7b5bfSEvan Cheng } else if (DefMI->isInsertSubreg()) { 102*62c7b5bfSEvan Cheng Reg = DefMI->getOperand(2).getReg(); 103*62c7b5bfSEvan Cheng if (TargetRegisterInfo::isVirtualRegister(Reg)) { 104*62c7b5bfSEvan Cheng DefMI = MRI->getVRegDef(Reg); 105*62c7b5bfSEvan Cheng continue; 106*62c7b5bfSEvan Cheng } 107*62c7b5bfSEvan Cheng } 108*62c7b5bfSEvan Cheng break; 109*62c7b5bfSEvan Cheng } 110*62c7b5bfSEvan Cheng return DefMI; 111*62c7b5bfSEvan Cheng } 112*62c7b5bfSEvan Cheng 113*62c7b5bfSEvan Cheng unsigned MLxExpansion::getDefReg(MachineInstr *MI) const { 114*62c7b5bfSEvan Cheng unsigned Reg = MI->getOperand(0).getReg(); 115*62c7b5bfSEvan Cheng if (TargetRegisterInfo::isPhysicalRegister(Reg) || 116*62c7b5bfSEvan Cheng !MRI->hasOneNonDBGUse(Reg)) 117*62c7b5bfSEvan Cheng return Reg; 118*62c7b5bfSEvan Cheng 119*62c7b5bfSEvan Cheng MachineBasicBlock *MBB = MI->getParent(); 120*62c7b5bfSEvan Cheng MachineInstr *UseMI = &*MRI->use_nodbg_begin(Reg); 121*62c7b5bfSEvan Cheng if (UseMI->getParent() != MBB) 122*62c7b5bfSEvan Cheng return Reg; 123*62c7b5bfSEvan Cheng 124*62c7b5bfSEvan Cheng while (UseMI->isCopy() || UseMI->isInsertSubreg()) { 125*62c7b5bfSEvan Cheng Reg = UseMI->getOperand(0).getReg(); 126*62c7b5bfSEvan Cheng if (TargetRegisterInfo::isPhysicalRegister(Reg) || 127*62c7b5bfSEvan Cheng !MRI->hasOneNonDBGUse(Reg)) 128*62c7b5bfSEvan Cheng return Reg; 129*62c7b5bfSEvan Cheng UseMI = &*MRI->use_nodbg_begin(Reg); 130*62c7b5bfSEvan Cheng if (UseMI->getParent() != MBB) 131*62c7b5bfSEvan Cheng return Reg; 132*62c7b5bfSEvan Cheng } 133*62c7b5bfSEvan Cheng 134*62c7b5bfSEvan Cheng return Reg; 135*62c7b5bfSEvan Cheng } 136*62c7b5bfSEvan Cheng 137*62c7b5bfSEvan Cheng bool MLxExpansion::hasRAWHazard(unsigned Reg, MachineInstr *MI) const { 138*62c7b5bfSEvan Cheng const TargetInstrDesc &TID = MI->getDesc(); 139*62c7b5bfSEvan Cheng // FIXME: Detect integer instructions properly. 140*62c7b5bfSEvan Cheng unsigned Domain = TID.TSFlags & ARMII::DomainMask; 141*62c7b5bfSEvan Cheng if (Domain == ARMII::DomainVFP) { 142*62c7b5bfSEvan Cheng unsigned Opcode = TID.getOpcode(); 143*62c7b5bfSEvan Cheng if (Opcode == ARM::VSTRS || Opcode == ARM::VSTRD || 144*62c7b5bfSEvan Cheng Opcode == ARM::VMOVRS || Opcode == ARM::VMOVRRD) 145*62c7b5bfSEvan Cheng return false; 146*62c7b5bfSEvan Cheng } else if (Domain == ARMII::DomainNEON) { 147*62c7b5bfSEvan Cheng if (TID.mayStore() || TID.mayLoad()) 148*62c7b5bfSEvan Cheng return false; 149*62c7b5bfSEvan Cheng } else { 150*62c7b5bfSEvan Cheng return false; 151*62c7b5bfSEvan Cheng } 152*62c7b5bfSEvan Cheng 153*62c7b5bfSEvan Cheng return MI->readsRegister(Reg, TRI); 154*62c7b5bfSEvan Cheng return false; 155*62c7b5bfSEvan Cheng } 156*62c7b5bfSEvan Cheng 157*62c7b5bfSEvan Cheng 158*62c7b5bfSEvan Cheng bool MLxExpansion::FindMLxHazard(MachineInstr *MI) const { 159*62c7b5bfSEvan Cheng if (NumExpand >= ExpandLimit) 160*62c7b5bfSEvan Cheng return false; 161*62c7b5bfSEvan Cheng 162*62c7b5bfSEvan Cheng if (ForceExapnd) 163*62c7b5bfSEvan Cheng return true; 164*62c7b5bfSEvan Cheng 165*62c7b5bfSEvan Cheng MachineInstr *DefMI = getAccDefMI(MI); 166*62c7b5bfSEvan Cheng if (TII->isFpMLxInstruction(DefMI->getOpcode())) 167*62c7b5bfSEvan Cheng // r0 = vmla 168*62c7b5bfSEvan Cheng // r3 = vmla r0, r1, r2 169*62c7b5bfSEvan Cheng // takes 16 - 17 cycles 170*62c7b5bfSEvan Cheng // 171*62c7b5bfSEvan Cheng // r0 = vmla 172*62c7b5bfSEvan Cheng // r4 = vmul r1, r2 173*62c7b5bfSEvan Cheng // r3 = vadd r0, r4 174*62c7b5bfSEvan Cheng // takes about 14 - 15 cycles even with vmul stalling for 4 cycles. 175*62c7b5bfSEvan Cheng return true; 176*62c7b5bfSEvan Cheng 177*62c7b5bfSEvan Cheng // If a VMLA.F is followed by an VADD.F or VMUL.F with no RAW hazard, the 178*62c7b5bfSEvan Cheng // VADD.F or VMUL.F will stall 4 cycles before issue. The 4 cycle stall 179*62c7b5bfSEvan Cheng // preserves the in-order retirement of the instructions. 180*62c7b5bfSEvan Cheng // Look at the next few instructions, if *most* of them can cause hazards, 181*62c7b5bfSEvan Cheng // then the scheduler can't *fix* this, we'd better break up the VMLA. 182*62c7b5bfSEvan Cheng for (unsigned i = 1; i <= 4; ++i) { 183*62c7b5bfSEvan Cheng int Idx = ((int)MIIdx - i + 4) % 4; 184*62c7b5bfSEvan Cheng MachineInstr *NextMI = LastMIs[Idx]; 185*62c7b5bfSEvan Cheng if (!NextMI) 186*62c7b5bfSEvan Cheng continue; 187*62c7b5bfSEvan Cheng 188*62c7b5bfSEvan Cheng if (TII->canCauseFpMLxStall(NextMI->getOpcode())) 189*62c7b5bfSEvan Cheng return true; 190*62c7b5bfSEvan Cheng 191*62c7b5bfSEvan Cheng // Look for VMLx RAW hazard. 192*62c7b5bfSEvan Cheng if (hasRAWHazard(getDefReg(MI), NextMI)) 193*62c7b5bfSEvan Cheng return true; 194*62c7b5bfSEvan Cheng } 195*62c7b5bfSEvan Cheng 196*62c7b5bfSEvan Cheng return false; 197*62c7b5bfSEvan Cheng } 198*62c7b5bfSEvan Cheng 199*62c7b5bfSEvan Cheng /// ExpandFPMLxInstructions - Expand a MLA / MLS instruction into a pair 200*62c7b5bfSEvan Cheng /// of MUL + ADD / SUB instructions. 201*62c7b5bfSEvan Cheng void 202*62c7b5bfSEvan Cheng MLxExpansion::ExpandFPMLxInstruction(MachineBasicBlock &MBB, MachineInstr *MI, 203*62c7b5bfSEvan Cheng unsigned MulOpc, unsigned AddSubOpc, 204*62c7b5bfSEvan Cheng bool NegAcc, bool HasLane) { 205*62c7b5bfSEvan Cheng unsigned DstReg = MI->getOperand(0).getReg(); 206*62c7b5bfSEvan Cheng bool DstDead = MI->getOperand(0).isDead(); 207*62c7b5bfSEvan Cheng unsigned AccReg = MI->getOperand(1).getReg(); 208*62c7b5bfSEvan Cheng unsigned Src1Reg = MI->getOperand(2).getReg(); 209*62c7b5bfSEvan Cheng unsigned Src2Reg = MI->getOperand(3).getReg(); 210*62c7b5bfSEvan Cheng bool Src1Kill = MI->getOperand(2).isKill(); 211*62c7b5bfSEvan Cheng bool Src2Kill = MI->getOperand(3).isKill(); 212*62c7b5bfSEvan Cheng unsigned LaneImm = HasLane ? MI->getOperand(4).getImm() : 0; 213*62c7b5bfSEvan Cheng unsigned NextOp = HasLane ? 5 : 4; 214*62c7b5bfSEvan Cheng ARMCC::CondCodes Pred = (ARMCC::CondCodes)MI->getOperand(NextOp).getImm(); 215*62c7b5bfSEvan Cheng unsigned PredReg = MI->getOperand(++NextOp).getReg(); 216*62c7b5bfSEvan Cheng 217*62c7b5bfSEvan Cheng const TargetInstrDesc &TID1 = TII->get(MulOpc); 218*62c7b5bfSEvan Cheng const TargetInstrDesc &TID2 = TII->get(AddSubOpc); 219*62c7b5bfSEvan Cheng unsigned TmpReg = MRI->createVirtualRegister(TID1.getRegClass(0, TRI)); 220*62c7b5bfSEvan Cheng 221*62c7b5bfSEvan Cheng MachineInstrBuilder MIB = BuildMI(MBB, *MI, MI->getDebugLoc(), TID1, TmpReg) 222*62c7b5bfSEvan Cheng .addReg(Src1Reg, getKillRegState(Src1Kill)) 223*62c7b5bfSEvan Cheng .addReg(Src2Reg, getKillRegState(Src2Kill)); 224*62c7b5bfSEvan Cheng if (HasLane) 225*62c7b5bfSEvan Cheng MIB.addImm(LaneImm); 226*62c7b5bfSEvan Cheng MIB.addImm(Pred).addReg(PredReg); 227*62c7b5bfSEvan Cheng 228*62c7b5bfSEvan Cheng MIB = BuildMI(MBB, *MI, MI->getDebugLoc(), TID2) 229*62c7b5bfSEvan Cheng .addReg(DstReg, getDefRegState(true) | getDeadRegState(DstDead)); 230*62c7b5bfSEvan Cheng 231*62c7b5bfSEvan Cheng if (NegAcc) { 232*62c7b5bfSEvan Cheng bool AccKill = MRI->hasOneNonDBGUse(AccReg); 233*62c7b5bfSEvan Cheng MIB.addReg(TmpReg, getKillRegState(true)) 234*62c7b5bfSEvan Cheng .addReg(AccReg, getKillRegState(AccKill)); 235*62c7b5bfSEvan Cheng } else { 236*62c7b5bfSEvan Cheng MIB.addReg(AccReg).addReg(TmpReg, getKillRegState(true)); 237*62c7b5bfSEvan Cheng } 238*62c7b5bfSEvan Cheng MIB.addImm(Pred).addReg(PredReg); 239*62c7b5bfSEvan Cheng 240*62c7b5bfSEvan Cheng DEBUG({ 241*62c7b5bfSEvan Cheng dbgs() << "Expanding: " << *MI; 242*62c7b5bfSEvan Cheng dbgs() << " to:\n"; 243*62c7b5bfSEvan Cheng MachineBasicBlock::iterator MII = MI; 244*62c7b5bfSEvan Cheng MII = llvm::prior(MII); 245*62c7b5bfSEvan Cheng MachineInstr &MI2 = *MII; 246*62c7b5bfSEvan Cheng MII = llvm::prior(MII); 247*62c7b5bfSEvan Cheng MachineInstr &MI1 = *MII; 248*62c7b5bfSEvan Cheng dbgs() << " " << MI1; 249*62c7b5bfSEvan Cheng dbgs() << " " << MI2; 250*62c7b5bfSEvan Cheng }); 251*62c7b5bfSEvan Cheng 252*62c7b5bfSEvan Cheng MI->eraseFromParent(); 253*62c7b5bfSEvan Cheng ++NumExpand; 254*62c7b5bfSEvan Cheng } 255*62c7b5bfSEvan Cheng 256*62c7b5bfSEvan Cheng bool MLxExpansion::ExpandFPMLxInstructions(MachineBasicBlock &MBB) { 257*62c7b5bfSEvan Cheng bool Changed = false; 258*62c7b5bfSEvan Cheng 259*62c7b5bfSEvan Cheng clearStack(); 260*62c7b5bfSEvan Cheng 261*62c7b5bfSEvan Cheng unsigned Skip = 0; 262*62c7b5bfSEvan Cheng MachineBasicBlock::reverse_iterator MII = MBB.rbegin(), E = MBB.rend(); 263*62c7b5bfSEvan Cheng while (MII != E) { 264*62c7b5bfSEvan Cheng MachineInstr *MI = &*MII; 265*62c7b5bfSEvan Cheng 266*62c7b5bfSEvan Cheng if (MI->isLabel() || MI->isImplicitDef() || MI->isCopy()) { 267*62c7b5bfSEvan Cheng ++MII; 268*62c7b5bfSEvan Cheng continue; 269*62c7b5bfSEvan Cheng } 270*62c7b5bfSEvan Cheng 271*62c7b5bfSEvan Cheng const TargetInstrDesc &TID = MI->getDesc(); 272*62c7b5bfSEvan Cheng if (TID.isBarrier()) { 273*62c7b5bfSEvan Cheng clearStack(); 274*62c7b5bfSEvan Cheng Skip = 0; 275*62c7b5bfSEvan Cheng ++MII; 276*62c7b5bfSEvan Cheng continue; 277*62c7b5bfSEvan Cheng } 278*62c7b5bfSEvan Cheng 279*62c7b5bfSEvan Cheng unsigned Domain = TID.TSFlags & ARMII::DomainMask; 280*62c7b5bfSEvan Cheng if (Domain == ARMII::DomainGeneral) { 281*62c7b5bfSEvan Cheng if (++Skip == 2) 282*62c7b5bfSEvan Cheng // Assume dual issues of non-VFP / NEON instructions. 283*62c7b5bfSEvan Cheng pushStack(0); 284*62c7b5bfSEvan Cheng } else { 285*62c7b5bfSEvan Cheng Skip = 0; 286*62c7b5bfSEvan Cheng 287*62c7b5bfSEvan Cheng unsigned MulOpc, AddSubOpc; 288*62c7b5bfSEvan Cheng bool NegAcc, HasLane; 289*62c7b5bfSEvan Cheng if (!TII->isFpMLxInstruction(TID.getOpcode(), 290*62c7b5bfSEvan Cheng MulOpc, AddSubOpc, NegAcc, HasLane) || 291*62c7b5bfSEvan Cheng !FindMLxHazard(MI)) 292*62c7b5bfSEvan Cheng pushStack(MI); 293*62c7b5bfSEvan Cheng else { 294*62c7b5bfSEvan Cheng ExpandFPMLxInstruction(MBB, MI, MulOpc, AddSubOpc, NegAcc, HasLane); 295*62c7b5bfSEvan Cheng E = MBB.rend(); // May have changed if MI was the 1st instruction. 296*62c7b5bfSEvan Cheng Changed = true; 297*62c7b5bfSEvan Cheng continue; 298*62c7b5bfSEvan Cheng } 299*62c7b5bfSEvan Cheng } 300*62c7b5bfSEvan Cheng 301*62c7b5bfSEvan Cheng ++MII; 302*62c7b5bfSEvan Cheng } 303*62c7b5bfSEvan Cheng 304*62c7b5bfSEvan Cheng return Changed; 305*62c7b5bfSEvan Cheng } 306*62c7b5bfSEvan Cheng 307*62c7b5bfSEvan Cheng bool MLxExpansion::runOnMachineFunction(MachineFunction &Fn) { 308*62c7b5bfSEvan Cheng TII = static_cast<const ARMBaseInstrInfo*>(Fn.getTarget().getInstrInfo()); 309*62c7b5bfSEvan Cheng TRI = Fn.getTarget().getRegisterInfo(); 310*62c7b5bfSEvan Cheng MRI = &Fn.getRegInfo(); 311*62c7b5bfSEvan Cheng 312*62c7b5bfSEvan Cheng bool Modified = false; 313*62c7b5bfSEvan Cheng for (MachineFunction::iterator MFI = Fn.begin(), E = Fn.end(); MFI != E; 314*62c7b5bfSEvan Cheng ++MFI) { 315*62c7b5bfSEvan Cheng MachineBasicBlock &MBB = *MFI; 316*62c7b5bfSEvan Cheng Modified |= ExpandFPMLxInstructions(MBB); 317*62c7b5bfSEvan Cheng } 318*62c7b5bfSEvan Cheng 319*62c7b5bfSEvan Cheng return Modified; 320*62c7b5bfSEvan Cheng } 321*62c7b5bfSEvan Cheng 322*62c7b5bfSEvan Cheng FunctionPass *llvm::createMLxExpansionPass() { 323*62c7b5bfSEvan Cheng return new MLxExpansion(); 324*62c7b5bfSEvan Cheng } 325