465 lines · cpp
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-exception6//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 20using namespace llvm;21 22char ErrataWorkaround::ID = 0;23 24ErrataWorkaround::ErrataWorkaround() : MachineFunctionPass(ID) {25 initializeErrataWorkaroundPass(*PassRegistry::getPassRegistry());26}27 28INITIALIZE_PASS(ErrataWorkaround, "errata-workaround", "Errata workaround pass",29 false, false)30 31// Move iterator to the next instruction in the function, ignoring32// meta instructions and inline assembly. Returns false when reaching33// the end of the function.34bool 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 52void ErrataWorkaround::insertNop(MachineBasicBlock::iterator I) {53 BuildMI(*I->getParent(), I, I->getDebugLoc(), TII->get(SP::NOP));54}55 56bool 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 71bool 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 after85// the first store instruction.86bool 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 after123// the first store instruction.124bool 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 atomic149// instruction at branch target. Also insert a NOP between load150// instruction and atomic instruction (swap or casa).151bool ErrataWorkaround::checkSeqTN0010(MachineBasicBlock::iterator I) {152 153 // Check for load instruction or branch bundled with load instruction154 if (!I->mayLoad())155 return false;156 157 // Check for branch to atomic instruction with load in delay slot158 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 instruction180 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 instruction197bool 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 the214// target is a floating-point instruction or floating-point branch.215bool 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 after239// 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 if241// 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).245bool 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 295bool 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 326LEONMachineFunctionPass::LEONMachineFunctionPass(char &ID)327 : MachineFunctionPass(ID) {}328 329//*****************************************************************************330//**** InsertNOPLoad pass331//*****************************************************************************332// This pass fixes the incorrectly working Load instructions that exists for333// some earlier versions of the LEON processor line. NOP instructions must334// be inserted after the load instruction to ensure that the Load instruction335// behaves as expected for these processors.336//337// This pass inserts a NOP after any LD or LDF instruction.338//339char InsertNOPLoad::ID = 0;340 341InsertNOPLoad::InsertNOPLoad() : LEONMachineFunctionPass(ID) {}342 343bool 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 pass371//*****************************************************************************372// To prevent any explicit change of the default rounding mode, this pass373// 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 processor377 378char DetectRoundChange::ID = 0;379 380DetectRoundChange::DetectRoundChange() : LEONMachineFunctionPass(ID) {}381 382bool 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 pass413//*****************************************************************************414// This pass fixes the incorrectly working FDIVx and FSQRTx instructions that415// exist for some earlier versions of the LEON processor line. Five NOP416// instructions need to be inserted after these instructions to ensure the417// 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 in424// the pipeline when this option is enabled, so this pass needs only to deal425// with the changes that still need implementing for the "double" versions426// of these instructions.427//428char FixAllFDIVSQRT::ID = 0;429 430FixAllFDIVSQRT::FixAllFDIVSQRT() : LEONMachineFunctionPass(ID) {}431 432bool 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 is447 // switched on so we don't need to check for them here. They will448 // already have been converted to FSQRTD or FDIVD earlier in the449 // 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