You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
934 lines
34 KiB
934 lines
34 KiB
//===------ 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;
|
|
}
|