summaryrefslogtreecommitdiffstats
path: root/llvm/lib/Target/Sparc
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Target/Sparc')
-rwxr-xr-xllvm/lib/Target/Sparc/LeonFeatures.td21
-rwxr-xr-xllvm/lib/Target/Sparc/LeonPasses.cpp335
-rwxr-xr-xllvm/lib/Target/Sparc/LeonPasses.h45
-rw-r--r--llvm/lib/Target/Sparc/Sparc.td2
-rw-r--r--llvm/lib/Target/Sparc/SparcISelLowering.cpp13
-rw-r--r--llvm/lib/Target/Sparc/SparcInstrInfo.td13
-rw-r--r--llvm/lib/Target/Sparc/SparcSubtarget.cpp3
-rw-r--r--llvm/lib/Target/Sparc/SparcSubtarget.h6
-rw-r--r--llvm/lib/Target/Sparc/SparcTargetMachine.cpp12
9 files changed, 449 insertions, 1 deletions
diff --git a/llvm/lib/Target/Sparc/LeonFeatures.td b/llvm/lib/Target/Sparc/LeonFeatures.td
index 7de98407dac..e2282abbbdb 100755
--- a/llvm/lib/Target/Sparc/LeonFeatures.td
+++ b/llvm/lib/Target/Sparc/LeonFeatures.td
@@ -43,3 +43,24 @@ def InsertNOPLoad: SubtargetFeature<
"true",
"LEON3 erratum fix: Insert a NOP instruction after every single-cycle load instruction when the next instruction is another load/store instruction"
>;
+
+def FixFSMULD : SubtargetFeature<
+ "fixfsmuld",
+ "FixFSMULD",
+ "true",
+ "LEON erratum fix: Do not use FSMULD"
+>;
+
+def ReplaceFMULS : SubtargetFeature<
+ "replacefmuls",
+ "ReplaceFMULS",
+ "true",
+ "LEON erratum fix: Replace FMULS instruction with FMULD and relevant conversion instructions"
+>;
+
+def FixAllFDIVSQRT : SubtargetFeature<
+ "fixallfdivsqrt",
+ "FixAllFDIVSQRT",
+ "true",
+ "LEON erratum fix: Fix FDIVS/FDIVD/FSQRTS/FSQRTD instructions with NOPs and floating-point store"
+>;
diff --git a/llvm/lib/Target/Sparc/LeonPasses.cpp b/llvm/lib/Target/Sparc/LeonPasses.cpp
index 31261c4a3e2..9d39fa2a8c7 100755
--- a/llvm/lib/Target/Sparc/LeonPasses.cpp
+++ b/llvm/lib/Target/Sparc/LeonPasses.cpp
@@ -30,6 +30,51 @@ LEONMachineFunctionPass::LEONMachineFunctionPass(char& 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;
+}
+
+void LEONMachineFunctionPass::clearUsedRegisterList()
+{
+ UsedRegisters.clear();
+}
+
+void LEONMachineFunctionPass::markRegisterUsed(int registerIndex)
+{
+ UsedRegisters.push_back(registerIndex);
+}
+
+//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
//*****************************************************************************
@@ -76,3 +121,293 @@ bool InsertNOPLoad::runOnMachineFunction(MachineFunction& MF)
return Modified;
}
+
+//*****************************************************************************
+//**** FixFSMULD pass
+//*****************************************************************************
+//this 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();
+
+ //errs() << "FixFSMULD on function " << MF.getName() << "\n";
+
+ 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) {
+ //errs() << "Detected FSMULD\n";
+ //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()) {
+ std::string AsmString (MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName());
+ std::string FMULSOpCoode ("fsmuld");
+ std::transform(AsmString.begin(), AsmString.end(), AsmString.begin(), ::tolower);
+ if (AsmString.find(FMULSOpCoode) == 0) { // this is an inline FSMULD instruction
+ //errs() << "Detected InlineAsm FSMULD\n";
+
+ 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 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();
+
+ //errs() << "ReplaceFMULS on function " << MF.getName() << "\n";
+
+ 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) {
+ //errs() << "Detected FMULS\n";
+ //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()) {
+ std::string AsmString (MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName());
+ std::string FMULSOpCoode ("fmuls");
+ std::transform(AsmString.begin(), AsmString.end(), AsmString.begin(), ::tolower);
+ if (AsmString.find(FMULSOpCoode) == 0) { // this is an inline FMULS instruction
+ //errs() << "Detected InlineAsm FMULS\n";
+
+ 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 implements two fixes:
+// 1) fixing the FSQRTS and FSQRTD instructions;
+// 2) fixing the FDIVS and FDIVD 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();
+
+ //errs() << "FixAllFDIVSQRT on function " << MF.getName() << "\n";
+
+ bool Modified = false;
+ for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) {
+ MachineBasicBlock &MBB = *MFI;
+ //MBB.print(errs());
+ for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++ MBBI) {
+ MachineInstr &MI = *MBBI;
+ //MI.print(errs());
+ unsigned Opcode = MI.getOpcode();
+
+ if (MI.isInlineAsm()) {
+ std::string AsmString (MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName());
+ std::string FSQRTDOpCode ("fsqrtd");
+ std::string FDIVDOpCode ("fdivd");
+ std::transform(AsmString.begin(), AsmString.end(), AsmString.begin(), ::tolower);
+ if (AsmString.find(FSQRTDOpCode) == 0) { // this is an inline fsqrts instruction
+ //errs() << "Detected InlineAsm FSQRTD\n";
+ Opcode = SP::FSQRTD;
+ }
+ else if (AsmString.find(FDIVDOpCode) == 0) { // this is an inline fsqrts instruction
+ //errs() << "Detected InlineAsm FDIVD\n";
+ 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) {
+ //errs() << "Inserting 5 NOPs before FSQRTD,FDIVD.\n";
+ for (int InsertedCount=0; InsertedCount<5; InsertedCount++)
+ BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
+
+ MachineBasicBlock::iterator NMBBI = std::next(MBBI);
+ //errs() << "Inserting 28 NOPs after FSQRTD,FDIVD.\n";
+ for (int InsertedCount=0; InsertedCount<28; InsertedCount++)
+ BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
+
+ Modified = true;
+ }
+ }
+ }
+
+ return Modified;
+}
diff --git a/llvm/lib/Target/Sparc/LeonPasses.h b/llvm/lib/Target/Sparc/LeonPasses.h
index ca4b0f90c82..798f63407e3 100755
--- a/llvm/lib/Target/Sparc/LeonPasses.h
+++ b/llvm/lib/Target/Sparc/LeonPasses.h
@@ -25,10 +25,19 @@ class LLVM_LIBRARY_VISIBILITY LEONMachineFunctionPass
: public MachineFunctionPass {
protected:
const SparcSubtarget *Subtarget;
+ const int LAST_OPERAND = -1;
+
+ //this vector holds free registers that we allocate in groups for some of the LEON passes
+ std::vector <int> UsedRegisters;
protected:
LEONMachineFunctionPass(TargetMachine &tm, char& ID);
LEONMachineFunctionPass(char& ID);
+
+ int GetRegIndexForOperand(MachineInstr& MI, int OperandIndex);
+ void clearUsedRegisterList();
+ void markRegisterUsed(int registerIndex);
+ int getUnusedFPRegister(MachineRegisterInfo& MRI);
};
class LLVM_LIBRARY_VISIBILITY InsertNOPLoad : public LEONMachineFunctionPass {
@@ -42,6 +51,42 @@ public:
return "InsertNOPLoad: Erratum Fix LBR35: insert a NOP instruction after every single-cycle load instruction when the next instruction is another load/store instruction";
}
};
+
+class LLVM_LIBRARY_VISIBILITY FixFSMULD : public LEONMachineFunctionPass {
+public:
+ static char ID;
+
+ FixFSMULD(TargetMachine &tm);
+ bool runOnMachineFunction(MachineFunction& MF) override;
+
+ const char *getPassName() const override {
+ return "FixFSMULD: Erratum Fix LBR31: do not select FSMULD";
+ }
+};
+
+class LLVM_LIBRARY_VISIBILITY ReplaceFMULS : public LEONMachineFunctionPass {
+public:
+ static char ID;
+
+ ReplaceFMULS(TargetMachine &tm);
+ bool runOnMachineFunction(MachineFunction& MF) override;
+
+ const char *getPassName() const override {
+ return "ReplaceFMULS: Erratum Fix LBR32: replace FMULS instruction with a routine using conversions/double precision operations to replace FMULS";
+ }
+};
+
+class LLVM_LIBRARY_VISIBILITY FixAllFDIVSQRT : public LEONMachineFunctionPass {
+public:
+ static char ID;
+
+ FixAllFDIVSQRT(TargetMachine &tm);
+ bool runOnMachineFunction(MachineFunction& MF) override;
+
+ const char *getPassName() const override {
+ return "FixAllFDIVSQRT: Erratum Fix LBR34: fix FDIVS/FDIVD/FSQRTS/FSQRTD instructions with NOPs and floating-point store";
+ }
+};
} // namespace llvm
#endif
diff --git a/llvm/lib/Target/Sparc/Sparc.td b/llvm/lib/Target/Sparc/Sparc.td
index 4fb82ff5c74..6ae73125c9e 100644
--- a/llvm/lib/Target/Sparc/Sparc.td
+++ b/llvm/lib/Target/Sparc/Sparc.td
@@ -122,7 +122,7 @@ def : Processor<"leon3", LEON3Itineraries,
// LEON 3 FT (UT699). Provides features for the UT699 processor
// - covers all the erratum fixes for LEON3, but does not support the CASA instruction.
def : Processor<"ut699", LEON3Itineraries,
- [FeatureLeon, InsertNOPLoad]>;
+ [FeatureLeon, InsertNOPLoad, FixFSMULD, ReplaceFMULS, FixAllFDIVSQRT]>;
// LEON3 FT (GR712RC). Provides features for the GR712RC processor.
// - covers all the erratum fixed for LEON3 and support for the CASA instruction.
diff --git a/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
index 605acd6df05..7837fc8a020 100644
--- a/llvm/lib/Target/Sparc/SparcISelLowering.cpp
+++ b/llvm/lib/Target/Sparc/SparcISelLowering.cpp
@@ -1824,6 +1824,19 @@ SparcTargetLowering::SparcTargetLowering(const TargetMachine &TM,
}
}
+ if (Subtarget->fixAllFDIVSQRT()) {
+ // Promote FDIVS and FSQRTS to FDIVD and FSQRTD instructions instead as
+ // the former instructions generate errata on LEON processors.
+ setOperationAction(ISD::FDIV, MVT::f32, Promote);
+ setOperationAction(ISD::FSQRT, MVT::f32, Promote);
+ }
+
+ if (Subtarget->replaceFMULS()) {
+ // Promote FMULS to FMULD instructions instead as
+ // the former instructions generate errata on LEON processors.
+ setOperationAction(ISD::FMUL, MVT::f32, Promote);
+ }
+
setOperationAction(ISD::INTRINSIC_WO_CHAIN, MVT::Other, Custom);
setMinFunctionAlignment(2);
diff --git a/llvm/lib/Target/Sparc/SparcInstrInfo.td b/llvm/lib/Target/Sparc/SparcInstrInfo.td
index 3f64ef0bac8..cc55c9c8e03 100644
--- a/llvm/lib/Target/Sparc/SparcInstrInfo.td
+++ b/llvm/lib/Target/Sparc/SparcInstrInfo.td
@@ -57,6 +57,10 @@ def HasLeonCASA : Predicate<"Subtarget->hasLeonCasa()">;
// UMAC and SMAC instructions
def HasUMAC_SMAC : Predicate<"Subtarget->hasUmacSmac()">;
+def HasNoFdivSqrtFix : Predicate<"!Subtarget->fixAllFDIVSQRT()">;
+def HasNoFmulsFix : Predicate<"!Subtarget->replaceFMULS()">;
+def HasNoFsmuldFix : Predicate<"!Subtarget->fixFSMULD()">;
+
// UseDeprecatedInsts - This predicate is true when the target processor is a
// V8, or when it is V9 but the V8 deprecated instructions are efficient enough
// to use when appropriate. In either of these cases, the instruction selector
@@ -1172,6 +1176,9 @@ def FABSS : F3_3u<2, 0b110100, 0b000001001,
// Floating-point Square Root Instructions, p.145
+// FSQRTS generates an erratum on LEON processors, so by disabling this instruction
+// this will be promoted to use FSQRTD with doubles instead.
+let Predicates = [HasNoFdivSqrtFix] in
def FSQRTS : F3_3u<2, 0b110100, 0b000101001,
(outs FPRegs:$rd), (ins FPRegs:$rs2),
"fsqrts $rs2, $rd",
@@ -1225,6 +1232,9 @@ def FSUBQ : F3_3<2, 0b110100, 0b001000111,
// Floating-point Multiply and Divide Instructions, p. 147
+// FMULS generates an erratum on LEON processors, so by disabling this instruction
+// this will be promoted to use FMULD with doubles instead.
+let Predicates = [HasNoFmulsFix] in
def FMULS : F3_3<2, 0b110100, 0b001001001,
(outs FPRegs:$rd), (ins FPRegs:$rs1, FPRegs:$rs2),
"fmuls $rs1, $rs2, $rd",
@@ -1241,6 +1251,7 @@ def FMULQ : F3_3<2, 0b110100, 0b001001011,
[(set f128:$rd, (fmul f128:$rs1, f128:$rs2))]>,
Requires<[HasHardQuad]>;
+let Predicates = [HasNoFsmuldFix] in
def FSMULD : F3_3<2, 0b110100, 0b001101001,
(outs DFPRegs:$rd), (ins FPRegs:$rs1, FPRegs:$rs2),
"fsmuld $rs1, $rs2, $rd",
@@ -1254,6 +1265,8 @@ def FDMULQ : F3_3<2, 0b110100, 0b001101110,
(fextend f64:$rs2)))]>,
Requires<[HasHardQuad]>;
+// FDIVS generates an erratum on LEON processors, so by disabling this instruction
+// this will be promoted to use FDIVD with doubles instead.
def FDIVS : F3_3<2, 0b110100, 0b001001101,
(outs FPRegs:$rd), (ins FPRegs:$rs1, FPRegs:$rs2),
"fdivs $rs1, $rs2, $rd",
diff --git a/llvm/lib/Target/Sparc/SparcSubtarget.cpp b/llvm/lib/Target/Sparc/SparcSubtarget.cpp
index 3dd8a84ba47..97d4aef3378 100644
--- a/llvm/lib/Target/Sparc/SparcSubtarget.cpp
+++ b/llvm/lib/Target/Sparc/SparcSubtarget.cpp
@@ -40,6 +40,9 @@ SparcSubtarget &SparcSubtarget::initializeSubtargetDependencies(StringRef CPU,
HasLeonCasa = false;
HasUmacSmac = false;
InsertNOPLoad = false;
+ FixFSMULD = false;
+ ReplaceFMULS = false;
+ FixAllFDIVSQRT = false;
// Determine default and user specified characteristics
std::string CPUName = CPU;
diff --git a/llvm/lib/Target/Sparc/SparcSubtarget.h b/llvm/lib/Target/Sparc/SparcSubtarget.h
index a69c2efd913..9122f54f7c8 100644
--- a/llvm/lib/Target/Sparc/SparcSubtarget.h
+++ b/llvm/lib/Target/Sparc/SparcSubtarget.h
@@ -45,6 +45,9 @@ class SparcSubtarget : public SparcGenSubtargetInfo {
bool HasUmacSmac;
bool HasLeonCasa;
bool InsertNOPLoad;
+ bool FixFSMULD;
+ bool ReplaceFMULS;
+ bool FixAllFDIVSQRT;
SparcInstrInfo InstrInfo;
SparcTargetLowering TLInfo;
@@ -85,6 +88,9 @@ public:
bool hasUmacSmac() const { return HasUmacSmac; }
bool hasLeonCasa() const { return HasLeonCasa; }
bool insertNOPLoad() const { return InsertNOPLoad; }
+ bool fixFSMULD() const { return FixFSMULD; }
+ bool replaceFMULS() const { return ReplaceFMULS; }
+ bool fixAllFDIVSQRT() const { return FixAllFDIVSQRT; }
/// ParseSubtargetFeatures - Parses features string setting specified
/// subtarget options. Definition of function is auto generated by tblgen.
diff --git a/llvm/lib/Target/Sparc/SparcTargetMachine.cpp b/llvm/lib/Target/Sparc/SparcTargetMachine.cpp
index cc2be3a9ef0..d8a047a72ba 100644
--- a/llvm/lib/Target/Sparc/SparcTargetMachine.cpp
+++ b/llvm/lib/Target/Sparc/SparcTargetMachine.cpp
@@ -149,6 +149,18 @@ void SparcPassConfig::addPreEmitPass(){
{
addPass(new InsertNOPLoad(getSparcTargetMachine()));
}
+ if (this->getSparcTargetMachine().getSubtargetImpl()->fixFSMULD())
+ {
+ addPass(new FixFSMULD(getSparcTargetMachine()));
+ }
+ if (this->getSparcTargetMachine().getSubtargetImpl()->replaceFMULS())
+ {
+ addPass(new ReplaceFMULS(getSparcTargetMachine()));
+ }
+ if (this->getSparcTargetMachine().getSubtargetImpl()->fixAllFDIVSQRT())
+ {
+ addPass(new FixAllFDIVSQRT(getSparcTargetMachine()));
+ }
}
void SparcV8TargetMachine::anchor() { }
OpenPOWER on IntegriCloud