1 //===------ LeonPasses.cpp - Define passes specific to LEON ---------------===// 2 // 3 // The LLVM Compiler Infrastructure 4 // 5 // This file is distributed under the University of Illinois Open Source 6 // License. See LICENSE.TXT for details. 7 // 8 //===----------------------------------------------------------------------===// 9 // 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "LeonPasses.h" 14 #include "llvm/CodeGen/ISDOpcodes.h" 15 #include "llvm/CodeGen/MachineFunction.h" 16 #include "llvm/CodeGen/MachineInstr.h" 17 #include "llvm/CodeGen/MachineInstrBuilder.h" 18 #include "llvm/CodeGen/MachineRegisterInfo.h" 19 #include "llvm/IR/DiagnosticInfo.h" 20 #include "llvm/IR/LLVMContext.h" 21 #include "llvm/Support/raw_ostream.h" 22 using namespace llvm; 23 24 LEONMachineFunctionPass::LEONMachineFunctionPass(TargetMachine &tm, char &ID) 25 : MachineFunctionPass(ID) {} 26 27 LEONMachineFunctionPass::LEONMachineFunctionPass(char &ID) 28 : MachineFunctionPass(ID) {} 29 30 int LEONMachineFunctionPass::GetRegIndexForOperand(MachineInstr &MI, 31 int OperandIndex) { 32 if (MI.getNumOperands() > 0) { 33 if (OperandIndex == LAST_OPERAND) { 34 OperandIndex = MI.getNumOperands() - 1; 35 } 36 37 if (MI.getNumOperands() > (unsigned)OperandIndex && 38 MI.getOperand(OperandIndex).isReg()) { 39 return (int)MI.getOperand(OperandIndex).getReg(); 40 } 41 } 42 43 static int NotFoundIndex = -10; 44 // Return a different number each time to avoid any comparisons between the 45 // values returned. 46 NotFoundIndex -= 10; 47 return NotFoundIndex; 48 } 49 50 // finds a new free FP register 51 // checks also the AllocatedRegisters vector 52 int LEONMachineFunctionPass::getUnusedFPRegister(MachineRegisterInfo &MRI) { 53 for (int RegisterIndex = SP::F0; RegisterIndex <= SP::F31; ++RegisterIndex) { 54 if (!MRI.isPhysRegUsed(RegisterIndex) && 55 !is_contained(UsedRegisters, RegisterIndex)) { 56 return RegisterIndex; 57 } 58 } 59 60 return -1; 61 } 62 63 //***************************************************************************** 64 //**** InsertNOPLoad pass 65 //***************************************************************************** 66 // This pass fixes the incorrectly working Load instructions that exists for 67 // some earlier versions of the LEON processor line. NOP instructions must 68 // be inserted after the load instruction to ensure that the Load instruction 69 // behaves as expected for these processors. 70 // 71 // This pass inserts a NOP after any LD or LDF instruction. 72 // 73 char InsertNOPLoad::ID = 0; 74 75 InsertNOPLoad::InsertNOPLoad(TargetMachine &tm) 76 : LEONMachineFunctionPass(tm, ID) {} 77 78 bool InsertNOPLoad::runOnMachineFunction(MachineFunction &MF) { 79 Subtarget = &MF.getSubtarget<SparcSubtarget>(); 80 const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); 81 DebugLoc DL = DebugLoc(); 82 83 bool Modified = false; 84 for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { 85 MachineBasicBlock &MBB = *MFI; 86 for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) { 87 MachineInstr &MI = *MBBI; 88 unsigned Opcode = MI.getOpcode(); 89 if (Opcode >= SP::LDDArr && Opcode <= SP::LDrr) { 90 MachineBasicBlock::iterator NMBBI = std::next(MBBI); 91 BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP)); 92 Modified = true; 93 } 94 } 95 } 96 97 return Modified; 98 } 99 100 //***************************************************************************** 101 //**** FixFSMULD pass 102 //***************************************************************************** 103 // This pass fixes the incorrectly working FSMULD instruction that exists for 104 // some earlier versions of the LEON processor line. 105 // 106 // The pass should convert the FSMULD operands to double precision in scratch 107 // registers, then calculate the result with the FMULD instruction. Therefore, 108 // the pass should replace operations of the form: 109 // fsmuld %f20,%f21,%f8 110 // with the sequence: 111 // fstod %f20,%f0 112 // fstod %f21,%f2 113 // fmuld %f0,%f2,%f8 114 // 115 char FixFSMULD::ID = 0; 116 117 FixFSMULD::FixFSMULD(TargetMachine &tm) : LEONMachineFunctionPass(tm, ID) {} 118 119 bool FixFSMULD::runOnMachineFunction(MachineFunction &MF) { 120 Subtarget = &MF.getSubtarget<SparcSubtarget>(); 121 const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); 122 DebugLoc DL = DebugLoc(); 123 124 bool Modified = false; 125 for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { 126 MachineBasicBlock &MBB = *MFI; 127 for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) { 128 129 MachineInstr &MI = *MBBI; 130 unsigned Opcode = MI.getOpcode(); 131 132 const int UNASSIGNED_INDEX = -1; 133 int Reg1Index = UNASSIGNED_INDEX; 134 int Reg2Index = UNASSIGNED_INDEX; 135 int Reg3Index = UNASSIGNED_INDEX; 136 137 if (Opcode == SP::FSMULD && MI.getNumOperands() == 3) { 138 // take the registers from fsmuld %f20,%f21,%f8 139 Reg1Index = MI.getOperand(0).getReg(); 140 Reg2Index = MI.getOperand(1).getReg(); 141 Reg3Index = MI.getOperand(2).getReg(); 142 } 143 144 if (Reg1Index != UNASSIGNED_INDEX && Reg2Index != UNASSIGNED_INDEX && 145 Reg3Index != UNASSIGNED_INDEX) { 146 clearUsedRegisterList(); 147 MachineBasicBlock::iterator NMBBI = std::next(MBBI); 148 // Whatever Reg3Index is hasn't been used yet, so we need to reserve it. 149 markRegisterUsed(Reg3Index); 150 const int ScratchReg1Index = getUnusedFPRegister(MF.getRegInfo()); 151 markRegisterUsed(ScratchReg1Index); 152 const int ScratchReg2Index = getUnusedFPRegister(MF.getRegInfo()); 153 markRegisterUsed(ScratchReg2Index); 154 155 if (ScratchReg1Index == UNASSIGNED_INDEX || 156 ScratchReg2Index == UNASSIGNED_INDEX) { 157 errs() << "Cannot allocate free scratch registers for the FixFSMULD " 158 "pass." 159 << "\n"; 160 } else { 161 // create fstod %f20,%f0 162 BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD)) 163 .addReg(ScratchReg1Index) 164 .addReg(Reg1Index); 165 166 // create fstod %f21,%f2 167 BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD)) 168 .addReg(ScratchReg2Index) 169 .addReg(Reg2Index); 170 171 // create fmuld %f0,%f2,%f8 172 BuildMI(MBB, MBBI, DL, TII.get(SP::FMULD)) 173 .addReg(Reg3Index) 174 .addReg(ScratchReg1Index) 175 .addReg(ScratchReg2Index); 176 177 MI.eraseFromParent(); 178 MBBI = NMBBI; 179 180 Modified = true; 181 } 182 } 183 } 184 } 185 186 return Modified; 187 } 188 189 //***************************************************************************** 190 //**** ReplaceFMULS pass 191 //***************************************************************************** 192 // This pass fixes the incorrectly working FMULS instruction that exists for 193 // some earlier versions of the LEON processor line. 194 // 195 // This pass converts the FMULS operands to double precision in scratch 196 // registers, then calculates the result with the FMULD instruction. 197 // The pass should replace operations of the form: 198 // fmuls %f20,%f21,%f8 199 // with the sequence: 200 // fstod %f20,%f0 201 // fstod %f21,%f2 202 // fmuld %f0,%f2,%f8 203 // 204 char ReplaceFMULS::ID = 0; 205 206 ReplaceFMULS::ReplaceFMULS(TargetMachine &tm) 207 : LEONMachineFunctionPass(tm, ID) {} 208 209 bool ReplaceFMULS::runOnMachineFunction(MachineFunction &MF) { 210 Subtarget = &MF.getSubtarget<SparcSubtarget>(); 211 const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); 212 DebugLoc DL = DebugLoc(); 213 214 bool Modified = false; 215 for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { 216 MachineBasicBlock &MBB = *MFI; 217 for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) { 218 MachineInstr &MI = *MBBI; 219 unsigned Opcode = MI.getOpcode(); 220 221 const int UNASSIGNED_INDEX = -1; 222 int Reg1Index = UNASSIGNED_INDEX; 223 int Reg2Index = UNASSIGNED_INDEX; 224 int Reg3Index = UNASSIGNED_INDEX; 225 226 if (Opcode == SP::FMULS && MI.getNumOperands() == 3) { 227 // take the registers from fmuls %f20,%f21,%f8 228 Reg1Index = MI.getOperand(0).getReg(); 229 Reg2Index = MI.getOperand(1).getReg(); 230 Reg3Index = MI.getOperand(2).getReg(); 231 } 232 233 if (Reg1Index != UNASSIGNED_INDEX && Reg2Index != UNASSIGNED_INDEX && 234 Reg3Index != UNASSIGNED_INDEX) { 235 clearUsedRegisterList(); 236 MachineBasicBlock::iterator NMBBI = std::next(MBBI); 237 // Whatever Reg3Index is hasn't been used yet, so we need to reserve it. 238 markRegisterUsed(Reg3Index); 239 const int ScratchReg1Index = getUnusedFPRegister(MF.getRegInfo()); 240 markRegisterUsed(ScratchReg1Index); 241 const int ScratchReg2Index = getUnusedFPRegister(MF.getRegInfo()); 242 markRegisterUsed(ScratchReg2Index); 243 244 if (ScratchReg1Index == UNASSIGNED_INDEX || 245 ScratchReg2Index == UNASSIGNED_INDEX) { 246 errs() << "Cannot allocate free scratch registers for the " 247 "ReplaceFMULS pass." 248 << "\n"; 249 } else { 250 // create fstod %f20,%f0 251 BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD)) 252 .addReg(ScratchReg1Index) 253 .addReg(Reg1Index); 254 255 // create fstod %f21,%f2 256 BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD)) 257 .addReg(ScratchReg2Index) 258 .addReg(Reg2Index); 259 260 // create fmuld %f0,%f2,%f8 261 BuildMI(MBB, MBBI, DL, TII.get(SP::FMULD)) 262 .addReg(Reg3Index) 263 .addReg(ScratchReg1Index) 264 .addReg(ScratchReg2Index); 265 266 MI.eraseFromParent(); 267 MBBI = NMBBI; 268 269 Modified = true; 270 } 271 } 272 } 273 } 274 275 return Modified; 276 } 277 278 279 //***************************************************************************** 280 //**** DetectRoundChange pass 281 //***************************************************************************** 282 // To prevent any explicit change of the default rounding mode, this pass 283 // detects any call of the fesetround function. 284 // A warning is generated to ensure the user knows this has happened. 285 // 286 // Detects an erratum in UT699 LEON 3 processor 287 288 char DetectRoundChange::ID = 0; 289 290 DetectRoundChange::DetectRoundChange(TargetMachine &tm) 291 : LEONMachineFunctionPass(tm, ID) {} 292 293 bool DetectRoundChange::runOnMachineFunction(MachineFunction &MF) { 294 Subtarget = &MF.getSubtarget<SparcSubtarget>(); 295 296 bool Modified = false; 297 for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { 298 MachineBasicBlock &MBB = *MFI; 299 for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) { 300 MachineInstr &MI = *MBBI; 301 unsigned Opcode = MI.getOpcode(); 302 if (Opcode == SP::CALL && MI.getNumOperands() > 0) { 303 MachineOperand &MO = MI.getOperand(0); 304 305 if (MO.isGlobal()) { 306 StringRef FuncName = MO.getGlobal()->getName(); 307 if (FuncName.compare_lower("fesetround") == 0) { 308 errs() << "Error: You are using the detectroundchange " 309 "option to detect rounding changes that will " 310 "cause LEON errata. The only way to fix this " 311 "is to remove the call to fesetround from " 312 "the source code.\n"; 313 } 314 } 315 } 316 } 317 } 318 319 return Modified; 320 } 321 322 //***************************************************************************** 323 //**** FixAllFDIVSQRT pass 324 //***************************************************************************** 325 // This pass fixes the incorrectly working FDIVx and FSQRTx instructions that 326 // exist for some earlier versions of the LEON processor line. Five NOP 327 // instructions need to be inserted after these instructions to ensure the 328 // correct result is placed in the destination registers before they are used. 329 // 330 // This pass implements two fixes: 331 // 1) fixing the FSQRTS and FSQRTD instructions. 332 // 2) fixing the FDIVS and FDIVD instructions. 333 // 334 // FSQRTS and FDIVS are converted to FDIVD and FSQRTD respectively earlier in 335 // the pipeline when this option is enabled, so this pass needs only to deal 336 // with the changes that still need implementing for the "double" versions 337 // of these instructions. 338 // 339 char FixAllFDIVSQRT::ID = 0; 340 341 FixAllFDIVSQRT::FixAllFDIVSQRT(TargetMachine &tm) 342 : LEONMachineFunctionPass(tm, ID) {} 343 344 bool FixAllFDIVSQRT::runOnMachineFunction(MachineFunction &MF) { 345 Subtarget = &MF.getSubtarget<SparcSubtarget>(); 346 const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); 347 DebugLoc DL = DebugLoc(); 348 349 bool Modified = false; 350 for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { 351 MachineBasicBlock &MBB = *MFI; 352 for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) { 353 MachineInstr &MI = *MBBI; 354 unsigned Opcode = MI.getOpcode(); 355 356 // Note: FDIVS and FSQRTS cannot be generated when this erratum fix is 357 // switched on so we don't need to check for them here. They will 358 // already have been converted to FSQRTD or FDIVD earlier in the 359 // pipeline. 360 if (Opcode == SP::FSQRTD || Opcode == SP::FDIVD) { 361 for (int InsertedCount = 0; InsertedCount < 5; InsertedCount++) 362 BuildMI(MBB, MBBI, DL, TII.get(SP::NOP)); 363 364 MachineBasicBlock::iterator NMBBI = std::next(MBBI); 365 for (int InsertedCount = 0; InsertedCount < 28; InsertedCount++) 366 BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP)); 367 368 Modified = true; 369 } 370 } 371 } 372 373 return Modified; 374 } 375