brintos

brintos / llvm-project-archived public Read only

0
0
Text · 12.8 KiB · 018d812 Raw
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