1303231Sdim//===------ LeonPasses.cpp - Define passes specific to LEON ---------------===// 2303231Sdim// 3353358Sdim// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4353358Sdim// See https://llvm.org/LICENSE.txt for license information. 5353358Sdim// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6303231Sdim// 7303231Sdim//===----------------------------------------------------------------------===// 8303231Sdim// 9303231Sdim// 10303231Sdim//===----------------------------------------------------------------------===// 11303231Sdim 12303231Sdim#include "LeonPasses.h" 13303231Sdim#include "llvm/CodeGen/ISDOpcodes.h" 14303231Sdim#include "llvm/CodeGen/MachineFunction.h" 15303231Sdim#include "llvm/CodeGen/MachineInstr.h" 16303231Sdim#include "llvm/CodeGen/MachineInstrBuilder.h" 17303231Sdim#include "llvm/CodeGen/MachineRegisterInfo.h" 18314564Sdim#include "llvm/IR/DiagnosticInfo.h" 19303231Sdim#include "llvm/IR/LLVMContext.h" 20303231Sdim#include "llvm/Support/raw_ostream.h" 21303231Sdimusing namespace llvm; 22303231Sdim 23303231SdimLEONMachineFunctionPass::LEONMachineFunctionPass(char &ID) 24303231Sdim : MachineFunctionPass(ID) {} 25303231Sdim 26303231Sdim//***************************************************************************** 27303231Sdim//**** InsertNOPLoad pass 28303231Sdim//***************************************************************************** 29303231Sdim// This pass fixes the incorrectly working Load instructions that exists for 30303231Sdim// some earlier versions of the LEON processor line. NOP instructions must 31303231Sdim// be inserted after the load instruction to ensure that the Load instruction 32303231Sdim// behaves as expected for these processors. 33303231Sdim// 34303231Sdim// This pass inserts a NOP after any LD or LDF instruction. 35303231Sdim// 36303231Sdimchar InsertNOPLoad::ID = 0; 37303231Sdim 38321369SdimInsertNOPLoad::InsertNOPLoad() : LEONMachineFunctionPass(ID) {} 39303231Sdim 40303231Sdimbool InsertNOPLoad::runOnMachineFunction(MachineFunction &MF) { 41303231Sdim Subtarget = &MF.getSubtarget<SparcSubtarget>(); 42303231Sdim const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); 43303231Sdim DebugLoc DL = DebugLoc(); 44303231Sdim 45303231Sdim bool Modified = false; 46303231Sdim for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { 47303231Sdim MachineBasicBlock &MBB = *MFI; 48303231Sdim for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) { 49303231Sdim MachineInstr &MI = *MBBI; 50303231Sdim unsigned Opcode = MI.getOpcode(); 51303231Sdim if (Opcode >= SP::LDDArr && Opcode <= SP::LDrr) { 52303231Sdim MachineBasicBlock::iterator NMBBI = std::next(MBBI); 53303231Sdim BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP)); 54303231Sdim Modified = true; 55303231Sdim } 56303231Sdim } 57303231Sdim } 58303231Sdim 59303231Sdim return Modified; 60303231Sdim} 61303231Sdim 62303231Sdim 63303231Sdim 64303231Sdim//***************************************************************************** 65314564Sdim//**** DetectRoundChange pass 66303231Sdim//***************************************************************************** 67314564Sdim// To prevent any explicit change of the default rounding mode, this pass 68314564Sdim// detects any call of the fesetround function. 69314564Sdim// A warning is generated to ensure the user knows this has happened. 70303231Sdim// 71314564Sdim// Detects an erratum in UT699 LEON 3 processor 72303231Sdim 73314564Sdimchar DetectRoundChange::ID = 0; 74303231Sdim 75321369SdimDetectRoundChange::DetectRoundChange() : LEONMachineFunctionPass(ID) {} 76303231Sdim 77314564Sdimbool DetectRoundChange::runOnMachineFunction(MachineFunction &MF) { 78303231Sdim Subtarget = &MF.getSubtarget<SparcSubtarget>(); 79303231Sdim 80303231Sdim bool Modified = false; 81303231Sdim for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { 82303231Sdim MachineBasicBlock &MBB = *MFI; 83303231Sdim for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) { 84303231Sdim MachineInstr &MI = *MBBI; 85303231Sdim unsigned Opcode = MI.getOpcode(); 86303231Sdim if (Opcode == SP::CALL && MI.getNumOperands() > 0) { 87303231Sdim MachineOperand &MO = MI.getOperand(0); 88303231Sdim 89303231Sdim if (MO.isGlobal()) { 90303231Sdim StringRef FuncName = MO.getGlobal()->getName(); 91303231Sdim if (FuncName.compare_lower("fesetround") == 0) { 92314564Sdim errs() << "Error: You are using the detectroundchange " 93314564Sdim "option to detect rounding changes that will " 94314564Sdim "cause LEON errata. The only way to fix this " 95314564Sdim "is to remove the call to fesetround from " 96314564Sdim "the source code.\n"; 97303231Sdim } 98303231Sdim } 99303231Sdim } 100303231Sdim } 101303231Sdim } 102303231Sdim 103303231Sdim return Modified; 104303231Sdim} 105314564Sdim 106303231Sdim//***************************************************************************** 107314564Sdim//**** FixAllFDIVSQRT pass 108303231Sdim//***************************************************************************** 109314564Sdim// This pass fixes the incorrectly working FDIVx and FSQRTx instructions that 110314564Sdim// exist for some earlier versions of the LEON processor line. Five NOP 111314564Sdim// instructions need to be inserted after these instructions to ensure the 112314564Sdim// correct result is placed in the destination registers before they are used. 113303231Sdim// 114314564Sdim// This pass implements two fixes: 115314564Sdim// 1) fixing the FSQRTS and FSQRTD instructions. 116314564Sdim// 2) fixing the FDIVS and FDIVD instructions. 117314564Sdim// 118314564Sdim// FSQRTS and FDIVS are converted to FDIVD and FSQRTD respectively earlier in 119314564Sdim// the pipeline when this option is enabled, so this pass needs only to deal 120314564Sdim// with the changes that still need implementing for the "double" versions 121314564Sdim// of these instructions. 122314564Sdim// 123314564Sdimchar FixAllFDIVSQRT::ID = 0; 124303231Sdim 125321369SdimFixAllFDIVSQRT::FixAllFDIVSQRT() : LEONMachineFunctionPass(ID) {} 126303231Sdim 127314564Sdimbool FixAllFDIVSQRT::runOnMachineFunction(MachineFunction &MF) { 128303231Sdim Subtarget = &MF.getSubtarget<SparcSubtarget>(); 129303231Sdim const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); 130303231Sdim DebugLoc DL = DebugLoc(); 131303231Sdim 132303231Sdim bool Modified = false; 133303231Sdim for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { 134303231Sdim MachineBasicBlock &MBB = *MFI; 135303231Sdim for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) { 136303231Sdim MachineInstr &MI = *MBBI; 137303231Sdim unsigned Opcode = MI.getOpcode(); 138303231Sdim 139314564Sdim // Note: FDIVS and FSQRTS cannot be generated when this erratum fix is 140314564Sdim // switched on so we don't need to check for them here. They will 141314564Sdim // already have been converted to FSQRTD or FDIVD earlier in the 142314564Sdim // pipeline. 143314564Sdim if (Opcode == SP::FSQRTD || Opcode == SP::FDIVD) { 144314564Sdim for (int InsertedCount = 0; InsertedCount < 5; InsertedCount++) 145303231Sdim BuildMI(MBB, MBBI, DL, TII.get(SP::NOP)); 146303231Sdim 147314564Sdim MachineBasicBlock::iterator NMBBI = std::next(MBBI); 148314564Sdim for (int InsertedCount = 0; InsertedCount < 28; InsertedCount++) 149314564Sdim BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP)); 150303231Sdim 151314564Sdim Modified = true; 152303231Sdim } 153303231Sdim } 154303231Sdim } 155303231Sdim 156303231Sdim return Modified; 157303231Sdim} 158