mirror of
https://github.com/RPCS3/llvm.git
synced 2025-02-19 10:15:00 +00:00

Errata fixes for various errata in different versions of the Leon variants of the Sparc 32 bit processor. The nature of the errata are listed in the comments preceding the errata fix passes. Relevant unit tests are implemented for each of these. Note: Running clang-format has changed a few other lines too, unrelated to the implemented errata fixes. These have been left in as this keeps the code formatting consistent. Differential Revision: http://reviews.llvm.org/D21960 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@274856 91177308-0d34-0410-b5e6-96231b3b80d8
934 lines
34 KiB
C++
Executable File
934 lines
34 KiB
C++
Executable File
//===------ LeonPasses.cpp - Define passes specific to LEON ---------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "LeonPasses.h"
|
|
#include "llvm/CodeGen/ISDOpcodes.h"
|
|
#include "llvm/CodeGen/MachineFunction.h"
|
|
#include "llvm/CodeGen/MachineInstr.h"
|
|
#include "llvm/CodeGen/MachineInstrBuilder.h"
|
|
#include "llvm/CodeGen/MachineRegisterInfo.h"
|
|
#include "llvm/IR/LLVMContext.h"
|
|
#include "llvm/Support/raw_ostream.h"
|
|
using namespace llvm;
|
|
|
|
LEONMachineFunctionPass::LEONMachineFunctionPass(TargetMachine &tm, char &ID)
|
|
: MachineFunctionPass(ID) {}
|
|
|
|
LEONMachineFunctionPass::LEONMachineFunctionPass(char &ID)
|
|
: MachineFunctionPass(ID) {}
|
|
|
|
int LEONMachineFunctionPass::GetRegIndexForOperand(MachineInstr &MI,
|
|
int OperandIndex) {
|
|
if (MI.getNumOperands() > 0) {
|
|
if (OperandIndex == LAST_OPERAND) {
|
|
OperandIndex = MI.getNumOperands() - 1;
|
|
}
|
|
|
|
if (MI.getNumOperands() > (unsigned)OperandIndex &&
|
|
MI.getOperand(OperandIndex).isReg()) {
|
|
return (int)MI.getOperand(OperandIndex).getReg();
|
|
}
|
|
}
|
|
|
|
static int NotFoundIndex = -10;
|
|
// Return a different number each time to avoid any comparisons between the
|
|
// values returned.
|
|
NotFoundIndex -= 10;
|
|
return NotFoundIndex;
|
|
}
|
|
|
|
// finds a new free FP register
|
|
// checks also the AllocatedRegisters vector
|
|
int LEONMachineFunctionPass::getUnusedFPRegister(MachineRegisterInfo &MRI) {
|
|
for (int RegisterIndex = SP::F0; RegisterIndex <= SP::F31; ++RegisterIndex) {
|
|
if (!MRI.isPhysRegUsed(RegisterIndex) &&
|
|
!(std::find(UsedRegisters.begin(), UsedRegisters.end(),
|
|
RegisterIndex) != UsedRegisters.end())) {
|
|
return RegisterIndex;
|
|
}
|
|
}
|
|
|
|
return -1;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//**** InsertNOPLoad pass
|
|
//*****************************************************************************
|
|
// This pass fixes the incorrectly working Load instructions that exists for
|
|
// some earlier versions of the LEON processor line. NOP instructions must
|
|
// be inserted after the load instruction to ensure that the Load instruction
|
|
// behaves as expected for these processors.
|
|
//
|
|
// This pass inserts a NOP after any LD or LDF instruction.
|
|
//
|
|
char InsertNOPLoad::ID = 0;
|
|
|
|
InsertNOPLoad::InsertNOPLoad(TargetMachine &tm)
|
|
: LEONMachineFunctionPass(tm, ID) {}
|
|
|
|
bool InsertNOPLoad::runOnMachineFunction(MachineFunction &MF) {
|
|
Subtarget = &MF.getSubtarget<SparcSubtarget>();
|
|
const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
|
|
DebugLoc DL = DebugLoc();
|
|
|
|
bool Modified = false;
|
|
for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
|
|
MachineBasicBlock &MBB = *MFI;
|
|
for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
|
|
MachineInstr &MI = *MBBI;
|
|
unsigned Opcode = MI.getOpcode();
|
|
if (Opcode >= SP::LDDArr && Opcode <= SP::LDrr) {
|
|
MachineBasicBlock::iterator NMBBI = std::next(MBBI);
|
|
BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
|
|
Modified = true;
|
|
} else if (MI.isInlineAsm()) {
|
|
// Look for an inline ld or ldf instruction.
|
|
StringRef AsmString =
|
|
MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName();
|
|
if (AsmString.startswith_lower("ld")) {
|
|
MachineBasicBlock::iterator NMBBI = std::next(MBBI);
|
|
BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
|
|
Modified = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return Modified;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//**** FixFSMULD pass
|
|
//*****************************************************************************
|
|
// This pass fixes the incorrectly working FSMULD instruction that exists for
|
|
// some earlier versions of the LEON processor line.
|
|
//
|
|
// The pass should convert the FSMULD operands to double precision in scratch
|
|
// registers, then calculate the result with the FMULD instruction. Therefore,
|
|
// the pass should replace operations of the form:
|
|
// fsmuld %f20,%f21,%f8
|
|
// with the sequence:
|
|
// fstod %f20,%f0
|
|
// fstod %f21,%f2
|
|
// fmuld %f0,%f2,%f8
|
|
//
|
|
char FixFSMULD::ID = 0;
|
|
|
|
FixFSMULD::FixFSMULD(TargetMachine &tm) : LEONMachineFunctionPass(tm, ID) {}
|
|
|
|
bool FixFSMULD::runOnMachineFunction(MachineFunction &MF) {
|
|
Subtarget = &MF.getSubtarget<SparcSubtarget>();
|
|
const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
|
|
DebugLoc DL = DebugLoc();
|
|
|
|
bool Modified = false;
|
|
for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
|
|
MachineBasicBlock &MBB = *MFI;
|
|
for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
|
|
|
|
MachineInstr &MI = *MBBI;
|
|
unsigned Opcode = MI.getOpcode();
|
|
|
|
const int UNASSIGNED_INDEX = -1;
|
|
int Reg1Index = UNASSIGNED_INDEX;
|
|
int Reg2Index = UNASSIGNED_INDEX;
|
|
int Reg3Index = UNASSIGNED_INDEX;
|
|
|
|
if (Opcode == SP::FSMULD && MI.getNumOperands() == 3) {
|
|
// take the registers from fsmuld %f20,%f21,%f8
|
|
Reg1Index = MI.getOperand(0).getReg();
|
|
Reg2Index = MI.getOperand(1).getReg();
|
|
Reg3Index = MI.getOperand(2).getReg();
|
|
} else if (MI.isInlineAsm()) {
|
|
StringRef AsmString =
|
|
MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName();
|
|
if (AsmString.startswith_lower("fsmuld")) {
|
|
// this is an inline FSMULD instruction
|
|
|
|
unsigned StartOp = InlineAsm::MIOp_FirstOperand;
|
|
|
|
// extracts the registers from the inline assembly instruction
|
|
for (unsigned i = StartOp, e = MI.getNumOperands(); i != e; ++i) {
|
|
const MachineOperand &MO = MI.getOperand(i);
|
|
if (MO.isReg()) {
|
|
if (Reg1Index == UNASSIGNED_INDEX)
|
|
Reg1Index = MO.getReg();
|
|
else if (Reg2Index == UNASSIGNED_INDEX)
|
|
Reg2Index = MO.getReg();
|
|
else if (Reg3Index == UNASSIGNED_INDEX)
|
|
Reg3Index = MO.getReg();
|
|
}
|
|
if (Reg3Index != UNASSIGNED_INDEX)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Reg1Index != UNASSIGNED_INDEX && Reg2Index != UNASSIGNED_INDEX &&
|
|
Reg3Index != UNASSIGNED_INDEX) {
|
|
clearUsedRegisterList();
|
|
MachineBasicBlock::iterator NMBBI = std::next(MBBI);
|
|
// Whatever Reg3Index is hasn't been used yet, so we need to reserve it.
|
|
markRegisterUsed(Reg3Index);
|
|
const int ScratchReg1Index = getUnusedFPRegister(MF.getRegInfo());
|
|
markRegisterUsed(ScratchReg1Index);
|
|
const int ScratchReg2Index = getUnusedFPRegister(MF.getRegInfo());
|
|
markRegisterUsed(ScratchReg2Index);
|
|
|
|
if (ScratchReg1Index == UNASSIGNED_INDEX ||
|
|
ScratchReg2Index == UNASSIGNED_INDEX) {
|
|
errs() << "Cannot allocate free scratch registers for the FixFSMULD "
|
|
"pass."
|
|
<< "\n";
|
|
} else {
|
|
// create fstod %f20,%f0
|
|
BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD))
|
|
.addReg(ScratchReg1Index)
|
|
.addReg(Reg1Index);
|
|
|
|
// create fstod %f21,%f2
|
|
BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD))
|
|
.addReg(ScratchReg2Index)
|
|
.addReg(Reg2Index);
|
|
|
|
// create fmuld %f0,%f2,%f8
|
|
BuildMI(MBB, MBBI, DL, TII.get(SP::FMULD))
|
|
.addReg(Reg3Index)
|
|
.addReg(ScratchReg1Index)
|
|
.addReg(ScratchReg2Index);
|
|
|
|
MI.eraseFromParent();
|
|
MBBI = NMBBI;
|
|
|
|
Modified = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return Modified;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//**** ReplaceFMULS pass
|
|
//*****************************************************************************
|
|
// This pass fixes the incorrectly working FMULS instruction that exists for
|
|
// some earlier versions of the LEON processor line.
|
|
//
|
|
// This pass converts the FMULS operands to double precision in scratch
|
|
// registers, then calculates the result with the FMULD instruction.
|
|
// The pass should replace operations of the form:
|
|
// fmuls %f20,%f21,%f8
|
|
// with the sequence:
|
|
// fstod %f20,%f0
|
|
// fstod %f21,%f2
|
|
// fmuld %f0,%f2,%f8
|
|
//
|
|
char ReplaceFMULS::ID = 0;
|
|
|
|
ReplaceFMULS::ReplaceFMULS(TargetMachine &tm)
|
|
: LEONMachineFunctionPass(tm, ID) {}
|
|
|
|
bool ReplaceFMULS::runOnMachineFunction(MachineFunction &MF) {
|
|
Subtarget = &MF.getSubtarget<SparcSubtarget>();
|
|
const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
|
|
DebugLoc DL = DebugLoc();
|
|
|
|
bool Modified = false;
|
|
for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
|
|
MachineBasicBlock &MBB = *MFI;
|
|
for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
|
|
MachineInstr &MI = *MBBI;
|
|
unsigned Opcode = MI.getOpcode();
|
|
|
|
const int UNASSIGNED_INDEX = -1;
|
|
int Reg1Index = UNASSIGNED_INDEX;
|
|
int Reg2Index = UNASSIGNED_INDEX;
|
|
int Reg3Index = UNASSIGNED_INDEX;
|
|
|
|
if (Opcode == SP::FMULS && MI.getNumOperands() == 3) {
|
|
// take the registers from fmuls %f20,%f21,%f8
|
|
Reg1Index = MI.getOperand(0).getReg();
|
|
Reg2Index = MI.getOperand(1).getReg();
|
|
Reg3Index = MI.getOperand(2).getReg();
|
|
} else if (MI.isInlineAsm()) {
|
|
StringRef AsmString =
|
|
MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName();
|
|
if (AsmString.startswith_lower("fmuls")) {
|
|
// this is an inline FMULS instruction
|
|
unsigned StartOp = InlineAsm::MIOp_FirstOperand;
|
|
|
|
// extracts the registers from the inline assembly instruction
|
|
for (unsigned i = StartOp, e = MI.getNumOperands(); i != e; ++i) {
|
|
const MachineOperand &MO = MI.getOperand(i);
|
|
if (MO.isReg()) {
|
|
if (Reg1Index == UNASSIGNED_INDEX)
|
|
Reg1Index = MO.getReg();
|
|
else if (Reg2Index == UNASSIGNED_INDEX)
|
|
Reg2Index = MO.getReg();
|
|
else if (Reg3Index == UNASSIGNED_INDEX)
|
|
Reg3Index = MO.getReg();
|
|
}
|
|
if (Reg3Index != UNASSIGNED_INDEX)
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
if (Reg1Index != UNASSIGNED_INDEX && Reg2Index != UNASSIGNED_INDEX &&
|
|
Reg3Index != UNASSIGNED_INDEX) {
|
|
clearUsedRegisterList();
|
|
MachineBasicBlock::iterator NMBBI = std::next(MBBI);
|
|
// Whatever Reg3Index is hasn't been used yet, so we need to reserve it.
|
|
markRegisterUsed(Reg3Index);
|
|
const int ScratchReg1Index = getUnusedFPRegister(MF.getRegInfo());
|
|
markRegisterUsed(ScratchReg1Index);
|
|
const int ScratchReg2Index = getUnusedFPRegister(MF.getRegInfo());
|
|
markRegisterUsed(ScratchReg2Index);
|
|
|
|
if (ScratchReg1Index == UNASSIGNED_INDEX ||
|
|
ScratchReg2Index == UNASSIGNED_INDEX) {
|
|
errs() << "Cannot allocate free scratch registers for the "
|
|
"ReplaceFMULS pass."
|
|
<< "\n";
|
|
} else {
|
|
// create fstod %f20,%f0
|
|
BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD))
|
|
.addReg(ScratchReg1Index)
|
|
.addReg(Reg1Index);
|
|
|
|
// create fstod %f21,%f2
|
|
BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD))
|
|
.addReg(ScratchReg2Index)
|
|
.addReg(Reg2Index);
|
|
|
|
// create fmuld %f0,%f2,%f8
|
|
BuildMI(MBB, MBBI, DL, TII.get(SP::FMULD))
|
|
.addReg(Reg3Index)
|
|
.addReg(ScratchReg1Index)
|
|
.addReg(ScratchReg2Index);
|
|
|
|
MI.eraseFromParent();
|
|
MBBI = NMBBI;
|
|
|
|
Modified = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return Modified;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//**** FixAllFDIVSQRT pass
|
|
//*****************************************************************************
|
|
// This pass fixes the incorrectly working FDIVx and FSQRTx instructions that
|
|
// exist for some earlier versions of the LEON processor line. Five NOP
|
|
// instructions need to be inserted after these instructions to ensure the
|
|
// correct result is placed in the destination registers before they are used.
|
|
//
|
|
// This pass implements two fixes:
|
|
// 1) fixing the FSQRTS and FSQRTD instructions.
|
|
// 2) fixing the FDIVS and FDIVD instructions.
|
|
//
|
|
// FSQRTS and FDIVS are converted to FDIVD and FSQRTD respectively earlier in
|
|
// the pipeline when this option is enabled, so this pass needs only to deal
|
|
// with the changes that still need implementing for the "double" versions
|
|
// of these instructions.
|
|
//
|
|
char FixAllFDIVSQRT::ID = 0;
|
|
|
|
FixAllFDIVSQRT::FixAllFDIVSQRT(TargetMachine &tm)
|
|
: LEONMachineFunctionPass(tm, ID) {}
|
|
|
|
bool FixAllFDIVSQRT::runOnMachineFunction(MachineFunction &MF) {
|
|
Subtarget = &MF.getSubtarget<SparcSubtarget>();
|
|
const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
|
|
DebugLoc DL = DebugLoc();
|
|
|
|
bool Modified = false;
|
|
for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
|
|
MachineBasicBlock &MBB = *MFI;
|
|
for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
|
|
MachineInstr &MI = *MBBI;
|
|
unsigned Opcode = MI.getOpcode();
|
|
|
|
if (MI.isInlineAsm()) {
|
|
StringRef AsmString =
|
|
MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName();
|
|
if (AsmString.startswith_lower("fsqrtd")) {
|
|
// this is an inline fsqrts instruction
|
|
Opcode = SP::FSQRTD;
|
|
} else if (AsmString.startswith_lower("fdivd")) {
|
|
// this is an inline fsqrts instruction
|
|
Opcode = SP::FDIVD;
|
|
}
|
|
}
|
|
|
|
// Note: FDIVS and FSQRTS cannot be generated when this erratum fix is
|
|
// switched on so we don't need to check for them here. They will
|
|
// already have been converted to FSQRTD or FDIVD earlier in the
|
|
// pipeline.
|
|
if (Opcode == SP::FSQRTD || Opcode == SP::FDIVD) {
|
|
// Insert 5 NOPs before FSQRTD,FDIVD.
|
|
for (int InsertedCount = 0; InsertedCount < 5; InsertedCount++)
|
|
BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
|
|
|
|
MachineBasicBlock::iterator NMBBI = std::next(MBBI);
|
|
// ... and inserting 28 NOPs after FSQRTD,FDIVD.
|
|
for (int InsertedCount = 0; InsertedCount < 28; InsertedCount++)
|
|
BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
|
|
|
|
Modified = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Modified;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//**** ReplaceSDIV pass
|
|
//*****************************************************************************
|
|
// This pass fixes the incorrectly working SDIV instruction that
|
|
// exist for some earlier versions of the LEON processor line. The instruction
|
|
// is replaced with an SDIVcc instruction instead, which is working.
|
|
//
|
|
char ReplaceSDIV::ID = 0;
|
|
|
|
ReplaceSDIV::ReplaceSDIV() : LEONMachineFunctionPass(ID) {}
|
|
|
|
ReplaceSDIV::ReplaceSDIV(TargetMachine &tm) : LEONMachineFunctionPass(tm, ID) {}
|
|
|
|
bool ReplaceSDIV::runOnMachineFunction(MachineFunction &MF) {
|
|
Subtarget = &MF.getSubtarget<SparcSubtarget>();
|
|
const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
|
|
|
|
bool Modified = false;
|
|
for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
|
|
MachineBasicBlock &MBB = *MFI;
|
|
for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
|
|
MachineInstr &MI = *MBBI;
|
|
unsigned Opcode = MI.getOpcode();
|
|
if (Opcode == SP::SDIVrr) {
|
|
MI.setDesc(TII.get(SP::SDIVCCrr));
|
|
Modified = true;
|
|
} else if (Opcode == SP::SDIVri) {
|
|
MI.setDesc(TII.get(SP::SDIVCCri));
|
|
Modified = true;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Modified;
|
|
}
|
|
|
|
static RegisterPass<ReplaceSDIV> X("replace-sdiv", "Replase SDIV Pass", false,
|
|
false);
|
|
|
|
//*****************************************************************************
|
|
//**** FixCALL pass
|
|
//*****************************************************************************
|
|
// This pass restricts the size of the immediate operand of the CALL
|
|
// instruction, which can cause problems on some earlier versions of the LEON
|
|
// processor, which can interpret some of the call address bits incorrectly.
|
|
//
|
|
char FixCALL::ID = 0;
|
|
|
|
FixCALL::FixCALL(TargetMachine &tm) : LEONMachineFunctionPass(tm, ID) {}
|
|
|
|
bool FixCALL::runOnMachineFunction(MachineFunction &MF) {
|
|
bool Modified = false;
|
|
|
|
for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
|
|
MachineBasicBlock &MBB = *MFI;
|
|
for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
|
|
MachineInstr &MI = *MBBI;
|
|
MI.print(errs());
|
|
errs() << "\n";
|
|
|
|
unsigned Opcode = MI.getOpcode();
|
|
if (Opcode == SP::CALL || Opcode == SP::CALLrr) {
|
|
unsigned NumOperands = MI.getNumOperands();
|
|
for (unsigned OperandIndex = 0; OperandIndex < NumOperands;
|
|
OperandIndex++) {
|
|
MachineOperand &MO = MI.getOperand(OperandIndex);
|
|
if (MO.isImm()) {
|
|
int64_t Value = MO.getImm();
|
|
MO.setImm(Value & 0x000fffffL);
|
|
Modified = true;
|
|
break;
|
|
}
|
|
}
|
|
} else if (MI.isInlineAsm()) // inline assembly immediate call
|
|
{
|
|
StringRef AsmString =
|
|
MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName();
|
|
if (AsmString.startswith_lower("call")) {
|
|
// this is an inline call instruction
|
|
unsigned StartOp = InlineAsm::MIOp_FirstOperand;
|
|
|
|
// extracts the registers from the inline assembly instruction
|
|
for (unsigned i = StartOp, e = MI.getNumOperands(); i != e; ++i) {
|
|
MachineOperand &MO = MI.getOperand(i);
|
|
if (MO.isImm()) {
|
|
int64_t Value = MO.getImm();
|
|
MO.setImm(Value & 0x000fffffL);
|
|
Modified = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return Modified;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//**** IgnoreZeroFlag pass
|
|
//*****************************************************************************
|
|
// This erratum fix fixes the overflow behavior of SDIVCC and UDIVCC
|
|
// instructions that exists on some earlier LEON processors. Where these
|
|
// instructions are detected, they are replaced by a sequence that will
|
|
// explicitly write the overflow bit flag if this is required.
|
|
//
|
|
char IgnoreZeroFlag::ID = 0;
|
|
|
|
IgnoreZeroFlag::IgnoreZeroFlag(TargetMachine &tm)
|
|
: LEONMachineFunctionPass(tm, ID) {}
|
|
|
|
bool IgnoreZeroFlag::runOnMachineFunction(MachineFunction &MF) {
|
|
Subtarget = &MF.getSubtarget<SparcSubtarget>();
|
|
const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
|
|
DebugLoc DL = DebugLoc();
|
|
|
|
bool Modified = false;
|
|
for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
|
|
MachineBasicBlock &MBB = *MFI;
|
|
for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
|
|
MachineInstr &MI = *MBBI;
|
|
unsigned Opcode = MI.getOpcode();
|
|
if (Opcode == SP::SDIVCCrr || Opcode == SP::SDIVCCri ||
|
|
Opcode == SP::UDIVCCrr || Opcode == SP::UDIVCCri) {
|
|
|
|
// split the current machine basic block - just after the sdivcc/udivcc
|
|
// instruction
|
|
// create a label that help us skip the zero flag update (of PSR -
|
|
// Processor Status Register)
|
|
// if conditions are not met
|
|
const BasicBlock *LLVM_BB = MBB.getBasicBlock();
|
|
MachineFunction::iterator It =
|
|
std::next(MachineFunction::iterator(MBB));
|
|
|
|
MachineBasicBlock *dneBB = MF.CreateMachineBasicBlock(LLVM_BB);
|
|
MF.insert(It, dneBB);
|
|
|
|
// Transfer the remainder of MBB and its successor edges to dneBB.
|
|
dneBB->splice(dneBB->begin(), &MBB,
|
|
std::next(MachineBasicBlock::iterator(MI)), MBB.end());
|
|
dneBB->transferSuccessorsAndUpdatePHIs(&MBB);
|
|
|
|
MBB.addSuccessor(dneBB);
|
|
|
|
MachineBasicBlock::iterator NextMBBI = std::next(MBBI);
|
|
|
|
// bvc - branch if overflow flag not set
|
|
BuildMI(MBB, NextMBBI, DL, TII.get(SP::BCOND))
|
|
.addMBB(dneBB)
|
|
.addImm(SPCC::ICC_VS);
|
|
|
|
// bnz - branch if not zero
|
|
BuildMI(MBB, NextMBBI, DL, TII.get(SP::BCOND))
|
|
.addMBB(dneBB)
|
|
.addImm(SPCC::ICC_NE);
|
|
|
|
// use the WRPSR (Write Processor State Register) instruction to set the
|
|
// zeo flag to 1
|
|
// create wr %g0, 1, %psr
|
|
BuildMI(MBB, NextMBBI, DL, TII.get(SP::WRPSRri))
|
|
.addReg(SP::G0)
|
|
.addImm(1);
|
|
|
|
BuildMI(MBB, NextMBBI, DL, TII.get(SP::NOP));
|
|
|
|
Modified = true;
|
|
} else if (MI.isInlineAsm()) {
|
|
StringRef AsmString =
|
|
MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName();
|
|
if (AsmString.startswith_lower("sdivcc") ||
|
|
AsmString.startswith_lower("udivcc")) {
|
|
// this is an inline SDIVCC or UDIVCC instruction
|
|
|
|
// split the current machine basic block - just after the
|
|
// sdivcc/udivcc instruction
|
|
// create a label that help us skip the zero flag update (of PSR -
|
|
// Processor Status Register)
|
|
// if conditions are not met
|
|
const BasicBlock *LLVM_BB = MBB.getBasicBlock();
|
|
MachineFunction::iterator It =
|
|
std::next(MachineFunction::iterator(MBB));
|
|
|
|
MachineBasicBlock *dneBB = MF.CreateMachineBasicBlock(LLVM_BB);
|
|
MF.insert(It, dneBB);
|
|
|
|
// Transfer the remainder of MBB and its successor edges to dneBB.
|
|
dneBB->splice(dneBB->begin(), &MBB,
|
|
std::next(MachineBasicBlock::iterator(MI)), MBB.end());
|
|
dneBB->transferSuccessorsAndUpdatePHIs(&MBB);
|
|
|
|
MBB.addSuccessor(dneBB);
|
|
|
|
MachineBasicBlock::iterator NextMBBI = std::next(MBBI);
|
|
|
|
// bvc - branch if overflow flag not set
|
|
BuildMI(MBB, NextMBBI, DL, TII.get(SP::BCOND))
|
|
.addMBB(dneBB)
|
|
.addImm(SPCC::ICC_VS);
|
|
|
|
// bnz - branch if not zero
|
|
BuildMI(MBB, NextMBBI, DL, TII.get(SP::BCOND))
|
|
.addMBB(dneBB)
|
|
.addImm(SPCC::ICC_NE);
|
|
|
|
// use the WRPSR (Write Processor State Register) instruction to set
|
|
// the zeo flag to 1
|
|
// create wr %g0, 1, %psr
|
|
BuildMI(MBB, NextMBBI, DL, TII.get(SP::WRPSRri))
|
|
.addReg(SP::G0)
|
|
.addImm(1);
|
|
|
|
BuildMI(MBB, NextMBBI, DL, TII.get(SP::NOP));
|
|
|
|
Modified = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return Modified;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//**** InsertNOPDoublePrecision pass
|
|
//*****************************************************************************
|
|
// This erratum fix for some earlier LEON processors fixes a problem where a
|
|
// double precision load will not yield the correct result if used in FMUL,
|
|
// FDIV, FADD, FSUB or FSQRT instructions later. If this sequence is detected,
|
|
// inserting a NOP between the two instructions will fix the erratum.
|
|
// 1.scans the code after register allocation;
|
|
// 2.checks for the problem conditions as described in the AT697E erratum
|
|
// “Odd-Numbered FPU Register Dependency not Properly Checked in some
|
|
// Double-Precision FPU Operations”;
|
|
// 3.inserts NOPs if the problem exists.
|
|
//
|
|
char InsertNOPDoublePrecision::ID = 0;
|
|
|
|
InsertNOPDoublePrecision::InsertNOPDoublePrecision(TargetMachine &tm)
|
|
: LEONMachineFunctionPass(tm, ID) {}
|
|
|
|
bool InsertNOPDoublePrecision::runOnMachineFunction(MachineFunction &MF) {
|
|
Subtarget = &MF.getSubtarget<SparcSubtarget>();
|
|
const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
|
|
DebugLoc DL = DebugLoc();
|
|
|
|
bool Modified = false;
|
|
for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
|
|
MachineBasicBlock &MBB = *MFI;
|
|
for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
|
|
MachineInstr &MI = *MBBI;
|
|
unsigned Opcode = MI.getOpcode();
|
|
if (Opcode == SP::LDDFri || Opcode == SP::LDDFrr) {
|
|
MachineBasicBlock::iterator NMBBI = std::next(MBBI);
|
|
MachineInstr &NMI = *NMBBI;
|
|
|
|
unsigned NextOpcode = NMI.getOpcode();
|
|
// NMI.print(errs());
|
|
if (NextOpcode == SP::FADDD || NextOpcode == SP::FSUBD ||
|
|
NextOpcode == SP::FMULD || NextOpcode == SP::FDIVD) {
|
|
int RegAIndex = GetRegIndexForOperand(MI, 0);
|
|
int RegBIndex = GetRegIndexForOperand(NMI, 0);
|
|
int RegCIndex =
|
|
GetRegIndexForOperand(NMI, 2); // Second source operand is index 2
|
|
int RegDIndex =
|
|
GetRegIndexForOperand(NMI, 1); // Destination operand is index 1
|
|
|
|
if ((RegAIndex == RegBIndex + 1 && RegBIndex == RegDIndex) ||
|
|
(RegAIndex == RegCIndex + 1 && RegCIndex == RegDIndex) ||
|
|
(RegAIndex == RegBIndex + 1 && RegCIndex == RegDIndex) ||
|
|
(RegAIndex == RegCIndex + 1 && RegBIndex == RegDIndex)) {
|
|
// Insert NOP between the two instructions.
|
|
BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
|
|
Modified = true;
|
|
}
|
|
|
|
// Check the errata patterns that only happen for FADDD and FMULD
|
|
if (Modified == false &&
|
|
(NextOpcode == SP::FADDD || NextOpcode == SP::FMULD)) {
|
|
RegAIndex = GetRegIndexForOperand(MI, 1);
|
|
if (RegAIndex == RegBIndex + 1 && RegBIndex == RegCIndex &&
|
|
RegBIndex == RegDIndex) {
|
|
// Insert NOP between the two instructions.
|
|
BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
|
|
Modified = true;
|
|
}
|
|
}
|
|
} else if (NextOpcode == SP::FSQRTD) {
|
|
int RegAIndex = GetRegIndexForOperand(MI, 1);
|
|
int RegBIndex = GetRegIndexForOperand(NMI, 0);
|
|
int RegCIndex = GetRegIndexForOperand(NMI, 1);
|
|
|
|
if (RegAIndex == RegBIndex + 1 && RegBIndex == RegCIndex) {
|
|
// Insert NOP between the two instructions.
|
|
BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
|
|
Modified = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return Modified;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//**** PreventRoundChange pass
|
|
//*****************************************************************************
|
|
// To prevent any explicit change of the default rounding mode, this pass
|
|
// detects any call of the fesetround function and removes this call from the
|
|
// list of generated operations.
|
|
//
|
|
char PreventRoundChange::ID = 0;
|
|
|
|
PreventRoundChange::PreventRoundChange(TargetMachine &tm)
|
|
: LEONMachineFunctionPass(tm, ID) {}
|
|
|
|
bool PreventRoundChange::runOnMachineFunction(MachineFunction &MF) {
|
|
Subtarget = &MF.getSubtarget<SparcSubtarget>();
|
|
|
|
bool Modified = false;
|
|
for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
|
|
MachineBasicBlock &MBB = *MFI;
|
|
for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
|
|
MachineInstr &MI = *MBBI;
|
|
unsigned Opcode = MI.getOpcode();
|
|
if (Opcode == SP::CALL && MI.getNumOperands() > 0) {
|
|
MachineOperand &MO = MI.getOperand(0);
|
|
|
|
if (MO.isGlobal()) {
|
|
StringRef FuncName = MO.getGlobal()->getName();
|
|
if (FuncName.compare_lower("fesetround") == 0) {
|
|
MachineBasicBlock::iterator NMBBI = std::next(MBBI);
|
|
MI.eraseFromParent();
|
|
MBBI = NMBBI;
|
|
Modified = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return Modified;
|
|
}
|
|
//*****************************************************************************
|
|
//**** FlushCacheLineSWAP pass
|
|
//*****************************************************************************
|
|
// This pass inserts FLUSHW just before any SWAP atomic instruction.
|
|
//
|
|
char FlushCacheLineSWAP::ID = 0;
|
|
|
|
FlushCacheLineSWAP::FlushCacheLineSWAP(TargetMachine &tm)
|
|
: LEONMachineFunctionPass(tm, ID) {}
|
|
|
|
bool FlushCacheLineSWAP::runOnMachineFunction(MachineFunction &MF) {
|
|
Subtarget = &MF.getSubtarget<SparcSubtarget>();
|
|
const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
|
|
DebugLoc DL = DebugLoc();
|
|
|
|
bool Modified = false;
|
|
for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
|
|
MachineBasicBlock &MBB = *MFI;
|
|
for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
|
|
MachineInstr &MI = *MBBI;
|
|
unsigned Opcode = MI.getOpcode();
|
|
if (Opcode == SP::SWAPrr || Opcode == SP::SWAPri ||
|
|
Opcode == SP::LDSTUBrr || Opcode == SP::LDSTUBri) {
|
|
// insert flush and 5 NOPs before the swap/ldstub instruction
|
|
BuildMI(MBB, MBBI, DL, TII.get(SP::FLUSH));
|
|
BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
|
|
BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
|
|
BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
|
|
BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
|
|
BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
|
|
|
|
Modified = true;
|
|
} else if (MI.isInlineAsm()) {
|
|
StringRef AsmString =
|
|
MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName();
|
|
if (AsmString.startswith_lower("swap") ||
|
|
AsmString.startswith_lower("ldstub")) {
|
|
// this is an inline swap or ldstub instruction
|
|
|
|
// insert flush and 5 NOPs before the swap/ldstub instruction
|
|
BuildMI(MBB, MBBI, DL, TII.get(SP::FLUSH));
|
|
BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
|
|
BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
|
|
BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
|
|
BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
|
|
BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
|
|
|
|
Modified = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return Modified;
|
|
}
|
|
|
|
//*****************************************************************************
|
|
//**** InsertNOPsLoadStore pass
|
|
//*****************************************************************************
|
|
// This pass shall insert NOPs between floating point loads and stores when the
|
|
// following circumstances are present [5]:
|
|
// Pattern 1:
|
|
// 1. single-precision load or single-precision FPOP to register %fX, where X is
|
|
// the same register as the store being checked;
|
|
// 2. single-precision load or single-precision FPOP to register %fY , where Y
|
|
// is the opposite register in the same double-precision pair;
|
|
// 3. 0-3 instructions of any kind, except stores from %fX or %fY or operations
|
|
// with %fX as destination;
|
|
// 4. the store (from register %fX) being considered.
|
|
// Pattern 2:
|
|
// 1. double-precision FPOP;
|
|
// 2. any number of operations on any kind, except no double-precision FPOP and
|
|
// at most one (less than two) single-precision or single-to-double FPOPs;
|
|
// 3. the store (from register %fX) being considered.
|
|
//
|
|
char InsertNOPsLoadStore::ID = 0;
|
|
|
|
InsertNOPsLoadStore::InsertNOPsLoadStore(TargetMachine &tm)
|
|
: LEONMachineFunctionPass(tm, ID) {}
|
|
|
|
bool InsertNOPsLoadStore::runOnMachineFunction(MachineFunction &MF) {
|
|
Subtarget = &MF.getSubtarget<SparcSubtarget>();
|
|
const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
|
|
DebugLoc DL = DebugLoc();
|
|
|
|
MachineInstr *Pattern1FirstInstruction = NULL;
|
|
MachineInstr *Pattern2FirstInstruction = NULL;
|
|
unsigned int StoreInstructionsToCheck = 0;
|
|
int FxRegIndex, FyRegIndex;
|
|
|
|
bool Modified = false;
|
|
for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
|
|
MachineBasicBlock &MBB = *MFI;
|
|
for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
|
|
MachineInstr &MI = *MBBI;
|
|
|
|
if (StoreInstructionsToCheck > 0) {
|
|
if (((MI.getOpcode() == SP::STFrr || MI.getOpcode() == SP::STFri) &&
|
|
(GetRegIndexForOperand(MI, LAST_OPERAND) == FxRegIndex ||
|
|
GetRegIndexForOperand(MI, LAST_OPERAND) == FyRegIndex)) ||
|
|
GetRegIndexForOperand(MI, 0) == FxRegIndex) {
|
|
// Insert four NOPs
|
|
for (unsigned InsertedCount = 0; InsertedCount < 4; InsertedCount++) {
|
|
BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
|
|
}
|
|
Modified = true;
|
|
}
|
|
StoreInstructionsToCheck--;
|
|
}
|
|
|
|
switch (MI.getOpcode()) {
|
|
// Watch for Pattern 1 FPop instructions
|
|
case SP::LDrr:
|
|
case SP::LDri:
|
|
case SP::LDFrr:
|
|
case SP::LDFri:
|
|
case SP::FADDS:
|
|
case SP::FSUBS:
|
|
case SP::FMULS:
|
|
case SP::FDIVS:
|
|
case SP::FSQRTS:
|
|
case SP::FCMPS:
|
|
case SP::FMOVS:
|
|
case SP::FNEGS:
|
|
case SP::FABSS:
|
|
case SP::FITOS:
|
|
case SP::FSTOI:
|
|
case SP::FITOD:
|
|
case SP::FDTOI:
|
|
case SP::FDTOS:
|
|
if (Pattern1FirstInstruction != NULL) {
|
|
FxRegIndex = GetRegIndexForOperand(*Pattern1FirstInstruction, 0);
|
|
FyRegIndex = GetRegIndexForOperand(MI, 0);
|
|
|
|
// Check to see if these registers are part of the same double
|
|
// precision
|
|
// register pair.
|
|
int DoublePrecRegIndexForX = (FxRegIndex - SP::F0) / 2;
|
|
int DoublePrecRegIndexForY = (FyRegIndex - SP::F0) / 2;
|
|
|
|
if (DoublePrecRegIndexForX == DoublePrecRegIndexForY)
|
|
StoreInstructionsToCheck = 4;
|
|
}
|
|
|
|
Pattern1FirstInstruction = &MI;
|
|
break;
|
|
// End of Pattern 1
|
|
|
|
// Search for Pattern 2
|
|
case SP::FADDD:
|
|
case SP::FSUBD:
|
|
case SP::FMULD:
|
|
case SP::FDIVD:
|
|
case SP::FSQRTD:
|
|
case SP::FCMPD:
|
|
Pattern2FirstInstruction = &MI;
|
|
Pattern1FirstInstruction = NULL;
|
|
break;
|
|
|
|
case SP::STFrr:
|
|
case SP::STFri:
|
|
case SP::STDFrr:
|
|
case SP::STDFri:
|
|
if (Pattern2FirstInstruction != NULL) {
|
|
if (GetRegIndexForOperand(MI, LAST_OPERAND) ==
|
|
GetRegIndexForOperand(*Pattern2FirstInstruction, 0)) {
|
|
// Insert four NOPs
|
|
for (unsigned InsertedCount = 0; InsertedCount < 4;
|
|
InsertedCount++) {
|
|
BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
|
|
}
|
|
|
|
Pattern2FirstInstruction = NULL;
|
|
}
|
|
}
|
|
Pattern1FirstInstruction = NULL;
|
|
break;
|
|
// End of Pattern 2
|
|
|
|
default:
|
|
// Ensure we don't count debug-only values while we're testing for the
|
|
// patterns.
|
|
if (!MI.isDebugValue())
|
|
Pattern1FirstInstruction = NULL;
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
return Modified;
|
|
}
|