Revert "[Sparc] Leon errata fix passes."

...and the two followup commits:
Revert "[Sparc][Leon] Missed resetting option flags from check-in 278489."
Revert "[Sparc][Leon] Errata fixes for various errata in different
versions of the Leon variants of the Sparc 32 bit processor."

This reverts commit r274856, r278489, and r278492.

llvm-svn: 278511
This commit is contained in:
James Y Knight 2016-08-12 14:48:09 +00:00
parent 69629c2314
commit 0e7885981e
16 changed files with 287 additions and 1095 deletions

View File

@ -10,85 +10,57 @@
// //
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
//===----------------------------------------------------------------------===//
// CASA Support differs between LEON3-FT GR712RC and LEON3-FT UT699
// We need to have the option to switch this on and off.
//===----------------------------------------------------------------------===//
// support to casa instruction; for leon3 subtarget only
def LeonCASA : SubtargetFeature<
"hasleoncasa", "HasLeonCasa", "true",
"Enable CASA instruction for LEON3 and LEON4 processors">;
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// UMAC and SMAC support for LEON3 and LEON4 processors. // UMAC and SMAC support for LEON3 and LEON4 processors.
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// support to casa instruction; for leon3 subtarget only //support to casa instruction; for leon3 subtarget only
def UMACSMACSupport def UMACSMACSupport : SubtargetFeature<
: SubtargetFeature<"hasumacsmac", "HasUmacSmac", "true", "hasumacsmac",
"Enable UMAC and SMAC for LEON3 and LEON4 processors">; "HasUmacSmac",
"true",
"Enable UMAC and SMAC for LEON3 and LEON4 processors"
>;
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// LEON Erratum fixes // CASA Support differs between LEON3-FT GR712RC and LEON3-FT UT699
// We need to have the option to switch this on and off.
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
def ReplaceSDIV //support to casa instruction; for leon3 subtarget only
: SubtargetFeature< def LeonCASA : SubtargetFeature<
"replacesdiv", "PerformSDIVReplace", "true", "hasleoncasa",
"AT697E erratum fix: Do not emit SDIV, emit SDIVCC instead">; "HasLeonCasa",
"true",
"Enable CASA instruction for LEON3 and LEON4 processors"
>;
def FixCALL def InsertNOPLoad: SubtargetFeature<
: SubtargetFeature<"fixcall", "FixCallImmediates", "true", "insertnopload",
"AT697E erratum fix: Restrict the size of the immediate " "InsertNOPLoad",
"operand of the CALL instruction to 20 bits">; "true",
"LEON3 erratum fix: Insert a NOP instruction after every single-cycle load instruction when the next instruction is another load/store instruction"
>;
def IgnoreZeroFlag def FixFSMULD : SubtargetFeature<
: SubtargetFeature<"ignrzeroflag", "IgnoreZeroFlag", "true", "fixfsmuld",
"AT697E erratum fix: Do not rely on the zero bit flag " "FixFSMULD",
"on a divide overflow for SDIVCC and UDIVCC">; "true",
"LEON erratum fix: Do not use FSMULD"
>;
def InsertNOPDoublePrecision def ReplaceFMULS : SubtargetFeature<
: SubtargetFeature<"insrtnopdblprcsn", "InsertNOPDoublePrecision", "true", "replacefmuls",
"LEON2 erratum fix: Insert a NOP before the double " "ReplaceFMULS",
"precision floating point instruction">; "true",
"LEON erratum fix: Replace FMULS instruction with FMULD and relevant conversion instructions"
>;
def FixFSMULD : SubtargetFeature<"fixfsmuld", "FixFSMULD", "true", def FixAllFDIVSQRT : SubtargetFeature<
"LEON3 erratum fix: Do not select FSMULD">; "fixallfdivsqrt",
"FixAllFDIVSQRT",
def ReplaceFMULS "true",
: SubtargetFeature<"replacefmuls", "ReplaceFMULS", "true", "LEON erratum fix: Fix FDIVS/FDIVD/FSQRTS/FSQRTD instructions with NOPs and floating-point store"
"LEON3 erratum fix: Replace FMULS instruction with a " >;
"routine using conversions/double precision operations "
"to replace FMULS">;
def PreventRoundChange
: SubtargetFeature<"prvntroundchange", "PreventRoundChange", "true",
"LEON3 erratum fix: Prevent any rounding mode change "
"request: use only the round-to-nearest rounding mode">;
def FixAllFDIVSQRT
: SubtargetFeature<"fixallfdivsqrt", "FixAllFDIVSQRT", "true",
"LEON3 erratum fix: Fix FDIVS/FDIVD/FSQRTS/FSQRTD "
"instructions with NOPs and floating-point store">;
def InsertNOPLoad
: SubtargetFeature<"insertnopload", "InsertNOPLoad", "true",
"LEON3 erratum fix: Insert a NOP instruction after "
"every single-cycle load instruction when the next "
"instruction is another load/store instruction">;
def InsertNOPsLoadStore
: SubtargetFeature<"insertnopsloadstore", "InsertNOPsLoadStore", "true",
"LEON3 erratum fix: Insert NOPs between "
"single-precision loads and the store, so the number of "
"instructions between is 4">;
def FillDataCache : SubtargetFeature<"filldatacache", "FillDataCache", "true",
"LEON2 erratum fix: Ensure data cache is "
"filled so that cache misses do not "
"happen later in program execution.">;
def RestoreExecAddress
: SubtargetFeature<"restexecaddr", "RestoreExecAddress", "true",
"LEON2 erratum fix: Restore execution address.">;

View File

@ -16,7 +16,6 @@
#include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineInstr.h"
#include "llvm/CodeGen/MachineInstrBuilder.h" #include "llvm/CodeGen/MachineInstrBuilder.h"
#include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/MachineRegisterInfo.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/LLVMContext.h" #include "llvm/IR/LLVMContext.h"
#include "llvm/Support/raw_ostream.h" #include "llvm/Support/raw_ostream.h"
using namespace llvm; using namespace llvm;
@ -90,6 +89,15 @@ bool InsertNOPLoad::runOnMachineFunction(MachineFunction &MF) {
MachineBasicBlock::iterator NMBBI = std::next(MBBI); MachineBasicBlock::iterator NMBBI = std::next(MBBI);
BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP)); BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
Modified = true; 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;
}
} }
} }
} }
@ -139,6 +147,32 @@ bool FixFSMULD::runOnMachineFunction(MachineFunction &MF) {
Reg1Index = MI.getOperand(0).getReg(); Reg1Index = MI.getOperand(0).getReg();
Reg2Index = MI.getOperand(1).getReg(); Reg2Index = MI.getOperand(1).getReg();
Reg3Index = MI.getOperand(2).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
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 && if (Reg1Index != UNASSIGNED_INDEX && Reg2Index != UNASSIGNED_INDEX &&
@ -228,6 +262,31 @@ bool ReplaceFMULS::runOnMachineFunction(MachineFunction &MF) {
Reg1Index = MI.getOperand(0).getReg(); Reg1Index = MI.getOperand(0).getReg();
Reg2Index = MI.getOperand(1).getReg(); Reg2Index = MI.getOperand(1).getReg();
Reg3Index = MI.getOperand(2).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
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 && if (Reg1Index != UNASSIGNED_INDEX && Reg2Index != UNASSIGNED_INDEX &&
@ -309,17 +368,31 @@ bool FixAllFDIVSQRT::runOnMachineFunction(MachineFunction &MF) {
MachineInstr &MI = *MBBI; MachineInstr &MI = *MBBI;
unsigned Opcode = MI.getOpcode(); 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
Opcode = SP::FSQRTD;
} else if (AsmString.find(FDIVDOpCode) ==
0) { // this is an inline fsqrts instruction
Opcode = SP::FDIVD;
}
}
// Note: FDIVS and FSQRTS cannot be generated when this erratum fix is // 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 // 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 // already have been converted to FSQRTD or FDIVD earlier in the
// pipeline. // pipeline.
if (Opcode == SP::FSQRTD || Opcode == SP::FDIVD) { if (Opcode == SP::FSQRTD || Opcode == SP::FDIVD) {
// Insert 5 NOPs before FSQRTD,FDIVD.
for (int InsertedCount = 0; InsertedCount < 5; InsertedCount++) for (int InsertedCount = 0; InsertedCount < 5; InsertedCount++)
BuildMI(MBB, MBBI, DL, TII.get(SP::NOP)); BuildMI(MBB, MBBI, DL, TII.get(SP::NOP));
MachineBasicBlock::iterator NMBBI = std::next(MBBI); MachineBasicBlock::iterator NMBBI = std::next(MBBI);
// ... and inserting 28 NOPs after FSQRTD,FDIVD.
for (int InsertedCount = 0; InsertedCount < 28; InsertedCount++) for (int InsertedCount = 0; InsertedCount < 28; InsertedCount++)
BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP)); BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP));
@ -330,604 +403,3 @@ bool FixAllFDIVSQRT::runOnMachineFunction(MachineFunction &MF) {
return Modified; 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;
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;
}
}
}
}
}
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;
}
}
}
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();
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);
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;
}
//*****************************************************************************
//**** 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;
}
//****************************************************************************************************************
//**** 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;
}

View File

@ -44,83 +44,17 @@ protected:
int getUnusedFPRegister(MachineRegisterInfo &MRI); int getUnusedFPRegister(MachineRegisterInfo &MRI);
}; };
class LLVM_LIBRARY_VISIBILITY ReplaceSDIV : public LEONMachineFunctionPass { class LLVM_LIBRARY_VISIBILITY InsertNOPLoad : public LEONMachineFunctionPass {
public: public:
static char ID; static char ID;
ReplaceSDIV(); InsertNOPLoad(TargetMachine &tm);
ReplaceSDIV(TargetMachine &tm);
bool runOnMachineFunction(MachineFunction &MF) override; bool runOnMachineFunction(MachineFunction &MF) override;
const char *getPassName() const override { const char *getPassName() const override {
return "ReplaceSDIV: Leon erratum fix: do not emit SDIV, but emit SDIVCC " return "InsertNOPLoad: Erratum Fix LBR35: insert a NOP instruction after "
"instead"; "every single-cycle load instruction when the next instruction is "
} "another load/store instruction";
};
class LLVM_LIBRARY_VISIBILITY FixCALL : public LEONMachineFunctionPass {
public:
static char ID;
FixCALL(TargetMachine &tm);
bool runOnMachineFunction(MachineFunction &MF) override;
const char *getPassName() const override {
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;
IgnoreZeroFlag(TargetMachine &tm);
bool runOnMachineFunction(MachineFunction &MF) override;
const char *getPassName() const override {
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:
static char ID;
InsertNOPDoublePrecision(TargetMachine &tm);
bool runOnMachineFunction(MachineFunction &MF) override;
const char *getPassName() const override {
return "InsertNOPDoublePrecision: Leon erratum fix: insert a NOP before "
"the double precision floating point instruction";
} }
}; };
@ -132,7 +66,7 @@ public:
bool runOnMachineFunction(MachineFunction &MF) override; bool runOnMachineFunction(MachineFunction &MF) override;
const char *getPassName() const override { const char *getPassName() const override {
return "FixFSMULD: Leon erratum fix: do not utilize FSMULD"; return "FixFSMULD: Erratum Fix LBR31: do not select FSMULD";
} }
}; };
@ -144,26 +78,12 @@ public:
bool runOnMachineFunction(MachineFunction &MF) override; bool runOnMachineFunction(MachineFunction &MF) override;
const char *getPassName() const override { const char *getPassName() const override {
return "ReplaceFMULS: Leon erratum fix: Replace FMULS instruction with a " return "ReplaceFMULS: Erratum Fix LBR32: replace FMULS instruction with a "
"routine using conversions/double precision operations to replace " "routine using conversions/double precision operations to replace "
"FMULS"; "FMULS";
} }
}; };
class LLVM_LIBRARY_VISIBILITY PreventRoundChange
: public LEONMachineFunctionPass {
public:
static char ID;
PreventRoundChange(TargetMachine &tm);
bool runOnMachineFunction(MachineFunction &MF) override;
const char *getPassName() const override {
return "PreventRoundChange: Leon erratum fix: prevent any rounding mode "
"change request: use only the round-to-nearest rounding mode";
}
};
class LLVM_LIBRARY_VISIBILITY FixAllFDIVSQRT : public LEONMachineFunctionPass { class LLVM_LIBRARY_VISIBILITY FixAllFDIVSQRT : public LEONMachineFunctionPass {
public: public:
static char ID; static char ID;
@ -172,39 +92,10 @@ public:
bool runOnMachineFunction(MachineFunction &MF) override; bool runOnMachineFunction(MachineFunction &MF) override;
const char *getPassName() const override { const char *getPassName() const override {
return "FixAllFDIVSQRT: Leon erratum fix: Fix FDIVS/FDIVD/FSQRTS/FSQRTD " return "FixAllFDIVSQRT: Erratum Fix LBR34: fix FDIVS/FDIVD/FSQRTS/FSQRTD "
"instructions with NOPs and floating-point store"; "instructions with NOPs and floating-point store";
} }
}; };
} // namespace llvm
class LLVM_LIBRARY_VISIBILITY InsertNOPLoad : public LEONMachineFunctionPass {
public:
static char ID;
InsertNOPLoad(TargetMachine &tm);
bool runOnMachineFunction(MachineFunction &MF) override;
const char *getPassName() const override {
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 InsertNOPsLoadStore
: public LEONMachineFunctionPass {
public:
static char ID;
InsertNOPsLoadStore(TargetMachine &tm);
bool runOnMachineFunction(MachineFunction &MF) override;
const char *getPassName() const override {
return "InsertNOPsLoadStore: Leon Erratum Fix: Insert NOPs between "
"single-precision loads and the store, so the number of "
"instructions between is 4";
}
};
} // namespace lllvm
#endif // LLVM_LIB_TARGET_SPARC_LEON_PASSES_H #endif // LLVM_LIB_TARGET_SPARC_LEON_PASSES_H

View File

@ -21,34 +21,35 @@ include "llvm/Target/Target.td"
// //
def FeatureV9 def FeatureV9
: SubtargetFeature<"v9", "IsV9", "true", "Enable SPARC-V9 instructions">; : SubtargetFeature<"v9", "IsV9", "true",
"Enable SPARC-V9 instructions">;
def FeatureV8Deprecated def FeatureV8Deprecated
: SubtargetFeature<"deprecated-v8", "V8DeprecatedInsts", "true", : SubtargetFeature<"deprecated-v8", "V8DeprecatedInsts", "true",
"Enable deprecated V8 instructions in V9 mode">; "Enable deprecated V8 instructions in V9 mode">;
def FeatureVIS def FeatureVIS
: SubtargetFeature<"vis", "IsVIS", "true", : SubtargetFeature<"vis", "IsVIS", "true",
"Enable UltraSPARC Visual Instruction Set extensions">; "Enable UltraSPARC Visual Instruction Set extensions">;
def FeatureVIS2 def FeatureVIS2
: SubtargetFeature<"vis2", "IsVIS2", "true", : SubtargetFeature<"vis2", "IsVIS2", "true",
"Enable Visual Instruction Set extensions II">; "Enable Visual Instruction Set extensions II">;
def FeatureVIS3 def FeatureVIS3
: SubtargetFeature<"vis3", "IsVIS3", "true", : SubtargetFeature<"vis3", "IsVIS3", "true",
"Enable Visual Instruction Set extensions III">; "Enable Visual Instruction Set extensions III">;
def FeatureLeon def FeatureLeon
: SubtargetFeature<"leon", "IsLeon", "true", "Enable LEON extensions">; : SubtargetFeature<"leon", "IsLeon", "true",
"Enable LEON extensions">;
def FeatureHardQuad def FeatureHardQuad
: SubtargetFeature<"hard-quad-float", "HasHardQuad", "true", : SubtargetFeature<"hard-quad-float", "HasHardQuad", "true",
"Enable quad-word floating point instructions">; "Enable quad-word floating point instructions">;
def UsePopc : SubtargetFeature<"popc", "UsePopc", "true", def UsePopc : SubtargetFeature<"popc", "UsePopc", "true",
"Use the popc (population count) instruction">; "Use the popc (population count) instruction">;
def FeatureSoftFloat def FeatureSoftFloat : SubtargetFeature<"soft-float", "UseSoftFloat", "true",
: SubtargetFeature<"soft-float", "UseSoftFloat", "true", "Use software emulation for floating point">;
"Use software emulation for floating point">;
//==== Features added predmoninantly for LEON subtarget support //==== Features added predmoninantly for LEON subtarget support
include "LeonFeatures.td" include "LeonFeatures.td"
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -62,93 +63,87 @@ include "SparcInstrInfo.td"
def SparcInstrInfo : InstrInfo; def SparcInstrInfo : InstrInfo;
def SparcAsmParser : AsmParser { bit ShouldEmitMatchRegisterName = 0; } def SparcAsmParser : AsmParser {
bit ShouldEmitMatchRegisterName = 0;
}
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// SPARC processors supported. // SPARC processors supported.
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
class Proc<string Name, list<SubtargetFeature> Features> class Proc<string Name, list<SubtargetFeature> Features>
: Processor<Name, NoItineraries, Features>; : Processor<Name, NoItineraries, Features>;
def : Proc<"generic", []>; def : Proc<"generic", []>;
def : Proc<"v7", []>; def : Proc<"v7", []>;
def : Proc<"v8", []>; def : Proc<"v8", []>;
def : Proc<"supersparc", []>; def : Proc<"supersparc", []>;
def : Proc<"sparclite", []>; def : Proc<"sparclite", []>;
def : Proc<"f934", []>; def : Proc<"f934", []>;
def : Proc<"hypersparc", []>; def : Proc<"hypersparc", []>;
def : Proc<"sparclite86x", []>; def : Proc<"sparclite86x", []>;
def : Proc<"sparclet", []>; def : Proc<"sparclet", []>;
def : Proc<"tsc701", []>; def : Proc<"tsc701", []>;
def : Proc<"myriad2", []>; def : Proc<"myriad2", []>;
def : Proc<"myriad2.1", []>; def : Proc<"myriad2.1", []>;
def : Proc<"myriad2.2", []>; def : Proc<"myriad2.2", []>;
def : Proc<"v9", [ FeatureV9 ]>; def : Proc<"v9", [FeatureV9]>;
def : Proc<"ultrasparc", [ FeatureV9, FeatureV8Deprecated, FeatureVIS ]>; def : Proc<"ultrasparc", [FeatureV9, FeatureV8Deprecated, FeatureVIS]>;
def : Proc<"ultrasparc3", def : Proc<"ultrasparc3", [FeatureV9, FeatureV8Deprecated, FeatureVIS,
[ FeatureV9, FeatureV8Deprecated, FeatureVIS, FeatureVIS2 ]>; FeatureVIS2]>;
def : Proc<"niagara", def : Proc<"niagara", [FeatureV9, FeatureV8Deprecated, FeatureVIS,
[ FeatureV9, FeatureV8Deprecated, FeatureVIS, FeatureVIS2 ]>; FeatureVIS2]>;
def : Proc<"niagara2", [ def : Proc<"niagara2", [FeatureV9, FeatureV8Deprecated, UsePopc,
FeatureV9, FeatureV8Deprecated, UsePopc, FeatureVIS, FeatureVIS2 FeatureVIS, FeatureVIS2]>;
]>; def : Proc<"niagara3", [FeatureV9, FeatureV8Deprecated, UsePopc,
def : Proc<"niagara3", [ FeatureVIS, FeatureVIS2]>;
FeatureV9, FeatureV8Deprecated, UsePopc, FeatureVIS, FeatureVIS2 def : Proc<"niagara4", [FeatureV9, FeatureV8Deprecated, UsePopc,
]>; FeatureVIS, FeatureVIS2, FeatureVIS3]>;
def : Proc<"niagara4", [
FeatureV9, FeatureV8Deprecated, UsePopc, FeatureVIS, FeatureVIS2, FeatureVIS3
]>;
// LEON 2 FT generic // LEON 2 FT generic
def : Processor<"leon2", LEON2Itineraries, [ FeatureLeon ]>; def : Processor<"leon2", LEON2Itineraries,
[FeatureLeon]>;
// LEON 2 FT (AT697E) // LEON 2 FT (AT697E)
// AT697E: Provides full coverage of AT697E - covers all the erratum fixes for // TO DO: Place-holder: Processor specific features will be added *very* soon here.
// LEON2 AT697E def : Processor<"at697e", LEON2Itineraries,
def : Processor<"at697e", LEON2Itineraries, [ [FeatureLeon, InsertNOPLoad]>;
FeatureLeon, ReplaceSDIV, FixCALL, IgnoreZeroFlag, InsertNOPDoublePrecision,
FillDataCache, RestoreExecAddress
]>;
// LEON 2 FT (AT697F) // LEON 2 FT (AT697F)
// AT697F: Provides full coverage of AT697F - covers all the erratum fixes for // TO DO: Place-holder: Processor specific features will be added *very* soon here.
// LEON2 AT697F
def : Processor<"at697f", LEON2Itineraries, def : Processor<"at697f", LEON2Itineraries,
[ FeatureLeon, InsertNOPDoublePrecision ]>; [FeatureLeon, InsertNOPLoad]>;
// LEON 3 FT generic // LEON 3 FT generic
def : Processor<"leon3", LEON3Itineraries, [ FeatureLeon, UMACSMACSupport ]>; def : Processor<"leon3", LEON3Itineraries,
[FeatureLeon, UMACSMACSupport]>;
// LEON 3 FT (UT699). Provides features for the UT699 processor // LEON 3 FT (UT699). Provides features for the UT699 processor
// - covers all the erratum fixes for LEON3, but does not support the CASA // - covers all the erratum fixes for LEON3, but does not support the CASA instruction.
// instruction. def : Processor<"ut699", LEON3Itineraries,
def : Processor<"ut699", LEON3Itineraries, [ [FeatureLeon, InsertNOPLoad, FixFSMULD, ReplaceFMULS, FixAllFDIVSQRT]>;
FeatureLeon, FixFSMULD, ReplaceFMULS, PreventRoundChange,
FixAllFDIVSQRT, InsertNOPLoad, InsertNOPsLoadStore
]>;
// LEON3 FT (GR712RC). Provides features for the GR712RC processor. // LEON3 FT (GR712RC). Provides features for the GR712RC processor.
// - covers all the erratum fixed for LEON3 and support for the CASA // - covers all the erratum fixed for LEON3 and support for the CASA instruction.
// instruction.
def : Processor<"gr712rc", LEON3Itineraries, def : Processor<"gr712rc", LEON3Itineraries,
[ FeatureLeon, LeonCASA ]>; [FeatureLeon, LeonCASA]>;
// LEON 4 FT generic // LEON 4 FT generic
def : Processor<"leon4", LEON4Itineraries, def : Processor<"leon4", LEON4Itineraries,
[ FeatureLeon, LeonCASA ]>; [FeatureLeon, UMACSMACSupport, LeonCASA]>;
// GR740: Provides full coverage of GR740 - covers all the erratum fixes for // LEON 4 FT (GR740)
// LEON3 + support to CASA + LEON 4 instruction timings // TO DO: Place-holder: Processor specific features will be added *very* soon here.
def : Processor<"gr740", LEON4Itineraries, def : Processor<"gr740", LEON4Itineraries,
[ FeatureLeon, LeonCASA ]> {} [FeatureLeon, UMACSMACSupport, LeonCASA]>;
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Declare the target which we are implementing // Declare the target which we are implementing
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
def SparcAsmWriter : AsmWriter { def SparcAsmWriter : AsmWriter {
string AsmWriterClassName = "InstPrinter"; string AsmWriterClassName = "InstPrinter";
int PassSubtarget = 1; int PassSubtarget = 1;
int Variant = 0; int Variant = 0;
} }
@ -156,6 +151,6 @@ def SparcAsmWriter : AsmWriter {
def Sparc : Target { def Sparc : Target {
// Pull in Instruction Info: // Pull in Instruction Info:
let InstructionSet = SparcInstrInfo; let InstructionSet = SparcInstrInfo;
let AssemblyParsers = [ SparcAsmParser ]; let AssemblyParsers = [SparcAsmParser];
let AssemblyWriters = [ SparcAsmWriter ]; let AssemblyWriters = [SparcAsmWriter];
} }

View File

@ -32,6 +32,7 @@
#include "llvm/Support/ErrorHandling.h" #include "llvm/Support/ErrorHandling.h"
using namespace llvm; using namespace llvm;
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
// Calling Convention Implementation // Calling Convention Implementation
//===----------------------------------------------------------------------===// //===----------------------------------------------------------------------===//
@ -1616,7 +1617,9 @@ SparcTargetLowering::SparcTargetLowering(const TargetMachine &TM,
// Atomics are supported on SparcV9. 32-bit atomics are also // Atomics are supported on SparcV9. 32-bit atomics are also
// supported by some Leon SparcV8 variants. Otherwise, atomics // supported by some Leon SparcV8 variants. Otherwise, atomics
// are unsupported. // are unsupported.
if (Subtarget->isV9() || Subtarget->hasLeonCasa()) if (Subtarget->isV9())
setMaxAtomicSizeInBitsSupported(64);
else if (Subtarget->hasLeonCasa())
setMaxAtomicSizeInBitsSupported(64); setMaxAtomicSizeInBitsSupported(64);
else else
setMaxAtomicSizeInBitsSupported(0); setMaxAtomicSizeInBitsSupported(0);
@ -2628,6 +2631,7 @@ static SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG,
uint64_t depth = Op.getConstantOperandVal(0); uint64_t depth = Op.getConstantOperandVal(0);
return getFRAMEADDR(depth, Op, DAG, Subtarget); return getFRAMEADDR(depth, Op, DAG, Subtarget);
} }
static SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG, static SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG,
@ -3042,7 +3046,7 @@ MachineBasicBlock *
SparcTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, SparcTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
MachineBasicBlock *BB) const { MachineBasicBlock *BB) const {
switch (MI.getOpcode()) { switch (MI.getOpcode()) {
default: llvm_unreachable("Unknown Custom Instruction!"); default: llvm_unreachable("Unknown SELECT_CC!");
case SP::SELECT_CC_Int_ICC: case SP::SELECT_CC_Int_ICC:
case SP::SELECT_CC_FP_ICC: case SP::SELECT_CC_FP_ICC:
case SP::SELECT_CC_DFP_ICC: case SP::SELECT_CC_DFP_ICC:
@ -3059,6 +3063,7 @@ SparcTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI,
case SP::EH_SJLJ_LONGJMP32rr: case SP::EH_SJLJ_LONGJMP32rr:
case SP::EH_SJLJ_LONGJMP32ri: case SP::EH_SJLJ_LONGJMP32ri:
return emitEHSjLjLongJmp(MI, BB); return emitEHSjLjLongJmp(MI, BB);
} }
} }
@ -3329,11 +3334,8 @@ SparcTargetLowering::ConstraintType
SparcTargetLowering::getConstraintType(StringRef Constraint) const { SparcTargetLowering::getConstraintType(StringRef Constraint) const {
if (Constraint.size() == 1) { if (Constraint.size() == 1) {
switch (Constraint[0]) { switch (Constraint[0]) {
default: default: break;
break; case 'r': return C_RegisterClass;
case 'f':
case 'r':
return C_RegisterClass;
case 'I': // SIMM13 case 'I': // SIMM13
return C_Other; return C_Other;
} }
@ -3407,9 +3409,6 @@ SparcTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
MVT VT) const { MVT VT) const {
if (Constraint.size() == 1) { if (Constraint.size() == 1) {
switch (Constraint[0]) { switch (Constraint[0]) {
case 'f':
return std::make_pair(0U, &SP::FPRegsRegClass);
case 'r': case 'r':
if (VT == MVT::v2i32) if (VT == MVT::v2i32)
return std::make_pair(0U, &SP::IntPairRegClass); return std::make_pair(0U, &SP::IntPairRegClass);

View File

@ -39,19 +39,10 @@ SparcSubtarget &SparcSubtarget::initializeSubtargetDependencies(StringRef CPU,
// Leon features // Leon features
HasLeonCasa = false; HasLeonCasa = false;
HasUmacSmac = false; HasUmacSmac = false;
PerformSDIVReplace = false; InsertNOPLoad = false;
FixCallImmediates = false;
IgnoreZeroFlag = false;
InsertNOPDoublePrecision = false;
FixFSMULD = false; FixFSMULD = false;
ReplaceFMULS = false; ReplaceFMULS = false;
PreventRoundChange = false;
FixAllFDIVSQRT = false; FixAllFDIVSQRT = false;
InsertNOPLoad = false;
InsertNOPsLoadStore = false;
FillDataCache = false;
RestoreExecAddress = false;
// Determine default and user specified characteristics // Determine default and user specified characteristics
std::string CPUName = CPU; std::string CPUName = CPU;

View File

@ -48,15 +48,6 @@ class SparcSubtarget : public SparcGenSubtargetInfo {
bool FixFSMULD; bool FixFSMULD;
bool ReplaceFMULS; bool ReplaceFMULS;
bool FixAllFDIVSQRT; bool FixAllFDIVSQRT;
bool UseSoftFpu;
bool PerformSDIVReplace;
bool FixCallImmediates;
bool IgnoreZeroFlag;
bool InsertNOPDoublePrecision;
bool PreventRoundChange;
bool InsertNOPsLoadStore;
bool FillDataCache;
bool RestoreExecAddress;
SparcInstrInfo InstrInfo; SparcInstrInfo InstrInfo;
SparcTargetLowering TLInfo; SparcTargetLowering TLInfo;
@ -94,21 +85,12 @@ public:
bool useSoftFloat() const { return UseSoftFloat; } bool useSoftFloat() const { return UseSoftFloat; }
// Leon options // Leon options
bool useSoftFpu() const { return UseSoftFpu; }
bool hasLeonCasa() const { return HasLeonCasa; }
bool hasUmacSmac() const { return HasUmacSmac; } bool hasUmacSmac() const { return HasUmacSmac; }
bool performSDIVReplace() const { return PerformSDIVReplace; } bool hasLeonCasa() const { return HasLeonCasa; }
bool fixCallImmediates() const { return FixCallImmediates; } bool insertNOPLoad() const { return InsertNOPLoad; }
bool ignoreZeroFlag() const { return IgnoreZeroFlag; }
bool insertNOPDoublePrecision() const { return InsertNOPDoublePrecision; }
bool fixFSMULD() const { return FixFSMULD; } bool fixFSMULD() const { return FixFSMULD; }
bool replaceFMULS() const { return ReplaceFMULS; } bool replaceFMULS() const { return ReplaceFMULS; }
bool preventRoundChange() const { return PreventRoundChange; }
bool fixAllFDIVSQRT() const { return FixAllFDIVSQRT; } bool fixAllFDIVSQRT() const { return FixAllFDIVSQRT; }
bool insertNOPsLoadStore() const { return InsertNOPsLoadStore; }
bool insertNOPLoad() const { return InsertNOPLoad; }
bool fillDataCache() const { return FillDataCache; }
bool restoreExecAddr() const { return RestoreExecAddress; }
/// ParseSubtargetFeatures - Parses features string setting specified /// ParseSubtargetFeatures - Parses features string setting specified
/// subtarget options. Definition of function is auto generated by tblgen. /// subtarget options. Definition of function is auto generated by tblgen.

View File

@ -76,7 +76,7 @@ SparcTargetMachine::SparcTargetMachine(const Target &T, const Triple &TT,
SparcTargetMachine::~SparcTargetMachine() {} SparcTargetMachine::~SparcTargetMachine() {}
const SparcSubtarget * const SparcSubtarget *
SparcTargetMachine::getSubtargetImpl(const Function &F) const { SparcTargetMachine::getSubtargetImpl(const Function &F) const {
Attribute CPUAttr = F.getFnAttribute("target-cpu"); Attribute CPUAttr = F.getFnAttribute("target-cpu");
Attribute FSAttr = F.getFnAttribute("target-features"); Attribute FSAttr = F.getFnAttribute("target-features");
@ -95,7 +95,7 @@ SparcTargetMachine::getSubtargetImpl(const Function &F) const {
F.hasFnAttribute("use-soft-float") && F.hasFnAttribute("use-soft-float") &&
F.getFnAttribute("use-soft-float").getValueAsString() == "true"; F.getFnAttribute("use-soft-float").getValueAsString() == "true";
if (softFloat) if (softFloat)
FS += FS.empty() ? "+soft-float" : ",+soft-float"; FS += FS.empty() ? "+soft-float" : ",+soft-float";
auto &I = SubtargetMap[CPU + FS]; auto &I = SubtargetMap[CPU + FS];
@ -115,7 +115,7 @@ namespace {
class SparcPassConfig : public TargetPassConfig { class SparcPassConfig : public TargetPassConfig {
public: public:
SparcPassConfig(SparcTargetMachine *TM, PassManagerBase &PM) SparcPassConfig(SparcTargetMachine *TM, PassManagerBase &PM)
: TargetPassConfig(TM, PM) {} : TargetPassConfig(TM, PM) {}
SparcTargetMachine &getSparcTargetMachine() const { SparcTargetMachine &getSparcTargetMachine() const {
return getTM<SparcTargetMachine>(); return getTM<SparcTargetMachine>();
@ -142,49 +142,28 @@ bool SparcPassConfig::addInstSelector() {
return false; return false;
} }
void SparcPassConfig::addPreEmitPass() { void SparcPassConfig::addPreEmitPass(){
addPass(createSparcDelaySlotFillerPass(getSparcTargetMachine())); addPass(createSparcDelaySlotFillerPass(getSparcTargetMachine()));
if (this->getSparcTargetMachine().getSubtargetImpl()->ignoreZeroFlag()) {
addPass(new IgnoreZeroFlag(getSparcTargetMachine())); if (this->getSparcTargetMachine().getSubtargetImpl()->insertNOPLoad())
} {
if (this->getSparcTargetMachine().getSubtargetImpl()->performSDIVReplace()) {
addPass(new ReplaceSDIV(getSparcTargetMachine()));
}
if (this->getSparcTargetMachine().getSubtargetImpl()->fixCallImmediates()) {
addPass(new FixCALL(getSparcTargetMachine()));
}
if (this->getSparcTargetMachine().getSubtargetImpl()->fixFSMULD()) {
addPass(new FixFSMULD(getSparcTargetMachine()));
}
if (this->getSparcTargetMachine().getSubtargetImpl()->replaceFMULS()) {
addPass(new ReplaceFMULS(getSparcTargetMachine()));
}
if (this->getSparcTargetMachine().getSubtargetImpl()->preventRoundChange()) {
addPass(new PreventRoundChange(getSparcTargetMachine()));
}
if (this->getSparcTargetMachine().getSubtargetImpl()->fixAllFDIVSQRT()) {
addPass(new FixAllFDIVSQRT(getSparcTargetMachine()));
}
if (this->getSparcTargetMachine().getSubtargetImpl()->insertNOPsLoadStore()) {
addPass(new InsertNOPsLoadStore(getSparcTargetMachine()));
}
if (this->getSparcTargetMachine().getSubtargetImpl()->insertNOPLoad()) {
addPass(new InsertNOPLoad(getSparcTargetMachine())); addPass(new InsertNOPLoad(getSparcTargetMachine()));
} }
if (this->getSparcTargetMachine().getSubtargetImpl()->fillDataCache()) { if (this->getSparcTargetMachine().getSubtargetImpl()->fixFSMULD())
addPass(new FillDataCache(getSparcTargetMachine())); {
addPass(new FixFSMULD(getSparcTargetMachine()));
} }
if (this->getSparcTargetMachine().getSubtargetImpl()->restoreExecAddr()) { if (this->getSparcTargetMachine().getSubtargetImpl()->replaceFMULS())
addPass(new RestoreExecAddress(getSparcTargetMachine())); {
addPass(new ReplaceFMULS(getSparcTargetMachine()));
} }
if (this->getSparcTargetMachine() if (this->getSparcTargetMachine().getSubtargetImpl()->fixAllFDIVSQRT())
.getSubtargetImpl() {
->insertNOPDoublePrecision()) { addPass(new FixAllFDIVSQRT(getSparcTargetMachine()));
addPass(new InsertNOPDoublePrecision(getSparcTargetMachine()));
} }
} }
void SparcV8TargetMachine::anchor() {} void SparcV8TargetMachine::anchor() { }
SparcV8TargetMachine::SparcV8TargetMachine(const Target &T, const Triple &TT, SparcV8TargetMachine::SparcV8TargetMachine(const Target &T, const Triple &TT,
StringRef CPU, StringRef FS, StringRef CPU, StringRef FS,
@ -194,7 +173,7 @@ SparcV8TargetMachine::SparcV8TargetMachine(const Target &T, const Triple &TT,
CodeGenOpt::Level OL) CodeGenOpt::Level OL)
: SparcTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, false) {} : SparcTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, false) {}
void SparcV9TargetMachine::anchor() {} void SparcV9TargetMachine::anchor() { }
SparcV9TargetMachine::SparcV9TargetMachine(const Target &T, const Triple &TT, SparcV9TargetMachine::SparcV9TargetMachine(const Target &T, const Triple &TT,
StringRef CPU, StringRef FS, StringRef CPU, StringRef FS,

View File

@ -1,27 +0,0 @@
; RUN: llc %s -O0 -march=sparc -mcpu=leon2 -mattr=+filldatacache -o - | FileCheck %s
; RUN: llc %s -O0 -march=sparc -mcpu=at697e -o - | FileCheck %s
; RUN: llc %s -O0 -march=sparc -mcpu=at697f -mattr=+filldatacache -o - | FileCheck %s
; CHECK-LABEL: test_filldatacache_1
; CHECK: or %g0, 1, %g1
; CHECK: nop
; CHECK-NEXT: add %g1, 1, %g1
; CHECK-NEXT: cmp %g1, 4096
; CHECK-NEXT: ble {{.+}}
define zeroext i1@test_filldatacache_1(i1 zeroext %a, i1 zeroext %b) {
%1 = tail call zeroext i1 asm sideeffect "udivcc $0, $1, $2", "=r,r,r"(i1 zeroext %a, i1 zeroext %b)
ret i1 %1
}
; CHECK-LABEL: test_filldatacache_2
; CHECK-NOT: or %g0, 1, %g1
; CHECK-NOT: add %g1, 1, %g1
; CHECK-NOT: cmp %g1, 4096
; CHECK-NOT: ble {{.+}}
define zeroext i1@test_filldatacache_2(i1 zeroext %a, i1 zeroext %b) {
%1 = tail call zeroext i1 asm sideeffect "sdivcc $0, $1, $2", "=r,r,r"(i1 zeroext %a, i1 zeroext %b)
ret i1 %1
}

View File

@ -1,17 +1,31 @@
; RUN: llc %s -O0 -march=sparc -mattr=fixfsmuld -o - | FileCheck %s ; RUN: llc %s -O0 -march=sparc -mcpu=ut699 -o - | FileCheck %s
; RUN: llc %s -O0 -march=sparc -o - | FileCheck %s --check-prefix=NOFIX
; CHECK-LABEL: test_fix_fsmuld_1 ; CHECK-LABEL: test_fix_fsmuld_1
; CHECK: fstod %f1, %f2 ; CHECK: fstod %f20, %f2
; CHECK: fstod %f0, %f4 ; CHECK: fstod %f21, %f3
; CHECK: fmuld %f2, %f4, %f0 ; CHECK: fmuld %f2, %f3, %f8
; NOFIX-LABEL: test_fix_fsmuld_1 ; CHECK: fstod %f20, %f0
; NOFIX: fsmuld %f1, %f0, %f0 define double @test_fix_fsmuld_1() {
define double @test_fix_fsmuld_1(float %a, float %b) {
entry: entry:
%0 = fpext float %a to double %a = alloca float, align 4
%1 = fpext float %b to double %b = alloca float, align 4
%mul = fmul double %0, %1 store float 0x402ECCCCC0000000, float* %a, align 4
store float 0x4022333340000000, float* %b, align 4
%0 = load float, float* %b, align 4
%1 = load float, float* %a, align 4
%mul = tail call double asm sideeffect "fsmuld $0, $1, $2", "={f20},{f21},{f8}"(float* %a, float* %b)
ret double %mul
}
; CHECK-LABEL: test_fix_fsmuld_2
; CHECK: fstod %f20, %f2
; CHECK: fstod %f21, %f3
; CHECK: fmuld %f2, %f3, %f8
; CHECK: fstod %f20, %f0
define double @test_fix_fsmuld_2(float* %a, float* %b) {
entry:
%mul = tail call double asm sideeffect "fsmuld $0, $1, $2", "={f20},{f21},{f8}"(float* %a, float* %b)
ret double %mul ret double %mul
} }

View File

@ -1,13 +0,0 @@
; RUN: llc %s -O0 -march=sparc -mcpu=ut699 -o - | FileCheck %s
; CHECK: ld [%o0+%lo(.LCPI0_0)], %f0
; CHECK-NEXT: nop
define float @X() #0 {
entry:
%f = alloca float, align 4
store float 0x3FF3C08320000000, float* %f, align 4
%0 = load float, float* %f, align 4
ret float %0
}

View File

@ -19,3 +19,25 @@ define i32 @ld_i32_test(i32 *%p) {
%res = load i32, i32* %p %res = load i32, i32* %p
ret i32 %res ret i32 %res
} }
; CHECK-LABEL: ld_inlineasm_test_1
; CHECK: ld [%o0], %o0
; CHECK-NEXT: !NO_APP
; CHECK-NEXT: nop
define float @ld_inlineasm_test_1(float* %a) {
entry:
%res = tail call float asm sideeffect "ld [$1], $0", "=r,r"(float* %a)
ret float %res
}
; CHECK-LABEL: ld_inlineasm_test_2
; CHECK: ld [%o0], %o0
; CHECK-NEXT: !NO_APP
; CHECK-NEXT: nop
define i32 @ld_inlineasm_test_2(i32* %a) {
entry:
%res = tail call i32 asm sideeffect "ld [$1], $0", "=r,r"(i32* %a)
ret i32 %res
}

View File

@ -1,17 +0,0 @@
; RUN: llc %s -O0 -march=sparc -mcpu=at697f -o - | FileCheck %s
; CHECK: ldd
; CHECK: ldd
; CHECK-NEXT: nop
define double @mult() #0 {
entry:
%x = alloca double, align 8
%y = alloca double, align 8
store double 3.141590e+00, double* %x, align 8
store double 1.234560e+00, double* %y, align 8
%0 = load double, double* %x, align 8
%1 = load double, double* %y, align 8
%mul = fmul double %0, %1
ret double %mul
}

View File

@ -1,65 +0,0 @@
; RUN: llc %s -O0 -march=sparc -mcpu=ut699 -o - | FileCheck %s -check-prefix=NO_ROUND_FUNC
; RUN: llc %s -O0 -march=sparc -mcpu=leon3 -mattr=+prvntroundchange -o - | FileCheck %s -check-prefix=NO_ROUND_FUNC
; RUN: llc %s -O0 -march=sparc -mcpu=ut699 -mattr=-prvntroundchange -o - | FileCheck %s -check-prefix=ROUND_FUNC
; RUN: llc %s -O0 -march=sparc -mcpu=leon3 -o - | FileCheck %s -check-prefix=ROUND_FUNC
; NO_ROUND_FUNC-LABEL: test_round_change
; NO_ROUND_FUNC-NOT: fesetround
; ROUND_FUNC-LABEL: test_round_change
; ROUND_FUNC: fesetround
; ModuleID = '<stdin>'
target datalayout = "E-m:e-p:32:32-i64:64-f128:64-n32-S64"
target triple = "sparc-unknown--eabi"
@.str = private unnamed_addr constant [17 x i8] c"-((-a)*b) != a*b\00", align 1
@.str.1 = private unnamed_addr constant [7 x i8] c"test.c\00", align 1
@__PRETTY_FUNCTION__.mult = private unnamed_addr constant [12 x i8] c"void mult()\00", align 1
; Function Attrs: nounwind
define void @test_round_change() #0 {
entry:
%a = alloca double, align 8
%b = alloca double, align 8
%x = alloca float, align 4
store double 1.100000e+00, double* %a, align 8
store double 1.010000e+01, double* %b, align 8
store float 0x400921FA00000000, float* %x, align 4
%call = call i32 @fesetround(i32 2048) #2
%0 = load double, double* %a, align 8
%sub = fsub double -0.000000e+00, %0
%1 = load double, double* %b, align 8
%mul = fmul double %sub, %1
%sub1 = fsub double -0.000000e+00, %mul
%2 = load double, double* %a, align 8
%3 = load double, double* %b, align 8
%mul2 = fmul double %2, %3
%cmp = fcmp une double %sub1, %mul2
br i1 %cmp, label %cond.true, label %cond.false
cond.true: ; preds = %entry
br label %cond.end
cond.false: ; preds = %entry
call void @__assert_fail(i8* getelementptr inbounds ([17 x i8], [17 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.1, i32 0, i32 0), i32 10, i8* getelementptr inbounds ([12 x i8], [12 x i8]* @__PRETTY_FUNCTION__.mult, i32 0, i32 0)) #3
unreachable
; No predecessors!
br label %cond.end
cond.end: ; preds = %4, %cond.true
ret void
}
; Function Attrs: nounwind
declare i32 @fesetround(i32) #0
; Function Attrs: noreturn nounwind
declare void @__assert_fail(i8*, i8*, i32, i8*) #1
attributes #0 = { nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #1 = { noreturn nounwind "disable-tail-calls"="false" "less-precise-fpmad"="false" "no-frame-pointer-elim"="true" "no-frame-pointer-elim-non-leaf" "no-infs-fp-math"="false" "no-nans-fp-math"="false" "stack-protector-buffer-size"="8" "unsafe-fp-math"="false" "use-soft-float"="false" }
attributes #2 = { nounwind }
attributes #3 = { noreturn nounwind }

View File

@ -1,13 +1,19 @@
; RUN: llc %s -O0 -march=sparc -mattr=replacefmuls -o - | FileCheck %s ; RUN: llc %s -O0 -march=sparc -mcpu=ut699 -o - | FileCheck %s
; CHECK-LABEL: test_replace_fmuls ; CHECK-LABEL: fmuls_fix_test
; CHECK: fsmuld %f1, %f0, %f2 ; CHECK: fstod %f20, %f2
; CHECK: fdtos %f2, %f0 ; CHECK: fstod %f21, %f3
; NOFIX-LABEL: test_replace_fmuls ; CHECK: fmuld %f2, %f3, %f8
; NOFIX: fmuls %f1, %f0, %f0 ; CHECK: fstod %f20, %f0
define float @test_replace_fmuls(float %a, float %b) { define double @fmuls_fix_test() {
entry: entry:
%mul = fmul float %a, %b %a = alloca float, align 4
%b = alloca float, align 4
store float 0x402ECCCCC0000000, float* %a, align 4
store float 0x4022333340000000, float* %b, align 4
%0 = load float, float* %b, align 4
%1 = load float, float* %a, align 4
%mul = tail call double asm sideeffect "fmuls $0, $1, $2", "={f20},{f21},{f8}"(float* %a, float* %b)
ret float %mul ret double %mul
} }

View File

@ -1,9 +0,0 @@
; RUN: llc %s -O0 -march=sparc -mcpu=at697e -o - | FileCheck %s
; CHECK: sdivcc %o0, %o1, %o0
define i32 @lbr59(i32 %a, i32 %b)
{
%r = sdiv i32 %a, %b
ret i32 %r
}