1 //===------ LeonPasses.cpp - Define passes specific to LEON ---------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "LeonPasses.h" 14 #include "llvm/CodeGen/MachineFunction.h" 15 #include "llvm/CodeGen/ISDOpcodes.h" 16 #include "llvm/Support/raw_ostream.h" 17 #include "llvm/IR/LLVMContext.h" 18 #include "llvm/CodeGen/MachineInstrBuilder.h" 19 #include "llvm/CodeGen/MachineInstr.h" 20 #include "llvm/CodeGen/MachineRegisterInfo.h" 21 using namespace llvm; 22 23 LEONMachineFunctionPass::LEONMachineFunctionPass(TargetMachine &tm, char& ID) : 24 MachineFunctionPass(ID) 25 { 26 } 27 28 LEONMachineFunctionPass::LEONMachineFunctionPass(char& ID) : 29 MachineFunctionPass(ID) 30 { 31 } 32 33 int LEONMachineFunctionPass::GetRegIndexForOperand(MachineInstr& MI, int OperandIndex) 34 { 35 if (MI.getNumOperands() > 0) { 36 if (OperandIndex == LAST_OPERAND) { 37 OperandIndex = MI.getNumOperands() - 1; 38 } 39 40 if (MI.getNumOperands() > (unsigned) OperandIndex 41 && 42 MI.getOperand(OperandIndex).isReg()) { 43 return (int) MI.getOperand(OperandIndex).getReg(); 44 } 45 } 46 47 static int NotFoundIndex = -10; 48 // Return a different number each time to avoid any comparisons between the values returned. 49 NotFoundIndex -= 10; 50 return NotFoundIndex; 51 } 52 53 void LEONMachineFunctionPass::clearUsedRegisterList() 54 { 55 UsedRegisters.clear(); 56 } 57 58 void LEONMachineFunctionPass::markRegisterUsed(int registerIndex) 59 { 60 UsedRegisters.push_back(registerIndex); 61 } 62 63 //finds a new free FP register 64 //checks also the AllocatedRegisters vector 65 int LEONMachineFunctionPass::getUnusedFPRegister(MachineRegisterInfo& MRI) 66 { 67 for (int RegisterIndex = SP::F0 ; RegisterIndex <= SP::F31 ; ++RegisterIndex) { 68 if (!MRI.isPhysRegUsed(RegisterIndex) && 69 !(std::find(UsedRegisters.begin(), UsedRegisters.end(), RegisterIndex) != UsedRegisters.end())) { 70 return RegisterIndex; 71 } 72 } 73 74 return -1; 75 } 76 77 78 //***************************************************************************** 79 //**** InsertNOPLoad pass 80 //***************************************************************************** 81 //This pass inserts a NOP after any LD or LDF instruction. 82 // 83 char InsertNOPLoad::ID = 0; 84 85 InsertNOPLoad::InsertNOPLoad(TargetMachine &tm) : 86 LEONMachineFunctionPass(tm, ID) 87 { 88 } 89 90 bool InsertNOPLoad::runOnMachineFunction(MachineFunction& MF) 91 { 92 Subtarget = &MF.getSubtarget<SparcSubtarget>(); 93 const TargetInstrInfo& TII = *Subtarget->getInstrInfo(); 94 DebugLoc DL = DebugLoc(); 95 96 bool Modified = false; 97 for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { 98 MachineBasicBlock &MBB = *MFI; 99 for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++ MBBI) { 100 MachineInstr &MI = *MBBI; 101 unsigned Opcode = MI.getOpcode(); 102 if (Opcode >= SP::LDDArr && Opcode <= SP::LDrr) { 103 //errs() << "Inserting NOP after LD instruction\n"; 104 MachineBasicBlock::iterator NMBBI = std::next(MBBI); 105 BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP)); 106 Modified = true; 107 } 108 else if (MI.isInlineAsm()) { 109 // Look for an inline ld or ldf instruction. 110 StringRef AsmString = 111 MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName(); 112 if (AsmString.startswith_lower("ld")) { 113 //errs() << "Inserting NOP after LD instruction\n"; 114 MachineBasicBlock::iterator NMBBI = std::next(MBBI); 115 BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP)); 116 Modified = true; 117 } 118 } 119 } 120 } 121 122 return Modified; 123 } 124 125 //***************************************************************************** 126 //**** FixFSMULD pass 127 //***************************************************************************** 128 //this pass should convert the FSMULD operands to double precision in scratch registers, 129 //then calculate the result with the FMULD instruction. Therefore, the pass should replace operations of the form: 130 //fsmuld %f20,%f21,%f8 131 //with the sequence: 132 //fstod %f20,%f0 133 //fstod %f21,%f2 134 //fmuld %f0,%f2,%f8 135 // 136 char FixFSMULD::ID = 0; 137 138 FixFSMULD::FixFSMULD(TargetMachine &tm) : 139 LEONMachineFunctionPass(tm, ID) 140 { 141 } 142 143 bool FixFSMULD::runOnMachineFunction(MachineFunction& MF) 144 { 145 Subtarget = &MF.getSubtarget<SparcSubtarget>(); 146 const TargetInstrInfo& TII = *Subtarget->getInstrInfo(); 147 DebugLoc DL = DebugLoc(); 148 149 //errs() << "FixFSMULD on function " << MF.getName() << "\n"; 150 151 bool Modified = false; 152 for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { 153 MachineBasicBlock &MBB = *MFI; 154 for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++ MBBI) { 155 156 MachineInstr &MI = *MBBI; 157 unsigned Opcode = MI.getOpcode(); 158 159 const int UNASSIGNED_INDEX = -1; 160 int Reg1Index = UNASSIGNED_INDEX; 161 int Reg2Index = UNASSIGNED_INDEX; 162 int Reg3Index = UNASSIGNED_INDEX; 163 164 if (Opcode == SP::FSMULD && MI.getNumOperands() == 3) { 165 //errs() << "Detected FSMULD\n"; 166 //take the registers from fsmuld %f20,%f21,%f8 167 Reg1Index = MI.getOperand(0).getReg(); 168 Reg2Index = MI.getOperand(1).getReg(); 169 Reg3Index = MI.getOperand(2).getReg(); 170 } 171 else if (MI.isInlineAsm()) { 172 StringRef AsmString( 173 MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName()); 174 if (AsmString.startswith_lower("fsmuld")) { 175 //errs() << "Detected InlineAsm FSMULD\n"; 176 177 unsigned StartOp = InlineAsm::MIOp_FirstOperand; 178 179 //extracts the registers from the inline assembly instruction 180 for (unsigned i = StartOp, e = MI.getNumOperands(); i != e; ++i) { 181 const MachineOperand &MO = MI.getOperand(i); 182 if (MO.isReg()) { 183 if (Reg1Index == UNASSIGNED_INDEX) Reg1Index = MO.getReg(); 184 else if (Reg2Index == UNASSIGNED_INDEX) Reg2Index = MO.getReg(); 185 else if (Reg3Index == UNASSIGNED_INDEX) Reg3Index = MO.getReg(); 186 } 187 if (Reg3Index != UNASSIGNED_INDEX) 188 break; 189 } 190 } 191 } 192 193 if (Reg1Index != UNASSIGNED_INDEX && Reg2Index != UNASSIGNED_INDEX && Reg3Index != UNASSIGNED_INDEX) { 194 clearUsedRegisterList(); 195 MachineBasicBlock::iterator NMBBI = std::next(MBBI); 196 //Whatever Reg3Index is hasn't been used yet, so we need to reserve it. 197 markRegisterUsed(Reg3Index); 198 const int ScratchReg1Index = getUnusedFPRegister(MF.getRegInfo()); 199 markRegisterUsed(ScratchReg1Index); 200 const int ScratchReg2Index = getUnusedFPRegister(MF.getRegInfo()); 201 markRegisterUsed(ScratchReg2Index); 202 203 if (ScratchReg1Index == UNASSIGNED_INDEX || ScratchReg2Index == UNASSIGNED_INDEX) { 204 //errs() << "Cannot allocate free scratch registers for the FixFSMULD pass." << "\n"; 205 } 206 else { 207 //create fstod %f20,%f0 208 BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD)) 209 .addReg(ScratchReg1Index) 210 .addReg(Reg1Index); 211 212 //create fstod %f21,%f2 213 BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD)) 214 .addReg(ScratchReg2Index) 215 .addReg(Reg2Index); 216 217 //create fmuld %f0,%f2,%f8 218 BuildMI(MBB, MBBI, DL, TII.get(SP::FMULD)) 219 .addReg(Reg3Index) 220 .addReg(ScratchReg1Index) 221 .addReg(ScratchReg2Index); 222 223 MI.eraseFromParent(); 224 MBBI = NMBBI; 225 226 Modified = true; 227 } 228 } 229 } 230 } 231 232 return Modified; 233 } 234 235 236 //***************************************************************************** 237 //**** ReplaceFMULS pass 238 //***************************************************************************** 239 //This pass converts the FMULS operands to double precision in scratch registers, 240 //then calculates the result with the FMULD instruction. 241 //The pass should replace operations of the form: 242 //fmuls %f20,%f21,%f8 243 //with the sequence: 244 //fstod %f20,%f0 245 //fstod %f21,%f2 246 //fmuld %f0,%f2,%f8 247 // 248 char ReplaceFMULS::ID = 0; 249 250 ReplaceFMULS::ReplaceFMULS(TargetMachine &tm) : 251 LEONMachineFunctionPass(tm, ID) 252 { 253 } 254 255 bool ReplaceFMULS::runOnMachineFunction(MachineFunction& MF) 256 { 257 Subtarget = &MF.getSubtarget<SparcSubtarget>(); 258 const TargetInstrInfo& TII = *Subtarget->getInstrInfo(); 259 DebugLoc DL = DebugLoc(); 260 261 //errs() << "ReplaceFMULS on function " << MF.getName() << "\n"; 262 263 bool Modified = false; 264 for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { 265 MachineBasicBlock &MBB = *MFI; 266 for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++ MBBI) { 267 MachineInstr &MI = *MBBI; 268 unsigned Opcode = MI.getOpcode(); 269 270 const int UNASSIGNED_INDEX = -1; 271 int Reg1Index = UNASSIGNED_INDEX; 272 int Reg2Index = UNASSIGNED_INDEX; 273 int Reg3Index = UNASSIGNED_INDEX; 274 275 if (Opcode == SP::FMULS && MI.getNumOperands() == 3) { 276 //errs() << "Detected FMULS\n"; 277 //take the registers from fmuls %f20,%f21,%f8 278 Reg1Index = MI.getOperand(0).getReg(); 279 Reg2Index = MI.getOperand(1).getReg(); 280 Reg3Index = MI.getOperand(2).getReg(); 281 } 282 else if (MI.isInlineAsm()) { 283 StringRef AsmString( 284 MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName()); 285 if (AsmString.startswith_lower("fmuls")) { 286 //errs() << "Detected InlineAsm FMULS\n"; 287 288 unsigned StartOp = InlineAsm::MIOp_FirstOperand; 289 290 //extracts the registers from the inline assembly instruction 291 for (unsigned i = StartOp, e = MI.getNumOperands(); i != e; ++i) { 292 const MachineOperand &MO = MI.getOperand(i); 293 if (MO.isReg()) { 294 if (Reg1Index == UNASSIGNED_INDEX) Reg1Index = MO.getReg(); 295 else if (Reg2Index == UNASSIGNED_INDEX) Reg2Index = MO.getReg(); 296 else if (Reg3Index == UNASSIGNED_INDEX) Reg3Index = MO.getReg(); 297 } 298 if (Reg3Index != UNASSIGNED_INDEX) 299 break; 300 } 301 } 302 } 303 304 if (Reg1Index != UNASSIGNED_INDEX && Reg2Index != UNASSIGNED_INDEX && Reg3Index != UNASSIGNED_INDEX) { 305 clearUsedRegisterList(); 306 MachineBasicBlock::iterator NMBBI = std::next(MBBI); 307 //Whatever Reg3Index is hasn't been used yet, so we need to reserve it. 308 markRegisterUsed(Reg3Index); 309 const int ScratchReg1Index = getUnusedFPRegister(MF.getRegInfo()); 310 markRegisterUsed(ScratchReg1Index); 311 const int ScratchReg2Index = getUnusedFPRegister(MF.getRegInfo()); 312 markRegisterUsed(ScratchReg2Index); 313 314 if (ScratchReg1Index == UNASSIGNED_INDEX || ScratchReg2Index == UNASSIGNED_INDEX) { 315 //errs() << "Cannot allocate free scratch registers for the ReplaceFMULS pass." << "\n"; 316 } 317 else { 318 //create fstod %f20,%f0 319 BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD)) 320 .addReg(ScratchReg1Index) 321 .addReg(Reg1Index); 322 323 //create fstod %f21,%f2 324 BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD)) 325 .addReg(ScratchReg2Index) 326 .addReg(Reg2Index); 327 328 //create fmuld %f0,%f2,%f8 329 BuildMI(MBB, MBBI, DL, TII.get(SP::FMULD)) 330 .addReg(Reg3Index) 331 .addReg(ScratchReg1Index) 332 .addReg(ScratchReg2Index); 333 334 MI.eraseFromParent(); 335 MBBI = NMBBI; 336 337 Modified = true; 338 } 339 } 340 } 341 } 342 343 return Modified; 344 } 345 346 //***************************************************************************** 347 //**** FixAllFDIVSQRT pass 348 //***************************************************************************** 349 //This pass implements two fixes: 350 // 1) fixing the FSQRTS and FSQRTD instructions; 351 // 2) fixing the FDIVS and FDIVD instructions. 352 // 353 char FixAllFDIVSQRT::ID = 0; 354 355 FixAllFDIVSQRT::FixAllFDIVSQRT(TargetMachine &tm) : 356 LEONMachineFunctionPass(tm, ID) 357 { 358 } 359 360 bool FixAllFDIVSQRT::runOnMachineFunction(MachineFunction& MF) 361 { 362 Subtarget = &MF.getSubtarget<SparcSubtarget>(); 363 const TargetInstrInfo& TII = *Subtarget->getInstrInfo(); 364 DebugLoc DL = DebugLoc(); 365 366 //errs() << "FixAllFDIVSQRT on function " << MF.getName() << "\n"; 367 368 bool Modified = false; 369 for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { 370 MachineBasicBlock &MBB = *MFI; 371 //MBB.print(errs()); 372 for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++ MBBI) { 373 MachineInstr &MI = *MBBI; 374 //MI.print(errs()); 375 unsigned Opcode = MI.getOpcode(); 376 377 if (MI.isInlineAsm()) { 378 StringRef AsmString( 379 MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName()); 380 if (AsmString.startswith_lower("fsqrtd")) { 381 //errs() << "Detected InlineAsm FSQRTD\n"; 382 Opcode = SP::FSQRTD; 383 } else if (AsmString.startswith_lower("fdivd")) { 384 //errs() << "Detected InlineAsm FDIVD\n"; 385 Opcode = SP::FDIVD; 386 } 387 } 388 389 // Note: FDIVS and FSQRTS cannot be generated when this erratum fix is switched on 390 // so we don't need to check for them here. They will already have been converted 391 // to FSQRTD or FDIVD earlier in the pipeline. 392 if (Opcode == SP::FSQRTD || Opcode == SP::FDIVD) { 393 //errs() << "Inserting 5 NOPs before FSQRTD,FDIVD.\n"; 394 for (int InsertedCount=0; InsertedCount<5; InsertedCount++) 395 BuildMI(MBB, MBBI, DL, TII.get(SP::NOP)); 396 397 MachineBasicBlock::iterator NMBBI = std::next(MBBI); 398 //errs() << "Inserting 28 NOPs after FSQRTD,FDIVD.\n"; 399 for (int InsertedCount=0; InsertedCount<28; InsertedCount++) 400 BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP)); 401 402 Modified = true; 403 } 404 } 405 } 406 407 return Modified; 408 } 409