1 //===------ LeonPasses.cpp - Define passes specific to LEON ---------------===// 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 // 10 //===----------------------------------------------------------------------===// 11 12 #include "LeonPasses.h" 13 #include "SparcSubtarget.h" 14 #include "llvm/CodeGen/MachineBasicBlock.h" 15 #include "llvm/CodeGen/MachineFunction.h" 16 #include "llvm/CodeGen/MachineInstr.h" 17 #include "llvm/CodeGen/MachineInstrBuilder.h" 18 #include "llvm/Support/raw_ostream.h" 19 20 using namespace llvm; 21 22 char ErrataWorkaround::ID = 0; 23 24 ErrataWorkaround::ErrataWorkaround() : MachineFunctionPass(ID) { 25 initializeErrataWorkaroundPass(*PassRegistry::getPassRegistry()); 26 } 27 28 INITIALIZE_PASS(ErrataWorkaround, "errata-workaround", "Errata workaround pass", 29 false, false) 30 31 // Move iterator to the next instruction in the function, ignoring 32 // meta instructions and inline assembly. Returns false when reaching 33 // the end of the function. 34 bool ErrataWorkaround::moveNext(MachineBasicBlock::iterator &I) { 35 36 MachineBasicBlock *MBB = I->getParent(); 37 38 do { 39 I++; 40 41 while (I == MBB->end()) { 42 if (MBB->getFallThrough() == nullptr) 43 return false; 44 MBB = MBB->getFallThrough(); 45 I = MBB->begin(); 46 } 47 } while (I->isMetaInstruction() || I->isInlineAsm()); 48 49 return true; 50 } 51 52 void ErrataWorkaround::insertNop(MachineBasicBlock::iterator I) { 53 BuildMI(*I->getParent(), I, I->getDebugLoc(), TII->get(SP::NOP)); 54 } 55 56 bool ErrataWorkaround::isFloat(MachineBasicBlock::iterator I) { 57 if (I->getNumOperands() == 0) 58 return false; 59 60 if (!I->getOperand(0).isReg()) 61 return false; 62 63 unsigned reg = I->getOperand(0).getReg(); 64 65 if (!SP::FPRegsRegClass.contains(reg) && !SP::DFPRegsRegClass.contains(reg)) 66 return false; 67 68 return true; 69 } 70 71 bool ErrataWorkaround::isDivSqrt(MachineBasicBlock::iterator I) { 72 switch (I->getOpcode()) { 73 case SP::FDIVS: 74 case SP::FDIVD: 75 case SP::FSQRTS: 76 case SP::FSQRTD: 77 return true; 78 } 79 return false; 80 } 81 82 // Prevents the following code sequence from being generated: 83 // (stb/sth/st/stf) -> (single non-store/load instruction) -> (any store) 84 // If the sequence is detected a NOP instruction is inserted after 85 // the first store instruction. 86 bool ErrataWorkaround::checkSeqTN0009A(MachineBasicBlock::iterator I) { 87 switch (I->getOpcode()) { 88 case SP::STrr: 89 case SP::STri: 90 case SP::STBrr: 91 case SP::STBri: 92 case SP::STHrr: 93 case SP::STHri: 94 case SP::STFrr: 95 case SP::STFri: 96 break; 97 default: 98 return false; 99 } 100 101 MachineBasicBlock::iterator MI = I; 102 if (!moveNext(MI)) 103 return false; 104 105 if (MI->mayStore() || MI->mayLoad()) 106 return false; 107 108 MachineBasicBlock::iterator PatchHere = MI; 109 110 if (!moveNext(MI)) 111 return false; 112 113 if (!MI->mayStore()) 114 return false; 115 116 insertNop(PatchHere); 117 return true; 118 } 119 120 // Prevents the following code sequence from being generated: 121 // (std/stdf) -> (any store) 122 // If the sequence is detected a NOP instruction is inserted after 123 // the first store instruction. 124 bool ErrataWorkaround::checkSeqTN0009B(MachineBasicBlock::iterator I) { 125 126 switch (I->getOpcode()) { 127 case SP::STDrr: 128 case SP::STDri: 129 case SP::STDFrr: 130 case SP::STDFri: 131 break; 132 default: 133 return false; 134 } 135 136 MachineBasicBlock::iterator MI = I; 137 138 if (!moveNext(MI)) 139 return false; 140 141 if (!MI->mayStore()) 142 return false; 143 144 insertNop(MI); 145 return true; 146 } 147 148 // Insert a NOP at branch target if load in delay slot and atomic 149 // instruction at branch target. Also insert a NOP between load 150 // instruction and atomic instruction (swap or casa). 151 bool ErrataWorkaround::checkSeqTN0010(MachineBasicBlock::iterator I) { 152 153 // Check for load instruction or branch bundled with load instruction 154 if (!I->mayLoad()) 155 return false; 156 157 // Check for branch to atomic instruction with load in delay slot 158 if (I->isBranch()) { 159 MachineBasicBlock *TargetMBB = I->getOperand(0).getMBB(); 160 MachineBasicBlock::iterator MI = TargetMBB->begin(); 161 162 while (MI != TargetMBB->end() && MI->isMetaInstruction()) 163 MI++; 164 165 if (MI == TargetMBB->end()) 166 return false; 167 168 switch (MI->getOpcode()) { 169 case SP::SWAPrr: 170 case SP::SWAPri: 171 case SP::CASArr: 172 insertNop(MI); 173 break; 174 default: 175 break; 176 } 177 } 178 179 // Check for load followed by atomic instruction 180 MachineBasicBlock::iterator MI = I; 181 if (!moveNext(MI)) 182 return false; 183 184 switch (MI->getOpcode()) { 185 case SP::SWAPrr: 186 case SP::SWAPri: 187 case SP::CASArr: 188 break; 189 default: 190 return false; 191 } 192 insertNop(MI); 193 return true; 194 } 195 196 // Do not allow functions to begin with an atomic instruction 197 bool ErrataWorkaround::checkSeqTN0010First(MachineBasicBlock &MBB) { 198 MachineBasicBlock::iterator I = MBB.begin(); 199 while (I != MBB.end() && I->isMetaInstruction()) 200 I++; 201 switch (I->getOpcode()) { 202 case SP::SWAPrr: 203 case SP::SWAPri: 204 case SP::CASArr: 205 break; 206 default: 207 return false; 208 } 209 insertNop(I); 210 return true; 211 } 212 213 // Inserts a NOP instruction at the target of an integer branch if the 214 // target is a floating-point instruction or floating-point branch. 215 bool ErrataWorkaround::checkSeqTN0012(MachineBasicBlock::iterator I) { 216 217 if (I->getOpcode() != SP::BCOND && I->getOpcode() != SP::BCONDA) 218 return false; 219 220 MachineBasicBlock *TargetMBB = I->getOperand(0).getMBB(); 221 MachineBasicBlock::iterator MI = TargetMBB->begin(); 222 223 while (MI != TargetMBB->end() && MI->isMetaInstruction()) 224 MI++; 225 226 if (MI == TargetMBB->end()) 227 return false; 228 229 if (!isFloat(MI) && MI->getOpcode() != SP::FBCOND) 230 return false; 231 232 insertNop(MI); 233 return true; 234 } 235 236 // Prevents the following code sequence from being generated: 237 // (div/sqrt) -> (2 to 3 floating-point operations or loads) -> (div/sqrt) 238 // If the sequence is detected one or two NOP instruction are inserted after 239 // the first div/sqrt instruction. No NOPs are inserted if one of the floating- 240 // point instructions in the middle of the sequence is a (div/sqrt), or if 241 // they have dependency on the destination register of the first (div/sqrt). 242 // 243 // The function also prevents the following code sequence from being generated, 244 // (div/sqrt) -> (branch), by inserting a NOP instruction after the (div/sqrt). 245 bool ErrataWorkaround::checkSeqTN0013(MachineBasicBlock::iterator I) { 246 247 if (!isDivSqrt(I)) 248 return false; 249 250 unsigned dstReg = I->getOperand(0).getReg(); 251 252 MachineBasicBlock::iterator MI = I; 253 if (!moveNext(MI)) 254 return false; 255 256 if (MI->isBranch()) { 257 insertNop(MI); 258 return true; 259 } 260 261 MachineBasicBlock::iterator PatchHere = MI; 262 263 unsigned fpFound = 0; 264 for (unsigned i = 0; i < 4; i++) { 265 266 if (!isFloat(MI)) { 267 if (!moveNext(MI)) 268 return false; 269 continue; 270 } 271 272 if (MI->readsRegister(dstReg, TRI)) 273 return false; 274 275 if (isDivSqrt(MI)) { 276 if (i < 2) 277 return false; 278 if (fpFound < 2) 279 return false; 280 281 insertNop(PatchHere); 282 if (i == 2) 283 insertNop(PatchHere); 284 return true; 285 } 286 287 fpFound++; 288 if (!moveNext(MI)) 289 return false; 290 } 291 292 return false; 293 } 294 295 bool ErrataWorkaround::runOnMachineFunction(MachineFunction &MF) { 296 bool Changed = false; 297 ST = &MF.getSubtarget<SparcSubtarget>(); 298 299 if (!(ST->fixTN0009() || ST->fixTN0010() || ST->fixTN0012() || 300 ST->fixTN0013())) 301 return false; 302 303 TII = ST->getInstrInfo(); 304 TRI = ST->getRegisterInfo(); 305 306 if (ST->fixTN0010()) 307 Changed |= checkSeqTN0010First(MF.front()); 308 309 for (auto &MBB : MF) { 310 for (auto &I : MBB) { 311 if (ST->fixTN0009()) { 312 Changed |= checkSeqTN0009A(I); 313 Changed |= checkSeqTN0009B(I); 314 } 315 if (ST->fixTN0010()) 316 Changed |= checkSeqTN0010(I); 317 if (ST->fixTN0012()) 318 Changed |= checkSeqTN0012(I); 319 if (ST->fixTN0013()) 320 Changed |= checkSeqTN0013(I); 321 } 322 } 323 return Changed; 324 } 325 326 LEONMachineFunctionPass::LEONMachineFunctionPass(char &ID) 327 : MachineFunctionPass(ID) {} 328 329 //***************************************************************************** 330 //**** InsertNOPLoad pass 331 //***************************************************************************** 332 // This pass fixes the incorrectly working Load instructions that exists for 333 // some earlier versions of the LEON processor line. NOP instructions must 334 // be inserted after the load instruction to ensure that the Load instruction 335 // behaves as expected for these processors. 336 // 337 // This pass inserts a NOP after any LD or LDF instruction. 338 // 339 char InsertNOPLoad::ID = 0; 340 341 InsertNOPLoad::InsertNOPLoad() : LEONMachineFunctionPass(ID) {} 342 343 bool InsertNOPLoad::runOnMachineFunction(MachineFunction &MF) { 344 Subtarget = &MF.getSubtarget<SparcSubtarget>(); 345 if (!Subtarget->insertNOPLoad()) 346 return false; 347 348 const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); 349 DebugLoc DL = DebugLoc(); 350 351 bool Modified = false; 352 for (MachineBasicBlock &MBB : MF) { 353 for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) { 354 MachineInstr &MI = *MBBI; 355 unsigned Opcode = MI.getOpcode(); 356 if (Opcode >= SP::LDDArr && Opcode <= SP::LDrr) { 357 MachineBasicBlock::iterator NMBBI = std::next(MBBI); 358 BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP)); 359 Modified = true; 360 } 361 } 362 } 363 364 return Modified; 365 } 366 367 368 369 //***************************************************************************** 370 //**** DetectRoundChange pass 371 //***************************************************************************** 372 // To prevent any explicit change of the default rounding mode, this pass 373 // detects any call of the fesetround function. 374 // A warning is generated to ensure the user knows this has happened. 375 // 376 // Detects an erratum in UT699 LEON 3 processor 377 378 char DetectRoundChange::ID = 0; 379 380 DetectRoundChange::DetectRoundChange() : LEONMachineFunctionPass(ID) {} 381 382 bool DetectRoundChange::runOnMachineFunction(MachineFunction &MF) { 383 Subtarget = &MF.getSubtarget<SparcSubtarget>(); 384 if (!Subtarget->detectRoundChange()) 385 return false; 386 387 bool Modified = false; 388 for (MachineBasicBlock &MBB : MF) { 389 for (MachineInstr &MI : MBB) { 390 unsigned Opcode = MI.getOpcode(); 391 if (Opcode == SP::CALL && MI.getNumOperands() > 0) { 392 MachineOperand &MO = MI.getOperand(0); 393 394 if (MO.isGlobal()) { 395 StringRef FuncName = MO.getGlobal()->getName(); 396 if (FuncName.compare_insensitive("fesetround") == 0) { 397 errs() << "Error: You are using the detectroundchange " 398 "option to detect rounding changes that will " 399 "cause LEON errata. The only way to fix this " 400 "is to remove the call to fesetround from " 401 "the source code.\n"; 402 } 403 } 404 } 405 } 406 } 407 408 return Modified; 409 } 410 411 //***************************************************************************** 412 //**** FixAllFDIVSQRT pass 413 //***************************************************************************** 414 // This pass fixes the incorrectly working FDIVx and FSQRTx instructions that 415 // exist for some earlier versions of the LEON processor line. Five NOP 416 // instructions need to be inserted after these instructions to ensure the 417 // correct result is placed in the destination registers before they are used. 418 // 419 // This pass implements two fixes: 420 // 1) fixing the FSQRTS and FSQRTD instructions. 421 // 2) fixing the FDIVS and FDIVD instructions. 422 // 423 // FSQRTS and FDIVS are converted to FDIVD and FSQRTD respectively earlier in 424 // the pipeline when this option is enabled, so this pass needs only to deal 425 // with the changes that still need implementing for the "double" versions 426 // of these instructions. 427 // 428 char FixAllFDIVSQRT::ID = 0; 429 430 FixAllFDIVSQRT::FixAllFDIVSQRT() : LEONMachineFunctionPass(ID) {} 431 432 bool FixAllFDIVSQRT::runOnMachineFunction(MachineFunction &MF) { 433 Subtarget = &MF.getSubtarget<SparcSubtarget>(); 434 if (!Subtarget->fixAllFDIVSQRT()) 435 return false; 436 437 const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); 438 DebugLoc DL = DebugLoc(); 439 440 bool Modified = false; 441 for (MachineBasicBlock &MBB : MF) { 442 for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) { 443 MachineInstr &MI = *MBBI; 444 unsigned Opcode = MI.getOpcode(); 445 446 // Note: FDIVS and FSQRTS cannot be generated when this erratum fix is 447 // switched on so we don't need to check for them here. They will 448 // already have been converted to FSQRTD or FDIVD earlier in the 449 // pipeline. 450 if (Opcode == SP::FSQRTD || Opcode == SP::FDIVD) { 451 for (int InsertedCount = 0; InsertedCount < 5; InsertedCount++) 452 BuildMI(MBB, MBBI, DL, TII.get(SP::NOP)); 453 454 MachineBasicBlock::iterator NMBBI = std::next(MBBI); 455 for (int InsertedCount = 0; InsertedCount < 28; InsertedCount++) 456 BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP)); 457 458 Modified = true; 459 } 460 } 461 } 462 463 return Modified; 464 } 465