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 std::string AsmString (MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName()); 173 std::string FMULSOpCoode ("fsmuld"); 174 std::transform(AsmString.begin(), AsmString.end(), AsmString.begin(), ::tolower); 175 if (AsmString.find(FMULSOpCoode) == 0) { // this is an inline FSMULD instruction 176 //errs() << "Detected InlineAsm FSMULD\n"; 177 178 unsigned StartOp = InlineAsm::MIOp_FirstOperand; 179 180 //extracts the registers from the inline assembly instruction 181 for (unsigned i = StartOp, e = MI.getNumOperands(); i != e; ++i) { 182 const MachineOperand &MO = MI.getOperand(i); 183 if (MO.isReg()) { 184 if (Reg1Index == UNASSIGNED_INDEX) Reg1Index = MO.getReg(); 185 else if (Reg2Index == UNASSIGNED_INDEX) Reg2Index = MO.getReg(); 186 else if (Reg3Index == UNASSIGNED_INDEX) Reg3Index = MO.getReg(); 187 } 188 if (Reg3Index != UNASSIGNED_INDEX) 189 break; 190 } 191 } 192 } 193 194 if (Reg1Index != UNASSIGNED_INDEX && Reg2Index != UNASSIGNED_INDEX && Reg3Index != UNASSIGNED_INDEX) { 195 clearUsedRegisterList(); 196 MachineBasicBlock::iterator NMBBI = std::next(MBBI); 197 //Whatever Reg3Index is hasn't been used yet, so we need to reserve it. 198 markRegisterUsed(Reg3Index); 199 const int ScratchReg1Index = getUnusedFPRegister(MF.getRegInfo()); 200 markRegisterUsed(ScratchReg1Index); 201 const int ScratchReg2Index = getUnusedFPRegister(MF.getRegInfo()); 202 markRegisterUsed(ScratchReg2Index); 203 204 if (ScratchReg1Index == UNASSIGNED_INDEX || ScratchReg2Index == UNASSIGNED_INDEX) { 205 //errs() << "Cannot allocate free scratch registers for the FixFSMULD pass." << "\n"; 206 } 207 else { 208 //create fstod %f20,%f0 209 BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD)) 210 .addReg(ScratchReg1Index) 211 .addReg(Reg1Index); 212 213 //create fstod %f21,%f2 214 BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD)) 215 .addReg(ScratchReg2Index) 216 .addReg(Reg2Index); 217 218 //create fmuld %f0,%f2,%f8 219 BuildMI(MBB, MBBI, DL, TII.get(SP::FMULD)) 220 .addReg(Reg3Index) 221 .addReg(ScratchReg1Index) 222 .addReg(ScratchReg2Index); 223 224 MI.eraseFromParent(); 225 MBBI = NMBBI; 226 227 Modified = true; 228 } 229 } 230 } 231 } 232 233 return Modified; 234 } 235 236 237 //***************************************************************************** 238 //**** ReplaceFMULS pass 239 //***************************************************************************** 240 //This pass converts the FMULS operands to double precision in scratch registers, 241 //then calculates the result with the FMULD instruction. 242 //The pass should replace operations of the form: 243 //fmuls %f20,%f21,%f8 244 //with the sequence: 245 //fstod %f20,%f0 246 //fstod %f21,%f2 247 //fmuld %f0,%f2,%f8 248 // 249 char ReplaceFMULS::ID = 0; 250 251 ReplaceFMULS::ReplaceFMULS(TargetMachine &tm) : 252 LEONMachineFunctionPass(tm, ID) 253 { 254 } 255 256 bool ReplaceFMULS::runOnMachineFunction(MachineFunction& MF) 257 { 258 Subtarget = &MF.getSubtarget<SparcSubtarget>(); 259 const TargetInstrInfo& TII = *Subtarget->getInstrInfo(); 260 DebugLoc DL = DebugLoc(); 261 262 //errs() << "ReplaceFMULS on function " << MF.getName() << "\n"; 263 264 bool Modified = false; 265 for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { 266 MachineBasicBlock &MBB = *MFI; 267 for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++ MBBI) { 268 MachineInstr &MI = *MBBI; 269 unsigned Opcode = MI.getOpcode(); 270 271 const int UNASSIGNED_INDEX = -1; 272 int Reg1Index = UNASSIGNED_INDEX; 273 int Reg2Index = UNASSIGNED_INDEX; 274 int Reg3Index = UNASSIGNED_INDEX; 275 276 if (Opcode == SP::FMULS && MI.getNumOperands() == 3) { 277 //errs() << "Detected FMULS\n"; 278 //take the registers from fmuls %f20,%f21,%f8 279 Reg1Index = MI.getOperand(0).getReg(); 280 Reg2Index = MI.getOperand(1).getReg(); 281 Reg3Index = MI.getOperand(2).getReg(); 282 } 283 else if (MI.isInlineAsm()) { 284 std::string AsmString (MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName()); 285 std::string FMULSOpCoode ("fmuls"); 286 std::transform(AsmString.begin(), AsmString.end(), AsmString.begin(), ::tolower); 287 if (AsmString.find(FMULSOpCoode) == 0) { // this is an inline FMULS instruction 288 //errs() << "Detected InlineAsm FMULS\n"; 289 290 unsigned StartOp = InlineAsm::MIOp_FirstOperand; 291 292 //extracts the registers from the inline assembly instruction 293 for (unsigned i = StartOp, e = MI.getNumOperands(); i != e; ++i) { 294 const MachineOperand &MO = MI.getOperand(i); 295 if (MO.isReg()) { 296 if (Reg1Index == UNASSIGNED_INDEX) Reg1Index = MO.getReg(); 297 else if (Reg2Index == UNASSIGNED_INDEX) Reg2Index = MO.getReg(); 298 else if (Reg3Index == UNASSIGNED_INDEX) Reg3Index = MO.getReg(); 299 } 300 if (Reg3Index != UNASSIGNED_INDEX) 301 break; 302 } 303 } 304 } 305 306 if (Reg1Index != UNASSIGNED_INDEX && Reg2Index != UNASSIGNED_INDEX && Reg3Index != UNASSIGNED_INDEX) { 307 clearUsedRegisterList(); 308 MachineBasicBlock::iterator NMBBI = std::next(MBBI); 309 //Whatever Reg3Index is hasn't been used yet, so we need to reserve it. 310 markRegisterUsed(Reg3Index); 311 const int ScratchReg1Index = getUnusedFPRegister(MF.getRegInfo()); 312 markRegisterUsed(ScratchReg1Index); 313 const int ScratchReg2Index = getUnusedFPRegister(MF.getRegInfo()); 314 markRegisterUsed(ScratchReg2Index); 315 316 if (ScratchReg1Index == UNASSIGNED_INDEX || ScratchReg2Index == UNASSIGNED_INDEX) { 317 //errs() << "Cannot allocate free scratch registers for the ReplaceFMULS pass." << "\n"; 318 } 319 else { 320 //create fstod %f20,%f0 321 BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD)) 322 .addReg(ScratchReg1Index) 323 .addReg(Reg1Index); 324 325 //create fstod %f21,%f2 326 BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD)) 327 .addReg(ScratchReg2Index) 328 .addReg(Reg2Index); 329 330 //create fmuld %f0,%f2,%f8 331 BuildMI(MBB, MBBI, DL, TII.get(SP::FMULD)) 332 .addReg(Reg3Index) 333 .addReg(ScratchReg1Index) 334 .addReg(ScratchReg2Index); 335 336 MI.eraseFromParent(); 337 MBBI = NMBBI; 338 339 Modified = true; 340 } 341 } 342 } 343 } 344 345 return Modified; 346 } 347 348 //***************************************************************************** 349 //**** FixAllFDIVSQRT pass 350 //***************************************************************************** 351 //This pass implements two fixes: 352 // 1) fixing the FSQRTS and FSQRTD instructions; 353 // 2) fixing the FDIVS and FDIVD instructions. 354 // 355 char FixAllFDIVSQRT::ID = 0; 356 357 FixAllFDIVSQRT::FixAllFDIVSQRT(TargetMachine &tm) : 358 LEONMachineFunctionPass(tm, ID) 359 { 360 } 361 362 bool FixAllFDIVSQRT::runOnMachineFunction(MachineFunction& MF) 363 { 364 Subtarget = &MF.getSubtarget<SparcSubtarget>(); 365 const TargetInstrInfo& TII = *Subtarget->getInstrInfo(); 366 DebugLoc DL = DebugLoc(); 367 368 //errs() << "FixAllFDIVSQRT on function " << MF.getName() << "\n"; 369 370 bool Modified = false; 371 for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { 372 MachineBasicBlock &MBB = *MFI; 373 //MBB.print(errs()); 374 for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++ MBBI) { 375 MachineInstr &MI = *MBBI; 376 //MI.print(errs()); 377 unsigned Opcode = MI.getOpcode(); 378 379 if (MI.isInlineAsm()) { 380 std::string AsmString (MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName()); 381 std::string FSQRTDOpCode ("fsqrtd"); 382 std::string FDIVDOpCode ("fdivd"); 383 std::transform(AsmString.begin(), AsmString.end(), AsmString.begin(), ::tolower); 384 if (AsmString.find(FSQRTDOpCode) == 0) { // this is an inline fsqrts instruction 385 //errs() << "Detected InlineAsm FSQRTD\n"; 386 Opcode = SP::FSQRTD; 387 } 388 else if (AsmString.find(FDIVDOpCode) == 0) { // this is an inline fsqrts instruction 389 //errs() << "Detected InlineAsm FDIVD\n"; 390 Opcode = SP::FDIVD; 391 } 392 } 393 394 // Note: FDIVS and FSQRTS cannot be generated when this erratum fix is switched on 395 // so we don't need to check for them here. They will already have been converted 396 // to FSQRTD or FDIVD earlier in the pipeline. 397 if (Opcode == SP::FSQRTD || Opcode == SP::FDIVD) { 398 //errs() << "Inserting 5 NOPs before FSQRTD,FDIVD.\n"; 399 for (int InsertedCount=0; InsertedCount<5; InsertedCount++) 400 BuildMI(MBB, MBBI, DL, TII.get(SP::NOP)); 401 402 MachineBasicBlock::iterator NMBBI = std::next(MBBI); 403 //errs() << "Inserting 28 NOPs after FSQRTD,FDIVD.\n"; 404 for (int InsertedCount=0; InsertedCount<28; InsertedCount++) 405 BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP)); 406 407 Modified = true; 408 } 409 } 410 } 411 412 return Modified; 413 } 414