LeonPasses.cpp revision 321369
1303231Sdim//===------ LeonPasses.cpp - Define passes specific to LEON ---------------===// 2303231Sdim// 3303231Sdim// The LLVM Compiler Infrastructure 4303231Sdim// 5303231Sdim// This file is distributed under the University of Illinois Open Source 6303231Sdim// License. See LICENSE.TXT for details. 7303231Sdim// 8303231Sdim//===----------------------------------------------------------------------===// 9303231Sdim// 10303231Sdim// 11303231Sdim//===----------------------------------------------------------------------===// 12303231Sdim 13303231Sdim#include "LeonPasses.h" 14303231Sdim#include "llvm/CodeGen/ISDOpcodes.h" 15303231Sdim#include "llvm/CodeGen/MachineFunction.h" 16303231Sdim#include "llvm/CodeGen/MachineInstr.h" 17303231Sdim#include "llvm/CodeGen/MachineInstrBuilder.h" 18303231Sdim#include "llvm/CodeGen/MachineRegisterInfo.h" 19314564Sdim#include "llvm/IR/DiagnosticInfo.h" 20303231Sdim#include "llvm/IR/LLVMContext.h" 21303231Sdim#include "llvm/Support/raw_ostream.h" 22303231Sdimusing namespace llvm; 23303231Sdim 24303231SdimLEONMachineFunctionPass::LEONMachineFunctionPass(char &ID) 25303231Sdim : MachineFunctionPass(ID) {} 26303231Sdim 27303231Sdimint LEONMachineFunctionPass::GetRegIndexForOperand(MachineInstr &MI, 28303231Sdim int OperandIndex) { 29303231Sdim if (MI.getNumOperands() > 0) { 30303231Sdim if (OperandIndex == LAST_OPERAND) { 31303231Sdim OperandIndex = MI.getNumOperands() - 1; 32303231Sdim } 33303231Sdim 34303231Sdim if (MI.getNumOperands() > (unsigned)OperandIndex && 35303231Sdim MI.getOperand(OperandIndex).isReg()) { 36303231Sdim return (int)MI.getOperand(OperandIndex).getReg(); 37303231Sdim } 38303231Sdim } 39303231Sdim 40303231Sdim static int NotFoundIndex = -10; 41303231Sdim // Return a different number each time to avoid any comparisons between the 42303231Sdim // values returned. 43303231Sdim NotFoundIndex -= 10; 44303231Sdim return NotFoundIndex; 45303231Sdim} 46303231Sdim 47303231Sdim// finds a new free FP register 48303231Sdim// checks also the AllocatedRegisters vector 49303231Sdimint LEONMachineFunctionPass::getUnusedFPRegister(MachineRegisterInfo &MRI) { 50303231Sdim for (int RegisterIndex = SP::F0; RegisterIndex <= SP::F31; ++RegisterIndex) { 51303231Sdim if (!MRI.isPhysRegUsed(RegisterIndex) && 52314564Sdim !is_contained(UsedRegisters, RegisterIndex)) { 53303231Sdim return RegisterIndex; 54303231Sdim } 55303231Sdim } 56303231Sdim 57303231Sdim return -1; 58303231Sdim} 59303231Sdim 60303231Sdim//***************************************************************************** 61303231Sdim//**** InsertNOPLoad pass 62303231Sdim//***************************************************************************** 63303231Sdim// This pass fixes the incorrectly working Load instructions that exists for 64303231Sdim// some earlier versions of the LEON processor line. NOP instructions must 65303231Sdim// be inserted after the load instruction to ensure that the Load instruction 66303231Sdim// behaves as expected for these processors. 67303231Sdim// 68303231Sdim// This pass inserts a NOP after any LD or LDF instruction. 69303231Sdim// 70303231Sdimchar InsertNOPLoad::ID = 0; 71303231Sdim 72321369SdimInsertNOPLoad::InsertNOPLoad() : LEONMachineFunctionPass(ID) {} 73303231Sdim 74303231Sdimbool InsertNOPLoad::runOnMachineFunction(MachineFunction &MF) { 75303231Sdim Subtarget = &MF.getSubtarget<SparcSubtarget>(); 76303231Sdim const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); 77303231Sdim DebugLoc DL = DebugLoc(); 78303231Sdim 79303231Sdim bool Modified = false; 80303231Sdim for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { 81303231Sdim MachineBasicBlock &MBB = *MFI; 82303231Sdim for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) { 83303231Sdim MachineInstr &MI = *MBBI; 84303231Sdim unsigned Opcode = MI.getOpcode(); 85303231Sdim if (Opcode >= SP::LDDArr && Opcode <= SP::LDrr) { 86303231Sdim MachineBasicBlock::iterator NMBBI = std::next(MBBI); 87303231Sdim BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP)); 88303231Sdim Modified = true; 89303231Sdim } 90303231Sdim } 91303231Sdim } 92303231Sdim 93303231Sdim return Modified; 94303231Sdim} 95303231Sdim 96303231Sdim//***************************************************************************** 97303231Sdim//**** FixFSMULD pass 98303231Sdim//***************************************************************************** 99303231Sdim// This pass fixes the incorrectly working FSMULD instruction that exists for 100303231Sdim// some earlier versions of the LEON processor line. 101303231Sdim// 102303231Sdim// The pass should convert the FSMULD operands to double precision in scratch 103303231Sdim// registers, then calculate the result with the FMULD instruction. Therefore, 104303231Sdim// the pass should replace operations of the form: 105303231Sdim// fsmuld %f20,%f21,%f8 106303231Sdim// with the sequence: 107303231Sdim// fstod %f20,%f0 108303231Sdim// fstod %f21,%f2 109303231Sdim// fmuld %f0,%f2,%f8 110303231Sdim// 111303231Sdimchar FixFSMULD::ID = 0; 112303231Sdim 113321369SdimFixFSMULD::FixFSMULD() : LEONMachineFunctionPass(ID) {} 114303231Sdim 115303231Sdimbool FixFSMULD::runOnMachineFunction(MachineFunction &MF) { 116303231Sdim Subtarget = &MF.getSubtarget<SparcSubtarget>(); 117303231Sdim const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); 118303231Sdim DebugLoc DL = DebugLoc(); 119303231Sdim 120303231Sdim bool Modified = false; 121303231Sdim for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { 122303231Sdim MachineBasicBlock &MBB = *MFI; 123303231Sdim for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) { 124303231Sdim 125303231Sdim MachineInstr &MI = *MBBI; 126303231Sdim unsigned Opcode = MI.getOpcode(); 127303231Sdim 128303231Sdim const int UNASSIGNED_INDEX = -1; 129303231Sdim int Reg1Index = UNASSIGNED_INDEX; 130303231Sdim int Reg2Index = UNASSIGNED_INDEX; 131303231Sdim int Reg3Index = UNASSIGNED_INDEX; 132303231Sdim 133303231Sdim if (Opcode == SP::FSMULD && MI.getNumOperands() == 3) { 134303231Sdim // take the registers from fsmuld %f20,%f21,%f8 135303231Sdim Reg1Index = MI.getOperand(0).getReg(); 136303231Sdim Reg2Index = MI.getOperand(1).getReg(); 137303231Sdim Reg3Index = MI.getOperand(2).getReg(); 138303231Sdim } 139303231Sdim 140303231Sdim if (Reg1Index != UNASSIGNED_INDEX && Reg2Index != UNASSIGNED_INDEX && 141303231Sdim Reg3Index != UNASSIGNED_INDEX) { 142303231Sdim clearUsedRegisterList(); 143303231Sdim MachineBasicBlock::iterator NMBBI = std::next(MBBI); 144303231Sdim // Whatever Reg3Index is hasn't been used yet, so we need to reserve it. 145303231Sdim markRegisterUsed(Reg3Index); 146303231Sdim const int ScratchReg1Index = getUnusedFPRegister(MF.getRegInfo()); 147303231Sdim markRegisterUsed(ScratchReg1Index); 148303231Sdim const int ScratchReg2Index = getUnusedFPRegister(MF.getRegInfo()); 149303231Sdim markRegisterUsed(ScratchReg2Index); 150303231Sdim 151303231Sdim if (ScratchReg1Index == UNASSIGNED_INDEX || 152303231Sdim ScratchReg2Index == UNASSIGNED_INDEX) { 153303231Sdim errs() << "Cannot allocate free scratch registers for the FixFSMULD " 154303231Sdim "pass." 155303231Sdim << "\n"; 156303231Sdim } else { 157303231Sdim // create fstod %f20,%f0 158303231Sdim BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD)) 159303231Sdim .addReg(ScratchReg1Index) 160303231Sdim .addReg(Reg1Index); 161303231Sdim 162303231Sdim // create fstod %f21,%f2 163303231Sdim BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD)) 164303231Sdim .addReg(ScratchReg2Index) 165303231Sdim .addReg(Reg2Index); 166303231Sdim 167303231Sdim // create fmuld %f0,%f2,%f8 168303231Sdim BuildMI(MBB, MBBI, DL, TII.get(SP::FMULD)) 169303231Sdim .addReg(Reg3Index) 170303231Sdim .addReg(ScratchReg1Index) 171303231Sdim .addReg(ScratchReg2Index); 172303231Sdim 173303231Sdim MI.eraseFromParent(); 174303231Sdim MBBI = NMBBI; 175303231Sdim 176303231Sdim Modified = true; 177303231Sdim } 178303231Sdim } 179303231Sdim } 180303231Sdim } 181303231Sdim 182303231Sdim return Modified; 183303231Sdim} 184303231Sdim 185303231Sdim//***************************************************************************** 186303231Sdim//**** ReplaceFMULS pass 187303231Sdim//***************************************************************************** 188303231Sdim// This pass fixes the incorrectly working FMULS instruction that exists for 189303231Sdim// some earlier versions of the LEON processor line. 190303231Sdim// 191303231Sdim// This pass converts the FMULS operands to double precision in scratch 192303231Sdim// registers, then calculates the result with the FMULD instruction. 193303231Sdim// The pass should replace operations of the form: 194303231Sdim// fmuls %f20,%f21,%f8 195303231Sdim// with the sequence: 196303231Sdim// fstod %f20,%f0 197303231Sdim// fstod %f21,%f2 198303231Sdim// fmuld %f0,%f2,%f8 199303231Sdim// 200303231Sdimchar ReplaceFMULS::ID = 0; 201303231Sdim 202321369SdimReplaceFMULS::ReplaceFMULS() : LEONMachineFunctionPass(ID) {} 203303231Sdim 204303231Sdimbool ReplaceFMULS::runOnMachineFunction(MachineFunction &MF) { 205303231Sdim Subtarget = &MF.getSubtarget<SparcSubtarget>(); 206303231Sdim const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); 207303231Sdim DebugLoc DL = DebugLoc(); 208303231Sdim 209303231Sdim bool Modified = false; 210303231Sdim for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { 211303231Sdim MachineBasicBlock &MBB = *MFI; 212303231Sdim for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) { 213303231Sdim MachineInstr &MI = *MBBI; 214303231Sdim unsigned Opcode = MI.getOpcode(); 215303231Sdim 216303231Sdim const int UNASSIGNED_INDEX = -1; 217303231Sdim int Reg1Index = UNASSIGNED_INDEX; 218303231Sdim int Reg2Index = UNASSIGNED_INDEX; 219303231Sdim int Reg3Index = UNASSIGNED_INDEX; 220303231Sdim 221303231Sdim if (Opcode == SP::FMULS && MI.getNumOperands() == 3) { 222303231Sdim // take the registers from fmuls %f20,%f21,%f8 223303231Sdim Reg1Index = MI.getOperand(0).getReg(); 224303231Sdim Reg2Index = MI.getOperand(1).getReg(); 225303231Sdim Reg3Index = MI.getOperand(2).getReg(); 226303231Sdim } 227303231Sdim 228303231Sdim if (Reg1Index != UNASSIGNED_INDEX && Reg2Index != UNASSIGNED_INDEX && 229303231Sdim Reg3Index != UNASSIGNED_INDEX) { 230303231Sdim clearUsedRegisterList(); 231303231Sdim MachineBasicBlock::iterator NMBBI = std::next(MBBI); 232303231Sdim // Whatever Reg3Index is hasn't been used yet, so we need to reserve it. 233303231Sdim markRegisterUsed(Reg3Index); 234303231Sdim const int ScratchReg1Index = getUnusedFPRegister(MF.getRegInfo()); 235303231Sdim markRegisterUsed(ScratchReg1Index); 236303231Sdim const int ScratchReg2Index = getUnusedFPRegister(MF.getRegInfo()); 237303231Sdim markRegisterUsed(ScratchReg2Index); 238303231Sdim 239303231Sdim if (ScratchReg1Index == UNASSIGNED_INDEX || 240303231Sdim ScratchReg2Index == UNASSIGNED_INDEX) { 241303231Sdim errs() << "Cannot allocate free scratch registers for the " 242303231Sdim "ReplaceFMULS pass." 243303231Sdim << "\n"; 244303231Sdim } else { 245303231Sdim // create fstod %f20,%f0 246303231Sdim BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD)) 247303231Sdim .addReg(ScratchReg1Index) 248303231Sdim .addReg(Reg1Index); 249303231Sdim 250303231Sdim // create fstod %f21,%f2 251303231Sdim BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD)) 252303231Sdim .addReg(ScratchReg2Index) 253303231Sdim .addReg(Reg2Index); 254303231Sdim 255303231Sdim // create fmuld %f0,%f2,%f8 256303231Sdim BuildMI(MBB, MBBI, DL, TII.get(SP::FMULD)) 257303231Sdim .addReg(Reg3Index) 258303231Sdim .addReg(ScratchReg1Index) 259303231Sdim .addReg(ScratchReg2Index); 260303231Sdim 261303231Sdim MI.eraseFromParent(); 262303231Sdim MBBI = NMBBI; 263303231Sdim 264303231Sdim Modified = true; 265303231Sdim } 266303231Sdim } 267303231Sdim } 268303231Sdim } 269303231Sdim 270303231Sdim return Modified; 271303231Sdim} 272303231Sdim 273303231Sdim 274303231Sdim//***************************************************************************** 275314564Sdim//**** DetectRoundChange pass 276303231Sdim//***************************************************************************** 277314564Sdim// To prevent any explicit change of the default rounding mode, this pass 278314564Sdim// detects any call of the fesetround function. 279314564Sdim// A warning is generated to ensure the user knows this has happened. 280303231Sdim// 281314564Sdim// Detects an erratum in UT699 LEON 3 processor 282303231Sdim 283314564Sdimchar DetectRoundChange::ID = 0; 284303231Sdim 285321369SdimDetectRoundChange::DetectRoundChange() : LEONMachineFunctionPass(ID) {} 286303231Sdim 287314564Sdimbool DetectRoundChange::runOnMachineFunction(MachineFunction &MF) { 288303231Sdim Subtarget = &MF.getSubtarget<SparcSubtarget>(); 289303231Sdim 290303231Sdim bool Modified = false; 291303231Sdim for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { 292303231Sdim MachineBasicBlock &MBB = *MFI; 293303231Sdim for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) { 294303231Sdim MachineInstr &MI = *MBBI; 295303231Sdim unsigned Opcode = MI.getOpcode(); 296303231Sdim if (Opcode == SP::CALL && MI.getNumOperands() > 0) { 297303231Sdim MachineOperand &MO = MI.getOperand(0); 298303231Sdim 299303231Sdim if (MO.isGlobal()) { 300303231Sdim StringRef FuncName = MO.getGlobal()->getName(); 301303231Sdim if (FuncName.compare_lower("fesetround") == 0) { 302314564Sdim errs() << "Error: You are using the detectroundchange " 303314564Sdim "option to detect rounding changes that will " 304314564Sdim "cause LEON errata. The only way to fix this " 305314564Sdim "is to remove the call to fesetround from " 306314564Sdim "the source code.\n"; 307303231Sdim } 308303231Sdim } 309303231Sdim } 310303231Sdim } 311303231Sdim } 312303231Sdim 313303231Sdim return Modified; 314303231Sdim} 315314564Sdim 316303231Sdim//***************************************************************************** 317314564Sdim//**** FixAllFDIVSQRT pass 318303231Sdim//***************************************************************************** 319314564Sdim// This pass fixes the incorrectly working FDIVx and FSQRTx instructions that 320314564Sdim// exist for some earlier versions of the LEON processor line. Five NOP 321314564Sdim// instructions need to be inserted after these instructions to ensure the 322314564Sdim// correct result is placed in the destination registers before they are used. 323303231Sdim// 324314564Sdim// This pass implements two fixes: 325314564Sdim// 1) fixing the FSQRTS and FSQRTD instructions. 326314564Sdim// 2) fixing the FDIVS and FDIVD instructions. 327314564Sdim// 328314564Sdim// FSQRTS and FDIVS are converted to FDIVD and FSQRTD respectively earlier in 329314564Sdim// the pipeline when this option is enabled, so this pass needs only to deal 330314564Sdim// with the changes that still need implementing for the "double" versions 331314564Sdim// of these instructions. 332314564Sdim// 333314564Sdimchar FixAllFDIVSQRT::ID = 0; 334303231Sdim 335321369SdimFixAllFDIVSQRT::FixAllFDIVSQRT() : LEONMachineFunctionPass(ID) {} 336303231Sdim 337314564Sdimbool FixAllFDIVSQRT::runOnMachineFunction(MachineFunction &MF) { 338303231Sdim Subtarget = &MF.getSubtarget<SparcSubtarget>(); 339303231Sdim const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); 340303231Sdim DebugLoc DL = DebugLoc(); 341303231Sdim 342303231Sdim bool Modified = false; 343303231Sdim for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { 344303231Sdim MachineBasicBlock &MBB = *MFI; 345303231Sdim for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) { 346303231Sdim MachineInstr &MI = *MBBI; 347303231Sdim unsigned Opcode = MI.getOpcode(); 348303231Sdim 349314564Sdim // Note: FDIVS and FSQRTS cannot be generated when this erratum fix is 350314564Sdim // switched on so we don't need to check for them here. They will 351314564Sdim // already have been converted to FSQRTD or FDIVD earlier in the 352314564Sdim // pipeline. 353314564Sdim if (Opcode == SP::FSQRTD || Opcode == SP::FDIVD) { 354314564Sdim for (int InsertedCount = 0; InsertedCount < 5; InsertedCount++) 355303231Sdim BuildMI(MBB, MBBI, DL, TII.get(SP::NOP)); 356303231Sdim 357314564Sdim MachineBasicBlock::iterator NMBBI = std::next(MBBI); 358314564Sdim for (int InsertedCount = 0; InsertedCount < 28; InsertedCount++) 359314564Sdim BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP)); 360303231Sdim 361314564Sdim Modified = true; 362303231Sdim } 363303231Sdim } 364303231Sdim } 365303231Sdim 366303231Sdim return Modified; 367303231Sdim} 368