#include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/Support/raw_ostream.h"
using namespace llvm;
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;
- }
}
}
}
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 &&
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 &&
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
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) {
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;
- }
- }
- }
}
}
}
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;
- }
}
}
}
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);
StringRef FuncName = MO.getGlobal()->getName();
if (FuncName.compare_lower("fesetround") == 0) {
MachineBasicBlock::iterator NMBBI = std::next(MBBI);
+ emitOptimizationRemark(
+ MF.getFunction()->getContext(), getPassName(), *MF.getFunction(),
+ MI.getDebugLoc(), "Warning: You are using the prvntroundchange "
+ "option to prevent rounding changes caused "
+ "by LEON errata. A call to fesetround to be "
+ "removed from the output.");
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
return Modified;
}
+
+
+//****************************************************************************************************************
+//**** FillDataCache pass
+//****************************************************************************************************************
+// This erratum fix inserts after the first operand a loop performing 4096 NOP
+// instructions.
+//
+// mov 0, %l0
+// mov 4096, %l1
+// loop1:
+// inc %l0
+// cmp %l0, %l1
+// ble loop1
+
+char FillDataCache::ID = 0;
+bool FillDataCache::CacheFilled = false;
+
+FillDataCache::FillDataCache(TargetMachine &tm)
+ : LEONMachineFunctionPass(tm, ID) {}
+
+bool FillDataCache::runOnMachineFunction(MachineFunction &MF) {
+ Subtarget = &MF.getSubtarget<SparcSubtarget>();
+ const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
+ DebugLoc DL = DebugLoc();
+
+ unsigned int CountInstr = 0;
+
+ bool Modified = false;
+ if (!CacheFilled) {
+ for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
+
+ if (CacheFilled)
+ break;
+
+ MachineBasicBlock &MBB = *MFI;
+
+ for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) {
+ MachineInstr &MI = *MBBI;
+
+ CountInstr++;
+ MachineBasicBlock::iterator NextMBBI = std::next(MBBI);
+ MBBI = NextMBBI;
+
+ // insert the following sequence right after the first instruction
+ // initializing the stack pointer (sp register)
+ // or %g0, 1, %g1
+ // loop1:
+ // nop
+ // add %g1, 1, %g1
+ // cmp %g1, 4096
+ // ble .LBB0_1
+ if (CountInstr == 1) {
+ BuildMI(MBB, NextMBBI, DL, TII.get(SP::ORrr))
+ .addReg(SP::G1)
+ .addReg(SP::G0)
+ .addImm(1);
+ } else {
+ const BasicBlock *LLVM_BB = MBB.getBasicBlock();
+ MachineBasicBlock *dneBB = MF.CreateMachineBasicBlock(LLVM_BB);
+
+ MachineFunction::iterator It =
+ std::next(MachineFunction::iterator(MBB));
+
+ MF.insert(It, dneBB);
+
+ BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
+
+ BuildMI(MBB, MBBI, DL, TII.get(SP::ADDri))
+ .addReg(SP::G1)
+ .addReg(SP::G1)
+ .addImm(1);
+
+ BuildMI(MBB, MBBI, DL, TII.get(SP::CMPri))
+ .addReg(SP::G1)
+ .addImm(4096);
+
+ BuildMI(MBB, MBBI, DL, TII.get(SP::BCOND))
+ .addMBB(dneBB)
+ .addImm(SPCC::ICC_LE);
+
+ dneBB->splice(dneBB->begin(), &MBB,
+ std::next(MachineBasicBlock::iterator(MI)), MBB.end());
+ dneBB->transferSuccessorsAndUpdatePHIs(&MBB);
+
+ MBB.addSuccessor(dneBB);
+
+ CacheFilled = true;
+ Modified = true;
+ break;
+ }
+ }
+ }
+ }
+
+ return Modified;
+}
+
+
+//****************************************************************************************************************
+//**** RestoreExecAddress pass
+//****************************************************************************************************************
+// This erratum fix should handle user traps of FPU exceptions and restore the
+// execution address by skipping the trapped FPU instruction.
+// The algorithm:
+// find rett - return from trap
+// insert code before rett to:
+// 1. load the FSR register
+// 2. check if there is an FPU exception
+// 3. branch to old rett if there is no exception
+// 4. rett to a restored exec address
+char RestoreExecAddress::ID = 0;
+
+RestoreExecAddress::RestoreExecAddress(TargetMachine &tm)
+ : LEONMachineFunctionPass(tm, ID) {}
+
+bool RestoreExecAddress::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;
+ bool ExecAddressRestored = false;
+ for (auto NMBBI = MBB.begin(), E = MBB.end(); NMBBI != E; ++NMBBI) {
+
+ if (NMBBI != E && !ExecAddressRestored) {
+ MachineBasicBlock::iterator MBBI = std::next(NMBBI);
+ MachineInstr &MI = *MBBI;
+ unsigned Opcode = MI.getOpcode();
+
+ if (Opcode == SP::RETTrr || Opcode == SP::RETTri) {
+
+ const BasicBlock *LLVM_BB = MBB.getBasicBlock();
+
+ MachineBasicBlock *dneBB = MF.CreateMachineBasicBlock(LLVM_BB);
+
+ // gets the FSR - floating point status register;
+ // the firts 4 bits are *cexc* - current exception flags
+ BuildMI(MBB, MBBI, DL, TII.get(SP::STFSRrr)).addReg(SP::L7).addImm(0);
+
+ BuildMI(MBB, MBBI, DL, TII.get(SP::LDrr))
+ .addReg(SP::L7)
+ .addReg(SP::L7)
+ .addImm(0);
+
+ // performs a bitwise AND with b1111 to check the first 4 bits of FSR
+ // (cexc)
+ // if cexc is not zero, then it is an FPU exception
+ BuildMI(MBB, MBBI, DL, TII.get(SP::ANDri))
+ .addReg(SP::L7)
+ .addReg(SP::L7)
+ .addImm(15);
+
+ BuildMI(MBB, MBBI, DL, TII.get(SP::CMPri)).addReg(SP::L7).addImm(0);
+
+ BuildMI(MBB, MBBI, DL, TII.get(SP::BCOND))
+ .addMBB(dneBB)
+ .addImm(SPCC::ICC_E);
+ // BuildMI(&MBB, DL,
+ // TII.get(SP::BCOND)).addMBB(dneBB).addImm(SPCC::ICC_E);
+
+ BuildMI(MBB, MBBI, DL, TII.get(SP::RETTri)).addReg(SP::L2).addImm(4);
+
+ MachineFunction::iterator It =
+ std::next(MachineFunction::iterator(MBB));
+ MF.insert(It, dneBB);
+
+ // Transfer the remainder of MBB and its successor edges to dneBB.
+ dneBB->splice(dneBB->begin(), &MBB, MachineBasicBlock::iterator(MI),
+ MBB.end());
+ dneBB->transferSuccessorsAndUpdatePHIs(&MBB);
+
+ MBB.addSuccessor(dneBB);
+
+ ExecAddressRestored = true;
+ Modified = true;
+ }
+ }
+ }
+ }
+
+ return Modified;
+}
+
bool runOnMachineFunction(MachineFunction &MF) override;
const char *getPassName() const override {
- return "ReplaceSDIV: Erratum Fix LBR25: do not emit SDIV, but emit SDIVCC "
+ return "ReplaceSDIV: Leon erratum fix: do not emit SDIV, but emit SDIVCC "
"instead";
}
};
bool runOnMachineFunction(MachineFunction &MF) override;
const char *getPassName() const override {
- return "FixCALL: Erratum Fix LBR26: restrict the size of the immediate "
+ return "FixCALL: Leon erratum fix: restrict the size of the immediate "
"operand of the CALL instruction to 20 bits";
}
};
+class LLVM_LIBRARY_VISIBILITY RestoreExecAddress : public LEONMachineFunctionPass {
+public:
+ static char ID;
+
+ RestoreExecAddress(TargetMachine &tm);
+ bool runOnMachineFunction(MachineFunction& MF) override;
+
+ const char *getPassName() const override {
+ return "RestoreExecAddress: Leon erratum fix: ensure execution "
+ "address is restored for bad floating point trap handlers.";
+ }
+};
+
class LLVM_LIBRARY_VISIBILITY IgnoreZeroFlag : public LEONMachineFunctionPass {
public:
static char ID;
bool runOnMachineFunction(MachineFunction &MF) override;
const char *getPassName() const override {
- return "IgnoreZeroFlag: Erratum Fix LBR28: do not rely on the zero bit "
+ return "IgnoreZeroFlag: Leon erratum fix: do not rely on the zero bit "
"flag on a divide overflow for SDIVCC and UDIVCC";
}
};
+class LLVM_LIBRARY_VISIBILITY FillDataCache : public LEONMachineFunctionPass {
+public:
+ static char ID;
+ static bool CacheFilled;
+
+ FillDataCache(TargetMachine &tm);
+ bool runOnMachineFunction(MachineFunction& MF) override;
+
+ const char *getPassName() const override {
+ return "FillDataCache: Leon erratum fix: fill data cache with values at application startup";
+ }
+};
+
class LLVM_LIBRARY_VISIBILITY InsertNOPDoublePrecision
: public LEONMachineFunctionPass {
public:
bool runOnMachineFunction(MachineFunction &MF) override;
const char *getPassName() const override {
- return "InsertNOPDoublePrecision: Erratum Fix LBR30: insert a NOP before "
+ return "InsertNOPDoublePrecision: Leon erratum fix: insert a NOP before "
"the double precision floating point instruction";
}
};
bool runOnMachineFunction(MachineFunction &MF) override;
const char *getPassName() const override {
- return "FixFSMULD: Erratum Fix LBR31: do not select FSMULD";
+ return "FixFSMULD: Leon erratum fix: do not utilize FSMULD";
}
};
bool runOnMachineFunction(MachineFunction &MF) override;
const char *getPassName() const override {
- return "ReplaceFMULS: Erratum Fix LBR32: replace FMULS instruction with a "
+ return "ReplaceFMULS: Leon erratum fix: Replace FMULS instruction with a "
"routine using conversions/double precision operations to replace "
"FMULS";
}
bool runOnMachineFunction(MachineFunction &MF) override;
const char *getPassName() const override {
- return "PreventRoundChange: Erratum Fix LBR33: prevent any rounding mode "
+ return "PreventRoundChange: Leon erratum fix: prevent any rounding mode "
"change request: use only the round-to-nearest rounding mode";
}
};
bool runOnMachineFunction(MachineFunction &MF) override;
const char *getPassName() const override {
- return "FixAllFDIVSQRT: Erratum Fix LBR34: fix FDIVS/FDIVD/FSQRTS/FSQRTD "
+ return "FixAllFDIVSQRT: Leon erratum fix: Fix FDIVS/FDIVD/FSQRTS/FSQRTD "
"instructions with NOPs and floating-point store";
}
};
bool runOnMachineFunction(MachineFunction &MF) override;
const char *getPassName() const override {
- return "InsertNOPLoad: insert a NOP instruction after "
+ return "InsertNOPLoad: Leon erratum fix: Insert a NOP instruction after "
"every single-cycle load instruction when the next instruction is "
"another load/store instruction";
}
};
-class LLVM_LIBRARY_VISIBILITY FlushCacheLineSWAP
- : public LEONMachineFunctionPass {
-public:
- static char ID;
-
- FlushCacheLineSWAP(TargetMachine &tm);
- bool runOnMachineFunction(MachineFunction &MF) override;
-
- const char *getPassName() const override {
- return "FlushCacheLineSWAP: Erratum Fix LBR36: flush cache line containing "
- "the lock before performing any of the atomic instructions SWAP and "
- "LDSTUB";
- }
-};
-
class LLVM_LIBRARY_VISIBILITY InsertNOPsLoadStore
: public LEONMachineFunctionPass {
public:
bool runOnMachineFunction(MachineFunction &MF) override;
const char *getPassName() const override {
- return "InsertNOPsLoadStore: Erratum Fix LBR37: insert NOPs between "
+ return "InsertNOPsLoadStore: Leon Erratum Fix: Insert NOPs between "
"single-precision loads and the store, so the number of "
"instructions between is 4";
}