diff options
Diffstat (limited to 'lib/Target/Sparc')
42 files changed, 3262 insertions, 996 deletions
diff --git a/lib/Target/Sparc/AsmParser/Makefile b/lib/Target/Sparc/AsmParser/Makefile deleted file mode 100644 index 46b3e45f2bed..000000000000 --- a/lib/Target/Sparc/AsmParser/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -##===- lib/Target/Sparc/AsmParser/Makefile ------------------*- Makefile-*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## -LEVEL = ../../../.. -LIBRARYNAME = LLVMSparcAsmParser - -# Hack: we need to include 'main' Sparc target directory to grab private headers -CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. - -include $(LEVEL)/Makefile.common diff --git a/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp b/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp index a55274744fd1..b2003b8f101b 100644 --- a/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp +++ b/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp @@ -7,18 +7,18 @@ // //===----------------------------------------------------------------------===// -#include "MCTargetDesc/SparcMCTargetDesc.h" #include "MCTargetDesc/SparcMCExpr.h" +#include "MCTargetDesc/SparcMCTargetDesc.h" #include "llvm/ADT/STLExtras.h" #include "llvm/MC/MCContext.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCObjectFileInfo.h" #include "llvm/MC/MCParser/MCParsedAsmOperand.h" +#include "llvm/MC/MCParser/MCTargetAsmParser.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCStreamer.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCSymbol.h" -#include "llvm/MC/MCTargetAsmParser.h" #include "llvm/Support/TargetRegistry.h" using namespace llvm; @@ -150,6 +150,22 @@ public: Sparc::L0_L1, Sparc::L2_L3, Sparc::L4_L5, Sparc::L6_L7, Sparc::I0_I1, Sparc::I2_I3, Sparc::I4_I5, Sparc::I6_I7}; + static const MCPhysReg CoprocRegs[32] = { + Sparc::C0, Sparc::C1, Sparc::C2, Sparc::C3, + Sparc::C4, Sparc::C5, Sparc::C6, Sparc::C7, + Sparc::C8, Sparc::C9, Sparc::C10, Sparc::C11, + Sparc::C12, Sparc::C13, Sparc::C14, Sparc::C15, + Sparc::C16, Sparc::C17, Sparc::C18, Sparc::C19, + Sparc::C20, Sparc::C21, Sparc::C22, Sparc::C23, + Sparc::C24, Sparc::C25, Sparc::C26, Sparc::C27, + Sparc::C28, Sparc::C29, Sparc::C30, Sparc::C31 }; + + static const MCPhysReg CoprocPairRegs[] = { + Sparc::C0_C1, Sparc::C2_C3, Sparc::C4_C5, Sparc::C6_C7, + Sparc::C8_C9, Sparc::C10_C11, Sparc::C12_C13, Sparc::C14_C15, + Sparc::C16_C17, Sparc::C18_C19, Sparc::C20_C21, Sparc::C22_C23, + Sparc::C24_C25, Sparc::C26_C27, Sparc::C28_C29, Sparc::C30_C31}; + /// SparcOperand - Instances of this class represent a parsed Sparc machine /// instruction. class SparcOperand : public MCParsedAsmOperand { @@ -161,6 +177,8 @@ public: rk_FloatReg, rk_DoubleReg, rk_QuadReg, + rk_CoprocReg, + rk_CoprocPairReg, rk_Special, }; @@ -224,6 +242,9 @@ public: || Reg.Kind == rk_DoubleReg)); } + bool isCoprocReg() const { + return (Kind == k_Register && Reg.Kind == rk_CoprocReg); + } StringRef getToken() const { assert(Kind == k_Token && "Invalid access!"); @@ -398,6 +419,19 @@ public: return true; } + static bool MorphToCoprocPairReg(SparcOperand &Op) { + unsigned Reg = Op.getReg(); + assert(Op.Reg.Kind == rk_CoprocReg); + unsigned regIdx = 32; + if (Reg >= Sparc::C0 && Reg <= Sparc::C31) + regIdx = Reg - Sparc::C0; + if (regIdx % 2 || regIdx > 31) + return false; + Op.Reg.RegNum = CoprocPairRegs[regIdx / 2]; + Op.Reg.Kind = rk_CoprocPairReg; + return true; + } + static std::unique_ptr<SparcOperand> MorphToMEMrr(unsigned Base, std::unique_ptr<SparcOperand> Op) { unsigned offsetReg = Op->getReg(); @@ -602,8 +636,12 @@ bool SparcAsmParser::ParseInstruction(ParseInstructionInfo &Info, return Error(Loc, "unexpected token"); } - while (getLexer().is(AsmToken::Comma)) { - Parser.Lex(); // Eat the comma. + while (getLexer().is(AsmToken::Comma) || getLexer().is(AsmToken::Plus)) { + if (getLexer().is(AsmToken::Plus)) { + // Plus tokens are significant in software_traps (p83, sparcv8.pdf). We must capture them. + Operands.push_back(SparcOperand::CreateToken("+", Parser.getTok().getLoc())); + } + Parser.Lex(); // Eat the comma or plus. // Parse and remember the operand. if (parseOperand(Operands, Name) != MatchOperand_Success) { SMLoc Loc = getLexer().getLoc(); @@ -646,6 +684,12 @@ ParseDirective(AsmToken DirectiveID) Parser.eatToEndOfStatement(); return false; } + if (IDVal == ".proc") { + // For compatibility, ignore this directive. + // (It's supposed to be an "optimization" in the Sun assembler) + Parser.eatToEndOfStatement(); + return false; + } // Let the MC layer to handle other directives. return true; @@ -728,7 +772,7 @@ SparcAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) { Parser.getTok().getLoc())); Parser.Lex(); // Eat the [ - if (Mnemonic == "cas" || Mnemonic == "casx") { + if (Mnemonic == "cas" || Mnemonic == "casx" || Mnemonic == "casa") { SMLoc S = Parser.getTok().getLoc(); if (getLexer().getKind() != AsmToken::Percent) return MatchOperand_NoMatch; @@ -809,6 +853,15 @@ SparcAsmParser::parseSparcAsmOperand(std::unique_ptr<SparcOperand> &Op, case Sparc::FSR: Op = SparcOperand::CreateToken("%fsr", S); break; + case Sparc::FQ: + Op = SparcOperand::CreateToken("%fq", S); + break; + case Sparc::CPSR: + Op = SparcOperand::CreateToken("%csr", S); + break; + case Sparc::CPQ: + Op = SparcOperand::CreateToken("%cq", S); + break; case Sparc::WIM: Op = SparcOperand::CreateToken("%wim", S); break; @@ -846,8 +899,7 @@ SparcAsmParser::parseSparcAsmOperand(std::unique_ptr<SparcOperand> &Op, const MCExpr *Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None, getContext()); - if (isCall && - getContext().getObjectFileInfo()->getRelocM() == Reloc::PIC_) + if (isCall && getContext().getObjectFileInfo()->isPositionIndependent()) Res = SparcMCExpr::create(SparcMCExpr::VK_Sparc_WPLT30, Res, getContext()); Op = SparcOperand::CreateImm(Res, S, E); @@ -941,6 +993,24 @@ bool SparcAsmParser::matchRegisterName(const AsmToken &Tok, return true; } + if (name.equals("fq")) { + RegNo = Sparc::FQ; + RegKind = SparcOperand::rk_Special; + return true; + } + + if (name.equals("csr")) { + RegNo = Sparc::CPSR; + RegKind = SparcOperand::rk_Special; + return true; + } + + if (name.equals("cq")) { + RegNo = Sparc::CPQ; + RegKind = SparcOperand::rk_Special; + return true; + } + if (name.equals("wim")) { RegNo = Sparc::WIM; RegKind = SparcOperand::rk_Special; @@ -1025,6 +1095,15 @@ bool SparcAsmParser::matchRegisterName(const AsmToken &Tok, return true; } + // %c0 - %c31 + if (name.substr(0, 1).equals_lower("c") + && !name.substr(1).getAsInteger(10, intVal) + && intVal < 32) { + RegNo = CoprocRegs[intVal]; + RegKind = SparcOperand::rk_CoprocReg; + return true; + } + if (name.equals("tpc")) { RegNo = Sparc::TPC; RegKind = SparcOperand::rk_Special; @@ -1141,7 +1220,7 @@ SparcAsmParser::adjustPICRelocation(SparcMCExpr::VariantKind VK, // actually a %pc10 or %pc22 relocation. Otherwise, they are interpreted // as %got10 or %got22 relocation. - if (getContext().getObjectFileInfo()->getRelocM() == Reloc::PIC_) { + if (getContext().getObjectFileInfo()->isPositionIndependent()) { switch(VK) { default: break; case SparcMCExpr::VK_Sparc_LO: @@ -1215,5 +1294,9 @@ unsigned SparcAsmParser::validateTargetOperandClass(MCParsedAsmOperand &GOp, if (SparcOperand::MorphToIntPairReg(Op)) return MCTargetAsmParser::Match_Success; } + if (Op.isCoprocReg() && Kind == MCK_CoprocPair) { + if (SparcOperand::MorphToCoprocPairReg(Op)) + return MCTargetAsmParser::Match_Success; + } return Match_InvalidOperand; } diff --git a/lib/Target/Sparc/CMakeLists.txt b/lib/Target/Sparc/CMakeLists.txt index 5b7bfdd28020..312215cf6cde 100644 --- a/lib/Target/Sparc/CMakeLists.txt +++ b/lib/Target/Sparc/CMakeLists.txt @@ -13,6 +13,7 @@ add_public_tablegen_target(SparcCommonTableGen) add_llvm_target(SparcCodeGen DelaySlotFiller.cpp + LeonPasses.cpp SparcAsmPrinter.cpp SparcInstrInfo.cpp SparcISelDAGToDAG.cpp diff --git a/lib/Target/Sparc/DelaySlotFiller.cpp b/lib/Target/Sparc/DelaySlotFiller.cpp index c689b7f7201e..944f3551279e 100644 --- a/lib/Target/Sparc/DelaySlotFiller.cpp +++ b/lib/Target/Sparc/DelaySlotFiller.cpp @@ -38,14 +38,10 @@ static cl::opt<bool> DisableDelaySlotFiller( namespace { struct Filler : public MachineFunctionPass { - /// Target machine description which we query for reg. names, data - /// layout, etc. - /// - TargetMachine &TM; const SparcSubtarget *Subtarget; static char ID; - Filler(TargetMachine &tm) : MachineFunctionPass(ID), TM(tm) {} + Filler() : MachineFunctionPass(ID) {} const char *getPassName() const override { return "SPARC Delay Slot Filler"; @@ -66,6 +62,11 @@ namespace { return Changed; } + MachineFunctionProperties getRequiredProperties() const override { + return MachineFunctionProperties().set( + MachineFunctionProperties::Property::AllVRegsAllocated); + } + void insertCallDefsUses(MachineBasicBlock::iterator MI, SmallSet<unsigned, 32>& RegDefs, SmallSet<unsigned, 32>& RegUses); @@ -98,7 +99,7 @@ namespace { /// slots in Sparc MachineFunctions /// FunctionPass *llvm::createSparcDelaySlotFillerPass(TargetMachine &tm) { - return new Filler(tm); + return new Filler; } @@ -268,6 +269,22 @@ bool Filler::delayHasHazard(MachineBasicBlock::iterator candidate, return true; } } + + unsigned Opcode = candidate->getOpcode(); + // LD and LDD may have NOPs inserted afterwards in the case of some LEON + // processors, so we can't use the delay slot if this feature is switched-on. + if (Subtarget->insertNOPLoad() + && + Opcode >= SP::LDDArr && Opcode <= SP::LDrr) + return true; + + // Same as above for FDIV and FSQRT on some LEON processors. + if (Subtarget->fixAllFDIVSQRT() + && + Opcode >= SP::FDIVD && Opcode <= SP::FSQRTD) + return true; + + return false; } @@ -290,12 +307,12 @@ void Filler::insertCallDefsUses(MachineBasicBlock::iterator MI, assert(Reg.isUse() && "CALL first operand is not a use."); RegUses.insert(Reg.getReg()); - const MachineOperand &RegOrImm = MI->getOperand(1); - if (RegOrImm.isImm()) + const MachineOperand &Operand1 = MI->getOperand(1); + if (Operand1.isImm() || Operand1.isGlobal()) break; - assert(RegOrImm.isReg() && "CALLrr second operand is not a register."); - assert(RegOrImm.isUse() && "CALLrr second operand is not a use."); - RegUses.insert(RegOrImm.getReg()); + assert(Operand1.isReg() && "CALLrr second operand is not a register."); + assert(Operand1.isUse() && "CALLrr second operand is not a use."); + RegUses.insert(Operand1.getReg()); break; } } diff --git a/lib/Target/Sparc/Disassembler/Makefile b/lib/Target/Sparc/Disassembler/Makefile deleted file mode 100644 index bc17ddc48c7d..000000000000 --- a/lib/Target/Sparc/Disassembler/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -##===- lib/Target/Sparc/Disassembler/Makefile --------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../../../.. -LIBRARYNAME = LLVMSparcDisassembler - -# Hack: we need to include 'main' Sparc target directory to grab private headers -CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. - -include $(LEVEL)/Makefile.common diff --git a/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp b/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp index 51751ec511c9..1dea379e14ec 100644 --- a/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp +++ b/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp @@ -14,7 +14,7 @@ #include "Sparc.h" #include "SparcRegisterInfo.h" #include "SparcSubtarget.h" -#include "llvm/MC/MCDisassembler.h" +#include "llvm/MC/MCDisassembler/MCDisassembler.h" #include "llvm/MC/MCFixedLenDisassembler.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCContext.h" @@ -130,6 +130,25 @@ static const uint16_t IntPairDecoderTable[] = { SP::I0_I1, SP::I2_I3, SP::I4_I5, SP::I6_I7, }; +static const unsigned CPRegDecoderTable[] = { + SP::C0, SP::C1, SP::C2, SP::C3, + SP::C4, SP::C5, SP::C6, SP::C7, + SP::C8, SP::C9, SP::C10, SP::C11, + SP::C12, SP::C13, SP::C14, SP::C15, + SP::C16, SP::C17, SP::C18, SP::C19, + SP::C20, SP::C21, SP::C22, SP::C23, + SP::C24, SP::C25, SP::C26, SP::C27, + SP::C28, SP::C29, SP::C30, SP::C31 +}; + + +static const uint16_t CPPairDecoderTable[] = { + SP::C0_C1, SP::C2_C3, SP::C4_C5, SP::C6_C7, + SP::C8_C9, SP::C10_C11, SP::C12_C13, SP::C14_C15, + SP::C16_C17, SP::C18_C19, SP::C20_C21, SP::C22_C23, + SP::C24_C25, SP::C26_C27, SP::C28_C29, SP::C30_C31 +}; + static DecodeStatus DecodeIntRegsRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address, @@ -191,6 +210,17 @@ static DecodeStatus DecodeQFPRegsRegisterClass(MCInst &Inst, return MCDisassembler::Success; } +static DecodeStatus DecodeCPRegsRegisterClass(MCInst &Inst, + unsigned RegNo, + uint64_t Address, + const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + unsigned Reg = CPRegDecoderTable[RegNo]; + Inst.addOperand(MCOperand::createReg(Reg)); + return MCDisassembler::Success; +} + static DecodeStatus DecodeFCCRegsRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address, const void *Decoder) { @@ -233,6 +263,16 @@ static DecodeStatus DecodeIntPairRegisterClass(MCInst &Inst, unsigned RegNo, return S; } +static DecodeStatus DecodeCPPairRegisterClass(MCInst &Inst, unsigned RegNo, + uint64_t Address, const void *Decoder) { + if (RegNo > 31) + return MCDisassembler::Fail; + + unsigned RegisterPair = CPPairDecoderTable[RegNo/2]; + Inst.addOperand(MCOperand::createReg(RegisterPair)); + return MCDisassembler::Success; +} + static DecodeStatus DecodeLoadInt(MCInst &Inst, unsigned insn, uint64_t Address, const void *Decoder); static DecodeStatus DecodeLoadIntPair(MCInst &Inst, unsigned insn, uint64_t Address, @@ -243,6 +283,10 @@ static DecodeStatus DecodeLoadDFP(MCInst &Inst, unsigned insn, uint64_t Address, const void *Decoder); static DecodeStatus DecodeLoadQFP(MCInst &Inst, unsigned insn, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeLoadCP(MCInst &Inst, unsigned insn, uint64_t Address, + const void *Decoder); +static DecodeStatus DecodeLoadCPPair(MCInst &Inst, unsigned insn, uint64_t Address, + const void *Decoder); static DecodeStatus DecodeStoreInt(MCInst &Inst, unsigned insn, uint64_t Address, const void *Decoder); static DecodeStatus DecodeStoreIntPair(MCInst &Inst, unsigned insn, @@ -253,6 +297,10 @@ static DecodeStatus DecodeStoreDFP(MCInst &Inst, unsigned insn, uint64_t Address, const void *Decoder); static DecodeStatus DecodeStoreQFP(MCInst &Inst, unsigned insn, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeStoreCP(MCInst &Inst, unsigned insn, + uint64_t Address, const void *Decoder); +static DecodeStatus DecodeStoreCPPair(MCInst &Inst, unsigned insn, + uint64_t Address, const void *Decoder); static DecodeStatus DecodeCall(MCInst &Inst, unsigned insn, uint64_t Address, const void *Decoder); static DecodeStatus DecodeSIMM13(MCInst &Inst, unsigned insn, @@ -263,6 +311,8 @@ static DecodeStatus DecodeReturn(MCInst &MI, unsigned insn, uint64_t Address, const void *Decoder); static DecodeStatus DecodeSWAP(MCInst &Inst, unsigned insn, uint64_t Address, const void *Decoder); +static DecodeStatus DecodeTRAP(MCInst &Inst, unsigned insn, uint64_t Address, + const void *Decoder); #include "SparcGenDisassemblerTables.inc" @@ -298,6 +348,18 @@ DecodeStatus SparcDisassembler::getInstruction(MCInst &Instr, uint64_t &Size, return MCDisassembler::Fail; // Calling the auto-generated decoder function. + + if (STI.getFeatureBits()[Sparc::FeatureV9]) + { + Result = decodeInstruction(DecoderTableSparcV932, Instr, Insn, Address, this, STI); + } + else + { + Result = decodeInstruction(DecoderTableSparcV832, Instr, Insn, Address, this, STI); + } + if (Result != MCDisassembler::Fail) + return Result; + Result = decodeInstruction(DecoderTableSparc32, Instr, Insn, Address, this, STI); @@ -390,6 +452,18 @@ static DecodeStatus DecodeLoadQFP(MCInst &Inst, unsigned insn, uint64_t Address, DecodeQFPRegsRegisterClass); } +static DecodeStatus DecodeLoadCP(MCInst &Inst, unsigned insn, uint64_t Address, + const void *Decoder) { + return DecodeMem(Inst, insn, Address, Decoder, true, + DecodeCPRegsRegisterClass); +} + +static DecodeStatus DecodeLoadCPPair(MCInst &Inst, unsigned insn, uint64_t Address, + const void *Decoder) { + return DecodeMem(Inst, insn, Address, Decoder, true, + DecodeCPPairRegisterClass); +} + static DecodeStatus DecodeStoreInt(MCInst &Inst, unsigned insn, uint64_t Address, const void *Decoder) { return DecodeMem(Inst, insn, Address, Decoder, false, @@ -420,6 +494,18 @@ static DecodeStatus DecodeStoreQFP(MCInst &Inst, unsigned insn, DecodeQFPRegsRegisterClass); } +static DecodeStatus DecodeStoreCP(MCInst &Inst, unsigned insn, + uint64_t Address, const void *Decoder) { + return DecodeMem(Inst, insn, Address, Decoder, false, + DecodeCPRegsRegisterClass); +} + +static DecodeStatus DecodeStoreCPPair(MCInst &Inst, unsigned insn, + uint64_t Address, const void *Decoder) { + return DecodeMem(Inst, insn, Address, Decoder, false, + DecodeCPPairRegisterClass); +} + static bool tryAddingSymbolicOperand(int64_t Value, bool isBranch, uint64_t Address, uint64_t Offset, uint64_t Width, MCInst &MI, @@ -547,3 +633,36 @@ static DecodeStatus DecodeSWAP(MCInst &MI, unsigned insn, uint64_t Address, return MCDisassembler::Success; } + +static DecodeStatus DecodeTRAP(MCInst &MI, unsigned insn, uint64_t Address, + const void *Decoder) { + + unsigned rs1 = fieldFromInstruction(insn, 14, 5); + unsigned isImm = fieldFromInstruction(insn, 13, 1); + unsigned cc =fieldFromInstruction(insn, 25, 4); + unsigned rs2 = 0; + unsigned imm7 = 0; + if (isImm) + imm7 = fieldFromInstruction(insn, 0, 7); + else + rs2 = fieldFromInstruction(insn, 0, 5); + + // Decode RS1. + DecodeStatus status = DecodeIntRegsRegisterClass(MI, rs1, Address, Decoder); + if (status != MCDisassembler::Success) + return status; + + // Decode RS1 | IMM7. + if (isImm) + MI.addOperand(MCOperand::createImm(imm7)); + else { + status = DecodeIntRegsRegisterClass(MI, rs2, Address, Decoder); + if (status != MCDisassembler::Success) + return status; + } + + // Decode CC + MI.addOperand(MCOperand::createImm(cc)); + + return MCDisassembler::Success; +} diff --git a/lib/Target/Sparc/InstPrinter/Makefile b/lib/Target/Sparc/InstPrinter/Makefile deleted file mode 100644 index 2dabd82965f4..000000000000 --- a/lib/Target/Sparc/InstPrinter/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -##===- lib/Target/Sparc/InstPrinter/Makefile ---------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../../../.. -LIBRARYNAME = LLVMSparcAsmPrinter - -# Hack: we need to include 'main' target directory to grab private headers -CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. - -include $(LEVEL)/Makefile.common diff --git a/lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp b/lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp index 5d714fe4da92..4981deae6af6 100644 --- a/lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp +++ b/lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp @@ -16,6 +16,7 @@ #include "llvm/MC/MCExpr.h" #include "llvm/MC/MCInst.h" #include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" #include "llvm/MC/MCSymbol.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; @@ -115,8 +116,21 @@ void SparcInstPrinter::printOperand(const MCInst *MI, int opNum, } if (MO.isImm()) { - O << (int)MO.getImm(); - return; + switch (MI->getOpcode()) { + default: + O << (int)MO.getImm(); + return; + + case SP::TICCri: // Fall through + case SP::TICCrr: // Fall through + case SP::TRAPri: // Fall through + case SP::TRAPrr: // Fall through + case SP::TXCCri: // Fall through + case SP::TXCCrr: // Fall through + // Only seven-bit values up to 127. + O << ((int) MO.getImm() & 0x7f); + return; + } } assert(MO.isExpr() && "Unknown operand kind in printOperand"); @@ -166,6 +180,11 @@ void SparcInstPrinter::printCCOperand(const MCInst *MI, int opNum, // Make sure CC is a fp conditional flag. CC = (CC < 16) ? (CC + 16) : CC; break; + case SP::CBCOND: + case SP::CBCONDA: + // Make sure CC is a cp conditional flag. + CC = (CC < 32) ? (CC + 32) : CC; + break; } O << SPARCCondCodeToString((SPCC::CondCodes)CC); } diff --git a/lib/Target/Sparc/LeonFeatures.td b/lib/Target/Sparc/LeonFeatures.td new file mode 100755 index 000000000000..63f8b33c80cf --- /dev/null +++ b/lib/Target/Sparc/LeonFeatures.td @@ -0,0 +1,91 @@ +//===-- LeonFeatures.td - Describe the Leon Features -------*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +//===----------------------------------------------------------------------===// +// 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. +//===----------------------------------------------------------------------===// + +// support to casa instruction; for leon3 subtarget only +def UMACSMACSupport + : SubtargetFeature<"hasumacsmac", "HasUmacSmac", "true", + "Enable UMAC and SMAC for LEON3 and LEON4 processors">; + +//===----------------------------------------------------------------------===// +// LEON Erratum fixes +//===----------------------------------------------------------------------===// + +def ReplaceSDIV + : SubtargetFeature< + "replacesdiv", "PerformSDIVReplace", "true", + "AT697E erratum fix: Do not emit SDIV, emit SDIVCC instead">; + +def FixCALL + : SubtargetFeature<"fixcall", "FixCallImmediates", "true", + "AT697E erratum fix: Restrict the size of the immediate " + "operand of the CALL instruction to 20 bits">; + +def IgnoreZeroFlag + : SubtargetFeature<"ignrzeroflag", "IgnoreZeroFlag", "true", + "AT697E erratum fix: Do not rely on the zero bit flag " + "on a divide overflow for SDIVCC and UDIVCC">; + +def InsertNOPDoublePrecision + : SubtargetFeature<"insrtnopdblprcsn", "InsertNOPDoublePrecision", "true", + "LEON2 erratum fix: Insert a NOP before the double " + "precision floating point instruction">; + +def FixFSMULD : SubtargetFeature<"fixfsmuld", "FixFSMULD", "true", + "LEON3 erratum fix: Do not select FSMULD">; + +def ReplaceFMULS + : SubtargetFeature<"replacefmuls", "ReplaceFMULS", "true", + "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 FlushCacheLineSWAP + : SubtargetFeature<"flshcachelineswap", "FlushCacheLineSWAP", "true", + "LEON3 erratum fix: Flush cache line containing the " + "lock before performing any of the atomic instructions " + "SWAP and LDSTUB">; + +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">; diff --git a/lib/Target/Sparc/LeonPasses.cpp b/lib/Target/Sparc/LeonPasses.cpp new file mode 100755 index 000000000000..5d0920892ff0 --- /dev/null +++ b/lib/Target/Sparc/LeonPasses.cpp @@ -0,0 +1,933 @@ +//===------ LeonPasses.cpp - Define passes specific to LEON ---------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +#include "LeonPasses.h" +#include "llvm/CodeGen/ISDOpcodes.h" +#include "llvm/CodeGen/MachineFunction.h" +#include "llvm/CodeGen/MachineInstr.h" +#include "llvm/CodeGen/MachineInstrBuilder.h" +#include "llvm/CodeGen/MachineRegisterInfo.h" +#include "llvm/IR/LLVMContext.h" +#include "llvm/Support/raw_ostream.h" +using namespace llvm; + +LEONMachineFunctionPass::LEONMachineFunctionPass(TargetMachine &tm, char &ID) + : MachineFunctionPass(ID) {} + +LEONMachineFunctionPass::LEONMachineFunctionPass(char &ID) + : MachineFunctionPass(ID) {} + +int LEONMachineFunctionPass::GetRegIndexForOperand(MachineInstr &MI, + int OperandIndex) { + if (MI.getNumOperands() > 0) { + if (OperandIndex == LAST_OPERAND) { + OperandIndex = MI.getNumOperands() - 1; + } + + if (MI.getNumOperands() > (unsigned)OperandIndex && + MI.getOperand(OperandIndex).isReg()) { + return (int)MI.getOperand(OperandIndex).getReg(); + } + } + + static int NotFoundIndex = -10; + // Return a different number each time to avoid any comparisons between the + // values returned. + NotFoundIndex -= 10; + return NotFoundIndex; +} + +// finds a new free FP register +// checks also the AllocatedRegisters vector +int LEONMachineFunctionPass::getUnusedFPRegister(MachineRegisterInfo &MRI) { + for (int RegisterIndex = SP::F0; RegisterIndex <= SP::F31; ++RegisterIndex) { + if (!MRI.isPhysRegUsed(RegisterIndex) && + !(std::find(UsedRegisters.begin(), UsedRegisters.end(), + RegisterIndex) != UsedRegisters.end())) { + return RegisterIndex; + } + } + + return -1; +} + +//***************************************************************************** +//**** InsertNOPLoad pass +//***************************************************************************** +// This pass fixes the incorrectly working Load instructions that exists for +// some earlier versions of the LEON processor line. NOP instructions must +// be inserted after the load instruction to ensure that the Load instruction +// behaves as expected for these processors. +// +// This pass inserts a NOP after any LD or LDF instruction. +// +char InsertNOPLoad::ID = 0; + +InsertNOPLoad::InsertNOPLoad(TargetMachine &tm) + : LEONMachineFunctionPass(tm, ID) {} + +bool InsertNOPLoad::runOnMachineFunction(MachineFunction &MF) { + Subtarget = &MF.getSubtarget<SparcSubtarget>(); + const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); + DebugLoc DL = DebugLoc(); + + bool Modified = false; + for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { + MachineBasicBlock &MBB = *MFI; + for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) { + MachineInstr &MI = *MBBI; + unsigned Opcode = MI.getOpcode(); + if (Opcode >= SP::LDDArr && Opcode <= SP::LDrr) { + MachineBasicBlock::iterator NMBBI = std::next(MBBI); + BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP)); + Modified = true; + } else if (MI.isInlineAsm()) { + // Look for an inline ld or ldf instruction. + StringRef AsmString = + MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName(); + if (AsmString.startswith_lower("ld")) { + MachineBasicBlock::iterator NMBBI = std::next(MBBI); + BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP)); + Modified = true; + } + } + } + } + + return Modified; +} + +//***************************************************************************** +//**** FixFSMULD pass +//***************************************************************************** +// This pass fixes the incorrectly working FSMULD instruction that exists for +// some earlier versions of the LEON processor line. +// +// The pass should convert the FSMULD operands to double precision in scratch +// registers, then calculate the result with the FMULD instruction. Therefore, +// the pass should replace operations of the form: +// fsmuld %f20,%f21,%f8 +// with the sequence: +// fstod %f20,%f0 +// fstod %f21,%f2 +// fmuld %f0,%f2,%f8 +// +char FixFSMULD::ID = 0; + +FixFSMULD::FixFSMULD(TargetMachine &tm) : LEONMachineFunctionPass(tm, ID) {} + +bool FixFSMULD::runOnMachineFunction(MachineFunction &MF) { + Subtarget = &MF.getSubtarget<SparcSubtarget>(); + const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); + DebugLoc DL = DebugLoc(); + + bool Modified = false; + for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { + MachineBasicBlock &MBB = *MFI; + for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) { + + MachineInstr &MI = *MBBI; + unsigned Opcode = MI.getOpcode(); + + const int UNASSIGNED_INDEX = -1; + int Reg1Index = UNASSIGNED_INDEX; + int Reg2Index = UNASSIGNED_INDEX; + int Reg3Index = UNASSIGNED_INDEX; + + if (Opcode == SP::FSMULD && MI.getNumOperands() == 3) { + // take the registers from fsmuld %f20,%f21,%f8 + Reg1Index = MI.getOperand(0).getReg(); + Reg2Index = MI.getOperand(1).getReg(); + Reg3Index = MI.getOperand(2).getReg(); + } else if (MI.isInlineAsm()) { + StringRef AsmString = + MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName(); + if (AsmString.startswith_lower("fsmuld")) { + // this is an inline FSMULD instruction + + unsigned StartOp = InlineAsm::MIOp_FirstOperand; + + // extracts the registers from the inline assembly instruction + for (unsigned i = StartOp, e = MI.getNumOperands(); i != e; ++i) { + const MachineOperand &MO = MI.getOperand(i); + if (MO.isReg()) { + if (Reg1Index == UNASSIGNED_INDEX) + Reg1Index = MO.getReg(); + else if (Reg2Index == UNASSIGNED_INDEX) + Reg2Index = MO.getReg(); + else if (Reg3Index == UNASSIGNED_INDEX) + Reg3Index = MO.getReg(); + } + if (Reg3Index != UNASSIGNED_INDEX) + break; + } + } + } + + if (Reg1Index != UNASSIGNED_INDEX && Reg2Index != UNASSIGNED_INDEX && + Reg3Index != UNASSIGNED_INDEX) { + clearUsedRegisterList(); + MachineBasicBlock::iterator NMBBI = std::next(MBBI); + // Whatever Reg3Index is hasn't been used yet, so we need to reserve it. + markRegisterUsed(Reg3Index); + const int ScratchReg1Index = getUnusedFPRegister(MF.getRegInfo()); + markRegisterUsed(ScratchReg1Index); + const int ScratchReg2Index = getUnusedFPRegister(MF.getRegInfo()); + markRegisterUsed(ScratchReg2Index); + + if (ScratchReg1Index == UNASSIGNED_INDEX || + ScratchReg2Index == UNASSIGNED_INDEX) { + errs() << "Cannot allocate free scratch registers for the FixFSMULD " + "pass." + << "\n"; + } else { + // create fstod %f20,%f0 + BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD)) + .addReg(ScratchReg1Index) + .addReg(Reg1Index); + + // create fstod %f21,%f2 + BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD)) + .addReg(ScratchReg2Index) + .addReg(Reg2Index); + + // create fmuld %f0,%f2,%f8 + BuildMI(MBB, MBBI, DL, TII.get(SP::FMULD)) + .addReg(Reg3Index) + .addReg(ScratchReg1Index) + .addReg(ScratchReg2Index); + + MI.eraseFromParent(); + MBBI = NMBBI; + + Modified = true; + } + } + } + } + + return Modified; +} + +//***************************************************************************** +//**** ReplaceFMULS pass +//***************************************************************************** +// This pass fixes the incorrectly working FMULS instruction that exists for +// some earlier versions of the LEON processor line. +// +// This pass converts the FMULS operands to double precision in scratch +// registers, then calculates the result with the FMULD instruction. +// The pass should replace operations of the form: +// fmuls %f20,%f21,%f8 +// with the sequence: +// fstod %f20,%f0 +// fstod %f21,%f2 +// fmuld %f0,%f2,%f8 +// +char ReplaceFMULS::ID = 0; + +ReplaceFMULS::ReplaceFMULS(TargetMachine &tm) + : LEONMachineFunctionPass(tm, ID) {} + +bool ReplaceFMULS::runOnMachineFunction(MachineFunction &MF) { + Subtarget = &MF.getSubtarget<SparcSubtarget>(); + const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); + DebugLoc DL = DebugLoc(); + + bool Modified = false; + for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { + MachineBasicBlock &MBB = *MFI; + for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) { + MachineInstr &MI = *MBBI; + unsigned Opcode = MI.getOpcode(); + + const int UNASSIGNED_INDEX = -1; + int Reg1Index = UNASSIGNED_INDEX; + int Reg2Index = UNASSIGNED_INDEX; + int Reg3Index = UNASSIGNED_INDEX; + + if (Opcode == SP::FMULS && MI.getNumOperands() == 3) { + // take the registers from fmuls %f20,%f21,%f8 + Reg1Index = MI.getOperand(0).getReg(); + Reg2Index = MI.getOperand(1).getReg(); + Reg3Index = MI.getOperand(2).getReg(); + } else if (MI.isInlineAsm()) { + StringRef AsmString = + MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName(); + if (AsmString.startswith_lower("fmuls")) { + // this is an inline FMULS instruction + unsigned StartOp = InlineAsm::MIOp_FirstOperand; + + // extracts the registers from the inline assembly instruction + for (unsigned i = StartOp, e = MI.getNumOperands(); i != e; ++i) { + const MachineOperand &MO = MI.getOperand(i); + if (MO.isReg()) { + if (Reg1Index == UNASSIGNED_INDEX) + Reg1Index = MO.getReg(); + else if (Reg2Index == UNASSIGNED_INDEX) + Reg2Index = MO.getReg(); + else if (Reg3Index == UNASSIGNED_INDEX) + Reg3Index = MO.getReg(); + } + if (Reg3Index != UNASSIGNED_INDEX) + break; + } + } + } + + if (Reg1Index != UNASSIGNED_INDEX && Reg2Index != UNASSIGNED_INDEX && + Reg3Index != UNASSIGNED_INDEX) { + clearUsedRegisterList(); + MachineBasicBlock::iterator NMBBI = std::next(MBBI); + // Whatever Reg3Index is hasn't been used yet, so we need to reserve it. + markRegisterUsed(Reg3Index); + const int ScratchReg1Index = getUnusedFPRegister(MF.getRegInfo()); + markRegisterUsed(ScratchReg1Index); + const int ScratchReg2Index = getUnusedFPRegister(MF.getRegInfo()); + markRegisterUsed(ScratchReg2Index); + + if (ScratchReg1Index == UNASSIGNED_INDEX || + ScratchReg2Index == UNASSIGNED_INDEX) { + errs() << "Cannot allocate free scratch registers for the " + "ReplaceFMULS pass." + << "\n"; + } else { + // create fstod %f20,%f0 + BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD)) + .addReg(ScratchReg1Index) + .addReg(Reg1Index); + + // create fstod %f21,%f2 + BuildMI(MBB, MBBI, DL, TII.get(SP::FSTOD)) + .addReg(ScratchReg2Index) + .addReg(Reg2Index); + + // create fmuld %f0,%f2,%f8 + BuildMI(MBB, MBBI, DL, TII.get(SP::FMULD)) + .addReg(Reg3Index) + .addReg(ScratchReg1Index) + .addReg(ScratchReg2Index); + + MI.eraseFromParent(); + MBBI = NMBBI; + + Modified = true; + } + } + } + } + + return Modified; +} + +//***************************************************************************** +//**** FixAllFDIVSQRT pass +//***************************************************************************** +// This pass fixes the incorrectly working FDIVx and FSQRTx instructions that +// exist for some earlier versions of the LEON processor line. Five NOP +// instructions need to be inserted after these instructions to ensure the +// correct result is placed in the destination registers before they are used. +// +// This pass implements two fixes: +// 1) fixing the FSQRTS and FSQRTD instructions. +// 2) fixing the FDIVS and FDIVD instructions. +// +// FSQRTS and FDIVS are converted to FDIVD and FSQRTD respectively earlier in +// the pipeline when this option is enabled, so this pass needs only to deal +// with the changes that still need implementing for the "double" versions +// of these instructions. +// +char FixAllFDIVSQRT::ID = 0; + +FixAllFDIVSQRT::FixAllFDIVSQRT(TargetMachine &tm) + : LEONMachineFunctionPass(tm, ID) {} + +bool FixAllFDIVSQRT::runOnMachineFunction(MachineFunction &MF) { + Subtarget = &MF.getSubtarget<SparcSubtarget>(); + const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); + DebugLoc DL = DebugLoc(); + + bool Modified = false; + for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { + MachineBasicBlock &MBB = *MFI; + for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) { + MachineInstr &MI = *MBBI; + unsigned Opcode = MI.getOpcode(); + + if (MI.isInlineAsm()) { + StringRef AsmString = + MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName(); + if (AsmString.startswith_lower("fsqrtd")) { + // this is an inline fsqrts instruction + Opcode = SP::FSQRTD; + } else if (AsmString.startswith_lower("fdivd")) { + // this is an inline fsqrts instruction + Opcode = SP::FDIVD; + } + } + + // Note: FDIVS and FSQRTS cannot be generated when this erratum fix is + // switched on so we don't need to check for them here. They will + // already have been converted to FSQRTD or FDIVD earlier in the + // pipeline. + if (Opcode == SP::FSQRTD || Opcode == SP::FDIVD) { + // Insert 5 NOPs before FSQRTD,FDIVD. + for (int InsertedCount = 0; InsertedCount < 5; InsertedCount++) + BuildMI(MBB, MBBI, DL, TII.get(SP::NOP)); + + MachineBasicBlock::iterator NMBBI = std::next(MBBI); + // ... and inserting 28 NOPs after FSQRTD,FDIVD. + for (int InsertedCount = 0; InsertedCount < 28; InsertedCount++) + BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP)); + + Modified = true; + } + } + } + + return Modified; +} + +//***************************************************************************** +//**** ReplaceSDIV pass +//***************************************************************************** +// This pass fixes the incorrectly working SDIV instruction that +// exist for some earlier versions of the LEON processor line. The instruction +// is replaced with an SDIVcc instruction instead, which is working. +// +char ReplaceSDIV::ID = 0; + +ReplaceSDIV::ReplaceSDIV() : LEONMachineFunctionPass(ID) {} + +ReplaceSDIV::ReplaceSDIV(TargetMachine &tm) : LEONMachineFunctionPass(tm, ID) {} + +bool ReplaceSDIV::runOnMachineFunction(MachineFunction &MF) { + Subtarget = &MF.getSubtarget<SparcSubtarget>(); + const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); + + bool Modified = false; + for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { + MachineBasicBlock &MBB = *MFI; + for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) { + MachineInstr &MI = *MBBI; + unsigned Opcode = MI.getOpcode(); + if (Opcode == SP::SDIVrr) { + MI.setDesc(TII.get(SP::SDIVCCrr)); + Modified = true; + } else if (Opcode == SP::SDIVri) { + MI.setDesc(TII.get(SP::SDIVCCri)); + Modified = true; + } + } + } + + return Modified; +} + +static RegisterPass<ReplaceSDIV> X("replace-sdiv", "Replase SDIV Pass", false, + false); + +//***************************************************************************** +//**** FixCALL pass +//***************************************************************************** +// This pass restricts the size of the immediate operand of the CALL +// instruction, which can cause problems on some earlier versions of the LEON +// processor, which can interpret some of the call address bits incorrectly. +// +char FixCALL::ID = 0; + +FixCALL::FixCALL(TargetMachine &tm) : LEONMachineFunctionPass(tm, ID) {} + +bool FixCALL::runOnMachineFunction(MachineFunction &MF) { + bool Modified = false; + + for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { + MachineBasicBlock &MBB = *MFI; + for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) { + MachineInstr &MI = *MBBI; + MI.print(errs()); + errs() << "\n"; + + unsigned Opcode = MI.getOpcode(); + if (Opcode == SP::CALL || Opcode == SP::CALLrr) { + unsigned NumOperands = MI.getNumOperands(); + for (unsigned OperandIndex = 0; OperandIndex < NumOperands; + OperandIndex++) { + MachineOperand &MO = MI.getOperand(OperandIndex); + if (MO.isImm()) { + int64_t Value = MO.getImm(); + MO.setImm(Value & 0x000fffffL); + Modified = true; + break; + } + } + } else if (MI.isInlineAsm()) // inline assembly immediate call + { + StringRef AsmString = + MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName(); + if (AsmString.startswith_lower("call")) { + // this is an inline call instruction + unsigned StartOp = InlineAsm::MIOp_FirstOperand; + + // extracts the registers from the inline assembly instruction + for (unsigned i = StartOp, e = MI.getNumOperands(); i != e; ++i) { + MachineOperand &MO = MI.getOperand(i); + if (MO.isImm()) { + int64_t Value = MO.getImm(); + MO.setImm(Value & 0x000fffffL); + Modified = true; + } + } + } + } + } + } + + return Modified; +} + +//***************************************************************************** +//**** IgnoreZeroFlag pass +//***************************************************************************** +// This erratum fix fixes the overflow behavior of SDIVCC and UDIVCC +// instructions that exists on some earlier LEON processors. Where these +// instructions are detected, they are replaced by a sequence that will +// explicitly write the overflow bit flag if this is required. +// +char IgnoreZeroFlag::ID = 0; + +IgnoreZeroFlag::IgnoreZeroFlag(TargetMachine &tm) + : LEONMachineFunctionPass(tm, ID) {} + +bool IgnoreZeroFlag::runOnMachineFunction(MachineFunction &MF) { + Subtarget = &MF.getSubtarget<SparcSubtarget>(); + const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); + DebugLoc DL = DebugLoc(); + + bool Modified = false; + for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { + MachineBasicBlock &MBB = *MFI; + for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) { + MachineInstr &MI = *MBBI; + unsigned Opcode = MI.getOpcode(); + if (Opcode == SP::SDIVCCrr || Opcode == SP::SDIVCCri || + Opcode == SP::UDIVCCrr || Opcode == SP::UDIVCCri) { + + // split the current machine basic block - just after the sdivcc/udivcc + // instruction + // create a label that help us skip the zero flag update (of PSR - + // Processor Status Register) + // if conditions are not met + const BasicBlock *LLVM_BB = MBB.getBasicBlock(); + MachineFunction::iterator It = + std::next(MachineFunction::iterator(MBB)); + + MachineBasicBlock *dneBB = MF.CreateMachineBasicBlock(LLVM_BB); + MF.insert(It, dneBB); + + // Transfer the remainder of MBB and its successor edges to dneBB. + dneBB->splice(dneBB->begin(), &MBB, + std::next(MachineBasicBlock::iterator(MI)), MBB.end()); + dneBB->transferSuccessorsAndUpdatePHIs(&MBB); + + MBB.addSuccessor(dneBB); + + MachineBasicBlock::iterator NextMBBI = std::next(MBBI); + + // bvc - branch if overflow flag not set + BuildMI(MBB, NextMBBI, DL, TII.get(SP::BCOND)) + .addMBB(dneBB) + .addImm(SPCC::ICC_VS); + + // bnz - branch if not zero + BuildMI(MBB, NextMBBI, DL, TII.get(SP::BCOND)) + .addMBB(dneBB) + .addImm(SPCC::ICC_NE); + + // use the WRPSR (Write Processor State Register) instruction to set the + // zeo flag to 1 + // create wr %g0, 1, %psr + BuildMI(MBB, NextMBBI, DL, TII.get(SP::WRPSRri)) + .addReg(SP::G0) + .addImm(1); + + BuildMI(MBB, NextMBBI, DL, TII.get(SP::NOP)); + + Modified = true; + } else if (MI.isInlineAsm()) { + StringRef AsmString = + MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName(); + if (AsmString.startswith_lower("sdivcc") || + AsmString.startswith_lower("udivcc")) { + // this is an inline SDIVCC or UDIVCC instruction + + // split the current machine basic block - just after the + // sdivcc/udivcc instruction + // create a label that help us skip the zero flag update (of PSR - + // Processor Status Register) + // if conditions are not met + const BasicBlock *LLVM_BB = MBB.getBasicBlock(); + MachineFunction::iterator It = + std::next(MachineFunction::iterator(MBB)); + + MachineBasicBlock *dneBB = MF.CreateMachineBasicBlock(LLVM_BB); + MF.insert(It, dneBB); + + // Transfer the remainder of MBB and its successor edges to dneBB. + dneBB->splice(dneBB->begin(), &MBB, + std::next(MachineBasicBlock::iterator(MI)), MBB.end()); + dneBB->transferSuccessorsAndUpdatePHIs(&MBB); + + MBB.addSuccessor(dneBB); + + MachineBasicBlock::iterator NextMBBI = std::next(MBBI); + + // bvc - branch if overflow flag not set + BuildMI(MBB, NextMBBI, DL, TII.get(SP::BCOND)) + .addMBB(dneBB) + .addImm(SPCC::ICC_VS); + + // bnz - branch if not zero + BuildMI(MBB, NextMBBI, DL, TII.get(SP::BCOND)) + .addMBB(dneBB) + .addImm(SPCC::ICC_NE); + + // use the WRPSR (Write Processor State Register) instruction to set + // the zeo flag to 1 + // create wr %g0, 1, %psr + BuildMI(MBB, NextMBBI, DL, TII.get(SP::WRPSRri)) + .addReg(SP::G0) + .addImm(1); + + BuildMI(MBB, NextMBBI, DL, TII.get(SP::NOP)); + + Modified = true; + } + } + } + } + + return Modified; +} + +//***************************************************************************** +//**** InsertNOPDoublePrecision pass +//***************************************************************************** +// This erratum fix for some earlier LEON processors fixes a problem where a +// double precision load will not yield the correct result if used in FMUL, +// FDIV, FADD, FSUB or FSQRT instructions later. If this sequence is detected, +// inserting a NOP between the two instructions will fix the erratum. +// 1.scans the code after register allocation; +// 2.checks for the problem conditions as described in the AT697E erratum +// “Odd-Numbered FPU Register Dependency not Properly Checked in some +// Double-Precision FPU Operations”; +// 3.inserts NOPs if the problem exists. +// +char InsertNOPDoublePrecision::ID = 0; + +InsertNOPDoublePrecision::InsertNOPDoublePrecision(TargetMachine &tm) + : LEONMachineFunctionPass(tm, ID) {} + +bool InsertNOPDoublePrecision::runOnMachineFunction(MachineFunction &MF) { + Subtarget = &MF.getSubtarget<SparcSubtarget>(); + const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); + DebugLoc DL = DebugLoc(); + + bool Modified = false; + for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { + MachineBasicBlock &MBB = *MFI; + for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) { + MachineInstr &MI = *MBBI; + unsigned Opcode = MI.getOpcode(); + if (Opcode == SP::LDDFri || Opcode == SP::LDDFrr) { + MachineBasicBlock::iterator NMBBI = std::next(MBBI); + MachineInstr &NMI = *NMBBI; + + unsigned NextOpcode = NMI.getOpcode(); + // NMI.print(errs()); + if (NextOpcode == SP::FADDD || NextOpcode == SP::FSUBD || + NextOpcode == SP::FMULD || NextOpcode == SP::FDIVD) { + int RegAIndex = GetRegIndexForOperand(MI, 0); + int RegBIndex = GetRegIndexForOperand(NMI, 0); + int RegCIndex = + GetRegIndexForOperand(NMI, 2); // Second source operand is index 2 + int RegDIndex = + GetRegIndexForOperand(NMI, 1); // Destination operand is index 1 + + if ((RegAIndex == RegBIndex + 1 && RegBIndex == RegDIndex) || + (RegAIndex == RegCIndex + 1 && RegCIndex == RegDIndex) || + (RegAIndex == RegBIndex + 1 && RegCIndex == RegDIndex) || + (RegAIndex == RegCIndex + 1 && RegBIndex == RegDIndex)) { + // Insert NOP between the two instructions. + BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP)); + Modified = true; + } + + // Check the errata patterns that only happen for FADDD and FMULD + if (Modified == false && + (NextOpcode == SP::FADDD || NextOpcode == SP::FMULD)) { + RegAIndex = GetRegIndexForOperand(MI, 1); + if (RegAIndex == RegBIndex + 1 && RegBIndex == RegCIndex && + RegBIndex == RegDIndex) { + // Insert NOP between the two instructions. + BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP)); + Modified = true; + } + } + } else if (NextOpcode == SP::FSQRTD) { + int RegAIndex = GetRegIndexForOperand(MI, 1); + int RegBIndex = GetRegIndexForOperand(NMI, 0); + int RegCIndex = GetRegIndexForOperand(NMI, 1); + + if (RegAIndex == RegBIndex + 1 && RegBIndex == RegCIndex) { + // Insert NOP between the two instructions. + BuildMI(MBB, NMBBI, DL, TII.get(SP::NOP)); + Modified = true; + } + } + } + } + } + + return Modified; +} + +//***************************************************************************** +//**** PreventRoundChange pass +//***************************************************************************** +// To prevent any explicit change of the default rounding mode, this pass +// detects any call of the fesetround function and removes this call from the +// list of generated operations. +// +char PreventRoundChange::ID = 0; + +PreventRoundChange::PreventRoundChange(TargetMachine &tm) + : LEONMachineFunctionPass(tm, ID) {} + +bool PreventRoundChange::runOnMachineFunction(MachineFunction &MF) { + Subtarget = &MF.getSubtarget<SparcSubtarget>(); + + bool Modified = false; + for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { + MachineBasicBlock &MBB = *MFI; + for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) { + MachineInstr &MI = *MBBI; + unsigned Opcode = MI.getOpcode(); + if (Opcode == SP::CALL && MI.getNumOperands() > 0) { + MachineOperand &MO = MI.getOperand(0); + + if (MO.isGlobal()) { + StringRef FuncName = MO.getGlobal()->getName(); + if (FuncName.compare_lower("fesetround") == 0) { + MachineBasicBlock::iterator NMBBI = std::next(MBBI); + MI.eraseFromParent(); + MBBI = NMBBI; + Modified = true; + } + } + } + } + } + + return Modified; +} +//***************************************************************************** +//**** FlushCacheLineSWAP pass +//***************************************************************************** +// This pass inserts FLUSHW just before any SWAP atomic instruction. +// +char FlushCacheLineSWAP::ID = 0; + +FlushCacheLineSWAP::FlushCacheLineSWAP(TargetMachine &tm) + : LEONMachineFunctionPass(tm, ID) {} + +bool FlushCacheLineSWAP::runOnMachineFunction(MachineFunction &MF) { + Subtarget = &MF.getSubtarget<SparcSubtarget>(); + const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); + DebugLoc DL = DebugLoc(); + + bool Modified = false; + for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { + MachineBasicBlock &MBB = *MFI; + for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) { + MachineInstr &MI = *MBBI; + unsigned Opcode = MI.getOpcode(); + if (Opcode == SP::SWAPrr || Opcode == SP::SWAPri || + Opcode == SP::LDSTUBrr || Opcode == SP::LDSTUBri) { + // insert flush and 5 NOPs before the swap/ldstub instruction + BuildMI(MBB, MBBI, DL, TII.get(SP::FLUSH)); + BuildMI(MBB, MBBI, DL, TII.get(SP::NOP)); + BuildMI(MBB, MBBI, DL, TII.get(SP::NOP)); + BuildMI(MBB, MBBI, DL, TII.get(SP::NOP)); + BuildMI(MBB, MBBI, DL, TII.get(SP::NOP)); + BuildMI(MBB, MBBI, DL, TII.get(SP::NOP)); + + Modified = true; + } else if (MI.isInlineAsm()) { + StringRef AsmString = + MI.getOperand(InlineAsm::MIOp_AsmString).getSymbolName(); + if (AsmString.startswith_lower("swap") || + AsmString.startswith_lower("ldstub")) { + // this is an inline swap or ldstub instruction + + // insert flush and 5 NOPs before the swap/ldstub instruction + BuildMI(MBB, MBBI, DL, TII.get(SP::FLUSH)); + BuildMI(MBB, MBBI, DL, TII.get(SP::NOP)); + BuildMI(MBB, MBBI, DL, TII.get(SP::NOP)); + BuildMI(MBB, MBBI, DL, TII.get(SP::NOP)); + BuildMI(MBB, MBBI, DL, TII.get(SP::NOP)); + BuildMI(MBB, MBBI, DL, TII.get(SP::NOP)); + + Modified = true; + } + } + } + } + + return Modified; +} + +//***************************************************************************** +//**** InsertNOPsLoadStore pass +//***************************************************************************** +// This pass shall insert NOPs between floating point loads and stores when the +// following circumstances are present [5]: +// Pattern 1: +// 1. single-precision load or single-precision FPOP to register %fX, where X is +// the same register as the store being checked; +// 2. single-precision load or single-precision FPOP to register %fY , where Y +// is the opposite register in the same double-precision pair; +// 3. 0-3 instructions of any kind, except stores from %fX or %fY or operations +// with %fX as destination; +// 4. the store (from register %fX) being considered. +// Pattern 2: +// 1. double-precision FPOP; +// 2. any number of operations on any kind, except no double-precision FPOP and +// at most one (less than two) single-precision or single-to-double FPOPs; +// 3. the store (from register %fX) being considered. +// +char InsertNOPsLoadStore::ID = 0; + +InsertNOPsLoadStore::InsertNOPsLoadStore(TargetMachine &tm) + : LEONMachineFunctionPass(tm, ID) {} + +bool InsertNOPsLoadStore::runOnMachineFunction(MachineFunction &MF) { + Subtarget = &MF.getSubtarget<SparcSubtarget>(); + const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); + DebugLoc DL = DebugLoc(); + + MachineInstr *Pattern1FirstInstruction = NULL; + MachineInstr *Pattern2FirstInstruction = NULL; + unsigned int StoreInstructionsToCheck = 0; + int FxRegIndex, FyRegIndex; + + bool Modified = false; + for (auto MFI = MF.begin(), E = MF.end(); MFI != E; ++MFI) { + MachineBasicBlock &MBB = *MFI; + for (auto MBBI = MBB.begin(), E = MBB.end(); MBBI != E; ++MBBI) { + MachineInstr &MI = *MBBI; + + if (StoreInstructionsToCheck > 0) { + if (((MI.getOpcode() == SP::STFrr || MI.getOpcode() == SP::STFri) && + (GetRegIndexForOperand(MI, LAST_OPERAND) == FxRegIndex || + GetRegIndexForOperand(MI, LAST_OPERAND) == FyRegIndex)) || + GetRegIndexForOperand(MI, 0) == FxRegIndex) { + // Insert four NOPs + for (unsigned InsertedCount = 0; InsertedCount < 4; InsertedCount++) { + BuildMI(MBB, MBBI, DL, TII.get(SP::NOP)); + } + Modified = true; + } + StoreInstructionsToCheck--; + } + + switch (MI.getOpcode()) { + // Watch for Pattern 1 FPop instructions + case SP::LDrr: + case SP::LDri: + case SP::LDFrr: + case SP::LDFri: + case SP::FADDS: + case SP::FSUBS: + case SP::FMULS: + case SP::FDIVS: + case SP::FSQRTS: + case SP::FCMPS: + case SP::FMOVS: + case SP::FNEGS: + case SP::FABSS: + case SP::FITOS: + case SP::FSTOI: + case SP::FITOD: + case SP::FDTOI: + case SP::FDTOS: + if (Pattern1FirstInstruction != NULL) { + FxRegIndex = GetRegIndexForOperand(*Pattern1FirstInstruction, 0); + FyRegIndex = GetRegIndexForOperand(MI, 0); + + // Check to see if these registers are part of the same double + // precision + // register pair. + int DoublePrecRegIndexForX = (FxRegIndex - SP::F0) / 2; + int DoublePrecRegIndexForY = (FyRegIndex - SP::F0) / 2; + + if (DoublePrecRegIndexForX == DoublePrecRegIndexForY) + StoreInstructionsToCheck = 4; + } + + Pattern1FirstInstruction = &MI; + break; + // End of Pattern 1 + + // Search for Pattern 2 + case SP::FADDD: + case SP::FSUBD: + case SP::FMULD: + case SP::FDIVD: + case SP::FSQRTD: + case SP::FCMPD: + Pattern2FirstInstruction = &MI; + Pattern1FirstInstruction = NULL; + break; + + case SP::STFrr: + case SP::STFri: + case SP::STDFrr: + case SP::STDFri: + if (Pattern2FirstInstruction != NULL) { + if (GetRegIndexForOperand(MI, LAST_OPERAND) == + GetRegIndexForOperand(*Pattern2FirstInstruction, 0)) { + // Insert four NOPs + for (unsigned InsertedCount = 0; InsertedCount < 4; + InsertedCount++) { + BuildMI(MBB, MBBI, DL, TII.get(SP::NOP)); + } + + Pattern2FirstInstruction = NULL; + } + } + Pattern1FirstInstruction = NULL; + break; + // End of Pattern 2 + + default: + // Ensure we don't count debug-only values while we're testing for the + // patterns. + if (!MI.isDebugValue()) + Pattern1FirstInstruction = NULL; + break; + } + } + } + + return Modified; +} diff --git a/lib/Target/Sparc/LeonPasses.h b/lib/Target/Sparc/LeonPasses.h new file mode 100755 index 000000000000..5e21813ed029 --- /dev/null +++ b/lib/Target/Sparc/LeonPasses.h @@ -0,0 +1,199 @@ +//===------- LeonPasses.h - Define passes specific to LEON ----------------===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_SPARC_LEON_PASSES_H +#define LLVM_LIB_TARGET_SPARC_LEON_PASSES_H + +#include "llvm/CodeGen/MachineBasicBlock.h" +#include "llvm/CodeGen/MachineFunctionPass.h" +#include "llvm/CodeGen/Passes.h" + +#include "Sparc.h" +#include "SparcSubtarget.h" + +namespace llvm { +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() { UsedRegisters.clear(); } + + void markRegisterUsed(int registerIndex) { + UsedRegisters.push_back(registerIndex); + } + int getUnusedFPRegister(MachineRegisterInfo &MRI); +}; + +class LLVM_LIBRARY_VISIBILITY ReplaceSDIV : public LEONMachineFunctionPass { +public: + static char ID; + + ReplaceSDIV(); + ReplaceSDIV(TargetMachine &tm); + bool runOnMachineFunction(MachineFunction &MF) override; + + const char *getPassName() const override { + return "ReplaceSDIV: Erratum Fix LBR25: do not emit SDIV, but emit SDIVCC " + "instead"; + } +}; + +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: Erratum Fix LBR26: restrict the size of the immediate " + "operand of the CALL instruction to 20 bits"; + } +}; + +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: Erratum Fix LBR28: do not rely on the zero bit " + "flag on a divide overflow for SDIVCC and UDIVCC"; + } +}; + +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: Erratum Fix LBR30: insert a NOP before " + "the double precision floating point 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 PreventRoundChange + : public LEONMachineFunctionPass { +public: + static char ID; + + PreventRoundChange(TargetMachine &tm); + bool runOnMachineFunction(MachineFunction &MF) override; + + const char *getPassName() const override { + return "PreventRoundChange: Erratum Fix LBR33: prevent any rounding mode " + "change request: use only the round-to-nearest rounding mode"; + } +}; + +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"; + } +}; + +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: 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: + static char ID; + + InsertNOPsLoadStore(TargetMachine &tm); + bool runOnMachineFunction(MachineFunction &MF) override; + + const char *getPassName() const override { + return "InsertNOPsLoadStore: Erratum Fix LBR37: 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 diff --git a/lib/Target/Sparc/MCTargetDesc/Makefile b/lib/Target/Sparc/MCTargetDesc/Makefile deleted file mode 100644 index abcbe2da18ec..000000000000 --- a/lib/Target/Sparc/MCTargetDesc/Makefile +++ /dev/null @@ -1,16 +0,0 @@ -##===- lib/Target/Sparc/TargetDesc/Makefile ----------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../../../.. -LIBRARYNAME = LLVMSparcDesc - -# Hack: we need to include 'main' target directory to grab private headers -CPP.Flags += -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. - -include $(LEVEL)/Makefile.common diff --git a/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp b/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp index d1d7aaa07eab..14a70d862f11 100644 --- a/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp +++ b/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp @@ -248,7 +248,8 @@ namespace { llvm_unreachable("fixupNeedsRelaxation() unimplemented"); return false; } - void relaxInstruction(const MCInst &Inst, MCInst &Res) const override { + void relaxInstruction(const MCInst &Inst, const MCSubtargetInfo &STI, + MCInst &Res) const override { // FIXME. llvm_unreachable("relaxInstruction() unimplemented"); } diff --git a/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp b/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp index 0be60fd7a051..d35e45e03466 100644 --- a/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp +++ b/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp @@ -29,8 +29,8 @@ namespace { ~SparcELFObjectWriter() override {} protected: - unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup, - bool IsPCRel) const override; + unsigned getRelocType(MCContext &Ctx, const MCValue &Target, + const MCFixup &Fixup, bool IsPCRel) const override; bool needsRelocateWithSymbol(const MCSymbol &Sym, unsigned Type) const override; @@ -38,7 +38,8 @@ namespace { }; } -unsigned SparcELFObjectWriter::GetRelocType(const MCValue &Target, +unsigned SparcELFObjectWriter::getRelocType(MCContext &Ctx, + const MCValue &Target, const MCFixup &Fixup, bool IsPCRel) const { diff --git a/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp b/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp index 9171d4dc9c00..45bc4a1de01b 100644 --- a/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp +++ b/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp @@ -22,6 +22,7 @@ #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSymbol.h" #include "llvm/MC/MCAsmInfo.h" +#include "llvm/Support/EndianStream.h" #include "llvm/Support/raw_ostream.h" using namespace llvm; diff --git a/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp b/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp index 9113e4a46b96..dceaca791aab 100644 --- a/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp +++ b/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp @@ -15,7 +15,6 @@ #include "InstPrinter/SparcInstPrinter.h" #include "SparcMCAsmInfo.h" #include "SparcTargetStreamer.h" -#include "llvm/MC/MCCodeGenInfo.h" #include "llvm/MC/MCInstrInfo.h" #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSubtargetInfo.h" @@ -81,12 +80,8 @@ createSparcMCSubtargetInfo(const Triple &TT, StringRef CPU, StringRef FS) { // // All code models require that the text segment is smaller than 2GB. -static MCCodeGenInfo *createSparcMCCodeGenInfo(const Triple &TT, - Reloc::Model RM, - CodeModel::Model CM, - CodeGenOpt::Level OL) { - MCCodeGenInfo *X = new MCCodeGenInfo(); - +static void adjustCodeGenOpts(const Triple &TT, Reloc::Model RM, + CodeModel::Model &CM) { // The default 32-bit code model is abs32/pic32 and the default 32-bit // code model for JIT is abs32. switch (CM) { @@ -94,17 +89,10 @@ static MCCodeGenInfo *createSparcMCCodeGenInfo(const Triple &TT, case CodeModel::Default: case CodeModel::JITDefault: CM = CodeModel::Small; break; } - - X->initMCCodeGenInfo(RM, CM, OL); - return X; } -static MCCodeGenInfo *createSparcV9MCCodeGenInfo(const Triple &TT, - Reloc::Model RM, - CodeModel::Model CM, - CodeGenOpt::Level OL) { - MCCodeGenInfo *X = new MCCodeGenInfo(); - +static void adjustCodeGenOptsV9(const Triple &TT, Reloc::Model RM, + CodeModel::Model &CM) { // The default 64-bit code model is abs44/pic32 and the default 64-bit // code model for JIT is abs64. switch (CM) { @@ -116,9 +104,6 @@ static MCCodeGenInfo *createSparcV9MCCodeGenInfo(const Triple &TT, CM = CodeModel::Large; break; } - - X->initMCCodeGenInfo(RM, CM, OL); - return X; } static MCTargetStreamer * @@ -175,10 +160,10 @@ extern "C" void LLVMInitializeSparcTargetMC() { } // Register the MC codegen info. - TargetRegistry::RegisterMCCodeGenInfo(TheSparcTarget, - createSparcMCCodeGenInfo); - TargetRegistry::RegisterMCCodeGenInfo(TheSparcV9Target, - createSparcV9MCCodeGenInfo); - TargetRegistry::RegisterMCCodeGenInfo(TheSparcelTarget, - createSparcMCCodeGenInfo); + TargetRegistry::registerMCAdjustCodeGenOpts(TheSparcTarget, + adjustCodeGenOpts); + TargetRegistry::registerMCAdjustCodeGenOpts(TheSparcV9Target, + adjustCodeGenOptsV9); + TargetRegistry::registerMCAdjustCodeGenOpts(TheSparcelTarget, + adjustCodeGenOpts); } diff --git a/lib/Target/Sparc/Makefile b/lib/Target/Sparc/Makefile deleted file mode 100644 index c2a95b47151a..000000000000 --- a/lib/Target/Sparc/Makefile +++ /dev/null @@ -1,24 +0,0 @@ -##===- lib/Target/Sparc/Makefile ---------------------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## - -LEVEL = ../../.. -LIBRARYNAME = LLVMSparcCodeGen -TARGET = Sparc - -# Make sure that tblgen is run, first thing. -BUILT_SOURCES = SparcGenRegisterInfo.inc SparcGenInstrInfo.inc \ - SparcGenAsmWriter.inc SparcGenAsmMatcher.inc \ - SparcGenDAGISel.inc SparcGenDisassemblerTables.inc \ - SparcGenSubtargetInfo.inc SparcGenCallingConv.inc \ - SparcGenMCCodeEmitter.inc - -DIRS = InstPrinter AsmParser Disassembler TargetInfo MCTargetDesc - -include $(LEVEL)/Makefile.common - diff --git a/lib/Target/Sparc/README.txt b/lib/Target/Sparc/README.txt index 647c2763e521..d7686eba7af6 100644 --- a/lib/Target/Sparc/README.txt +++ b/lib/Target/Sparc/README.txt @@ -1,4 +1,3 @@ - To-do ----- diff --git a/lib/Target/Sparc/Sparc.h b/lib/Target/Sparc/Sparc.h index 96378d522dc0..0a8272d89297 100644 --- a/lib/Target/Sparc/Sparc.h +++ b/lib/Target/Sparc/Sparc.h @@ -72,7 +72,24 @@ namespace llvm { FCC_UGE = 12+16, // Unordered or Greater or Equal FCC_LE = 13+16, // Less or Equal FCC_ULE = 14+16, // Unordered or Less or Equal - FCC_O = 15+16 // Ordered + FCC_O = 15+16, // Ordered + + CPCC_A = 8+32, // Always + CPCC_N = 0+32, // Never + CPCC_3 = 7+32, + CPCC_2 = 6+32, + CPCC_23 = 5+32, + CPCC_1 = 4+32, + CPCC_13 = 3+32, + CPCC_12 = 2+32, + CPCC_123 = 1+32, + CPCC_0 = 9+32, + CPCC_03 = 10+32, + CPCC_02 = 11+32, + CPCC_023 = 12+32, + CPCC_01 = 13+32, + CPCC_013 = 14+32, + CPCC_012 = 15+32 }; } @@ -110,6 +127,22 @@ namespace llvm { case SPCC::FCC_LE: return "le"; case SPCC::FCC_ULE: return "ule"; case SPCC::FCC_O: return "o"; + case SPCC::CPCC_A: return "a"; + case SPCC::CPCC_N: return "n"; + case SPCC::CPCC_3: return "3"; + case SPCC::CPCC_2: return "2"; + case SPCC::CPCC_23: return "23"; + case SPCC::CPCC_1: return "1"; + case SPCC::CPCC_13: return "13"; + case SPCC::CPCC_12: return "12"; + case SPCC::CPCC_123: return "123"; + case SPCC::CPCC_0: return "0"; + case SPCC::CPCC_03: return "03"; + case SPCC::CPCC_02: return "02"; + case SPCC::CPCC_023: return "023"; + case SPCC::CPCC_01: return "01"; + case SPCC::CPCC_013: return "013"; + case SPCC::CPCC_012: return "012"; } llvm_unreachable("Invalid cond code"); } diff --git a/lib/Target/Sparc/Sparc.td b/lib/Target/Sparc/Sparc.td index c34122eef92f..7a3d12448d52 100644 --- a/lib/Target/Sparc/Sparc.td +++ b/lib/Target/Sparc/Sparc.td @@ -21,79 +21,133 @@ include "llvm/Target/Target.td" // def FeatureV9 - : SubtargetFeature<"v9", "IsV9", "true", - "Enable SPARC-V9 instructions">; + : SubtargetFeature<"v9", "IsV9", "true", "Enable SPARC-V9 instructions">; def FeatureV8Deprecated - : SubtargetFeature<"deprecated-v8", "V8DeprecatedInsts", "true", - "Enable deprecated V8 instructions in V9 mode">; + : SubtargetFeature<"deprecated-v8", "V8DeprecatedInsts", "true", + "Enable deprecated V8 instructions in V9 mode">; def FeatureVIS - : SubtargetFeature<"vis", "IsVIS", "true", - "Enable UltraSPARC Visual Instruction Set extensions">; + : SubtargetFeature<"vis", "IsVIS", "true", + "Enable UltraSPARC Visual Instruction Set extensions">; def FeatureVIS2 - : SubtargetFeature<"vis2", "IsVIS2", "true", - "Enable Visual Instruction Set extensions II">; + : SubtargetFeature<"vis2", "IsVIS2", "true", + "Enable Visual Instruction Set extensions II">; def FeatureVIS3 - : SubtargetFeature<"vis3", "IsVIS3", "true", - "Enable Visual Instruction Set extensions III">; + : SubtargetFeature<"vis3", "IsVIS3", "true", + "Enable Visual Instruction Set extensions III">; +def FeatureLeon + : SubtargetFeature<"leon", "IsLeon", "true", "Enable LEON extensions">; def FeatureHardQuad - : SubtargetFeature<"hard-quad-float", "HasHardQuad", "true", - "Enable quad-word floating point instructions">; + : SubtargetFeature<"hard-quad-float", "HasHardQuad", "true", + "Enable quad-word floating point instructions">; def UsePopc : SubtargetFeature<"popc", "UsePopc", "true", "Use the popc (population count) instruction">; +def FeatureSoftFloat + : SubtargetFeature<"soft-float", "UseSoftFloat", "true", + "Use software emulation for floating point">; + +//==== Features added predmoninantly for LEON subtarget support +include "LeonFeatures.td" + //===----------------------------------------------------------------------===// // Register File, Calling Conv, Instruction Descriptions //===----------------------------------------------------------------------===// include "SparcRegisterInfo.td" include "SparcCallingConv.td" +include "SparcSchedule.td" include "SparcInstrInfo.td" def SparcInstrInfo : InstrInfo; -def SparcAsmParser : AsmParser { - bit ShouldEmitMatchRegisterName = 0; -} +def SparcAsmParser : AsmParser { bit ShouldEmitMatchRegisterName = 0; } //===----------------------------------------------------------------------===// // SPARC processors supported. //===----------------------------------------------------------------------===// class Proc<string Name, list<SubtargetFeature> Features> - : Processor<Name, NoItineraries, Features>; - -def : Proc<"generic", []>; -def : Proc<"v7", []>; -def : Proc<"v8", []>; -def : Proc<"supersparc", []>; -def : Proc<"sparclite", []>; -def : Proc<"f934", []>; -def : Proc<"hypersparc", []>; -def : Proc<"sparclite86x", []>; -def : Proc<"sparclet", []>; -def : Proc<"tsc701", []>; -def : Proc<"v9", [FeatureV9]>; -def : Proc<"ultrasparc", [FeatureV9, FeatureV8Deprecated, FeatureVIS]>; -def : Proc<"ultrasparc3", [FeatureV9, FeatureV8Deprecated, FeatureVIS, - FeatureVIS2]>; -def : Proc<"niagara", [FeatureV9, FeatureV8Deprecated, FeatureVIS, - FeatureVIS2]>; -def : Proc<"niagara2", [FeatureV9, FeatureV8Deprecated, UsePopc, - FeatureVIS, FeatureVIS2]>; -def : Proc<"niagara3", [FeatureV9, FeatureV8Deprecated, UsePopc, - FeatureVIS, FeatureVIS2]>; -def : Proc<"niagara4", [FeatureV9, FeatureV8Deprecated, UsePopc, - FeatureVIS, FeatureVIS2, FeatureVIS3]>; - + : Processor<Name, NoItineraries, Features>; + +def : Proc<"generic", []>; +def : Proc<"v7", []>; +def : Proc<"v8", []>; +def : Proc<"supersparc", []>; +def : Proc<"sparclite", []>; +def : Proc<"f934", []>; +def : Proc<"hypersparc", []>; +def : Proc<"sparclite86x", []>; +def : Proc<"sparclet", []>; +def : Proc<"tsc701", []>; +def : Proc<"myriad2", []>; +def : Proc<"myriad2.1", []>; +def : Proc<"myriad2.2", []>; +def : Proc<"v9", [ FeatureV9 ]>; +def : Proc<"ultrasparc", [ FeatureV9, FeatureV8Deprecated, FeatureVIS ]>; +def : Proc<"ultrasparc3", + [ FeatureV9, FeatureV8Deprecated, FeatureVIS, FeatureVIS2 ]>; +def : Proc<"niagara", + [ FeatureV9, FeatureV8Deprecated, FeatureVIS, FeatureVIS2 ]>; +def : Proc<"niagara2", [ + FeatureV9, FeatureV8Deprecated, UsePopc, FeatureVIS, FeatureVIS2 +]>; +def : Proc<"niagara3", [ + FeatureV9, FeatureV8Deprecated, UsePopc, FeatureVIS, FeatureVIS2 +]>; +def : Proc<"niagara4", [ + FeatureV9, FeatureV8Deprecated, UsePopc, FeatureVIS, FeatureVIS2, FeatureVIS3 +]>; + +// LEON 2 FT generic +def : Processor<"leon2", LEON2Itineraries, [ FeatureLeon ]>; + +// LEON 2 FT (AT697E) +// AT697E: Provides full coverage of AT697E - covers all the erratum fixes for +// LEON2 AT697E +def : Processor<"at697e", LEON2Itineraries, [ + FeatureLeon, ReplaceSDIV, FixCALL, IgnoreZeroFlag, InsertNOPDoublePrecision +]>; + +// LEON 2 FT (AT697F) +// AT697F: Provides full coverage of AT697F - covers all the erratum fixes for +// LEON2 AT697F +def : Processor<"at697f", LEON2Itineraries, + [ FeatureLeon, InsertNOPDoublePrecision ]>; + +// LEON 3 FT generic +def : Processor<"leon3", LEON3Itineraries, [ FeatureLeon, UMACSMACSupport ]>; + +// 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, FixFSMULD, ReplaceFMULS, PreventRoundChange, + FixAllFDIVSQRT, InsertNOPLoad, FlushCacheLineSWAP, InsertNOPsLoadStore +]>; + +// LEON3 FT (GR712RC). Provides features for the GR712RC processor. +// - covers all the erratum fixed for LEON3 and support for the CASA +// instruction. +def : Processor<"gr712rc", LEON3Itineraries, + [ FeatureLeon, LeonCASA ]>; + +// LEON 4 FT generic +def : Processor<"leon4", LEON4Itineraries, + [ FeatureLeon, LeonCASA ]>; + +// GR740: Provides full coverage of GR740 - covers all the erratum fixes for +// LEON3 + support to CASA + LEON 4 instruction timings +def : Processor<"gr740", LEON4Itineraries, + [ FeatureLeon, LeonCASA ]> {} //===----------------------------------------------------------------------===// // Declare the target which we are implementing //===----------------------------------------------------------------------===// def SparcAsmWriter : AsmWriter { - string AsmWriterClassName = "InstPrinter"; + string AsmWriterClassName = "InstPrinter"; int PassSubtarget = 1; int Variant = 0; } @@ -101,6 +155,6 @@ def SparcAsmWriter : AsmWriter { def Sparc : Target { // Pull in Instruction Info: let InstructionSet = SparcInstrInfo; - let AssemblyParsers = [SparcAsmParser]; - let AssemblyWriters = [SparcAsmWriter]; + let AssemblyParsers = [ SparcAsmParser ]; + let AssemblyWriters = [ SparcAsmWriter ]; } diff --git a/lib/Target/Sparc/SparcAsmPrinter.cpp b/lib/Target/Sparc/SparcAsmPrinter.cpp index e3b0f5266747..c068440f7c05 100644 --- a/lib/Target/Sparc/SparcAsmPrinter.cpp +++ b/lib/Target/Sparc/SparcAsmPrinter.cpp @@ -18,7 +18,6 @@ #include "SparcInstrInfo.h" #include "SparcTargetMachine.h" #include "SparcTargetStreamer.h" -#include "llvm/ADT/SmallString.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/MachineInstr.h" #include "llvm/CodeGen/MachineModuleInfoImpls.h" @@ -54,7 +53,6 @@ namespace { void printOperand(const MachineInstr *MI, int opNum, raw_ostream &OS); void printMemOperand(const MachineInstr *MI, int opNum, raw_ostream &OS, const char *Modifier = nullptr); - void printCCOperand(const MachineInstr *MI, int opNum, raw_ostream &OS); void EmitFunctionBodyStart() override; void EmitInstruction(const MachineInstr *MI) override; @@ -185,7 +183,7 @@ void SparcAsmPrinter::LowerGETPCXAndEmitMCInsts(const MachineInstr *MI, MCOperand MCRegOP = MCOperand::createReg(MO.getReg()); - if (TM.getRelocationModel() != Reloc::PIC_) { + if (!isPositionIndependent()) { // Just load the address of GOT to MCRegOP. switch(TM.getCodeModel()) { default: @@ -376,6 +374,9 @@ void SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum, O << DL.getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_" << MO.getIndex(); break; + case MachineOperand::MO_Metadata: + MO.getMetadata()->printAsOperand(O, MMI->getModule()); + break; default: llvm_unreachable("<unknown operand type>"); } @@ -417,6 +418,7 @@ bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo, default: // See if this is a generic print operand return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O); + case 'f': case 'r': break; } diff --git a/lib/Target/Sparc/SparcFrameLowering.cpp b/lib/Target/Sparc/SparcFrameLowering.cpp index 39b5e809c9be..87b01553b37e 100644 --- a/lib/Target/Sparc/SparcFrameLowering.cpp +++ b/lib/Target/Sparc/SparcFrameLowering.cpp @@ -146,7 +146,7 @@ void SparcFrameLowering::emitPrologue(MachineFunction &MF, // Finally, ensure that the size is sufficiently aligned for the // data on the stack. if (MFI->getMaxAlignment() > 0) { - NumBytes = RoundUpToAlignment(NumBytes, MFI->getMaxAlignment()); + NumBytes = alignTo(NumBytes, MFI->getMaxAlignment()); } // Update stack size with corrected value. @@ -183,7 +183,7 @@ void SparcFrameLowering::emitPrologue(MachineFunction &MF, } } -void SparcFrameLowering:: +MachineBasicBlock::iterator SparcFrameLowering:: eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const { if (!hasReservedCallFrame(MF)) { @@ -195,7 +195,7 @@ eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, if (Size) emitSPAdjustment(MF, MBB, I, Size, SP::ADDrr, SP::ADDri); } - MBB.erase(I); + return MBB.erase(I); } @@ -350,7 +350,7 @@ void SparcFrameLowering::remapRegsForLeafProc(MachineFunction &MF) const { } assert(verifyLeafProcRegUse(&MRI)); -#ifdef XDEBUG +#ifdef EXPENSIVE_CHECKS MF.verify(0, "After LeafProc Remapping"); #endif } diff --git a/lib/Target/Sparc/SparcFrameLowering.h b/lib/Target/Sparc/SparcFrameLowering.h index cbb4dc04fc23..ac0e69ccde1e 100644 --- a/lib/Target/Sparc/SparcFrameLowering.h +++ b/lib/Target/Sparc/SparcFrameLowering.h @@ -29,7 +29,7 @@ public: void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override; void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override; - void + MachineBasicBlock::iterator eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB, MachineBasicBlock::iterator I) const override; diff --git a/lib/Target/Sparc/SparcISelDAGToDAG.cpp b/lib/Target/Sparc/SparcISelDAGToDAG.cpp index c4c641659df3..07948a33cde6 100644 --- a/lib/Target/Sparc/SparcISelDAGToDAG.cpp +++ b/lib/Target/Sparc/SparcISelDAGToDAG.cpp @@ -15,7 +15,6 @@ #include "llvm/CodeGen/MachineRegisterInfo.h" #include "llvm/CodeGen/SelectionDAGISel.h" #include "llvm/IR/Intrinsics.h" -#include "llvm/Support/Compiler.h" #include "llvm/Support/Debug.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/raw_ostream.h" @@ -42,7 +41,7 @@ public: return SelectionDAGISel::runOnMachineFunction(MF); } - SDNode *Select(SDNode *N) override; + void Select(SDNode *N) override; // Complex Pattern Selectors. bool SelectADDRrr(SDValue N, SDValue &R1, SDValue &R2); @@ -63,7 +62,7 @@ public: private: SDNode* getGlobalBaseReg(); - SDNode *SelectInlineAsm(SDNode *N); + bool tryInlineAsm(SDNode *N); }; } // end anonymous namespace @@ -155,7 +154,7 @@ bool SparcDAGToDAGISel::SelectADDRrr(SDValue Addr, SDValue &R1, SDValue &R2) { // TODO: fix inline asm support so I can simply tell it that 'i64' // inputs to asm need to be allocated to the IntPair register type, // and have that work. Then, delete this function. -SDNode *SparcDAGToDAGISel::SelectInlineAsm(SDNode *N){ +bool SparcDAGToDAGISel::tryInlineAsm(SDNode *N){ std::vector<SDValue> AsmNodeOperands; unsigned Flag, Kind; bool Changed = false; @@ -310,31 +309,32 @@ SDNode *SparcDAGToDAGISel::SelectInlineAsm(SDNode *N){ if (Glue.getNode()) AsmNodeOperands.push_back(Glue); if (!Changed) - return nullptr; + return false; SDValue New = CurDAG->getNode(ISD::INLINEASM, SDLoc(N), CurDAG->getVTList(MVT::Other, MVT::Glue), AsmNodeOperands); New->setNodeId(-1); - return New.getNode(); + ReplaceNode(N, New.getNode()); + return true; } -SDNode *SparcDAGToDAGISel::Select(SDNode *N) { +void SparcDAGToDAGISel::Select(SDNode *N) { SDLoc dl(N); if (N->isMachineOpcode()) { N->setNodeId(-1); - return nullptr; // Already selected. + return; // Already selected. } switch (N->getOpcode()) { default: break; - case ISD::INLINEASM: { - SDNode *ResNode = SelectInlineAsm(N); - if (ResNode) - return ResNode; + case ISD::INLINEASM: { + if (tryInlineAsm(N)) + return; break; } case SPISD::GLOBAL_BASE_REG: - return getGlobalBaseReg(); + ReplaceNode(N, getGlobalBaseReg()); + return; case ISD::SDIV: case ISD::UDIV: { @@ -360,8 +360,8 @@ SDNode *SparcDAGToDAGISel::Select(SDNode *N) { // FIXME: Handle div by immediate. unsigned Opcode = N->getOpcode() == ISD::SDIV ? SP::SDIVrr : SP::UDIVrr; - return CurDAG->SelectNodeTo(N, Opcode, MVT::i32, DivLHS, DivRHS, - TopPart); + CurDAG->SelectNodeTo(N, Opcode, MVT::i32, DivLHS, DivRHS, TopPart); + return; } case ISD::MULHU: case ISD::MULHS: { @@ -373,11 +373,12 @@ SDNode *SparcDAGToDAGISel::Select(SDNode *N) { CurDAG->getMachineNode(Opcode, dl, MVT::i32, MVT::i32, MulLHS, MulRHS); SDValue ResultHigh = SDValue(Mul, 1); ReplaceUses(SDValue(N, 0), ResultHigh); - return nullptr; + CurDAG->RemoveDeadNode(N); + return; } } - return SelectCode(N); + SelectCode(N); } @@ -391,6 +392,7 @@ SparcDAGToDAGISel::SelectInlineAsmMemoryOperand(const SDValue &Op, switch (ConstraintID) { default: return true; case InlineAsm::Constraint_i: + case InlineAsm::Constraint_o: case InlineAsm::Constraint_m: // memory if (!SelectADDRrr(Op, Op0, Op1)) SelectADDRri(Op, Op0, Op1); diff --git a/lib/Target/Sparc/SparcISelLowering.cpp b/lib/Target/Sparc/SparcISelLowering.cpp index 5e70ffe2223c..8738bc82683d 100644 --- a/lib/Target/Sparc/SparcISelLowering.cpp +++ b/lib/Target/Sparc/SparcISelLowering.cpp @@ -18,6 +18,7 @@ #include "SparcRegisterInfo.h" #include "SparcTargetMachine.h" #include "SparcTargetObjectFile.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/CodeGen/CallingConvLower.h" #include "llvm/CodeGen/MachineFrameInfo.h" #include "llvm/CodeGen/MachineFunction.h" @@ -31,7 +32,6 @@ #include "llvm/Support/ErrorHandling.h" using namespace llvm; - //===----------------------------------------------------------------------===// // Calling Convention Implementation //===----------------------------------------------------------------------===// @@ -184,29 +184,30 @@ static bool CC_Sparc64_Half(unsigned &ValNo, MVT &ValVT, // callee's register window. This function translates registers to the // corresponding caller window %o register. static unsigned toCallerWindow(unsigned Reg) { - assert(SP::I0 + 7 == SP::I7 && SP::O0 + 7 == SP::O7 && "Unexpected enum"); + static_assert(SP::I0 + 7 == SP::I7 && SP::O0 + 7 == SP::O7, + "Unexpected enum"); if (Reg >= SP::I0 && Reg <= SP::I7) return Reg - SP::I0 + SP::O0; return Reg; } SDValue -SparcTargetLowering::LowerReturn(SDValue Chain, - CallingConv::ID CallConv, bool IsVarArg, +SparcTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv, + bool IsVarArg, const SmallVectorImpl<ISD::OutputArg> &Outs, const SmallVectorImpl<SDValue> &OutVals, - SDLoc DL, SelectionDAG &DAG) const { + const SDLoc &DL, SelectionDAG &DAG) const { if (Subtarget->is64Bit()) return LowerReturn_64(Chain, CallConv, IsVarArg, Outs, OutVals, DL, DAG); return LowerReturn_32(Chain, CallConv, IsVarArg, Outs, OutVals, DL, DAG); } SDValue -SparcTargetLowering::LowerReturn_32(SDValue Chain, - CallingConv::ID CallConv, bool IsVarArg, +SparcTargetLowering::LowerReturn_32(SDValue Chain, CallingConv::ID CallConv, + bool IsVarArg, const SmallVectorImpl<ISD::OutputArg> &Outs, const SmallVectorImpl<SDValue> &OutVals, - SDLoc DL, SelectionDAG &DAG) const { + const SDLoc &DL, SelectionDAG &DAG) const { MachineFunction &MF = DAG.getMachineFunction(); // CCValAssign - represent the assignment of the return value to locations. @@ -287,11 +288,11 @@ SparcTargetLowering::LowerReturn_32(SDValue Chain, // Lower return values for the 64-bit ABI. // Return values are passed the exactly the same way as function arguments. SDValue -SparcTargetLowering::LowerReturn_64(SDValue Chain, - CallingConv::ID CallConv, bool IsVarArg, +SparcTargetLowering::LowerReturn_64(SDValue Chain, CallingConv::ID CallConv, + bool IsVarArg, const SmallVectorImpl<ISD::OutputArg> &Outs, const SmallVectorImpl<SDValue> &OutVals, - SDLoc DL, SelectionDAG &DAG) const { + const SDLoc &DL, SelectionDAG &DAG) const { // CCValAssign - represent the assignment of the return value to locations. SmallVector<CCValAssign, 16> RVLocs; @@ -363,14 +364,10 @@ SparcTargetLowering::LowerReturn_64(SDValue Chain, return DAG.getNode(SPISD::RET_FLAG, DL, MVT::Other, RetOps); } -SDValue SparcTargetLowering:: -LowerFormalArguments(SDValue Chain, - CallingConv::ID CallConv, - bool IsVarArg, - const SmallVectorImpl<ISD::InputArg> &Ins, - SDLoc DL, - SelectionDAG &DAG, - SmallVectorImpl<SDValue> &InVals) const { +SDValue SparcTargetLowering::LowerFormalArguments( + SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL, + SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { if (Subtarget->is64Bit()) return LowerFormalArguments_64(Chain, CallConv, IsVarArg, Ins, DL, DAG, InVals); @@ -381,14 +378,10 @@ LowerFormalArguments(SDValue Chain, /// LowerFormalArguments32 - V8 uses a very simple ABI, where all values are /// passed in either one or two GPRs, including FP values. TODO: we should /// pass FP values in FP registers for fastcc functions. -SDValue SparcTargetLowering:: -LowerFormalArguments_32(SDValue Chain, - CallingConv::ID CallConv, - bool isVarArg, - const SmallVectorImpl<ISD::InputArg> &Ins, - SDLoc dl, - SelectionDAG &DAG, - SmallVectorImpl<SDValue> &InVals) const { +SDValue SparcTargetLowering::LowerFormalArguments_32( + SDValue Chain, CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &dl, + SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { MachineFunction &MF = DAG.getMachineFunction(); MachineRegisterInfo &RegInfo = MF.getRegInfo(); SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>(); @@ -412,9 +405,8 @@ LowerFormalArguments_32(SDValue Chain, // Get SRet from [%fp+64]. int FrameIdx = MF.getFrameInfo()->CreateFixedObject(4, 64, true); SDValue FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32); - SDValue Arg = DAG.getLoad(MVT::i32, dl, Chain, FIPtr, - MachinePointerInfo(), - false, false, false, 0); + SDValue Arg = + DAG.getLoad(MVT::i32, dl, Chain, FIPtr, MachinePointerInfo()); InVals.push_back(Arg); continue; } @@ -435,9 +427,7 @@ LowerFormalArguments_32(SDValue Chain, int FrameIdx = MF.getFrameInfo()-> CreateFixedObject(4, StackOffset+NextVA.getLocMemOffset(),true); SDValue FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32); - LoVal = DAG.getLoad(MVT::i32, dl, Chain, FIPtr, - MachinePointerInfo(), - false, false, false, 0); + LoVal = DAG.getLoad(MVT::i32, dl, Chain, FIPtr, MachinePointerInfo()); } else { unsigned loReg = MF.addLiveIn(NextVA.getLocReg(), &SP::IntRegsRegClass); @@ -473,16 +463,15 @@ LowerFormalArguments_32(SDValue Chain, auto PtrVT = getPointerTy(DAG.getDataLayout()); if (VA.needsCustom()) { - assert(VA.getValVT() == MVT::f64 || MVT::v2i32); + assert(VA.getValVT() == MVT::f64 || VA.getValVT() == MVT::v2i32); // If it is double-word aligned, just load. if (Offset % 8 == 0) { int FI = MF.getFrameInfo()->CreateFixedObject(8, Offset, true); SDValue FIPtr = DAG.getFrameIndex(FI, PtrVT); - SDValue Load = DAG.getLoad(VA.getValVT(), dl, Chain, FIPtr, - MachinePointerInfo(), - false,false, false, 0); + SDValue Load = + DAG.getLoad(VA.getValVT(), dl, Chain, FIPtr, MachinePointerInfo()); InVals.push_back(Load); continue; } @@ -491,17 +480,15 @@ LowerFormalArguments_32(SDValue Chain, Offset, true); SDValue FIPtr = DAG.getFrameIndex(FI, PtrVT); - SDValue HiVal = DAG.getLoad(MVT::i32, dl, Chain, FIPtr, - MachinePointerInfo(), - false, false, false, 0); + SDValue HiVal = + DAG.getLoad(MVT::i32, dl, Chain, FIPtr, MachinePointerInfo()); int FI2 = MF.getFrameInfo()->CreateFixedObject(4, Offset+4, true); SDValue FIPtr2 = DAG.getFrameIndex(FI2, PtrVT); - SDValue LoVal = DAG.getLoad(MVT::i32, dl, Chain, FIPtr2, - MachinePointerInfo(), - false, false, false, 0); + SDValue LoVal = + DAG.getLoad(MVT::i32, dl, Chain, FIPtr2, MachinePointerInfo()); if (IsLittleEndian) std::swap(LoVal, HiVal); @@ -519,9 +506,7 @@ LowerFormalArguments_32(SDValue Chain, SDValue FIPtr = DAG.getFrameIndex(FI, PtrVT); SDValue Load ; if (VA.getValVT() == MVT::i32 || VA.getValVT() == MVT::f32) { - Load = DAG.getLoad(VA.getValVT(), dl, Chain, FIPtr, - MachinePointerInfo(), - false, false, false, 0); + Load = DAG.getLoad(VA.getValVT(), dl, Chain, FIPtr, MachinePointerInfo()); } else if (VA.getValVT() == MVT::f128) { report_fatal_error("SPARCv8 does not handle f128 in calls; " "pass indirectly"); @@ -573,9 +558,8 @@ LowerFormalArguments_32(SDValue Chain, true); SDValue FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32); - OutChains.push_back(DAG.getStore(DAG.getRoot(), dl, Arg, FIPtr, - MachinePointerInfo(), - false, false, 0)); + OutChains.push_back( + DAG.getStore(DAG.getRoot(), dl, Arg, FIPtr, MachinePointerInfo())); ArgOffset += 4; } @@ -589,14 +573,10 @@ LowerFormalArguments_32(SDValue Chain, } // Lower formal arguments for the 64 bit ABI. -SDValue SparcTargetLowering:: -LowerFormalArguments_64(SDValue Chain, - CallingConv::ID CallConv, - bool IsVarArg, - const SmallVectorImpl<ISD::InputArg> &Ins, - SDLoc DL, - SelectionDAG &DAG, - SmallVectorImpl<SDValue> &InVals) const { +SDValue SparcTargetLowering::LowerFormalArguments_64( + SDValue Chain, CallingConv::ID CallConv, bool IsVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, const SDLoc &DL, + SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const { MachineFunction &MF = DAG.getMachineFunction(); // Analyze arguments according to CC_Sparc64. @@ -659,10 +639,10 @@ LowerFormalArguments_64(SDValue Chain, if (VA.isExtInLoc()) Offset += 8 - ValSize; int FI = MF.getFrameInfo()->CreateFixedObject(ValSize, Offset, true); - InVals.push_back(DAG.getLoad( - VA.getValVT(), DL, Chain, - DAG.getFrameIndex(FI, getPointerTy(MF.getDataLayout())), - MachinePointerInfo::getFixedStack(MF, FI), false, false, false, 0)); + InVals.push_back( + DAG.getLoad(VA.getValVT(), DL, Chain, + DAG.getFrameIndex(FI, getPointerTy(MF.getDataLayout())), + MachinePointerInfo::getFixedStack(MF, FI))); } if (!IsVarArg) @@ -690,9 +670,9 @@ LowerFormalArguments_64(SDValue Chain, SDValue VArg = DAG.getCopyFromReg(Chain, DL, VReg, MVT::i64); int FI = MF.getFrameInfo()->CreateFixedObject(8, ArgOffset + ArgArea, true); auto PtrVT = getPointerTy(MF.getDataLayout()); - OutChains.push_back(DAG.getStore( - Chain, DL, VArg, DAG.getFrameIndex(FI, PtrVT), - MachinePointerInfo::getFixedStack(MF, FI), false, false, 0)); + OutChains.push_back( + DAG.getStore(Chain, DL, VArg, DAG.getFrameIndex(FI, PtrVT), + MachinePointerInfo::getFixedStack(MF, FI))); } if (!OutChains.empty()) @@ -773,16 +753,22 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI, unsigned Size = Flags.getByValSize(); unsigned Align = Flags.getByValAlign(); - int FI = MFI->CreateStackObject(Size, Align, false); - SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); - SDValue SizeNode = DAG.getConstant(Size, dl, MVT::i32); - - Chain = DAG.getMemcpy(Chain, dl, FIPtr, Arg, SizeNode, Align, - false, // isVolatile, - (Size <= 32), // AlwaysInline if size <= 32, - false, // isTailCall - MachinePointerInfo(), MachinePointerInfo()); - ByValArgs.push_back(FIPtr); + if (Size > 0U) { + int FI = MFI->CreateStackObject(Size, Align, false); + SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); + SDValue SizeNode = DAG.getConstant(Size, dl, MVT::i32); + + Chain = DAG.getMemcpy(Chain, dl, FIPtr, Arg, SizeNode, Align, + false, // isVolatile, + (Size <= 32), // AlwaysInline if size <= 32, + false, // isTailCall + MachinePointerInfo(), MachinePointerInfo()); + ByValArgs.push_back(FIPtr); + } + else { + SDValue nullVal; + ByValArgs.push_back(nullVal); + } } Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(ArgsSize, dl, true), @@ -803,8 +789,12 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI, ISD::ArgFlagsTy Flags = Outs[realArgIdx].Flags; // Use local copy if it is a byval arg. - if (Flags.isByVal()) + if (Flags.isByVal()) { Arg = ByValArgs[byvalArgIdx++]; + if (!Arg) { + continue; + } + } // Promote the value if needed. switch (VA.getLocInfo()) { @@ -830,9 +820,8 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI, SDValue StackPtr = DAG.getRegister(SP::O6, MVT::i32); SDValue PtrOff = DAG.getIntPtrConstant(64, dl); PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, PtrOff); - MemOpChains.push_back(DAG.getStore(Chain, dl, Arg, PtrOff, - MachinePointerInfo(), - false, false, 0)); + MemOpChains.push_back( + DAG.getStore(Chain, dl, Arg, PtrOff, MachinePointerInfo())); hasStructRetAttr = true; continue; } @@ -847,9 +836,8 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI, SDValue StackPtr = DAG.getRegister(SP::O6, MVT::i32); SDValue PtrOff = DAG.getIntPtrConstant(Offset, dl); PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, PtrOff); - MemOpChains.push_back(DAG.getStore(Chain, dl, Arg, PtrOff, - MachinePointerInfo(), - false, false, 0)); + MemOpChains.push_back( + DAG.getStore(Chain, dl, Arg, PtrOff, MachinePointerInfo())); continue; } } @@ -884,9 +872,8 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI, SDValue StackPtr = DAG.getRegister(SP::O6, MVT::i32); SDValue PtrOff = DAG.getIntPtrConstant(Offset, dl); PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, PtrOff); - MemOpChains.push_back(DAG.getStore(Chain, dl, Part1, PtrOff, - MachinePointerInfo(), - false, false, 0)); + MemOpChains.push_back( + DAG.getStore(Chain, dl, Part1, PtrOff, MachinePointerInfo())); } } else { unsigned Offset = VA.getLocMemOffset() + StackOffset; @@ -894,15 +881,13 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI, SDValue StackPtr = DAG.getRegister(SP::O6, MVT::i32); SDValue PtrOff = DAG.getIntPtrConstant(Offset, dl); PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, PtrOff); - MemOpChains.push_back(DAG.getStore(Chain, dl, Part0, PtrOff, - MachinePointerInfo(), - false, false, 0)); + MemOpChains.push_back( + DAG.getStore(Chain, dl, Part0, PtrOff, MachinePointerInfo())); // Store the second part. PtrOff = DAG.getIntPtrConstant(Offset + 4, dl); PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, PtrOff); - MemOpChains.push_back(DAG.getStore(Chain, dl, Part1, PtrOff, - MachinePointerInfo(), - false, false, 0)); + MemOpChains.push_back( + DAG.getStore(Chain, dl, Part1, PtrOff, MachinePointerInfo())); } continue; } @@ -926,9 +911,8 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI, SDValue PtrOff = DAG.getIntPtrConstant(VA.getLocMemOffset() + StackOffset, dl); PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, PtrOff); - MemOpChains.push_back(DAG.getStore(Chain, dl, Arg, PtrOff, - MachinePointerInfo(), - false, false, 0)); + MemOpChains.push_back( + DAG.getStore(Chain, dl, Arg, PtrOff, MachinePointerInfo())); } @@ -953,8 +937,7 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI, // If the callee is a GlobalAddress node (quite common, every direct call is) // turn it into a TargetGlobalAddress node so that legalize doesn't hack it. // Likewise ExternalSymbol -> TargetExternalSymbol. - unsigned TF = ((getTargetMachine().getRelocationModel() == Reloc::PIC_) - ? SparcMCExpr::VK_Sparc_WPLT30 : 0); + unsigned TF = isPositionIndependent() ? SparcMCExpr::VK_Sparc_WPLT30 : 0; if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, MVT::i32, 0, TF); else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee)) @@ -999,15 +982,55 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI, // Copy all of the result registers out of their specified physreg. for (unsigned i = 0; i != RVLocs.size(); ++i) { - Chain = DAG.getCopyFromReg(Chain, dl, toCallerWindow(RVLocs[i].getLocReg()), - RVLocs[i].getValVT(), InFlag).getValue(1); - InFlag = Chain.getValue(2); - InVals.push_back(Chain.getValue(0)); + if (RVLocs[i].getLocVT() == MVT::v2i32) { + SDValue Vec = DAG.getNode(ISD::UNDEF, dl, MVT::v2i32); + SDValue Lo = DAG.getCopyFromReg( + Chain, dl, toCallerWindow(RVLocs[i++].getLocReg()), MVT::i32, InFlag); + Chain = Lo.getValue(1); + InFlag = Lo.getValue(2); + Vec = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, MVT::v2i32, Vec, Lo, + DAG.getConstant(0, dl, MVT::i32)); + SDValue Hi = DAG.getCopyFromReg( + Chain, dl, toCallerWindow(RVLocs[i].getLocReg()), MVT::i32, InFlag); + Chain = Hi.getValue(1); + InFlag = Hi.getValue(2); + Vec = DAG.getNode(ISD::INSERT_VECTOR_ELT, dl, MVT::v2i32, Vec, Hi, + DAG.getConstant(1, dl, MVT::i32)); + InVals.push_back(Vec); + } else { + Chain = + DAG.getCopyFromReg(Chain, dl, toCallerWindow(RVLocs[i].getLocReg()), + RVLocs[i].getValVT(), InFlag) + .getValue(1); + InFlag = Chain.getValue(2); + InVals.push_back(Chain.getValue(0)); + } } return Chain; } +// FIXME? Maybe this could be a TableGen attribute on some registers and +// this table could be generated automatically from RegInfo. +unsigned SparcTargetLowering::getRegisterByName(const char* RegName, EVT VT, + SelectionDAG &DAG) const { + unsigned Reg = StringSwitch<unsigned>(RegName) + .Case("i0", SP::I0).Case("i1", SP::I1).Case("i2", SP::I2).Case("i3", SP::I3) + .Case("i4", SP::I4).Case("i5", SP::I5).Case("i6", SP::I6).Case("i7", SP::I7) + .Case("o0", SP::O0).Case("o1", SP::O1).Case("o2", SP::O2).Case("o3", SP::O3) + .Case("o4", SP::O4).Case("o5", SP::O5).Case("o6", SP::O6).Case("o7", SP::O7) + .Case("l0", SP::L0).Case("l1", SP::L1).Case("l2", SP::L2).Case("l3", SP::L3) + .Case("l4", SP::L4).Case("l5", SP::L5).Case("l6", SP::L6).Case("l7", SP::L7) + .Case("g0", SP::G0).Case("g1", SP::G1).Case("g2", SP::G2).Case("g3", SP::G3) + .Case("g4", SP::G4).Case("g5", SP::G5).Case("g6", SP::G6).Case("g7", SP::G7) + .Default(0); + + if (Reg) + return Reg; + + report_fatal_error("Invalid register name global variable"); +} + // This functions returns true if CalleeName is a ABI function that returns // a long double (fp128). static bool isFP128ABICall(const char *CalleeName) @@ -1131,7 +1154,7 @@ SparcTargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI, unsigned ArgsSize = std::max(6*8u, CCInfo.getNextStackOffset()); // Keep stack frames 16-byte aligned. - ArgsSize = RoundUpToAlignment(ArgsSize, 16); + ArgsSize = alignTo(ArgsSize, 16); // Varargs calls require special treatment. if (CLI.IsVarArg) @@ -1194,16 +1217,13 @@ SparcTargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI, LoPtrOff = DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr, LoPtrOff); // Store to %sp+BIAS+128+Offset - SDValue Store = DAG.getStore(Chain, DL, Arg, HiPtrOff, - MachinePointerInfo(), - false, false, 0); + SDValue Store = + DAG.getStore(Chain, DL, Arg, HiPtrOff, MachinePointerInfo()); // Load into Reg and Reg+1 - SDValue Hi64 = DAG.getLoad(MVT::i64, DL, Store, HiPtrOff, - MachinePointerInfo(), - false, false, false, 0); - SDValue Lo64 = DAG.getLoad(MVT::i64, DL, Store, LoPtrOff, - MachinePointerInfo(), - false, false, false, 0); + SDValue Hi64 = + DAG.getLoad(MVT::i64, DL, Store, HiPtrOff, MachinePointerInfo()); + SDValue Lo64 = + DAG.getLoad(MVT::i64, DL, Store, LoPtrOff, MachinePointerInfo()); RegsToPass.push_back(std::make_pair(toCallerWindow(VA.getLocReg()), Hi64)); RegsToPass.push_back(std::make_pair(toCallerWindow(VA.getLocReg()+1), @@ -1242,9 +1262,8 @@ SparcTargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI, Subtarget->getStackPointerBias() + 128, DL); PtrOff = DAG.getNode(ISD::ADD, DL, PtrVT, StackPtr, PtrOff); - MemOpChains.push_back(DAG.getStore(Chain, DL, Arg, PtrOff, - MachinePointerInfo(), - false, false, 0)); + MemOpChains.push_back( + DAG.getStore(Chain, DL, Arg, PtrOff, MachinePointerInfo())); } // Emit all stores, make sure they occur before the call. @@ -1267,8 +1286,7 @@ SparcTargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI, // Likewise ExternalSymbol -> TargetExternalSymbol. SDValue Callee = CLI.Callee; bool hasReturnsTwice = hasReturnsTwiceAttr(DAG, Callee, CLI.CS); - unsigned TF = ((getTargetMachine().getRelocationModel() == Reloc::PIC_) - ? SparcMCExpr::VK_Sparc_WPLT30 : 0); + unsigned TF = isPositionIndependent() ? SparcMCExpr::VK_Sparc_WPLT30 : 0; if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) Callee = DAG.getTargetGlobalAddress(G->getGlobal(), DL, PtrVT, 0, TF); else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee)) @@ -1375,6 +1393,14 @@ SparcTargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI, // TargetLowering Implementation //===----------------------------------------------------------------------===// +TargetLowering::AtomicExpansionKind SparcTargetLowering::shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const { + if (AI->getOperation() == AtomicRMWInst::Xchg && + AI->getType()->getPrimitiveSizeInBits() == 32) + return AtomicExpansionKind::None; // Uses xchg instruction + + return AtomicExpansionKind::CmpXChg; +} + /// IntCondCCodeToICC - Convert a DAG integer condition code to a SPARC ICC /// condition. static SPCC::CondCodes IntCondCCodeToICC(ISD::CondCode CC) { @@ -1421,7 +1447,7 @@ static SPCC::CondCodes FPCondCCodeToFCC(ISD::CondCode CC) { } } -SparcTargetLowering::SparcTargetLowering(TargetMachine &TM, +SparcTargetLowering::SparcTargetLowering(const TargetMachine &TM, const SparcSubtarget &STI) : TargetLowering(TM), Subtarget(&STI) { MVT PtrVT = MVT::getIntegerVT(8 * TM.getPointerSize()); @@ -1436,9 +1462,11 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM, // Set up the register classes. addRegisterClass(MVT::i32, &SP::IntRegsRegClass); - addRegisterClass(MVT::f32, &SP::FPRegsRegClass); - addRegisterClass(MVT::f64, &SP::DFPRegsRegClass); - addRegisterClass(MVT::f128, &SP::QFPRegsRegClass); + if (!Subtarget->useSoftFloat()) { + addRegisterClass(MVT::f32, &SP::FPRegsRegClass); + addRegisterClass(MVT::f64, &SP::DFPRegsRegClass); + addRegisterClass(MVT::f128, &SP::QFPRegsRegClass); + } if (Subtarget->is64Bit()) { addRegisterClass(MVT::i64, &SP::I64RegsRegClass); } else { @@ -1559,6 +1587,9 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM, setOperationAction(ISD::SELECT_CC, MVT::f64, Custom); setOperationAction(ISD::SELECT_CC, MVT::f128, Custom); + setOperationAction(ISD::EH_SJLJ_SETJMP, MVT::i32, Custom); + setOperationAction(ISD::EH_SJLJ_LONGJMP, MVT::Other, Custom); + if (Subtarget->is64Bit()) { setOperationAction(ISD::ADDC, MVT::i64, Custom); setOperationAction(ISD::ADDE, MVT::i64, Custom); @@ -1574,9 +1605,7 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM, setOperationAction(ISD::CTPOP, MVT::i64, Subtarget->usePopc() ? Legal : Expand); setOperationAction(ISD::CTTZ , MVT::i64, Expand); - setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i64, Expand); setOperationAction(ISD::CTLZ , MVT::i64, Expand); - setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i64, Expand); setOperationAction(ISD::BSWAP, MVT::i64, Expand); setOperationAction(ISD::ROTL , MVT::i64, Expand); setOperationAction(ISD::ROTR , MVT::i64, Expand); @@ -1584,15 +1613,17 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM, } // ATOMICs. - // FIXME: We insert fences for each atomics and generate sub-optimal code - // for PSO/TSO. Also, implement other atomicrmw operations. + // Atomics are supported on SparcV9. 32-bit atomics are also + // supported by some Leon SparcV8 variants. Otherwise, atomics + // are unsupported. + if (Subtarget->isV9() || Subtarget->hasLeonCasa()) + setMaxAtomicSizeInBitsSupported(64); + else + setMaxAtomicSizeInBitsSupported(0); - setInsertFencesForAtomic(true); + setMinCmpXchgSizeInBits(32); setOperationAction(ISD::ATOMIC_SWAP, MVT::i32, Legal); - setOperationAction(ISD::ATOMIC_CMP_SWAP, MVT::i32, - (Subtarget->isV9() ? Legal: Expand)); - setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Legal); @@ -1629,9 +1660,7 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM, setOperationAction(ISD::FREM , MVT::f32, Expand); setOperationAction(ISD::FMA , MVT::f32, Expand); setOperationAction(ISD::CTTZ , MVT::i32, Expand); - setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i32, Expand); setOperationAction(ISD::CTLZ , MVT::i32, Expand); - setOperationAction(ISD::CTLZ_ZERO_UNDEF, MVT::i32, Expand); setOperationAction(ISD::ROTL , MVT::i32, Expand); setOperationAction(ISD::ROTR , MVT::i32, Expand); setOperationAction(ISD::BSWAP, MVT::i32, Expand); @@ -1730,7 +1759,7 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM, setOperationAction(ISD::FP_ROUND, MVT::f32, Custom); // Setup Runtime library names. - if (Subtarget->is64Bit()) { + if (Subtarget->is64Bit() && !Subtarget->useSoftFloat()) { setLibcallName(RTLIB::ADD_F128, "_Qp_add"); setLibcallName(RTLIB::SUB_F128, "_Qp_sub"); setLibcallName(RTLIB::MUL_F128, "_Qp_mul"); @@ -1748,7 +1777,7 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM, setLibcallName(RTLIB::FPEXT_F64_F128, "_Qp_dtoq"); setLibcallName(RTLIB::FPROUND_F128_F32, "_Qp_qtos"); setLibcallName(RTLIB::FPROUND_F128_F64, "_Qp_qtod"); - } else { + } else if (!Subtarget->useSoftFloat()) { setLibcallName(RTLIB::ADD_F128, "_Q_add"); setLibcallName(RTLIB::SUB_F128, "_Q_sub"); setLibcallName(RTLIB::MUL_F128, "_Q_mul"); @@ -1769,35 +1798,56 @@ SparcTargetLowering::SparcTargetLowering(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); computeRegisterProperties(Subtarget->getRegisterInfo()); } +bool SparcTargetLowering::useSoftFloat() const { + return Subtarget->useSoftFloat(); +} + const char *SparcTargetLowering::getTargetNodeName(unsigned Opcode) const { switch ((SPISD::NodeType)Opcode) { - case SPISD::FIRST_NUMBER: break; - case SPISD::CMPICC: return "SPISD::CMPICC"; - case SPISD::CMPFCC: return "SPISD::CMPFCC"; - case SPISD::BRICC: return "SPISD::BRICC"; - case SPISD::BRXCC: return "SPISD::BRXCC"; - case SPISD::BRFCC: return "SPISD::BRFCC"; - case SPISD::SELECT_ICC: return "SPISD::SELECT_ICC"; - case SPISD::SELECT_XCC: return "SPISD::SELECT_XCC"; - case SPISD::SELECT_FCC: return "SPISD::SELECT_FCC"; - case SPISD::Hi: return "SPISD::Hi"; - case SPISD::Lo: return "SPISD::Lo"; - case SPISD::FTOI: return "SPISD::FTOI"; - case SPISD::ITOF: return "SPISD::ITOF"; - case SPISD::FTOX: return "SPISD::FTOX"; - case SPISD::XTOF: return "SPISD::XTOF"; - case SPISD::CALL: return "SPISD::CALL"; - case SPISD::RET_FLAG: return "SPISD::RET_FLAG"; + case SPISD::FIRST_NUMBER: break; + case SPISD::CMPICC: return "SPISD::CMPICC"; + case SPISD::CMPFCC: return "SPISD::CMPFCC"; + case SPISD::BRICC: return "SPISD::BRICC"; + case SPISD::BRXCC: return "SPISD::BRXCC"; + case SPISD::BRFCC: return "SPISD::BRFCC"; + case SPISD::SELECT_ICC: return "SPISD::SELECT_ICC"; + case SPISD::SELECT_XCC: return "SPISD::SELECT_XCC"; + case SPISD::SELECT_FCC: return "SPISD::SELECT_FCC"; + case SPISD::EH_SJLJ_SETJMP: return "SPISD::EH_SJLJ_SETJMP"; + case SPISD::EH_SJLJ_LONGJMP: return "SPISD::EH_SJLJ_LONGJMP"; + case SPISD::Hi: return "SPISD::Hi"; + case SPISD::Lo: return "SPISD::Lo"; + case SPISD::FTOI: return "SPISD::FTOI"; + case SPISD::ITOF: return "SPISD::ITOF"; + case SPISD::FTOX: return "SPISD::FTOX"; + case SPISD::XTOF: return "SPISD::XTOF"; + case SPISD::CALL: return "SPISD::CALL"; + case SPISD::RET_FLAG: return "SPISD::RET_FLAG"; case SPISD::GLOBAL_BASE_REG: return "SPISD::GLOBAL_BASE_REG"; - case SPISD::FLUSHW: return "SPISD::FLUSHW"; - case SPISD::TLS_ADD: return "SPISD::TLS_ADD"; - case SPISD::TLS_LD: return "SPISD::TLS_LD"; - case SPISD::TLS_CALL: return "SPISD::TLS_CALL"; + case SPISD::FLUSHW: return "SPISD::FLUSHW"; + case SPISD::TLS_ADD: return "SPISD::TLS_ADD"; + case SPISD::TLS_LD: return "SPISD::TLS_LD"; + case SPISD::TLS_CALL: return "SPISD::TLS_CALL"; } return nullptr; } @@ -1902,8 +1952,8 @@ SDValue SparcTargetLowering::makeAddress(SDValue Op, SelectionDAG &DAG) const { SDLoc DL(Op); EVT VT = getPointerTy(DAG.getDataLayout()); - // Handle PIC mode first. - if (getTargetMachine().getRelocationModel() == Reloc::PIC_) { + // Handle PIC mode first. SPARC needs a got load for every variable! + if (isPositionIndependent()) { // This is the pic32 code model, the GOT is known to be smaller than 4GB. SDValue HiLo = makeHiLoPair(Op, SparcMCExpr::VK_Sparc_GOT22, SparcMCExpr::VK_Sparc_GOT10, DAG); @@ -1914,8 +1964,7 @@ SDValue SparcTargetLowering::makeAddress(SDValue Op, SelectionDAG &DAG) const { MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); MFI->setHasCalls(true); return DAG.getLoad(VT, DL, DAG.getEntryNode(), AbsAddr, - MachinePointerInfo::getGOT(DAG.getMachineFunction()), - false, false, false, 0); + MachinePointerInfo::getGOT(DAG.getMachineFunction())); } // This is one of the absolute code models. @@ -2004,16 +2053,15 @@ SDValue SparcTargetLowering::LowerGlobalTLSAddress(SDValue Op, SDValue Symbol = withTargetFlags(Op, callTF, DAG); SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue); - SmallVector<SDValue, 4> Ops; - Ops.push_back(Chain); - Ops.push_back(Callee); - Ops.push_back(Symbol); - Ops.push_back(DAG.getRegister(SP::O0, PtrVT)); const uint32_t *Mask = Subtarget->getRegisterInfo()->getCallPreservedMask( DAG.getMachineFunction(), CallingConv::C); assert(Mask && "Missing call preserved mask for calling convention"); - Ops.push_back(DAG.getRegisterMask(Mask)); - Ops.push_back(InFlag); + SDValue Ops[] = {Chain, + Callee, + Symbol, + DAG.getRegister(SP::O0, PtrVT), + DAG.getRegisterMask(Mask), + InFlag}; Chain = DAG.getNode(SPISD::TLS_CALL, DL, NodeTys, Ops); InFlag = Chain.getValue(1); Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(1, DL, true), @@ -2068,10 +2116,10 @@ SDValue SparcTargetLowering::LowerGlobalTLSAddress(SDValue Op, DAG.getRegister(SP::G7, PtrVT), Offset); } -SDValue -SparcTargetLowering::LowerF128_LibCallArg(SDValue Chain, ArgListTy &Args, - SDValue Arg, SDLoc DL, - SelectionDAG &DAG) const { +SDValue SparcTargetLowering::LowerF128_LibCallArg(SDValue Chain, + ArgListTy &Args, SDValue Arg, + const SDLoc &DL, + SelectionDAG &DAG) const { MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo(); EVT ArgVT = Arg.getValueType(); Type *ArgTy = ArgVT.getTypeForEVT(*DAG.getContext()); @@ -2084,14 +2132,8 @@ SparcTargetLowering::LowerF128_LibCallArg(SDValue Chain, ArgListTy &Args, // Create a stack object and pass the pointer to the library function. int FI = MFI->CreateStackObject(16, 8, false); SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy(DAG.getDataLayout())); - Chain = DAG.getStore(Chain, - DL, - Entry.Node, - FIPtr, - MachinePointerInfo(), - false, - false, - 8); + Chain = DAG.getStore(Chain, DL, Entry.Node, FIPtr, MachinePointerInfo(), + /* Alignment = */ 8); Entry.Node = FIPtr; Entry.Ty = PointerType::getUnqual(ArgTy); @@ -2136,7 +2178,7 @@ SparcTargetLowering::LowerF128Op(SDValue Op, SelectionDAG &DAG, } TargetLowering::CallLoweringInfo CLI(DAG); CLI.setDebugLoc(SDLoc(Op)).setChain(Chain) - .setCallee(CallingConv::C, RetTyABI, Callee, std::move(Args), 0); + .setCallee(CallingConv::C, RetTyABI, Callee, std::move(Args)); std::pair<SDValue, SDValue> CallInfo = LowerCallTo(CLI); @@ -2149,19 +2191,13 @@ SparcTargetLowering::LowerF128Op(SDValue Op, SelectionDAG &DAG, Chain = CallInfo.second; // Load RetPtr to get the return value. - return DAG.getLoad(Op.getValueType(), - SDLoc(Op), - Chain, - RetPtr, - MachinePointerInfo(), - false, false, false, 8); + return DAG.getLoad(Op.getValueType(), SDLoc(Op), Chain, RetPtr, + MachinePointerInfo(), /* Alignment = */ 8); } -SDValue -SparcTargetLowering::LowerF128Compare(SDValue LHS, SDValue RHS, - unsigned &SPCC, - SDLoc DL, - SelectionDAG &DAG) const { +SDValue SparcTargetLowering::LowerF128Compare(SDValue LHS, SDValue RHS, + unsigned &SPCC, const SDLoc &DL, + SelectionDAG &DAG) const { const char *LibCall = nullptr; bool is64Bit = Subtarget->is64Bit(); @@ -2193,7 +2229,7 @@ SparcTargetLowering::LowerF128Compare(SDValue LHS, SDValue RHS, TargetLowering::CallLoweringInfo CLI(DAG); CLI.setDebugLoc(DL).setChain(Chain) - .setCallee(CallingConv::C, RetTy, Callee, std::move(Args), 0); + .setCallee(CallingConv::C, RetTy, Callee, std::move(Args)); std::pair<SDValue, SDValue> CallInfo = LowerCallTo(CLI); @@ -2460,6 +2496,20 @@ static SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG, DAG.getConstant(SPCC, dl, MVT::i32), CompareFlag); } +SDValue SparcTargetLowering::LowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG, + const SparcTargetLowering &TLI) const { + SDLoc DL(Op); + return DAG.getNode(SPISD::EH_SJLJ_SETJMP, DL, + DAG.getVTList(MVT::i32, MVT::Other), Op.getOperand(0), Op.getOperand(1)); + +} + +SDValue SparcTargetLowering::LowerEH_SJLJ_LONGJMP(SDValue Op, SelectionDAG &DAG, + const SparcTargetLowering &TLI) const { + SDLoc DL(Op); + return DAG.getNode(SPISD::EH_SJLJ_LONGJMP, DL, MVT::Other, Op.getOperand(0), Op.getOperand(1)); +} + static SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG, const SparcTargetLowering &TLI) { MachineFunction &MF = DAG.getMachineFunction(); @@ -2477,7 +2527,7 @@ static SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG, DAG.getIntPtrConstant(FuncInfo->getVarArgsFrameOffset(), DL)); const Value *SV = cast<SrcValueSDNode>(Op.getOperand(2))->getValue(); return DAG.getStore(Op.getOperand(0), DL, Offset, Op.getOperand(1), - MachinePointerInfo(SV), false, false, 0); + MachinePointerInfo(SV)); } static SDValue LowerVAARG(SDValue Op, SelectionDAG &DAG) { @@ -2488,20 +2538,19 @@ static SDValue LowerVAARG(SDValue Op, SelectionDAG &DAG) { EVT PtrVT = VAListPtr.getValueType(); const Value *SV = cast<SrcValueSDNode>(Node->getOperand(2))->getValue(); SDLoc DL(Node); - SDValue VAList = DAG.getLoad(PtrVT, DL, InChain, VAListPtr, - MachinePointerInfo(SV), false, false, false, 0); + SDValue VAList = + DAG.getLoad(PtrVT, DL, InChain, VAListPtr, MachinePointerInfo(SV)); // Increment the pointer, VAList, to the next vaarg. SDValue NextPtr = DAG.getNode(ISD::ADD, DL, PtrVT, VAList, DAG.getIntPtrConstant(VT.getSizeInBits()/8, DL)); // Store the incremented VAList to the legalized pointer. - InChain = DAG.getStore(VAList.getValue(1), DL, NextPtr, - VAListPtr, MachinePointerInfo(SV), false, false, 0); + InChain = DAG.getStore(VAList.getValue(1), DL, NextPtr, VAListPtr, + MachinePointerInfo(SV)); // Load the actual argument out of the pointer VAList. // We can't count on greater alignment than the word size. return DAG.getLoad(VT, DL, InChain, VAList, MachinePointerInfo(), - false, false, false, - std::min(PtrVT.getSizeInBits(), VT.getSizeInBits())/8); + std::min(PtrVT.getSizeInBits(), VT.getSizeInBits()) / 8); } static SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG, @@ -2564,8 +2613,7 @@ static SDValue getFRAMEADDR(uint64_t depth, SDValue Op, SelectionDAG &DAG, while (depth--) { SDValue Ptr = DAG.getNode(ISD::ADD, dl, VT, FrameAddr, DAG.getIntPtrConstant(Offset, dl)); - FrameAddr = DAG.getLoad(VT, dl, Chain, Ptr, MachinePointerInfo(), - false, false, false, 0); + FrameAddr = DAG.getLoad(VT, dl, Chain, Ptr, MachinePointerInfo()); } if (Subtarget->is64Bit()) FrameAddr = DAG.getNode(ISD::ADD, dl, VT, FrameAddr, @@ -2580,7 +2628,6 @@ static SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG, uint64_t depth = Op.getConstantOperandVal(0); return getFRAMEADDR(depth, Op, DAG, Subtarget); - } static SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG, @@ -2613,30 +2660,34 @@ static SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG, dl, VT, FrameAddr, DAG.getIntPtrConstant(Offset, dl)); - RetAddr = DAG.getLoad(VT, dl, DAG.getEntryNode(), Ptr, - MachinePointerInfo(), false, false, false, 0); + RetAddr = DAG.getLoad(VT, dl, DAG.getEntryNode(), Ptr, MachinePointerInfo()); return RetAddr; } -static SDValue LowerF64Op(SDValue Op, SelectionDAG &DAG, unsigned opcode) -{ - SDLoc dl(Op); - - assert(Op.getValueType() == MVT::f64 && "LowerF64Op called on non-double!"); +static SDValue LowerF64Op(SDValue SrcReg64, const SDLoc &dl, SelectionDAG &DAG, + unsigned opcode) { + assert(SrcReg64.getValueType() == MVT::f64 && "LowerF64Op called on non-double!"); assert(opcode == ISD::FNEG || opcode == ISD::FABS); // Lower fneg/fabs on f64 to fneg/fabs on f32. // fneg f64 => fneg f32:sub_even, fmov f32:sub_odd. // fabs f64 => fabs f32:sub_even, fmov f32:sub_odd. - SDValue SrcReg64 = Op.getOperand(0); + // Note: in little-endian, the floating-point value is stored in the + // registers are in the opposite order, so the subreg with the sign + // bit is the highest-numbered (odd), rather than the + // lowest-numbered (even). + SDValue Hi32 = DAG.getTargetExtractSubreg(SP::sub_even, dl, MVT::f32, SrcReg64); SDValue Lo32 = DAG.getTargetExtractSubreg(SP::sub_odd, dl, MVT::f32, SrcReg64); - Hi32 = DAG.getNode(opcode, dl, MVT::f32, Hi32); + if (DAG.getDataLayout().isLittleEndian()) + Lo32 = DAG.getNode(opcode, dl, MVT::f32, Lo32); + else + Hi32 = DAG.getNode(opcode, dl, MVT::f32, Hi32); SDValue DstReg64 = SDValue(DAG.getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, MVT::f64), 0); @@ -2652,29 +2703,22 @@ static SDValue LowerF128Load(SDValue Op, SelectionDAG &DAG) { SDLoc dl(Op); LoadSDNode *LdNode = dyn_cast<LoadSDNode>(Op.getNode()); - assert(LdNode && LdNode->getOffset().getOpcode() == ISD::UNDEF + assert(LdNode && LdNode->getOffset().isUndef() && "Unexpected node type"); unsigned alignment = LdNode->getAlignment(); if (alignment > 8) alignment = 8; - SDValue Hi64 = DAG.getLoad(MVT::f64, - dl, - LdNode->getChain(), - LdNode->getBasePtr(), - LdNode->getPointerInfo(), - false, false, false, alignment); + SDValue Hi64 = + DAG.getLoad(MVT::f64, dl, LdNode->getChain(), LdNode->getBasePtr(), + LdNode->getPointerInfo(), alignment); EVT addrVT = LdNode->getBasePtr().getValueType(); SDValue LoPtr = DAG.getNode(ISD::ADD, dl, addrVT, LdNode->getBasePtr(), DAG.getConstant(8, dl, addrVT)); - SDValue Lo64 = DAG.getLoad(MVT::f64, - dl, - LdNode->getChain(), - LoPtr, - LdNode->getPointerInfo(), - false, false, false, alignment); + SDValue Lo64 = DAG.getLoad(MVT::f64, dl, LdNode->getChain(), LoPtr, + LdNode->getPointerInfo(), alignment); SDValue SubRegEven = DAG.getTargetConstant(SP::sub_even64, dl, MVT::i32); SDValue SubRegOdd = DAG.getTargetConstant(SP::sub_odd64, dl, MVT::i32); @@ -2713,7 +2757,7 @@ static SDValue LowerLOAD(SDValue Op, SelectionDAG &DAG) static SDValue LowerF128Store(SDValue Op, SelectionDAG &DAG) { SDLoc dl(Op); StoreSDNode *StNode = dyn_cast<StoreSDNode>(Op.getNode()); - assert(StNode && StNode->getOffset().getOpcode() == ISD::UNDEF + assert(StNode && StNode->getOffset().isUndef() && "Unexpected node type"); SDValue SubRegEven = DAG.getTargetConstant(SP::sub_even64, dl, MVT::i32); SDValue SubRegOdd = DAG.getTargetConstant(SP::sub_odd64, dl, MVT::i32); @@ -2734,22 +2778,15 @@ static SDValue LowerF128Store(SDValue Op, SelectionDAG &DAG) { alignment = 8; SDValue OutChains[2]; - OutChains[0] = DAG.getStore(StNode->getChain(), - dl, - SDValue(Hi64, 0), - StNode->getBasePtr(), - MachinePointerInfo(), - false, false, alignment); + OutChains[0] = + DAG.getStore(StNode->getChain(), dl, SDValue(Hi64, 0), + StNode->getBasePtr(), MachinePointerInfo(), alignment); EVT addrVT = StNode->getBasePtr().getValueType(); SDValue LoPtr = DAG.getNode(ISD::ADD, dl, addrVT, StNode->getBasePtr(), DAG.getConstant(8, dl, addrVT)); - OutChains[1] = DAG.getStore(StNode->getChain(), - dl, - SDValue(Lo64, 0), - LoPtr, - MachinePointerInfo(), - false, false, alignment); + OutChains[1] = DAG.getStore(StNode->getChain(), dl, SDValue(Lo64, 0), LoPtr, + MachinePointerInfo(), alignment); return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, OutChains); } @@ -2768,8 +2805,7 @@ static SDValue LowerSTORE(SDValue Op, SelectionDAG &DAG) SDValue Val = DAG.getNode(ISD::BITCAST, dl, MVT::v2i32, St->getValue()); SDValue Chain = DAG.getStore( St->getChain(), dl, Val, St->getBasePtr(), St->getPointerInfo(), - St->isVolatile(), St->isNonTemporal(), St->getAlignment(), - St->getAAInfo()); + St->isVolatile(), St->getMemOperand()->getFlags(), St->getAAInfo()); return Chain; } @@ -2780,24 +2816,35 @@ static SDValue LowerFNEGorFABS(SDValue Op, SelectionDAG &DAG, bool isV9) { assert((Op.getOpcode() == ISD::FNEG || Op.getOpcode() == ISD::FABS) && "invalid opcode"); + SDLoc dl(Op); + if (Op.getValueType() == MVT::f64) - return LowerF64Op(Op, DAG, Op.getOpcode()); + return LowerF64Op(Op.getOperand(0), dl, DAG, Op.getOpcode()); if (Op.getValueType() != MVT::f128) return Op; // Lower fabs/fneg on f128 to fabs/fneg on f64 // fabs/fneg f128 => fabs/fneg f64:sub_even64, fmov f64:sub_odd64 + // (As with LowerF64Op, on little-endian, we need to negate the odd + // subreg) - SDLoc dl(Op); SDValue SrcReg128 = Op.getOperand(0); SDValue Hi64 = DAG.getTargetExtractSubreg(SP::sub_even64, dl, MVT::f64, SrcReg128); SDValue Lo64 = DAG.getTargetExtractSubreg(SP::sub_odd64, dl, MVT::f64, SrcReg128); - if (isV9) - Hi64 = DAG.getNode(Op.getOpcode(), dl, MVT::f64, Hi64); - else - Hi64 = LowerF64Op(Hi64, DAG, Op.getOpcode()); + + if (DAG.getDataLayout().isLittleEndian()) { + if (isV9) + Lo64 = DAG.getNode(Op.getOpcode(), dl, MVT::f64, Lo64); + else + Lo64 = LowerF64Op(Lo64, dl, DAG, Op.getOpcode()); + } else { + if (isV9) + Hi64 = DAG.getNode(Op.getOpcode(), dl, MVT::f64, Hi64); + else + Hi64 = LowerF64Op(Hi64, dl, DAG, Op.getOpcode()); + } SDValue DstReg128 = SDValue(DAG.getMachineNode(TargetOpcode::IMPLICIT_DEF, dl, MVT::f128), 0); @@ -2906,12 +2953,25 @@ static SDValue LowerUMULO_SMULO(SDValue Op, SelectionDAG &DAG, } static SDValue LowerATOMIC_LOAD_STORE(SDValue Op, SelectionDAG &DAG) { + if (isStrongerThanMonotonic(cast<AtomicSDNode>(Op)->getOrdering())) + // Expand with a fence. + return SDValue(); + // Monotonic load/stores are legal. - if (cast<AtomicSDNode>(Op)->getOrdering() <= Monotonic) - return Op; + return Op; +} - // Otherwise, expand with a fence. - return SDValue(); +SDValue SparcTargetLowering::LowerINTRINSIC_WO_CHAIN(SDValue Op, + SelectionDAG &DAG) const { + unsigned IntNo = cast<ConstantSDNode>(Op.getOperand(0))->getZExtValue(); + SDLoc dl(Op); + switch (IntNo) { + default: return SDValue(); // Don't custom lower most intrinsics. + case Intrinsic::thread_pointer: { + EVT PtrVT = getPointerTy(DAG.getDataLayout()); + return DAG.getRegister(SP::G7, PtrVT); + } + } } SDValue SparcTargetLowering:: @@ -2943,6 +3003,8 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const { hasHardQuad); case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG, *this, hasHardQuad); + case ISD::EH_SJLJ_SETJMP: return LowerEH_SJLJ_SETJMP(Op, DAG, *this); + case ISD::EH_SJLJ_LONGJMP: return LowerEH_SJLJ_LONGJMP(Op, DAG, *this); case ISD::VASTART: return LowerVASTART(Op, DAG, *this); case ISD::VAARG: return LowerVAARG(Op, DAG); case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG, @@ -2972,14 +3034,15 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const { case ISD::SMULO: return LowerUMULO_SMULO(Op, DAG, *this); case ISD::ATOMIC_LOAD: case ISD::ATOMIC_STORE: return LowerATOMIC_LOAD_STORE(Op, DAG); + case ISD::INTRINSIC_WO_CHAIN: return LowerINTRINSIC_WO_CHAIN(Op, DAG); } } MachineBasicBlock * -SparcTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, +SparcTargetLowering::EmitInstrWithCustomInserter(MachineInstr &MI, MachineBasicBlock *BB) const { - switch (MI->getOpcode()) { - default: llvm_unreachable("Unknown SELECT_CC!"); + switch (MI.getOpcode()) { + default: llvm_unreachable("Unknown Custom Instruction!"); case SP::SELECT_CC_Int_ICC: case SP::SELECT_CC_FP_ICC: case SP::SELECT_CC_DFP_ICC: @@ -2990,61 +3053,21 @@ SparcTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI, case SP::SELECT_CC_DFP_FCC: case SP::SELECT_CC_QFP_FCC: return expandSelectCC(MI, BB, SP::FBCOND); + case SP::EH_SJLJ_SETJMP32ri: + case SP::EH_SJLJ_SETJMP32rr: + return emitEHSjLjSetJmp(MI, BB); + case SP::EH_SJLJ_LONGJMP32rr: + case SP::EH_SJLJ_LONGJMP32ri: + return emitEHSjLjLongJmp(MI, BB); + } +} - case SP::ATOMIC_LOAD_ADD_32: - return expandAtomicRMW(MI, BB, SP::ADDrr); - case SP::ATOMIC_LOAD_ADD_64: - return expandAtomicRMW(MI, BB, SP::ADDXrr); - case SP::ATOMIC_LOAD_SUB_32: - return expandAtomicRMW(MI, BB, SP::SUBrr); - case SP::ATOMIC_LOAD_SUB_64: - return expandAtomicRMW(MI, BB, SP::SUBXrr); - case SP::ATOMIC_LOAD_AND_32: - return expandAtomicRMW(MI, BB, SP::ANDrr); - case SP::ATOMIC_LOAD_AND_64: - return expandAtomicRMW(MI, BB, SP::ANDXrr); - case SP::ATOMIC_LOAD_OR_32: - return expandAtomicRMW(MI, BB, SP::ORrr); - case SP::ATOMIC_LOAD_OR_64: - return expandAtomicRMW(MI, BB, SP::ORXrr); - case SP::ATOMIC_LOAD_XOR_32: - return expandAtomicRMW(MI, BB, SP::XORrr); - case SP::ATOMIC_LOAD_XOR_64: - return expandAtomicRMW(MI, BB, SP::XORXrr); - case SP::ATOMIC_LOAD_NAND_32: - return expandAtomicRMW(MI, BB, SP::ANDrr); - case SP::ATOMIC_LOAD_NAND_64: - return expandAtomicRMW(MI, BB, SP::ANDXrr); - - case SP::ATOMIC_SWAP_64: - return expandAtomicRMW(MI, BB, 0); - - case SP::ATOMIC_LOAD_MAX_32: - return expandAtomicRMW(MI, BB, SP::MOVICCrr, SPCC::ICC_G); - case SP::ATOMIC_LOAD_MAX_64: - return expandAtomicRMW(MI, BB, SP::MOVXCCrr, SPCC::ICC_G); - case SP::ATOMIC_LOAD_MIN_32: - return expandAtomicRMW(MI, BB, SP::MOVICCrr, SPCC::ICC_LE); - case SP::ATOMIC_LOAD_MIN_64: - return expandAtomicRMW(MI, BB, SP::MOVXCCrr, SPCC::ICC_LE); - case SP::ATOMIC_LOAD_UMAX_32: - return expandAtomicRMW(MI, BB, SP::MOVICCrr, SPCC::ICC_GU); - case SP::ATOMIC_LOAD_UMAX_64: - return expandAtomicRMW(MI, BB, SP::MOVXCCrr, SPCC::ICC_GU); - case SP::ATOMIC_LOAD_UMIN_32: - return expandAtomicRMW(MI, BB, SP::MOVICCrr, SPCC::ICC_LEU); - case SP::ATOMIC_LOAD_UMIN_64: - return expandAtomicRMW(MI, BB, SP::MOVXCCrr, SPCC::ICC_LEU); - } -} - -MachineBasicBlock* -SparcTargetLowering::expandSelectCC(MachineInstr *MI, - MachineBasicBlock *BB, +MachineBasicBlock * +SparcTargetLowering::expandSelectCC(MachineInstr &MI, MachineBasicBlock *BB, unsigned BROpcode) const { const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); - DebugLoc dl = MI->getDebugLoc(); - unsigned CC = (SPCC::CondCodes)MI->getOperand(3).getImm(); + DebugLoc dl = MI.getDebugLoc(); + unsigned CC = (SPCC::CondCodes)MI.getOperand(3).getImm(); // To "insert" a SELECT_CC instruction, we actually have to insert the diamond // control-flow pattern. The incoming instruction knows the destination vreg @@ -3089,107 +3112,211 @@ SparcTargetLowering::expandSelectCC(MachineInstr *MI, // %Result = phi [ %FalseValue, copy0MBB ], [ %TrueValue, thisMBB ] // ... BB = sinkMBB; - BuildMI(*BB, BB->begin(), dl, TII.get(SP::PHI), MI->getOperand(0).getReg()) - .addReg(MI->getOperand(2).getReg()).addMBB(copy0MBB) - .addReg(MI->getOperand(1).getReg()).addMBB(thisMBB); + BuildMI(*BB, BB->begin(), dl, TII.get(SP::PHI), MI.getOperand(0).getReg()) + .addReg(MI.getOperand(2).getReg()) + .addMBB(copy0MBB) + .addReg(MI.getOperand(1).getReg()) + .addMBB(thisMBB); - MI->eraseFromParent(); // The pseudo instruction is gone now. + MI.eraseFromParent(); // The pseudo instruction is gone now. return BB; } -MachineBasicBlock* -SparcTargetLowering::expandAtomicRMW(MachineInstr *MI, - MachineBasicBlock *MBB, - unsigned Opcode, - unsigned CondCode) const { - const TargetInstrInfo &TII = *Subtarget->getInstrInfo(); - MachineRegisterInfo &MRI = MBB->getParent()->getRegInfo(); - DebugLoc DL = MI->getDebugLoc(); +MachineBasicBlock * +SparcTargetLowering::emitEHSjLjLongJmp(MachineInstr &MI, + MachineBasicBlock *MBB) const { + DebugLoc DL = MI.getDebugLoc(); + const TargetInstrInfo *TII = Subtarget->getInstrInfo(); + + MachineFunction *MF = MBB->getParent(); + MachineRegisterInfo &MRI = MF->getRegInfo(); + MachineInstrBuilder MIB; + + MVT PVT = getPointerTy(MF->getDataLayout()); + unsigned RegSize = PVT.getStoreSize(); + assert(PVT == MVT::i32 && "Invalid Pointer Size!"); + + unsigned Buf = MI.getOperand(0).getReg(); + unsigned JmpLoc = MRI.createVirtualRegister(&SP::IntRegsRegClass); + + // TO DO: If we do 64-bit handling, this perhaps should be FLUSHW, not TA 3 + MIB = BuildMI(*MBB, MI, DL, TII->get(SP::TRAPri), SP::G0).addImm(3).addImm(SPCC::ICC_A); + + // Instruction to restore FP + const unsigned FP = SP::I6; + MIB = BuildMI(*MBB, MI, DL, TII->get(SP::LDri)) + .addReg(FP) + .addReg(Buf) + .addImm(0); - // MI is an atomic read-modify-write instruction of the form: + // Instruction to load jmp location + MIB = BuildMI(*MBB, MI, DL, TII->get(SP::LDri)) + .addReg(JmpLoc, RegState::Define) + .addReg(Buf) + .addImm(RegSize); + + // Instruction to restore SP + const unsigned SP = SP::O6; + MIB = BuildMI(*MBB, MI, DL, TII->get(SP::LDri)) + .addReg(SP) + .addReg(Buf) + .addImm(2 * RegSize); + + // Instruction to restore I7 + MIB = BuildMI(*MBB, MI, DL, TII->get(SP::LDri)) + .addReg(SP::I7) + .addReg(Buf, RegState::Kill) + .addImm(3 * RegSize); + + // Jump to JmpLoc + BuildMI(*MBB, MI, DL, TII->get(SP::JMPLrr)).addReg(SP::G0).addReg(JmpLoc, RegState::Kill).addReg(SP::G0); + + MI.eraseFromParent(); + return MBB; +} + +MachineBasicBlock * +SparcTargetLowering::emitEHSjLjSetJmp(MachineInstr &MI, + MachineBasicBlock *MBB) const { + DebugLoc DL = MI.getDebugLoc(); + const TargetInstrInfo *TII = Subtarget->getInstrInfo(); + + MachineFunction *MF = MBB->getParent(); + MachineRegisterInfo &MRI = MF->getRegInfo(); + MachineInstrBuilder MIB; + + MVT PVT = getPointerTy(MF->getDataLayout()); + unsigned RegSize = PVT.getStoreSize(); + assert(PVT == MVT::i32 && "Invalid Pointer Size!"); + + unsigned DstReg = MI.getOperand(0).getReg(); + const TargetRegisterClass *RC = MRI.getRegClass(DstReg); + assert(RC->hasType(MVT::i32) && "Invalid destination!"); + unsigned mainDstReg = MRI.createVirtualRegister(RC); + unsigned restoreDstReg = MRI.createVirtualRegister(RC); + + // For v = setjmp(buf), we generate // - // rd = atomicrmw<op> addr, rs2 + // thisMBB: + // buf[0] = FP + // buf[RegSize] = restoreMBB <-- takes address of restoreMBB + // buf[RegSize * 2] = O6 + // buf[RegSize * 3] = I7 + // Ensure restoreMBB remains in the relocations list (done using a bn instruction) + // b mainMBB // - // All three operands are registers. - unsigned DestReg = MI->getOperand(0).getReg(); - unsigned AddrReg = MI->getOperand(1).getReg(); - unsigned Rs2Reg = MI->getOperand(2).getReg(); - - // SelectionDAG has already inserted memory barriers before and after MI, so - // we simply have to implement the operatiuon in terms of compare-and-swap. + // mainMBB: + // v_main = 0 + // b sinkMBB // - // %val0 = load %addr - // loop: - // %val = phi %val0, %dest - // %upd = op %val, %rs2 - // %dest = cas %addr, %val, %upd - // cmp %val, %dest - // bne loop - // done: + // restoreMBB: + // v_restore = 1 + // --fall through-- // - bool is64Bit = SP::I64RegsRegClass.hasSubClassEq(MRI.getRegClass(DestReg)); - const TargetRegisterClass *ValueRC = - is64Bit ? &SP::I64RegsRegClass : &SP::IntRegsRegClass; - unsigned Val0Reg = MRI.createVirtualRegister(ValueRC); + // sinkMBB: + // v = phi(main, restore) - BuildMI(*MBB, MI, DL, TII.get(is64Bit ? SP::LDXri : SP::LDri), Val0Reg) - .addReg(AddrReg).addImm(0); + const BasicBlock *BB = MBB->getBasicBlock(); + MachineFunction::iterator It = ++MBB->getIterator(); + MachineBasicBlock *thisMBB = MBB; + MachineBasicBlock *mainMBB = MF->CreateMachineBasicBlock(BB); + MachineBasicBlock *restoreMBB = MF->CreateMachineBasicBlock(BB); + MachineBasicBlock *sinkMBB = MF->CreateMachineBasicBlock(BB); - // Split the basic block MBB before MI and insert the loop block in the hole. - MachineFunction::iterator MFI = MBB->getIterator(); - const BasicBlock *LLVM_BB = MBB->getBasicBlock(); - MachineFunction *MF = MBB->getParent(); - MachineBasicBlock *LoopMBB = MF->CreateMachineBasicBlock(LLVM_BB); - MachineBasicBlock *DoneMBB = MF->CreateMachineBasicBlock(LLVM_BB); - ++MFI; - MF->insert(MFI, LoopMBB); - MF->insert(MFI, DoneMBB); - - // Move MI and following instructions to DoneMBB. - DoneMBB->splice(DoneMBB->begin(), MBB, MI, MBB->end()); - DoneMBB->transferSuccessorsAndUpdatePHIs(MBB); - - // Connect the CFG again. - MBB->addSuccessor(LoopMBB); - LoopMBB->addSuccessor(LoopMBB); - LoopMBB->addSuccessor(DoneMBB); - - // Build the loop block. - unsigned ValReg = MRI.createVirtualRegister(ValueRC); - // Opcode == 0 means try to write Rs2Reg directly (ATOMIC_SWAP). - unsigned UpdReg = (Opcode ? MRI.createVirtualRegister(ValueRC) : Rs2Reg); - - BuildMI(LoopMBB, DL, TII.get(SP::PHI), ValReg) - .addReg(Val0Reg).addMBB(MBB) - .addReg(DestReg).addMBB(LoopMBB); - - if (CondCode) { - // This is one of the min/max operations. We need a CMPrr followed by a - // MOVXCC/MOVICC. - BuildMI(LoopMBB, DL, TII.get(SP::CMPrr)).addReg(ValReg).addReg(Rs2Reg); - BuildMI(LoopMBB, DL, TII.get(Opcode), UpdReg) - .addReg(ValReg).addReg(Rs2Reg).addImm(CondCode); - } else if (Opcode) { - BuildMI(LoopMBB, DL, TII.get(Opcode), UpdReg) - .addReg(ValReg).addReg(Rs2Reg); - } - - if (MI->getOpcode() == SP::ATOMIC_LOAD_NAND_32 || - MI->getOpcode() == SP::ATOMIC_LOAD_NAND_64) { - unsigned TmpReg = UpdReg; - UpdReg = MRI.createVirtualRegister(ValueRC); - BuildMI(LoopMBB, DL, TII.get(SP::XORri), UpdReg).addReg(TmpReg).addImm(-1); - } - - BuildMI(LoopMBB, DL, TII.get(is64Bit ? SP::CASXrr : SP::CASrr), DestReg) - .addReg(AddrReg).addReg(ValReg).addReg(UpdReg) - .setMemRefs(MI->memoperands_begin(), MI->memoperands_end()); - BuildMI(LoopMBB, DL, TII.get(SP::CMPrr)).addReg(ValReg).addReg(DestReg); - BuildMI(LoopMBB, DL, TII.get(is64Bit ? SP::BPXCC : SP::BCOND)) - .addMBB(LoopMBB).addImm(SPCC::ICC_NE); - - MI->eraseFromParent(); - return DoneMBB; + MF->insert(It, mainMBB); + MF->insert(It, restoreMBB); + MF->insert(It, sinkMBB); + restoreMBB->setHasAddressTaken(); + + // Transfer the remainder of BB and its successor edges to sinkMBB. + sinkMBB->splice(sinkMBB->begin(), MBB, + std::next(MachineBasicBlock::iterator(MI)), + MBB->end()); + sinkMBB->transferSuccessorsAndUpdatePHIs(MBB); + + unsigned LabelReg = MRI.createVirtualRegister(&SP::IntRegsRegClass); + unsigned LabelReg2 = MRI.createVirtualRegister(&SP::IntRegsRegClass); + unsigned BufReg = MI.getOperand(1).getReg(); + + // Instruction to store FP + const unsigned FP = SP::I6; + MIB = BuildMI(thisMBB, DL, TII->get(SP::STri)) + .addReg(BufReg) + .addImm(0) + .addReg(FP); + + // Instructions to store jmp location + MIB = BuildMI(thisMBB, DL, TII->get(SP::SETHIi)) + .addReg(LabelReg, RegState::Define) + .addMBB(restoreMBB, SparcMCExpr::VK_Sparc_HI); + + MIB = BuildMI(thisMBB, DL, TII->get(SP::ORri)) + .addReg(LabelReg2, RegState::Define) + .addReg(LabelReg, RegState::Kill) + .addMBB(restoreMBB, SparcMCExpr::VK_Sparc_LO); + + MIB = BuildMI(thisMBB, DL, TII->get(SP::STri)) + .addReg(BufReg) + .addImm(RegSize) + .addReg(LabelReg2, RegState::Kill); + + // Instruction to store SP + const unsigned SP = SP::O6; + MIB = BuildMI(thisMBB, DL, TII->get(SP::STri)) + .addReg(BufReg) + .addImm(2 * RegSize) + .addReg(SP); + + // Instruction to store I7 + MIB = BuildMI(thisMBB, DL, TII->get(SP::STri)) + .addReg(BufReg) + .addImm(3 * RegSize) + .addReg(SP::I7); + + + // FIX ME: This next instruction ensures that the restoreMBB block address remains + // valid through optimization passes and serves no other purpose. The ICC_N ensures + // that the branch is never taken. This commented-out code here was an alternative + // attempt to achieve this which brought myriad problems. + //MIB = BuildMI(thisMBB, DL, TII->get(SP::EH_SjLj_Setup)).addMBB(restoreMBB, SparcMCExpr::VK_Sparc_None); + MIB = BuildMI(thisMBB, DL, TII->get(SP::BCOND)) + .addMBB(restoreMBB) + .addImm(SPCC::ICC_N); + + MIB = BuildMI(thisMBB, DL, TII->get(SP::BCOND)) + .addMBB(mainMBB) + .addImm(SPCC::ICC_A); + + thisMBB->addSuccessor(mainMBB); + thisMBB->addSuccessor(restoreMBB); + + + // mainMBB: + MIB = BuildMI(mainMBB, DL, TII->get(SP::ORrr)) + .addReg(mainDstReg, RegState::Define) + .addReg(SP::G0) + .addReg(SP::G0); + MIB = BuildMI(mainMBB, DL, TII->get(SP::BCOND)).addMBB(sinkMBB).addImm(SPCC::ICC_A); + + mainMBB->addSuccessor(sinkMBB); + + + // restoreMBB: + MIB = BuildMI(restoreMBB, DL, TII->get(SP::ORri)) + .addReg(restoreDstReg, RegState::Define) + .addReg(SP::G0) + .addImm(1); + //MIB = BuildMI(restoreMBB, DL, TII->get(SP::BCOND)).addMBB(sinkMBB).addImm(SPCC::ICC_A); + restoreMBB->addSuccessor(sinkMBB); + + // sinkMBB: + MIB = BuildMI(*sinkMBB, sinkMBB->begin(), DL, + TII->get(SP::PHI), DstReg) + .addReg(mainDstReg).addMBB(mainMBB) + .addReg(restoreDstReg).addMBB(restoreMBB); + + MI.eraseFromParent(); + return sinkMBB; } //===----------------------------------------------------------------------===// @@ -3202,8 +3329,11 @@ SparcTargetLowering::ConstraintType SparcTargetLowering::getConstraintType(StringRef Constraint) const { if (Constraint.size() == 1) { switch (Constraint[0]) { - default: break; - case 'r': return C_RegisterClass; + default: + break; + case 'f': + case 'r': + return C_RegisterClass; case 'I': // SIMM13 return C_Other; } @@ -3277,6 +3407,9 @@ SparcTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, MVT VT) const { if (Constraint.size() == 1) { switch (Constraint[0]) { + case 'f': + return std::make_pair(0U, &SP::FPRegsRegClass); + case 'r': if (VT == MVT::v2i32) return std::make_pair(0U, &SP::IntPairRegClass); @@ -3368,10 +3501,9 @@ void SparcTargetLowering::ReplaceNodeResults(SDNode *N, SDLoc dl(N); SDValue LoadRes = DAG.getExtLoad( - Ld->getExtensionType(), dl, MVT::v2i32, - Ld->getChain(), Ld->getBasePtr(), Ld->getPointerInfo(), - MVT::v2i32, Ld->isVolatile(), Ld->isNonTemporal(), - Ld->isInvariant(), Ld->getAlignment(), Ld->getAAInfo()); + Ld->getExtensionType(), dl, MVT::v2i32, Ld->getChain(), + Ld->getBasePtr(), Ld->getPointerInfo(), MVT::v2i32, Ld->getAlignment(), + Ld->getMemOperand()->getFlags(), Ld->getAAInfo()); SDValue Res = DAG.getNode(ISD::BITCAST, dl, MVT::i64, LoadRes); Results.push_back(Res); @@ -3380,3 +3512,16 @@ void SparcTargetLowering::ReplaceNodeResults(SDNode *N, } } } + +// Override to enable LOAD_STACK_GUARD lowering on Linux. +bool SparcTargetLowering::useLoadStackGuardNode() const { + if (!Subtarget->isTargetLinux()) + return TargetLowering::useLoadStackGuardNode(); + return true; +} + +// Override to disable global variable loading on Linux. +void SparcTargetLowering::insertSSPDeclarations(Module &M) const { + if (!Subtarget->isTargetLinux()) + return TargetLowering::insertSSPDeclarations(M); +} diff --git a/lib/Target/Sparc/SparcISelLowering.h b/lib/Target/Sparc/SparcISelLowering.h index 4e46709cfc09..e0a421b83712 100644 --- a/lib/Target/Sparc/SparcISelLowering.h +++ b/lib/Target/Sparc/SparcISelLowering.h @@ -33,6 +33,9 @@ namespace llvm { SELECT_XCC, // Select between two values using the current XCC flags. SELECT_FCC, // Select between two values using the current FCC flags. + EH_SJLJ_SETJMP, // builtin setjmp operation + EH_SJLJ_LONGJMP, // builtin longjmp operation + Hi, Lo, // Hi/Lo operations, typically on a global address. FTOI, // FP to Int within a FP register. @@ -54,9 +57,11 @@ namespace llvm { class SparcTargetLowering : public TargetLowering { const SparcSubtarget *Subtarget; public: - SparcTargetLowering(TargetMachine &TM, const SparcSubtarget &STI); + SparcTargetLowering(const TargetMachine &TM, const SparcSubtarget &STI); SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) const override; - + + bool useSoftFloat() const override; + /// computeKnownBitsForTargetNode - Determine which of the bits specified /// in Mask are known to be either zero or one and return them in the /// KnownZero/KnownOne bitsets. @@ -67,8 +72,8 @@ namespace llvm { unsigned Depth = 0) const override; MachineBasicBlock * - EmitInstrWithCustomInserter(MachineInstr *MI, - MachineBasicBlock *MBB) const override; + EmitInstrWithCustomInserter(MachineInstr &MI, + MachineBasicBlock *MBB) const override; const char *getTargetNodeName(unsigned Opcode) const override; @@ -80,6 +85,14 @@ namespace llvm { std::string &Constraint, std::vector<SDValue> &Ops, SelectionDAG &DAG) const override; + + unsigned + getInlineAsmMemConstraint(StringRef ConstraintCode) const override { + if (ConstraintCode == "o") + return InlineAsm::Constraint_o; + return TargetLowering::getInlineAsmMemConstraint(ConstraintCode); + } + std::pair<unsigned, const TargetRegisterClass *> getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI, StringRef Constraint, MVT VT) const override; @@ -89,6 +102,9 @@ namespace llvm { return MVT::i32; } + unsigned getRegisterByName(const char* RegName, EVT VT, + SelectionDAG &DAG) const override; + /// If a physical register, this returns the register that receives the /// exception address on entry to an EH pad. unsigned @@ -103,28 +119,28 @@ namespace llvm { return SP::I1; } + /// Override to support customized stack guard loading. + bool useLoadStackGuardNode() const override; + void insertSSPDeclarations(Module &M) const override; + /// getSetCCResultType - Return the ISD::SETCC ValueType EVT getSetCCResultType(const DataLayout &DL, LLVMContext &Context, EVT VT) const override; SDValue - LowerFormalArguments(SDValue Chain, - CallingConv::ID CallConv, - bool isVarArg, - const SmallVectorImpl<ISD::InputArg> &Ins, - SDLoc dl, SelectionDAG &DAG, - SmallVectorImpl<SDValue> &InVals) const override; - SDValue LowerFormalArguments_32(SDValue Chain, - CallingConv::ID CallConv, + LowerFormalArguments(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::InputArg> &Ins, + const SDLoc &dl, SelectionDAG &DAG, + SmallVectorImpl<SDValue> &InVals) const override; + SDValue LowerFormalArguments_32(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, const SmallVectorImpl<ISD::InputArg> &Ins, - SDLoc dl, SelectionDAG &DAG, + const SDLoc &dl, SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const; - SDValue LowerFormalArguments_64(SDValue Chain, - CallingConv::ID CallConv, + SDValue LowerFormalArguments_64(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, const SmallVectorImpl<ISD::InputArg> &Ins, - SDLoc dl, SelectionDAG &DAG, + const SDLoc &dl, SelectionDAG &DAG, SmallVectorImpl<SDValue> &InVals) const; SDValue @@ -135,44 +151,46 @@ namespace llvm { SDValue LowerCall_64(TargetLowering::CallLoweringInfo &CLI, SmallVectorImpl<SDValue> &InVals) const; - SDValue - LowerReturn(SDValue Chain, - CallingConv::ID CallConv, bool isVarArg, - const SmallVectorImpl<ISD::OutputArg> &Outs, - const SmallVectorImpl<SDValue> &OutVals, - SDLoc dl, SelectionDAG &DAG) const override; - SDValue LowerReturn_32(SDValue Chain, - CallingConv::ID CallConv, bool IsVarArg, + SDValue LowerReturn(SDValue Chain, CallingConv::ID CallConv, bool isVarArg, + const SmallVectorImpl<ISD::OutputArg> &Outs, + const SmallVectorImpl<SDValue> &OutVals, + const SDLoc &dl, SelectionDAG &DAG) const override; + SDValue LowerReturn_32(SDValue Chain, CallingConv::ID CallConv, + bool IsVarArg, const SmallVectorImpl<ISD::OutputArg> &Outs, const SmallVectorImpl<SDValue> &OutVals, - SDLoc DL, SelectionDAG &DAG) const; - SDValue LowerReturn_64(SDValue Chain, - CallingConv::ID CallConv, bool IsVarArg, + const SDLoc &DL, SelectionDAG &DAG) const; + SDValue LowerReturn_64(SDValue Chain, CallingConv::ID CallConv, + bool IsVarArg, const SmallVectorImpl<ISD::OutputArg> &Outs, const SmallVectorImpl<SDValue> &OutVals, - SDLoc DL, SelectionDAG &DAG) const; + const SDLoc &DL, SelectionDAG &DAG) const; SDValue LowerGlobalAddress(SDValue Op, SelectionDAG &DAG) const; SDValue LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const; SDValue LowerConstantPool(SDValue Op, SelectionDAG &DAG) const; SDValue LowerBlockAddress(SDValue Op, SelectionDAG &DAG) const; + SDValue LowerEH_SJLJ_SETJMP(SDValue Op, SelectionDAG &DAG, + const SparcTargetLowering &TLI) const ; + SDValue LowerEH_SJLJ_LONGJMP(SDValue Op, SelectionDAG &DAG, + const SparcTargetLowering &TLI) const ; + unsigned getSRetArgSize(SelectionDAG &DAG, SDValue Callee) const; SDValue withTargetFlags(SDValue Op, unsigned TF, SelectionDAG &DAG) const; SDValue makeHiLoPair(SDValue Op, unsigned HiTF, unsigned LoTF, SelectionDAG &DAG) const; SDValue makeAddress(SDValue Op, SelectionDAG &DAG) const; - SDValue LowerF128_LibCallArg(SDValue Chain, ArgListTy &Args, - SDValue Arg, SDLoc DL, - SelectionDAG &DAG) const; + SDValue LowerF128_LibCallArg(SDValue Chain, ArgListTy &Args, SDValue Arg, + const SDLoc &DL, SelectionDAG &DAG) const; SDValue LowerF128Op(SDValue Op, SelectionDAG &DAG, const char *LibFuncName, unsigned numArgs) const; - SDValue LowerF128Compare(SDValue LHS, SDValue RHS, - unsigned &SPCC, - SDLoc DL, - SelectionDAG &DAG) const; + SDValue LowerF128Compare(SDValue LHS, SDValue RHS, unsigned &SPCC, + const SDLoc &DL, SelectionDAG &DAG) const; + + SDValue LowerINTRINSIC_WO_CHAIN(SDValue Op, SelectionDAG &DAG) const; bool ShouldShrinkFPConstant(EVT VT) const override { // Do not shrink FP constpool if VT == MVT::f128. @@ -180,16 +198,25 @@ namespace llvm { return VT != MVT::f128; } + bool shouldInsertFencesForAtomic(const Instruction *I) const override { + // FIXME: We insert fences for each atomics and generate + // sub-optimal code for PSO/TSO. (Approximately nobody uses any + // mode but TSO, which makes this even more silly) + return true; + } + + AtomicExpansionKind shouldExpandAtomicRMWInIR(AtomicRMWInst *AI) const override; + void ReplaceNodeResults(SDNode *N, SmallVectorImpl<SDValue>& Results, SelectionDAG &DAG) const override; - MachineBasicBlock *expandSelectCC(MachineInstr *MI, MachineBasicBlock *BB, + MachineBasicBlock *expandSelectCC(MachineInstr &MI, MachineBasicBlock *BB, unsigned BROpcode) const; - MachineBasicBlock *expandAtomicRMW(MachineInstr *MI, - MachineBasicBlock *BB, - unsigned Opcode, - unsigned CondCode = 0) const; + MachineBasicBlock *emitEHSjLjSetJmp(MachineInstr &MI, + MachineBasicBlock *MBB) const; + MachineBasicBlock *emitEHSjLjLongJmp(MachineInstr &MI, + MachineBasicBlock *MBB) const; }; } // end namespace llvm diff --git a/lib/Target/Sparc/SparcInstr64Bit.td b/lib/Target/Sparc/SparcInstr64Bit.td index 419e8ccb1024..f6518c936ebc 100644 --- a/lib/Target/Sparc/SparcInstr64Bit.td +++ b/lib/Target/Sparc/SparcInstr64Bit.td @@ -492,7 +492,7 @@ let Predicates = [Is64Bit], Constraints = "$swap = $rd", asi = 0b10000000 in { I64Regs:$swap), "casx [$rs1], $rs2, $rd", [(set i64:$rd, - (atomic_cmp_swap i64:$rs1, i64:$rs2, i64:$swap))]>; + (atomic_cmp_swap_64 i64:$rs1, i64:$rs2, i64:$swap))]>; } // Predicates = [Is64Bit], Constraints = ... @@ -501,48 +501,15 @@ let Predicates = [Is64Bit] in { def : Pat<(atomic_fence imm, imm), (MEMBARi 0xf)>; // atomic_load_64 addr -> load addr -def : Pat<(i64 (atomic_load ADDRrr:$src)), (LDXrr ADDRrr:$src)>; -def : Pat<(i64 (atomic_load ADDRri:$src)), (LDXri ADDRri:$src)>; +def : Pat<(i64 (atomic_load_64 ADDRrr:$src)), (LDXrr ADDRrr:$src)>; +def : Pat<(i64 (atomic_load_64 ADDRri:$src)), (LDXri ADDRri:$src)>; // atomic_store_64 val, addr -> store val, addr -def : Pat<(atomic_store ADDRrr:$dst, i64:$val), (STXrr ADDRrr:$dst, $val)>; -def : Pat<(atomic_store ADDRri:$dst, i64:$val), (STXri ADDRri:$dst, $val)>; +def : Pat<(atomic_store_64 ADDRrr:$dst, i64:$val), (STXrr ADDRrr:$dst, $val)>; +def : Pat<(atomic_store_64 ADDRri:$dst, i64:$val), (STXri ADDRri:$dst, $val)>; } // Predicates = [Is64Bit] -let usesCustomInserter = 1, hasCtrlDep = 1, mayLoad = 1, mayStore = 1, - Defs = [ICC] in -multiclass AtomicRMW<SDPatternOperator op32, SDPatternOperator op64> { - - def _32 : Pseudo<(outs IntRegs:$rd), - (ins ptr_rc:$addr, IntRegs:$rs2), "", - [(set i32:$rd, (op32 iPTR:$addr, i32:$rs2))]>; - - let Predicates = [Is64Bit] in - def _64 : Pseudo<(outs I64Regs:$rd), - (ins ptr_rc:$addr, I64Regs:$rs2), "", - [(set i64:$rd, (op64 iPTR:$addr, i64:$rs2))]>; -} - -defm ATOMIC_LOAD_ADD : AtomicRMW<atomic_load_add_32, atomic_load_add_64>; -defm ATOMIC_LOAD_SUB : AtomicRMW<atomic_load_sub_32, atomic_load_sub_64>; -defm ATOMIC_LOAD_AND : AtomicRMW<atomic_load_and_32, atomic_load_and_64>; -defm ATOMIC_LOAD_OR : AtomicRMW<atomic_load_or_32, atomic_load_or_64>; -defm ATOMIC_LOAD_XOR : AtomicRMW<atomic_load_xor_32, atomic_load_xor_64>; -defm ATOMIC_LOAD_NAND : AtomicRMW<atomic_load_nand_32, atomic_load_nand_64>; -defm ATOMIC_LOAD_MIN : AtomicRMW<atomic_load_min_32, atomic_load_min_64>; -defm ATOMIC_LOAD_MAX : AtomicRMW<atomic_load_max_32, atomic_load_max_64>; -defm ATOMIC_LOAD_UMIN : AtomicRMW<atomic_load_umin_32, atomic_load_umin_64>; -defm ATOMIC_LOAD_UMAX : AtomicRMW<atomic_load_umax_32, atomic_load_umax_64>; - -// There is no 64-bit variant of SWAP, so use a pseudo. -let usesCustomInserter = 1, hasCtrlDep = 1, mayLoad = 1, mayStore = 1, - Defs = [ICC], Predicates = [Is64Bit] in -def ATOMIC_SWAP_64 : Pseudo<(outs I64Regs:$rd), - (ins ptr_rc:$addr, I64Regs:$rs2), "", - [(set i64:$rd, - (atomic_swap_64 iPTR:$addr, i64:$rs2))]>; - let Predicates = [Is64Bit], hasSideEffects = 1, Uses = [ICC], cc = 0b10 in defm TXCC : TRAP<"%xcc">; diff --git a/lib/Target/Sparc/SparcInstrAliases.td b/lib/Target/Sparc/SparcInstrAliases.td index 361d21440a97..df570cea8da8 100644 --- a/lib/Target/Sparc/SparcInstrAliases.td +++ b/lib/Target/Sparc/SparcInstrAliases.td @@ -136,59 +136,68 @@ multiclass int_cond_alias<string cond, int condVal> { (FMOVQ_XCC QFPRegs:$rd, QFPRegs:$rs2, condVal)>, Requires<[Is64Bit, HasHardQuad]>; - // t<cond> %icc, rs1 + rs2 - def : InstAlias<!strconcat(!strconcat("t", cond), " %icc, $rs1 + $rs2"), - (TICCrr IntRegs:$rs1, IntRegs:$rs2, condVal)>, - Requires<[HasV9]>; - // t<cond> %icc, rs => t<cond> %icc, G0 + rs def : InstAlias<!strconcat(!strconcat("t", cond), " %icc, $rs2"), (TICCrr G0, IntRegs:$rs2, condVal)>, Requires<[HasV9]>; - - // t<cond> %xcc, rs1 + rs2 - def : InstAlias<!strconcat(!strconcat("t", cond), " %xcc, $rs1 + $rs2"), - (TXCCrr IntRegs:$rs1, IntRegs:$rs2, condVal)>, + // t<cond> %icc, rs1 + rs2 + def : InstAlias<!strconcat(!strconcat("t", cond), " %icc, $rs1 + $rs2"), + (TICCrr IntRegs:$rs1, IntRegs:$rs2, condVal)>, Requires<[HasV9]>; + // t<cond> %xcc, rs => t<cond> %xcc, G0 + rs def : InstAlias<!strconcat(!strconcat("t", cond), " %xcc, $rs2"), (TXCCrr G0, IntRegs:$rs2, condVal)>, Requires<[HasV9]>; + // t<cond> %xcc, rs1 + rs2 + def : InstAlias<!strconcat(!strconcat("t", cond), " %xcc, $rs1 + $rs2"), + (TXCCrr IntRegs:$rs1, IntRegs:$rs2, condVal)>, + Requires<[HasV9]>; - // t<cond> rs1 + rs2 => t<cond> %icc, rs1 + rs2 - def : InstAlias<!strconcat(!strconcat("t", cond), " $rs1 + $rs2"), - (TICCrr IntRegs:$rs1, IntRegs:$rs2, condVal)>; // t<cond> rs=> t<cond> %icc, G0 + rs2 - def : InstAlias<!strconcat(!strconcat("t", cond), " $rs2"), - (TICCrr G0, IntRegs:$rs2, condVal)>; + //def : InstAlias<!strconcat(!strconcat("t", cond), " $rs2"), + // (TICCrr G0, IntRegs:$rs2, condVal)>, + // Requires<[HasV9]>; + + // t<cond> rs1 + rs2 => t<cond> %icc, rs1 + rs2 + //def : InstAlias<!strconcat(!strconcat("t", cond), " $rs1 + $rs2"), + // (TICCrr IntRegs:$rs1, IntRegs:$rs2, condVal)>, + // Requires<[HasV9]>; - // t<cond> %icc, rs1 + imm - def : InstAlias<!strconcat(!strconcat("t", cond), " %icc, $rs1 + $imm"), - (TICCri IntRegs:$rs1, i32imm:$imm, condVal)>, - Requires<[HasV9]>; // t<cond> %icc, imm => t<cond> %icc, G0 + imm def : InstAlias<!strconcat(!strconcat("t", cond), " %icc, $imm"), (TICCri G0, i32imm:$imm, condVal)>, Requires<[HasV9]>; - // t<cond> %xcc, rs1 + imm - def : InstAlias<!strconcat(!strconcat("t", cond), " %xcc, $rs1 + $imm"), - (TXCCri IntRegs:$rs1, i32imm:$imm, condVal)>, + // t<cond> %icc, rs1 + imm + def : InstAlias<!strconcat(!strconcat("t", cond), " %icc, $rs1 + $imm"), + (TICCri IntRegs:$rs1, i32imm:$imm, condVal)>, Requires<[HasV9]>; // t<cond> %xcc, imm => t<cond> %xcc, G0 + imm def : InstAlias<!strconcat(!strconcat("t", cond), " %xcc, $imm"), (TXCCri G0, i32imm:$imm, condVal)>, Requires<[HasV9]>; + // t<cond> %xcc, rs1 + imm + def : InstAlias<!strconcat(!strconcat("t", cond), " %xcc, $rs1 + $imm"), + (TXCCri IntRegs:$rs1, i32imm:$imm, condVal)>, + Requires<[HasV9]>; + + // t<cond> imm => t<cond> G0 + imm + def : InstAlias<!strconcat(!strconcat("t", cond), " $imm"), + (TRAPri G0, i32imm:$imm, condVal)>; - // t<cond> rs1 + imm => t<cond> %icc, rs1 + imm + // t<cond> rs1 + imm => t<cond> rs1 + imm def : InstAlias<!strconcat(!strconcat("t", cond), " $rs1 + $imm"), - (TICCri IntRegs:$rs1, i32imm:$imm, condVal)>; + (TRAPri IntRegs:$rs1, i32imm:$imm, condVal)>; - // t<cond> imm => t<cond> %icc, G0 + imm - def : InstAlias<!strconcat(!strconcat("t", cond), " $imm"), - (TICCri G0, i32imm:$imm, condVal)>; + // t<cond> rs1 => t<cond> G0 + rs1 + def : InstAlias<!strconcat(!strconcat("t", cond), " $rs1"), + (TRAPrr G0, IntRegs:$rs1, condVal)>; + // t<cond> rs1 + rs2 + def : InstAlias<!strconcat(!strconcat("t", cond), " $rs1 + $rs2"), + (TRAPrr IntRegs:$rs1, IntRegs:$rs2, condVal)>; } @@ -244,14 +253,23 @@ multiclass fp_cond_alias<string cond, int condVal> { Requires<[HasV9, HasHardQuad]>; } + +// Instruction aliases for co-processor conditional branches. +multiclass cp_cond_alias<string cond, int condVal> { + + // cb<cond> $imm + def : InstAlias<!strconcat(!strconcat("cb", cond), " $imm"), + (CBCOND brtarget:$imm, condVal), 0>; + + // cb<cond>,a $imm + def : InstAlias<!strconcat(!strconcat("cb", cond), ",a $imm"), + (CBCONDA brtarget:$imm, condVal), 0>; +} + defm : int_cond_alias<"a", 0b1000>; -defm : int_cond_alias<"", 0b1000>; // same as a; gnu asm, not in manual defm : int_cond_alias<"n", 0b0000>; defm : int_cond_alias<"ne", 0b1001>; -defm : int_cond_alias<"nz", 0b1001>; // same as ne defm : int_cond_alias<"e", 0b0001>; -defm : int_cond_alias<"eq", 0b0001>; // same as e -defm : int_cond_alias<"z", 0b0001>; // same as e defm : int_cond_alias<"g", 0b1010>; defm : int_cond_alias<"le", 0b0010>; defm : int_cond_alias<"ge", 0b1011>; @@ -259,16 +277,21 @@ defm : int_cond_alias<"l", 0b0011>; defm : int_cond_alias<"gu", 0b1100>; defm : int_cond_alias<"leu", 0b0100>; defm : int_cond_alias<"cc", 0b1101>; -defm : int_cond_alias<"geu", 0b1101>; // same as cc defm : int_cond_alias<"cs", 0b0101>; -defm : int_cond_alias<"lu", 0b0101>; // same as cs defm : int_cond_alias<"pos", 0b1110>; defm : int_cond_alias<"neg", 0b0110>; defm : int_cond_alias<"vc", 0b1111>; defm : int_cond_alias<"vs", 0b0111>; - +let EmitPriority = 0 in +{ + defm : int_cond_alias<"", 0b1000>; // same as a; gnu asm, not in manual + defm : int_cond_alias<"nz", 0b1001>; // same as ne + defm : int_cond_alias<"eq", 0b0001>; // same as e + defm : int_cond_alias<"z", 0b0001>; // same as e + defm : int_cond_alias<"geu", 0b1101>; // same as cc + defm : int_cond_alias<"lu", 0b0101>; // same as cs +} defm : fp_cond_alias<"a", 0b1000>; -defm : fp_cond_alias<"", 0b1000>; // same as a; gnu asm, not in manual defm : fp_cond_alias<"n", 0b0000>; defm : fp_cond_alias<"u", 0b0111>; defm : fp_cond_alias<"g", 0b0110>; @@ -277,15 +300,37 @@ defm : fp_cond_alias<"l", 0b0100>; defm : fp_cond_alias<"ul", 0b0011>; defm : fp_cond_alias<"lg", 0b0010>; defm : fp_cond_alias<"ne", 0b0001>; -defm : fp_cond_alias<"nz", 0b0001>; // same as ne defm : fp_cond_alias<"e", 0b1001>; -defm : fp_cond_alias<"z", 0b1001>; // same as e defm : fp_cond_alias<"ue", 0b1010>; defm : fp_cond_alias<"ge", 0b1011>; defm : fp_cond_alias<"uge", 0b1100>; defm : fp_cond_alias<"le", 0b1101>; defm : fp_cond_alias<"ule", 0b1110>; defm : fp_cond_alias<"o", 0b1111>; +let EmitPriority = 0 in +{ + defm : fp_cond_alias<"", 0b1000>; // same as a; gnu asm, not in manual + defm : fp_cond_alias<"nz", 0b0001>; // same as ne + defm : fp_cond_alias<"z", 0b1001>; // same as e +} + +defm : cp_cond_alias<"a", 0b1000>; +defm : cp_cond_alias<"n", 0b0000>; +defm : cp_cond_alias<"3", 0b0111>; +defm : cp_cond_alias<"2", 0b0110>; +defm : cp_cond_alias<"23", 0b0101>; +defm : cp_cond_alias<"1", 0b0100>; +defm : cp_cond_alias<"13", 0b0011>; +defm : cp_cond_alias<"12", 0b0010>; +defm : cp_cond_alias<"123", 0b0001>; +defm : cp_cond_alias<"0", 0b1001>; +defm : cp_cond_alias<"03", 0b1010>; +defm : cp_cond_alias<"02", 0b1011>; +defm : cp_cond_alias<"023", 0b1100>; +defm : cp_cond_alias<"01", 0b1101>; +defm : cp_cond_alias<"013", 0b1110>; +defm : cp_cond_alias<"012", 0b1111>; +let EmitPriority = 0 in defm : cp_cond_alias<"", 0b1000>; // same as a; gnu asm, not in manual // Section A.3 Synthetic Instructions diff --git a/lib/Target/Sparc/SparcInstrFormats.td b/lib/Target/Sparc/SparcInstrFormats.td index 74ccf551e473..76366c6695f4 100644 --- a/lib/Target/Sparc/SparcInstrFormats.td +++ b/lib/Target/Sparc/SparcInstrFormats.td @@ -7,8 +7,9 @@ // //===----------------------------------------------------------------------===// -class InstSP<dag outs, dag ins, string asmstr, list<dag> pattern> - : Instruction { +class InstSP<dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin = NoItinerary> + : Instruction { field bits<32> Inst; let Namespace = "SP"; @@ -24,6 +25,8 @@ class InstSP<dag outs, dag ins, string asmstr, list<dag> pattern> let DecoderNamespace = "Sparc"; field bits<32> SoftFail = 0; + + let Itinerary = itin; } //===----------------------------------------------------------------------===// @@ -31,8 +34,9 @@ class InstSP<dag outs, dag ins, string asmstr, list<dag> pattern> //===----------------------------------------------------------------------===// // Format 2 instructions -class F2<dag outs, dag ins, string asmstr, list<dag> pattern> - : InstSP<outs, ins, asmstr, pattern> { +class F2<dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin = NoItinerary> + : InstSP<outs, ins, asmstr, pattern, itin> { bits<3> op2; bits<22> imm22; let op = 0; // op = 0 @@ -42,8 +46,9 @@ class F2<dag outs, dag ins, string asmstr, list<dag> pattern> // Specific F2 classes: SparcV8 manual, page 44 // -class F2_1<bits<3> op2Val, dag outs, dag ins, string asmstr, list<dag> pattern> - : F2<outs, ins, asmstr, pattern> { +class F2_1<bits<3> op2Val, dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin = NoItinerary> + : F2<outs, ins, asmstr, pattern, itin> { bits<5> rd; let op2 = op2Val; @@ -52,7 +57,8 @@ class F2_1<bits<3> op2Val, dag outs, dag ins, string asmstr, list<dag> pattern> } class F2_2<bits<3> op2Val, bit annul, dag outs, dag ins, string asmstr, - list<dag> pattern> : F2<outs, ins, asmstr, pattern> { + list<dag> pattern, InstrItinClass itin = NoItinerary> + : F2<outs, ins, asmstr, pattern, itin> { bits<4> cond; let op2 = op2Val; @@ -61,8 +67,9 @@ class F2_2<bits<3> op2Val, bit annul, dag outs, dag ins, string asmstr, } class F2_3<bits<3> op2Val, bit annul, bit pred, - dag outs, dag ins, string asmstr, list<dag> pattern> - : InstSP<outs, ins, asmstr, pattern> { + dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin = NoItinerary> + : InstSP<outs, ins, asmstr, pattern, itin> { bits<2> cc; bits<4> cond; bits<19> imm19; @@ -77,9 +84,9 @@ class F2_3<bits<3> op2Val, bit annul, bit pred, let Inst{18-0} = imm19; } -class F2_4<bits<3> cond, bit annul, bit pred, - dag outs, dag ins, string asmstr, list<dag> pattern> - : InstSP<outs, ins, asmstr, pattern> { +class F2_4<bits<3> cond, bit annul, bit pred, dag outs, dag ins, + string asmstr, list<dag> pattern, InstrItinClass itin = NoItinerary> + : InstSP<outs, ins, asmstr, pattern, itin> { bits<16> imm16; bits<5> rs1; @@ -100,8 +107,9 @@ class F2_4<bits<3> cond, bit annul, bit pred, // Format #3 instruction classes in the Sparc //===----------------------------------------------------------------------===// -class F3<dag outs, dag ins, string asmstr, list<dag> pattern> - : InstSP<outs, ins, asmstr, pattern> { +class F3<dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin = NoItinerary> + : InstSP<outs, ins, asmstr, pattern, itin> { bits<5> rd; bits<6> op3; bits<5> rs1; @@ -114,7 +122,8 @@ class F3<dag outs, dag ins, string asmstr, list<dag> pattern> // Specific F3 classes: SparcV8 manual, page 44 // class F3_1_asi<bits<2> opVal, bits<6> op3val, dag outs, dag ins, - string asmstr, list<dag> pattern> : F3<outs, ins, asmstr, pattern> { + string asmstr, list<dag> pattern, InstrItinClass itin = NoItinerary> + : F3<outs, ins, asmstr, pattern, itin> { bits<8> asi; bits<5> rs2; @@ -127,13 +136,14 @@ class F3_1_asi<bits<2> opVal, bits<6> op3val, dag outs, dag ins, } class F3_1<bits<2> opVal, bits<6> op3val, dag outs, dag ins, string asmstr, - list<dag> pattern> : F3_1_asi<opVal, op3val, outs, ins, - asmstr, pattern> { + list<dag> pattern, InstrItinClass itin = IIC_iu_instr> + : F3_1_asi<opVal, op3val, outs, ins, asmstr, pattern, itin> { let asi = 0; } class F3_2<bits<2> opVal, bits<6> op3val, dag outs, dag ins, - string asmstr, list<dag> pattern> : F3<outs, ins, asmstr, pattern> { + string asmstr, list<dag> pattern, InstrItinClass itin = IIC_iu_instr> + : F3<outs, ins, asmstr, pattern, itin> { bits<13> simm13; let op = opVal; @@ -145,7 +155,8 @@ class F3_2<bits<2> opVal, bits<6> op3val, dag outs, dag ins, // floating-point class F3_3<bits<2> opVal, bits<6> op3val, bits<9> opfval, dag outs, dag ins, - string asmstr, list<dag> pattern> : F3<outs, ins, asmstr, pattern> { + string asmstr, list<dag> pattern, InstrItinClass itin = NoItinerary> + : F3<outs, ins, asmstr, pattern, itin> { bits<5> rs2; let op = opVal; @@ -157,7 +168,8 @@ class F3_3<bits<2> opVal, bits<6> op3val, bits<9> opfval, dag outs, dag ins, // floating-point unary operations. class F3_3u<bits<2> opVal, bits<6> op3val, bits<9> opfval, dag outs, dag ins, - string asmstr, list<dag> pattern> : F3<outs, ins, asmstr, pattern> { + string asmstr, list<dag> pattern, InstrItinClass itin = NoItinerary> + : F3<outs, ins, asmstr, pattern, itin> { bits<5> rs2; let op = opVal; @@ -170,7 +182,8 @@ class F3_3u<bits<2> opVal, bits<6> op3val, bits<9> opfval, dag outs, dag ins, // floating-point compares. class F3_3c<bits<2> opVal, bits<6> op3val, bits<9> opfval, dag outs, dag ins, - string asmstr, list<dag> pattern> : F3<outs, ins, asmstr, pattern> { + string asmstr, list<dag> pattern, InstrItinClass itin = NoItinerary> + : F3<outs, ins, asmstr, pattern, itin> { bits<5> rs2; let op = opVal; @@ -182,7 +195,8 @@ class F3_3c<bits<2> opVal, bits<6> op3val, bits<9> opfval, dag outs, dag ins, // Shift by register rs2. class F3_Sr<bits<2> opVal, bits<6> op3val, bit xVal, dag outs, dag ins, - string asmstr, list<dag> pattern> : F3<outs, ins, asmstr, pattern> { + string asmstr, list<dag> pattern, InstrItinClass itin = IIC_iu_instr> + : F3<outs, ins, asmstr, pattern, itin> { bit x = xVal; // 1 for 64-bit shifts. bits<5> rs2; @@ -196,7 +210,8 @@ class F3_Sr<bits<2> opVal, bits<6> op3val, bit xVal, dag outs, dag ins, // Shift by immediate. class F3_Si<bits<2> opVal, bits<6> op3val, bit xVal, dag outs, dag ins, - string asmstr, list<dag> pattern> : F3<outs, ins, asmstr, pattern> { + string asmstr, list<dag> pattern, InstrItinClass itin = IIC_iu_instr> + : F3<outs, ins, asmstr, pattern, itin> { bit x = xVal; // 1 for 64-bit shifts. bits<6> shcnt; // shcnt32 / shcnt64. @@ -210,17 +225,21 @@ class F3_Si<bits<2> opVal, bits<6> op3val, bit xVal, dag outs, dag ins, // Define rr and ri shift instructions with patterns. multiclass F3_S<string OpcStr, bits<6> Op3Val, bit XVal, SDNode OpNode, - ValueType VT, RegisterClass RC> { + ValueType VT, RegisterClass RC, + InstrItinClass itin = IIC_iu_instr> { def rr : F3_Sr<2, Op3Val, XVal, (outs RC:$rd), (ins RC:$rs1, IntRegs:$rs2), !strconcat(OpcStr, " $rs1, $rs2, $rd"), - [(set VT:$rd, (OpNode VT:$rs1, i32:$rs2))]>; + [(set VT:$rd, (OpNode VT:$rs1, i32:$rs2))], + itin>; def ri : F3_Si<2, Op3Val, XVal, (outs RC:$rd), (ins RC:$rs1, i32imm:$shcnt), !strconcat(OpcStr, " $rs1, $shcnt, $rd"), - [(set VT:$rd, (OpNode VT:$rs1, (i32 imm:$shcnt)))]>; + [(set VT:$rd, (OpNode VT:$rs1, (i32 imm:$shcnt)))], + itin>; } -class F4<bits<6> op3, dag outs, dag ins, string asmstr, list<dag> pattern> - : InstSP<outs, ins, asmstr, pattern> { +class F4<bits<6> op3, dag outs, dag ins, string asmstr, list<dag> pattern, + InstrItinClass itin = NoItinerary> + : InstSP<outs, ins, asmstr, pattern, itin> { bits<5> rd; let op = 2; @@ -230,9 +249,9 @@ class F4<bits<6> op3, dag outs, dag ins, string asmstr, list<dag> pattern> class F4_1<bits<6> op3, dag outs, dag ins, - string asmstr, list<dag> pattern> - : F4<op3, outs, ins, asmstr, pattern> { - + string asmstr, list<dag> pattern, + InstrItinClass itin = NoItinerary> + : F4<op3, outs, ins, asmstr, pattern, itin> { bit intcc; bits<2> cc; bits<4> cond; @@ -243,12 +262,12 @@ class F4_1<bits<6> op3, dag outs, dag ins, let Inst{13} = 0; let Inst{17-14} = cond; let Inst{18} = intcc; - } class F4_2<bits<6> op3, dag outs, dag ins, - string asmstr, list<dag> pattern> - : F4<op3, outs, ins, asmstr, pattern> { + string asmstr, list<dag> pattern, + InstrItinClass itin = NoItinerary> + : F4<op3, outs, ins, asmstr, pattern, itin> { bit intcc; bits<2> cc; bits<4> cond; @@ -262,8 +281,9 @@ class F4_2<bits<6> op3, dag outs, dag ins, } class F4_3<bits<6> op3, bits<6> opf_low, dag outs, dag ins, - string asmstr, list<dag> pattern> - : F4<op3, outs, ins, asmstr, pattern> { + string asmstr, list<dag> pattern, + InstrItinClass itin = NoItinerary> + : F4<op3, outs, ins, asmstr, pattern, itin> { bits<4> cond; bit intcc; bits<2> opf_cc; @@ -278,8 +298,9 @@ class F4_3<bits<6> op3, bits<6> opf_low, dag outs, dag ins, } class F4_4r<bits<6> op3, bits<5> opf_low, bits<3> rcond, dag outs, dag ins, - string asmstr, list<dag> pattern> - : F4<op3, outs, ins, asmstr, pattern> { + string asmstr, list<dag> pattern, + InstrItinClass itin = NoItinerary> + : F4<op3, outs, ins, asmstr, pattern, itin> { bits <5> rs1; bits <5> rs2; let Inst{18-14} = rs1; @@ -291,8 +312,9 @@ class F4_4r<bits<6> op3, bits<5> opf_low, bits<3> rcond, dag outs, dag ins, class F4_4i<bits<6> op3, bits<3> rcond, dag outs, dag ins, - string asmstr, list<dag> pattern> - : F4<op3, outs, ins, asmstr, pattern> { + string asmstr, list<dag> pattern, + InstrItinClass itin = NoItinerary> + : F4<op3, outs, ins, asmstr, pattern, itin> { bits<5> rs1; bits<10> simm10; let Inst{18-14} = rs1; @@ -302,9 +324,10 @@ class F4_4i<bits<6> op3, bits<3> rcond, dag outs, dag ins, } -class TRAPSP<bits<6> op3Val, bit isimm, dag outs, dag ins, string asmstr, - list<dag> pattern>: F3<outs, ins, asmstr, pattern> { - +class TRAPSP<bits<6> op3Val, bit isimm, dag outs, dag ins, + string asmstr, list<dag> pattern, + InstrItinClass itin = NoItinerary> + : F3<outs, ins, asmstr, pattern, itin> { bits<4> cond; bits<2> cc; @@ -317,15 +340,20 @@ class TRAPSP<bits<6> op3Val, bit isimm, dag outs, dag ins, string asmstr, } -class TRAPSPrr<bits<6> op3Val, dag outs, dag ins, string asmstr, - list<dag> pattern>: TRAPSP<op3Val, 0, outs, ins, asmstr, pattern> { +class TRAPSPrr<bits<6> op3Val, dag outs, dag ins, + string asmstr, list<dag> pattern, + InstrItinClass itin = NoItinerary> + : TRAPSP<op3Val, 0, outs, ins, asmstr, pattern, itin> { bits<5> rs2; let Inst{10-5} = 0; let Inst{4-0} = rs2; } -class TRAPSPri<bits<6> op3Val, dag outs, dag ins, string asmstr, - list<dag> pattern>: TRAPSP<op3Val, 1, outs, ins, asmstr, pattern> { + +class TRAPSPri<bits<6> op3Val, dag outs, dag ins, + string asmstr, list<dag> pattern, + InstrItinClass itin = NoItinerary> + : TRAPSP<op3Val, 1, outs, ins, asmstr, pattern, itin> { bits<8> imm; let Inst{10-8} = 0; diff --git a/lib/Target/Sparc/SparcInstrInfo.cpp b/lib/Target/Sparc/SparcInstrInfo.cpp index 05006ac5772b..cfd342410550 100644 --- a/lib/Target/Sparc/SparcInstrInfo.cpp +++ b/lib/Target/Sparc/SparcInstrInfo.cpp @@ -41,17 +41,15 @@ SparcInstrInfo::SparcInstrInfo(SparcSubtarget &ST) /// the destination along with the FrameIndex of the loaded stack slot. If /// not, return 0. This predicate must return 0 if the instruction has /// any side effects other than loading from the stack slot. -unsigned SparcInstrInfo::isLoadFromStackSlot(const MachineInstr *MI, +unsigned SparcInstrInfo::isLoadFromStackSlot(const MachineInstr &MI, int &FrameIndex) const { - if (MI->getOpcode() == SP::LDri || - MI->getOpcode() == SP::LDXri || - MI->getOpcode() == SP::LDFri || - MI->getOpcode() == SP::LDDFri || - MI->getOpcode() == SP::LDQFri) { - if (MI->getOperand(1).isFI() && MI->getOperand(2).isImm() && - MI->getOperand(2).getImm() == 0) { - FrameIndex = MI->getOperand(1).getIndex(); - return MI->getOperand(0).getReg(); + if (MI.getOpcode() == SP::LDri || MI.getOpcode() == SP::LDXri || + MI.getOpcode() == SP::LDFri || MI.getOpcode() == SP::LDDFri || + MI.getOpcode() == SP::LDQFri) { + if (MI.getOperand(1).isFI() && MI.getOperand(2).isImm() && + MI.getOperand(2).getImm() == 0) { + FrameIndex = MI.getOperand(1).getIndex(); + return MI.getOperand(0).getReg(); } } return 0; @@ -62,17 +60,15 @@ unsigned SparcInstrInfo::isLoadFromStackSlot(const MachineInstr *MI, /// the source reg along with the FrameIndex of the loaded stack slot. If /// not, return 0. This predicate must return 0 if the instruction has /// any side effects other than storing to the stack slot. -unsigned SparcInstrInfo::isStoreToStackSlot(const MachineInstr *MI, +unsigned SparcInstrInfo::isStoreToStackSlot(const MachineInstr &MI, int &FrameIndex) const { - if (MI->getOpcode() == SP::STri || - MI->getOpcode() == SP::STXri || - MI->getOpcode() == SP::STFri || - MI->getOpcode() == SP::STDFri || - MI->getOpcode() == SP::STQFri) { - if (MI->getOperand(0).isFI() && MI->getOperand(1).isImm() && - MI->getOperand(1).getImm() == 0) { - FrameIndex = MI->getOperand(0).getIndex(); - return MI->getOperand(2).getReg(); + if (MI.getOpcode() == SP::STri || MI.getOpcode() == SP::STXri || + MI.getOpcode() == SP::STFri || MI.getOpcode() == SP::STDFri || + MI.getOpcode() == SP::STQFri) { + if (MI.getOperand(0).isFI() && MI.getOperand(1).isImm() && + MI.getOperand(1).getImm() == 0) { + FrameIndex = MI.getOperand(0).getIndex(); + return MI.getOperand(2).getReg(); } } return 0; @@ -119,6 +115,28 @@ static SPCC::CondCodes GetOppositeBranchCondition(SPCC::CondCodes CC) case SPCC::FCC_UE: return SPCC::FCC_LG; case SPCC::FCC_NE: return SPCC::FCC_E; case SPCC::FCC_E: return SPCC::FCC_NE; + + case SPCC::CPCC_A: return SPCC::CPCC_N; + case SPCC::CPCC_N: return SPCC::CPCC_A; + case SPCC::CPCC_3: // Fall through + case SPCC::CPCC_2: // Fall through + case SPCC::CPCC_23: // Fall through + case SPCC::CPCC_1: // Fall through + case SPCC::CPCC_13: // Fall through + case SPCC::CPCC_12: // Fall through + case SPCC::CPCC_123: // Fall through + case SPCC::CPCC_0: // Fall through + case SPCC::CPCC_03: // Fall through + case SPCC::CPCC_02: // Fall through + case SPCC::CPCC_023: // Fall through + case SPCC::CPCC_01: // Fall through + case SPCC::CPCC_013: // Fall through + case SPCC::CPCC_012: + // "Opposite" code is not meaningful, as we don't know + // what the CoProc condition means here. The cond-code will + // only be used in inline assembler, so this code should + // not be reached in a normal compilation pass. + llvm_unreachable("Meaningless inversion of co-processor cond code"); } llvm_unreachable("Invalid cond code"); } @@ -139,7 +157,7 @@ static void parseCondBranch(MachineInstr *LastInst, MachineBasicBlock *&Target, Target = LastInst->getOperand(0).getMBB(); } -bool SparcInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB, +bool SparcInstrInfo::analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, MachineBasicBlock *&FBB, SmallVectorImpl<MachineOperand> &Cond, @@ -148,15 +166,15 @@ bool SparcInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB, if (I == MBB.end()) return false; - if (!isUnpredicatedTerminator(I)) + if (!isUnpredicatedTerminator(*I)) return false; // Get the last instruction in the block. - MachineInstr *LastInst = I; + MachineInstr *LastInst = &*I; unsigned LastOpc = LastInst->getOpcode(); // If there is only one terminator instruction, process it. - if (I == MBB.begin() || !isUnpredicatedTerminator(--I)) { + if (I == MBB.begin() || !isUnpredicatedTerminator(*--I)) { if (isUncondBranchOpcode(LastOpc)) { TBB = LastInst->getOperand(0).getMBB(); return false; @@ -170,7 +188,7 @@ bool SparcInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB, } // Get the instruction before it if it is a terminator. - MachineInstr *SecondLastInst = I; + MachineInstr *SecondLastInst = &*I; unsigned SecondLastOpc = SecondLastInst->getOpcode(); // If AllowModify is true and the block ends with two or more unconditional @@ -180,19 +198,19 @@ bool SparcInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB, LastInst->eraseFromParent(); LastInst = SecondLastInst; LastOpc = LastInst->getOpcode(); - if (I == MBB.begin() || !isUnpredicatedTerminator(--I)) { + if (I == MBB.begin() || !isUnpredicatedTerminator(*--I)) { // Return now the only terminator is an unconditional branch. TBB = LastInst->getOperand(0).getMBB(); return false; } else { - SecondLastInst = I; + SecondLastInst = &*I; SecondLastOpc = SecondLastInst->getOpcode(); } } } // If there are three terminators, we don't know what sort of block this is. - if (SecondLastInst && I != MBB.begin() && isUnpredicatedTerminator(--I)) + if (SecondLastInst && I != MBB.begin() && isUnpredicatedTerminator(*--I)) return true; // If the block ends with a B and a Bcc, handle it. @@ -222,11 +240,11 @@ bool SparcInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB, return true; } -unsigned -SparcInstrInfo::InsertBranch(MachineBasicBlock &MBB,MachineBasicBlock *TBB, - MachineBasicBlock *FBB, - ArrayRef<MachineOperand> Cond, - DebugLoc DL) const { +unsigned SparcInstrInfo::InsertBranch(MachineBasicBlock &MBB, + MachineBasicBlock *TBB, + MachineBasicBlock *FBB, + ArrayRef<MachineOperand> Cond, + const DebugLoc &DL) const { assert(TBB && "InsertBranch must not be told to insert a fallthrough"); assert((Cond.size() == 1 || Cond.size() == 0) && "Sparc branch conditions should have one component!"); @@ -282,9 +300,9 @@ bool SparcInstrInfo::ReverseBranchCondition( } void SparcInstrInfo::copyPhysReg(MachineBasicBlock &MBB, - MachineBasicBlock::iterator I, DebugLoc DL, - unsigned DestReg, unsigned SrcReg, - bool KillSrc) const { + MachineBasicBlock::iterator I, + const DebugLoc &DL, unsigned DestReg, + unsigned SrcReg, bool KillSrc) const { unsigned numSubRegs = 0; unsigned movOpc = 0; const unsigned *subRegIdx = nullptr; @@ -469,3 +487,20 @@ unsigned SparcInstrInfo::getGlobalBaseReg(MachineFunction *MF) const SparcFI->setGlobalBaseReg(GlobalBaseReg); return GlobalBaseReg; } + +bool SparcInstrInfo::expandPostRAPseudo(MachineInstr &MI) const { + switch (MI.getOpcode()) { + case TargetOpcode::LOAD_STACK_GUARD: { + assert(Subtarget.isTargetLinux() && + "Only Linux target is expected to contain LOAD_STACK_GUARD"); + // offsetof(tcbhead_t, stack_guard) from sysdeps/sparc/nptl/tls.h in glibc. + const int64_t Offset = Subtarget.is64Bit() ? 0x28 : 0x14; + MI.setDesc(get(Subtarget.is64Bit() ? SP::LDXri : SP::LDri)); + MachineInstrBuilder(*MI.getParent()->getParent(), MI) + .addReg(SP::G7) + .addImm(Offset); + return true; + } + } + return false; +} diff --git a/lib/Target/Sparc/SparcInstrInfo.h b/lib/Target/Sparc/SparcInstrInfo.h index 9de624cc9582..8ed97c1479ca 100644 --- a/lib/Target/Sparc/SparcInstrInfo.h +++ b/lib/Target/Sparc/SparcInstrInfo.h @@ -54,7 +54,7 @@ public: /// the destination along with the FrameIndex of the loaded stack slot. If /// not, return 0. This predicate must return 0 if the instruction has /// any side effects other than loading from the stack slot. - unsigned isLoadFromStackSlot(const MachineInstr *MI, + unsigned isLoadFromStackSlot(const MachineInstr &MI, int &FrameIndex) const override; /// isStoreToStackSlot - If the specified machine instruction is a direct @@ -62,26 +62,25 @@ public: /// the source reg along with the FrameIndex of the loaded stack slot. If /// not, return 0. This predicate must return 0 if the instruction has /// any side effects other than storing to the stack slot. - unsigned isStoreToStackSlot(const MachineInstr *MI, + unsigned isStoreToStackSlot(const MachineInstr &MI, int &FrameIndex) const override; - bool AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, + bool analyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB, MachineBasicBlock *&FBB, SmallVectorImpl<MachineOperand> &Cond, - bool AllowModify = false) const override ; + bool AllowModify = false) const override; unsigned RemoveBranch(MachineBasicBlock &MBB) const override; unsigned InsertBranch(MachineBasicBlock &MBB, MachineBasicBlock *TBB, MachineBasicBlock *FBB, ArrayRef<MachineOperand> Cond, - DebugLoc DL) const override; + const DebugLoc &DL) const override; bool ReverseBranchCondition(SmallVectorImpl<MachineOperand> &Cond) const override; - void copyPhysReg(MachineBasicBlock &MBB, - MachineBasicBlock::iterator I, DebugLoc DL, - unsigned DestReg, unsigned SrcReg, + void copyPhysReg(MachineBasicBlock &MBB, MachineBasicBlock::iterator I, + const DebugLoc &DL, unsigned DestReg, unsigned SrcReg, bool KillSrc) const override; void storeRegToStackSlot(MachineBasicBlock &MBB, @@ -97,6 +96,9 @@ public: const TargetRegisterInfo *TRI) const override; unsigned getGlobalBaseReg(MachineFunction *MF) const; + + // Lower pseudo instructions after register allocation. + bool expandPostRAPseudo(MachineInstr &MI) const override; }; } diff --git a/lib/Target/Sparc/SparcInstrInfo.td b/lib/Target/Sparc/SparcInstrInfo.td index ec37c22a5b33..cc55c9c8e032 100644 --- a/lib/Target/Sparc/SparcInstrInfo.td +++ b/lib/Target/Sparc/SparcInstrInfo.td @@ -49,6 +49,18 @@ def HasVIS3 : Predicate<"Subtarget->isVIS3()">, // point instructions. def HasHardQuad : Predicate<"Subtarget->hasHardQuad()">; +// HasLeonCASA - This is true when the target processor supports the CASA +// instruction +def HasLeonCASA : Predicate<"Subtarget->hasLeonCasa()">; + +// HasUMAC_SMAC - This is true when the target processor supports the +// 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 @@ -154,6 +166,9 @@ SDTypeProfile<1, 3, [SDTCisInt<0>, SDTCisSameAs<0, 1>, SDTCisPtrTy<2>]>; def SDTSPtlsld : SDTypeProfile<1, 2, [SDTCisPtrTy<0>, SDTCisPtrTy<1>]>; +def SDTSPeh_sjlj_setjmp : SDTypeProfile<1, 1, [SDTCisInt<0>, SDTCisPtrTy<1>]>; +def SDTSPeh_sjlj_longjmp: SDTypeProfile<0, 1, [SDTCisPtrTy<0>]>; + def SPcmpicc : SDNode<"SPISD::CMPICC", SDTSPcmpicc, [SDNPOutGlue]>; def SPcmpfcc : SDNode<"SPISD::CMPFCC", SDTSPcmpfcc, [SDNPOutGlue]>; def SPbricc : SDNode<"SPISD::BRICC", SDTSPbrcc, [SDNPHasChain, SDNPInGlue]>; @@ -172,6 +187,13 @@ def SPselecticc : SDNode<"SPISD::SELECT_ICC", SDTSPselectcc, [SDNPInGlue]>; def SPselectxcc : SDNode<"SPISD::SELECT_XCC", SDTSPselectcc, [SDNPInGlue]>; def SPselectfcc : SDNode<"SPISD::SELECT_FCC", SDTSPselectcc, [SDNPInGlue]>; +def SPsjlj_setjmp: SDNode<"SPISD::EH_SJLJ_SETJMP", + SDTSPeh_sjlj_setjmp, + [SDNPHasChain, SDNPSideEffect]>; +def SPsjlj_longjmp: SDNode<"SPISD::EH_SJLJ_LONGJMP", + SDTSPeh_sjlj_longjmp, + [SDNPHasChain, SDNPSideEffect]>; + // These are target-independent nodes, but have target-specific formats. def SDT_SPCallSeqStart : SDCallSeqStart<[ SDTCisVT<0, i32> ]>; def SDT_SPCallSeqEnd : SDCallSeqEnd<[ SDTCisVT<0, i32>, @@ -235,12 +257,28 @@ def FCC_UL : FCC_VAL<19>; // Unordered or Less def FCC_LG : FCC_VAL<18>; // Less or Greater def FCC_NE : FCC_VAL<17>; // Not Equal def FCC_E : FCC_VAL<25>; // Equal -def FCC_UE : FCC_VAL<24>; // Unordered or Equal -def FCC_GE : FCC_VAL<25>; // Greater or Equal -def FCC_UGE : FCC_VAL<26>; // Unordered or Greater or Equal -def FCC_LE : FCC_VAL<27>; // Less or Equal -def FCC_ULE : FCC_VAL<28>; // Unordered or Less or Equal -def FCC_O : FCC_VAL<29>; // Ordered +def FCC_UE : FCC_VAL<26>; // Unordered or Equal +def FCC_GE : FCC_VAL<27>; // Greater or Equal +def FCC_UGE : FCC_VAL<28>; // Unordered or Greater or Equal +def FCC_LE : FCC_VAL<29>; // Less or Equal +def FCC_ULE : FCC_VAL<30>; // Unordered or Less or Equal +def FCC_O : FCC_VAL<31>; // Ordered + +class CPCC_VAL<int N> : PatLeaf<(i32 N)>; +def CPCC_3 : CPCC_VAL<39>; // 3 +def CPCC_2 : CPCC_VAL<38>; // 2 +def CPCC_23 : CPCC_VAL<37>; // 2 or 3 +def CPCC_1 : CPCC_VAL<36>; // 1 +def CPCC_13 : CPCC_VAL<35>; // 1 or 3 +def CPCC_12 : CPCC_VAL<34>; // 1 or 2 +def CPCC_123 : CPCC_VAL<33>; // 1 or 2 or 3 +def CPCC_0 : CPCC_VAL<41>; // 0 +def CPCC_03 : CPCC_VAL<42>; // 0 or 3 +def CPCC_02 : CPCC_VAL<43>; // 0 or 2 +def CPCC_023 : CPCC_VAL<44>; // 0 or 2 or 3 +def CPCC_01 : CPCC_VAL<45>; // 0 or 1 +def CPCC_013 : CPCC_VAL<46>; // 0 or 1 or 3 +def CPCC_012 : CPCC_VAL<47>; // 0 or 1 or 2 //===----------------------------------------------------------------------===// // Instruction Class Templates @@ -248,53 +286,61 @@ def FCC_O : FCC_VAL<29>; // Ordered /// F3_12 multiclass - Define a normal F3_1/F3_2 pattern in one shot. multiclass F3_12<string OpcStr, bits<6> Op3Val, SDNode OpNode, - RegisterClass RC, ValueType Ty, Operand immOp> { + RegisterClass RC, ValueType Ty, Operand immOp, + InstrItinClass itin = IIC_iu_instr> { def rr : F3_1<2, Op3Val, (outs RC:$rd), (ins RC:$rs1, RC:$rs2), !strconcat(OpcStr, " $rs1, $rs2, $rd"), - [(set Ty:$rd, (OpNode Ty:$rs1, Ty:$rs2))]>; + [(set Ty:$rd, (OpNode Ty:$rs1, Ty:$rs2))], + itin>; def ri : F3_2<2, Op3Val, (outs RC:$rd), (ins RC:$rs1, immOp:$simm13), !strconcat(OpcStr, " $rs1, $simm13, $rd"), - [(set Ty:$rd, (OpNode Ty:$rs1, (Ty simm13:$simm13)))]>; + [(set Ty:$rd, (OpNode Ty:$rs1, (Ty simm13:$simm13)))], + itin>; } /// F3_12np multiclass - Define a normal F3_1/F3_2 pattern in one shot, with no /// pattern. -multiclass F3_12np<string OpcStr, bits<6> Op3Val> { +multiclass F3_12np<string OpcStr, bits<6> Op3Val, InstrItinClass itin = IIC_iu_instr> { def rr : F3_1<2, Op3Val, (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2), - !strconcat(OpcStr, " $rs1, $rs2, $rd"), []>; + !strconcat(OpcStr, " $rs1, $rs2, $rd"), [], + itin>; def ri : F3_2<2, Op3Val, (outs IntRegs:$rd), (ins IntRegs:$rs1, simm13Op:$simm13), - !strconcat(OpcStr, " $rs1, $simm13, $rd"), []>; + !strconcat(OpcStr, " $rs1, $simm13, $rd"), [], + itin>; } // Load multiclass - Define both Reg+Reg/Reg+Imm patterns in one shot. multiclass Load<string OpcStr, bits<6> Op3Val, SDPatternOperator OpNode, - RegisterClass RC, ValueType Ty> { + RegisterClass RC, ValueType Ty, InstrItinClass itin = IIC_iu_instr> { def rr : F3_1<3, Op3Val, (outs RC:$dst), (ins MEMrr:$addr), !strconcat(OpcStr, " [$addr], $dst"), - [(set Ty:$dst, (OpNode ADDRrr:$addr))]>; + [(set Ty:$dst, (OpNode ADDRrr:$addr))], + itin>; def ri : F3_2<3, Op3Val, (outs RC:$dst), (ins MEMri:$addr), !strconcat(OpcStr, " [$addr], $dst"), - [(set Ty:$dst, (OpNode ADDRri:$addr))]>; + [(set Ty:$dst, (OpNode ADDRri:$addr))], + itin>; } // TODO: Instructions of the LoadASI class are currently asm only; hooking up // CodeGen's address spaces to use these is a future task. class LoadASI<string OpcStr, bits<6> Op3Val, SDPatternOperator OpNode, - RegisterClass RC, ValueType Ty> : + RegisterClass RC, ValueType Ty, InstrItinClass itin = NoItinerary> : F3_1_asi<3, Op3Val, (outs RC:$dst), (ins MEMrr:$addr, i8imm:$asi), !strconcat(OpcStr, "a [$addr] $asi, $dst"), []>; // LoadA multiclass - As above, but also define alternate address space variant multiclass LoadA<string OpcStr, bits<6> Op3Val, bits<6> LoadAOp3Val, - SDPatternOperator OpNode, RegisterClass RC, ValueType Ty> : - Load<OpcStr, Op3Val, OpNode, RC, Ty> { + SDPatternOperator OpNode, RegisterClass RC, ValueType Ty, + InstrItinClass itin = NoItinerary> : + Load<OpcStr, Op3Val, OpNode, RC, Ty, itin> { def Arr : LoadASI<OpcStr, LoadAOp3Val, OpNode, RC, Ty>; } @@ -302,38 +348,43 @@ multiclass LoadA<string OpcStr, bits<6> Op3Val, bits<6> LoadAOp3Val, // It is unlikely that general-purpose code could make use of it. // CAS is preferred for sparc v9. def LDSTUBrr : F3_1<3, 0b001101, (outs IntRegs:$dst), (ins MEMrr:$addr), - "ldstub [$addr], $dst", []>; + "ldstub [$addr], $dst", []>; def LDSTUBri : F3_2<3, 0b001101, (outs IntRegs:$dst), (ins MEMri:$addr), - "ldstub [$addr], $dst", []>; + "ldstub [$addr], $dst", []>; def LDSTUBArr : F3_1_asi<3, 0b011101, (outs IntRegs:$dst), (ins MEMrr:$addr, i8imm:$asi), "ldstuba [$addr] $asi, $dst", []>; // Store multiclass - Define both Reg+Reg/Reg+Imm patterns in one shot. multiclass Store<string OpcStr, bits<6> Op3Val, SDPatternOperator OpNode, - RegisterClass RC, ValueType Ty> { + RegisterClass RC, ValueType Ty, InstrItinClass itin = IIC_st> { def rr : F3_1<3, Op3Val, (outs), (ins MEMrr:$addr, RC:$rd), !strconcat(OpcStr, " $rd, [$addr]"), - [(OpNode Ty:$rd, ADDRrr:$addr)]>; + [(OpNode Ty:$rd, ADDRrr:$addr)], + itin>; def ri : F3_2<3, Op3Val, (outs), (ins MEMri:$addr, RC:$rd), !strconcat(OpcStr, " $rd, [$addr]"), - [(OpNode Ty:$rd, ADDRri:$addr)]>; + [(OpNode Ty:$rd, ADDRri:$addr)], + itin>; } // TODO: Instructions of the StoreASI class are currently asm only; hooking up // CodeGen's address spaces to use these is a future task. class StoreASI<string OpcStr, bits<6> Op3Val, - SDPatternOperator OpNode, RegisterClass RC, ValueType Ty> : + SDPatternOperator OpNode, RegisterClass RC, ValueType Ty, + InstrItinClass itin = IIC_st> : F3_1_asi<3, Op3Val, (outs), (ins MEMrr:$addr, RC:$rd, i8imm:$asi), - !strconcat(OpcStr, "a $rd, [$addr] $asi"), - []>; + !strconcat(OpcStr, "a $rd, [$addr] $asi"), + [], + itin>; multiclass StoreA<string OpcStr, bits<6> Op3Val, bits<6> StoreAOp3Val, - SDPatternOperator OpNode, RegisterClass RC, ValueType Ty> : + SDPatternOperator OpNode, RegisterClass RC, ValueType Ty, + InstrItinClass itin = IIC_st> : Store<OpcStr, Op3Val, OpNode, RC, Ty> { - def Arr : StoreASI<OpcStr, StoreAOp3Val, OpNode, RC, Ty>; + def Arr : StoreASI<OpcStr, StoreAOp3Val, OpNode, RC, Ty, itin>; } //===----------------------------------------------------------------------===// @@ -418,6 +469,27 @@ let usesCustomInserter = 1, Uses = [FCC0] in { [(set f128:$dst, (SPselectfcc f128:$T, f128:$F, imm:$Cond))]>; } +let hasSideEffects = 1, isBarrier = 1, usesCustomInserter = 1 in { + let Defs = [WIM] in + def EH_SJLJ_SETJMP32ri : Pseudo<(outs IntRegs:$dst), (ins MEMri:$buf), + "#EH_SJLJ_SETJMP32", + [(set i32:$dst, (SPsjlj_setjmp ADDRri:$buf))]>, + Requires<[Is32Bit]>; + def EH_SJLJ_SETJMP32rr : Pseudo<(outs IntRegs:$dst), (ins MEMrr:$buf), + "#EH_SJLJ_SETJMP32", + [(set i32:$dst, (SPsjlj_setjmp ADDRrr:$buf))]>, + Requires<[Is32Bit]>; + let isTerminator = 1 in + def EH_SJLJ_LONGJMP32ri : Pseudo<(outs), (ins MEMri:$buf), + "#EH_SJLJ_LONGJMP32", + [(SPsjlj_longjmp ADDRri:$buf)]>, + Requires<[Is32Bit]>; + def EH_SJLJ_LONGJMP32rr : Pseudo<(outs), (ins MEMrr:$buf), + "#EH_SJLJ_LONGJMP32", + [(SPsjlj_longjmp ADDRrr:$buf)]>, + Requires<[Is32Bit]>; +} + // Section B.1 - Load Integer Instructions, p. 90 let DecoderMethod = "DecodeLoadInt" in { defm LDSB : LoadA<"ldsb", 0b001001, 0b011001, sextloadi8, IntRegs, i32>; @@ -428,16 +500,16 @@ let DecoderMethod = "DecodeLoadInt" in { } let DecoderMethod = "DecodeLoadIntPair" in - defm LDD : LoadA<"ldd", 0b000011, 0b010011, load, IntPair, v2i32>; + defm LDD : LoadA<"ldd", 0b000011, 0b010011, load, IntPair, v2i32, IIC_ldd>; // Section B.2 - Load Floating-point Instructions, p. 92 let DecoderMethod = "DecodeLoadFP" in { - defm LDF : Load<"ld", 0b100000, load, FPRegs, f32>; - def LDFArr : LoadASI<"ld", 0b110000, load, FPRegs, f32>, + defm LDF : Load<"ld", 0b100000, load, FPRegs, f32, IIC_iu_or_fpu_instr>; + def LDFArr : LoadASI<"ld", 0b110000, load, FPRegs, f32, IIC_iu_or_fpu_instr>, Requires<[HasV9]>; } let DecoderMethod = "DecodeLoadDFP" in { - defm LDDF : Load<"ldd", 0b100011, load, DFPRegs, f64>; + defm LDDF : Load<"ldd", 0b100011, load, DFPRegs, f64, IIC_ldd>; def LDDFArr : LoadASI<"ldd", 0b110011, load, DFPRegs, f64>, Requires<[HasV9]>; } @@ -445,13 +517,27 @@ let DecoderMethod = "DecodeLoadQFP" in defm LDQF : LoadA<"ldq", 0b100010, 0b110010, load, QFPRegs, f128>, Requires<[HasV9, HasHardQuad]>; +let DecoderMethod = "DecodeLoadCP" in + defm LDC : Load<"ld", 0b110000, load, CoprocRegs, i32>; +let DecoderMethod = "DecodeLoadCPPair" in + defm LDDC : Load<"ldd", 0b110011, load, CoprocPair, v2i32, IIC_ldd>; + +let DecoderMethod = "DecodeLoadCP", Defs = [CPSR] in { + let rd = 0 in { + def LDCSRrr : F3_1<3, 0b110001, (outs), (ins MEMrr:$addr), + "ld [$addr], %csr", []>; + def LDCSRri : F3_2<3, 0b110001, (outs), (ins MEMri:$addr), + "ld [$addr], %csr", []>; + } +} + let DecoderMethod = "DecodeLoadFP" in let Defs = [FSR] in { let rd = 0 in { def LDFSRrr : F3_1<3, 0b100001, (outs), (ins MEMrr:$addr), - "ld [$addr], %fsr", []>; + "ld [$addr], %fsr", [], IIC_iu_or_fpu_instr>; def LDFSRri : F3_2<3, 0b100001, (outs), (ins MEMri:$addr), - "ld [$addr], %fsr", []>; + "ld [$addr], %fsr", [], IIC_iu_or_fpu_instr>; } let rd = 1 in { def LDXFSRrr : F3_1<3, 0b100001, (outs), (ins MEMrr:$addr), @@ -469,7 +555,7 @@ let DecoderMethod = "DecodeStoreInt" in { } let DecoderMethod = "DecodeStoreIntPair" in - defm STD : StoreA<"std", 0b000111, 0b010111, store, IntPair, v2i32>; + defm STD : StoreA<"std", 0b000111, 0b010111, store, IntPair, v2i32, IIC_std>; // Section B.5 - Store Floating-point Instructions, p. 97 let DecoderMethod = "DecodeStoreFP" in { @@ -478,7 +564,7 @@ let DecoderMethod = "DecodeStoreFP" in { Requires<[HasV9]>; } let DecoderMethod = "DecodeStoreDFP" in { - defm STDF : Store<"std", 0b100111, store, DFPRegs, f64>; + defm STDF : Store<"std", 0b100111, store, DFPRegs, f64, IIC_std>; def STDFArr : StoreASI<"std", 0b110111, store, DFPRegs, f64>, Requires<[HasV9]>; } @@ -486,21 +572,49 @@ let DecoderMethod = "DecodeStoreQFP" in defm STQF : StoreA<"stq", 0b100110, 0b110110, store, QFPRegs, f128>, Requires<[HasV9, HasHardQuad]>; -let DecoderMethod = "DecodeStoreFP" in - let Defs = [FSR] in { - let rd = 0 in { +let DecoderMethod = "DecodeStoreCP" in + defm STC : Store<"st", 0b110100, store, CoprocRegs, i32>; + +let DecoderMethod = "DecodeStoreCPPair" in + defm STDC : Store<"std", 0b110111, store, CoprocPair, v2i32, IIC_std>; + +let DecoderMethod = "DecodeStoreCP", rd = 0 in { + let Defs = [CPSR] in { + def STCSRrr : F3_1<3, 0b110101, (outs MEMrr:$addr), (ins), + "st %csr, [$addr]", [], IIC_st>; + def STCSRri : F3_2<3, 0b110101, (outs MEMri:$addr), (ins), + "st %csr, [$addr]", [], IIC_st>; + } + let Defs = [CPQ] in { + def STDCQrr : F3_1<3, 0b110110, (outs MEMrr:$addr), (ins), + "std %cq, [$addr]", [], IIC_std>; + def STDCQri : F3_2<3, 0b110110, (outs MEMri:$addr), (ins), + "std %cq, [$addr]", [], IIC_std>; + } +} + +let DecoderMethod = "DecodeStoreFP" in { + let rd = 0 in { + let Defs = [FSR] in { def STFSRrr : F3_1<3, 0b100101, (outs MEMrr:$addr), (ins), - "st %fsr, [$addr]", []>; + "st %fsr, [$addr]", [], IIC_st>; def STFSRri : F3_2<3, 0b100101, (outs MEMri:$addr), (ins), - "st %fsr, [$addr]", []>; + "st %fsr, [$addr]", [], IIC_st>; } - let rd = 1 in { - def STXFSRrr : F3_1<3, 0b100101, (outs MEMrr:$addr), (ins), - "stx %fsr, [$addr]", []>, Requires<[HasV9]>; - def STXFSRri : F3_2<3, 0b100101, (outs MEMri:$addr), (ins), - "stx %fsr, [$addr]", []>, Requires<[HasV9]>; + let Defs = [FQ] in { + def STDFQrr : F3_1<3, 0b100110, (outs MEMrr:$addr), (ins), + "std %fq, [$addr]", [], IIC_std>; + def STDFQri : F3_2<3, 0b100110, (outs MEMri:$addr), (ins), + "std %fq, [$addr]", [], IIC_std>; } } + let rd = 1, Defs = [FSR] in { + def STXFSRrr : F3_1<3, 0b100101, (outs MEMrr:$addr), (ins), + "stx %fsr, [$addr]", []>, Requires<[HasV9]>; + def STXFSRri : F3_2<3, 0b100101, (outs MEMri:$addr), (ins), + "stx %fsr, [$addr]", []>, Requires<[HasV9]>; + } +} // Section B.8 - SWAP Register with Memory Instruction // (Atomic swap) @@ -524,7 +638,8 @@ let Constraints = "$val = $dst", DecoderMethod = "DecodeSWAP" in { def SETHIi: F2_1<0b100, (outs IntRegs:$rd), (ins i32imm:$imm22), "sethi $imm22, $rd", - [(set i32:$rd, SETHIimm:$imm22)]>; + [(set i32:$rd, SETHIimm:$imm22)], + IIC_iu_instr>; // Section B.10 - NOP Instruction, p. 105 // (It's a special case of SETHI) @@ -619,13 +734,13 @@ let Defs = [ICC], rd = 0 in { // Section B.18 - Multiply Instructions, p. 113 let Defs = [Y] in { - defm UMUL : F3_12np<"umul", 0b001010>; - defm SMUL : F3_12 <"smul", 0b001011, mul, IntRegs, i32, simm13Op>; + defm UMUL : F3_12np<"umul", 0b001010, IIC_iu_umul>; + defm SMUL : F3_12 <"smul", 0b001011, mul, IntRegs, i32, simm13Op, IIC_iu_smul>; } let Defs = [Y, ICC] in { - defm UMULCC : F3_12np<"umulcc", 0b011010>; - defm SMULCC : F3_12np<"smulcc", 0b011011>; + defm UMULCC : F3_12np<"umulcc", 0b011010, IIC_iu_umul>; + defm SMULCC : F3_12np<"smulcc", 0b011011, IIC_iu_smul>; } let Defs = [Y, ICC], Uses = [Y, ICC] in { @@ -634,13 +749,13 @@ let Defs = [Y, ICC], Uses = [Y, ICC] in { // Section B.19 - Divide Instructions, p. 115 let Uses = [Y], Defs = [Y] in { - defm UDIV : F3_12np<"udiv", 0b001110>; - defm SDIV : F3_12np<"sdiv", 0b001111>; + defm UDIV : F3_12np<"udiv", 0b001110, IIC_iu_div>; + defm SDIV : F3_12np<"sdiv", 0b001111, IIC_iu_div>; } let Uses = [Y], Defs = [Y, ICC] in { - defm UDIVCC : F3_12np<"udivcc", 0b011110>; - defm SDIVCC : F3_12np<"sdivcc", 0b011111>; + defm UDIVCC : F3_12np<"udivcc", 0b011110, IIC_iu_div>; + defm SDIVCC : F3_12np<"sdivcc", 0b011111, IIC_iu_div>; } // Section B.20 - SAVE and RESTORE, p. 117 @@ -666,26 +781,30 @@ let isBranch = 1, isTerminator = 1, hasDelaySlot = 1 in { // conditional branch class: class BranchSP<dag ins, string asmstr, list<dag> pattern> - : F2_2<0b010, 0, (outs), ins, asmstr, pattern>; + : F2_2<0b010, 0, (outs), ins, asmstr, pattern, IIC_iu_instr>; // conditional branch with annul class: class BranchSPA<dag ins, string asmstr, list<dag> pattern> - : F2_2<0b010, 1, (outs), ins, asmstr, pattern>; + : F2_2<0b010, 1, (outs), ins, asmstr, pattern, IIC_iu_instr>; // Conditional branch class on %icc|%xcc with predication: multiclass IPredBranch<string regstr, list<dag> CCPattern> { def CC : F2_3<0b001, 0, 1, (outs), (ins bprtarget:$imm19, CCOp:$cond), - !strconcat("b$cond ", !strconcat(regstr, ", $imm19")), - CCPattern>; + !strconcat("b$cond ", !strconcat(regstr, ", $imm19")), + CCPattern, + IIC_iu_instr>; def CCA : F2_3<0b001, 1, 1, (outs), (ins bprtarget:$imm19, CCOp:$cond), - !strconcat("b$cond,a ", !strconcat(regstr, ", $imm19")), - []>; + !strconcat("b$cond,a ", !strconcat(regstr, ", $imm19")), + [], + IIC_iu_instr>; def CCNT : F2_3<0b001, 0, 0, (outs), (ins bprtarget:$imm19, CCOp:$cond), !strconcat("b$cond,pn ", !strconcat(regstr, ", $imm19")), - []>; + [], + IIC_iu_instr>; def CCANT : F2_3<0b001, 1, 0, (outs), (ins bprtarget:$imm19, CCOp:$cond), !strconcat("b$cond,a,pn ", !strconcat(regstr, ", $imm19")), - []>; + [], + IIC_iu_instr>; } } // let isBranch = 1, isTerminator = 1, hasDelaySlot = 1 @@ -721,26 +840,26 @@ let isBranch = 1, isTerminator = 1, hasDelaySlot = 1 in { // floating-point conditional branch class: class FPBranchSP<dag ins, string asmstr, list<dag> pattern> - : F2_2<0b110, 0, (outs), ins, asmstr, pattern>; + : F2_2<0b110, 0, (outs), ins, asmstr, pattern, IIC_fpu_normal_instr>; // floating-point conditional branch with annul class: class FPBranchSPA<dag ins, string asmstr, list<dag> pattern> - : F2_2<0b110, 1, (outs), ins, asmstr, pattern>; + : F2_2<0b110, 1, (outs), ins, asmstr, pattern, IIC_fpu_normal_instr>; // Conditional branch class on %fcc0-%fcc3 with predication: multiclass FPredBranch { def CC : F2_3<0b101, 0, 1, (outs), (ins bprtarget:$imm19, CCOp:$cond, FCCRegs:$cc), - "fb$cond $cc, $imm19", []>; + "fb$cond $cc, $imm19", [], IIC_fpu_normal_instr>; def CCA : F2_3<0b101, 1, 1, (outs), (ins bprtarget:$imm19, CCOp:$cond, FCCRegs:$cc), - "fb$cond,a $cc, $imm19", []>; + "fb$cond,a $cc, $imm19", [], IIC_fpu_normal_instr>; def CCNT : F2_3<0b101, 0, 0, (outs), (ins bprtarget:$imm19, CCOp:$cond, FCCRegs:$cc), - "fb$cond,pn $cc, $imm19", []>; + "fb$cond,pn $cc, $imm19", [], IIC_fpu_normal_instr>; def CCANT : F2_3<0b101, 1, 0, (outs), (ins bprtarget:$imm19, CCOp:$cond, FCCRegs:$cc), - "fb$cond,a,pn $cc, $imm19", []>; + "fb$cond,a,pn $cc, $imm19", [], IIC_fpu_normal_instr>; } } // let isBranch = 1, isTerminator = 1, hasDelaySlot = 1 @@ -755,13 +874,33 @@ let Uses = [FCC0] in { let Predicates = [HasV9] in defm BPF : FPredBranch; +// Section B.22 - Branch on Co-processor Condition Codes Instructions, p. 123 +let isBranch = 1, isTerminator = 1, hasDelaySlot = 1 in { + +// co-processor conditional branch class: +class CPBranchSP<dag ins, string asmstr, list<dag> pattern> + : F2_2<0b111, 0, (outs), ins, asmstr, pattern>; +// co-processor conditional branch with annul class: +class CPBranchSPA<dag ins, string asmstr, list<dag> pattern> + : F2_2<0b111, 1, (outs), ins, asmstr, pattern>; + +} // let isBranch = 1, isTerminator = 1, hasDelaySlot = 1 + +def CBCOND : CPBranchSP<(ins brtarget:$imm22, CCOp:$cond), + "cb$cond $imm22", + [(SPbrfcc bb:$imm22, imm:$cond)]>; +def CBCONDA : CPBranchSPA<(ins brtarget:$imm22, CCOp:$cond), + "cb$cond,a $imm22", []>; + // Section B.24 - Call and Link Instruction, p. 125 // This is the only Format 1 instruction let Uses = [O6], hasDelaySlot = 1, isCall = 1 in { def CALL : InstSP<(outs), (ins calltarget:$disp, variable_ops), - "call $disp", []> { + "call $disp", + [], + IIC_jmp_or_call> { bits<30> disp; let op = 1; let Inst{29-0} = disp; @@ -772,11 +911,13 @@ let Uses = [O6], def CALLrr : F3_1<2, 0b111000, (outs), (ins MEMrr:$ptr, variable_ops), "call $ptr", - [(call ADDRrr:$ptr)]>; + [(call ADDRrr:$ptr)], + IIC_jmp_or_call>; def CALLri : F3_2<2, 0b111000, (outs), (ins MEMri:$ptr, variable_ops), "call $ptr", - [(call ADDRri:$ptr)]>; + [(call ADDRri:$ptr)], + IIC_jmp_or_call>; } } @@ -785,10 +926,16 @@ let Uses = [O6], // JMPL Instruction. let isTerminator = 1, hasDelaySlot = 1, isBarrier = 1, DecoderMethod = "DecodeJMPL" in { - def JMPLrr: F3_1<2, 0b111000, (outs IntRegs:$dst), (ins MEMrr:$addr), - "jmpl $addr, $dst", []>; - def JMPLri: F3_2<2, 0b111000, (outs IntRegs:$dst), (ins MEMri:$addr), - "jmpl $addr, $dst", []>; + def JMPLrr: F3_1<2, 0b111000, + (outs IntRegs:$dst), (ins MEMrr:$addr), + "jmpl $addr, $dst", + [], + IIC_jmp_or_call>; + def JMPLri: F3_2<2, 0b111000, + (outs IntRegs:$dst), (ins MEMri:$addr), + "jmpl $addr, $dst", + [], + IIC_jmp_or_call>; } // Section A.3 - Synthetic Instructions, p. 85 @@ -796,37 +943,65 @@ let isTerminator = 1, hasDelaySlot = 1, isBarrier = 1, let isReturn = 1, isTerminator = 1, hasDelaySlot = 1, isBarrier = 1, isCodeGenOnly = 1 in { let rd = 0, rs1 = 15 in - def RETL: F3_2<2, 0b111000, (outs), (ins i32imm:$val), - "jmp %o7+$val", [(retflag simm13:$val)]>; + def RETL: F3_2<2, 0b111000, + (outs), (ins i32imm:$val), + "jmp %o7+$val", + [(retflag simm13:$val)], + IIC_jmp_or_call>; let rd = 0, rs1 = 31 in - def RET: F3_2<2, 0b111000, (outs), (ins i32imm:$val), - "jmp %i7+$val", []>; + def RET: F3_2<2, 0b111000, + (outs), (ins i32imm:$val), + "jmp %i7+$val", + [], + IIC_jmp_or_call>; } // Section B.26 - Return from Trap Instruction let isReturn = 1, isTerminator = 1, hasDelaySlot = 1, isBarrier = 1, rd = 0, DecoderMethod = "DecodeReturn" in { - def RETTrr : F3_1<2, 0b111001, (outs), (ins MEMrr:$addr), - "rett $addr", []>; - def RETTri : F3_2<2, 0b111001, (outs), (ins MEMri:$addr), - "rett $addr", []>; + def RETTrr : F3_1<2, 0b111001, + (outs), (ins MEMrr:$addr), + "rett $addr", + [], + IIC_jmp_or_call>; + def RETTri : F3_2<2, 0b111001, + (outs), (ins MEMri:$addr), + "rett $addr", + [], + IIC_jmp_or_call>; } // Section B.27 - Trap on Integer Condition Codes Instruction +// conditional branch class: +let DecoderNamespace = "SparcV8", DecoderMethod = "DecodeTRAP", hasSideEffects = 1, Uses = [ICC], cc = 0b00 in +{ + def TRAPrr : TRAPSPrr<0b111010, + (outs), (ins IntRegs:$rs1, IntRegs:$rs2, CCOp:$cond), + "t$cond $rs1 + $rs2", + []>; + def TRAPri : TRAPSPri<0b111010, + (outs), (ins IntRegs:$rs1, i32imm:$imm, CCOp:$cond), + "t$cond $rs1 + $imm", + []>; +} + multiclass TRAP<string regStr> { - def rr : TRAPSPrr<0b111010, (outs), (ins IntRegs:$rs1, IntRegs:$rs2, - CCOp:$cond), - !strconcat(!strconcat("t$cond ", regStr), ", $rs1 + $rs2"), []>; - def ri : TRAPSPri<0b111010, (outs), (ins IntRegs:$rs1, i32imm:$imm, - CCOp:$cond), - !strconcat(!strconcat("t$cond ", regStr), ", $rs1 + $imm"), []>; + def rr : TRAPSPrr<0b111010, + (outs), (ins IntRegs:$rs1, IntRegs:$rs2, CCOp:$cond), + !strconcat(!strconcat("t$cond ", regStr), ", $rs1 + $rs2"), + []>; + def ri : TRAPSPri<0b111010, + (outs), (ins IntRegs:$rs1, i32imm:$imm, CCOp:$cond), + !strconcat(!strconcat("t$cond ", regStr), ", $rs1 + $imm"), + []>; } -let hasSideEffects = 1, Uses = [ICC], cc = 0b00 in +let DecoderNamespace = "SparcV9", DecoderMethod = "DecodeTRAP", Predicates = [HasV9], hasSideEffects = 1, Uses = [ICC], cc = 0b00 in defm TICC : TRAP<"%icc">; + let isBarrier = 1, isTerminator = 1, rd = 0b01000, rs1 = 0, simm13 = 5 in def TA5 : F3_2<0b10, 0b111010, (outs), (ins), "ta 5", [(trap)]>; @@ -922,11 +1097,13 @@ let rd = 0 in { def FITOS : F3_3u<2, 0b110100, 0b011000100, (outs FPRegs:$rd), (ins FPRegs:$rs2), "fitos $rs2, $rd", - [(set FPRegs:$rd, (SPitof FPRegs:$rs2))]>; + [(set FPRegs:$rd, (SPitof FPRegs:$rs2))], + IIC_fpu_fast_instr>; def FITOD : F3_3u<2, 0b110100, 0b011001000, (outs DFPRegs:$rd), (ins FPRegs:$rs2), "fitod $rs2, $rd", - [(set DFPRegs:$rd, (SPitof FPRegs:$rs2))]>; + [(set DFPRegs:$rd, (SPitof FPRegs:$rs2))], + IIC_fpu_fast_instr>; def FITOQ : F3_3u<2, 0b110100, 0b011001100, (outs QFPRegs:$rd), (ins FPRegs:$rs2), "fitoq $rs2, $rd", @@ -937,11 +1114,13 @@ def FITOQ : F3_3u<2, 0b110100, 0b011001100, def FSTOI : F3_3u<2, 0b110100, 0b011010001, (outs FPRegs:$rd), (ins FPRegs:$rs2), "fstoi $rs2, $rd", - [(set FPRegs:$rd, (SPftoi FPRegs:$rs2))]>; + [(set FPRegs:$rd, (SPftoi FPRegs:$rs2))], + IIC_fpu_fast_instr>; def FDTOI : F3_3u<2, 0b110100, 0b011010010, (outs FPRegs:$rd), (ins DFPRegs:$rs2), "fdtoi $rs2, $rd", - [(set FPRegs:$rd, (SPftoi DFPRegs:$rs2))]>; + [(set FPRegs:$rd, (SPftoi DFPRegs:$rs2))], + IIC_fpu_fast_instr>; def FQTOI : F3_3u<2, 0b110100, 0b011010011, (outs FPRegs:$rd), (ins QFPRegs:$rs2), "fqtoi $rs2, $rd", @@ -952,7 +1131,8 @@ def FQTOI : F3_3u<2, 0b110100, 0b011010011, def FSTOD : F3_3u<2, 0b110100, 0b011001001, (outs DFPRegs:$rd), (ins FPRegs:$rs2), "fstod $rs2, $rd", - [(set f64:$rd, (fextend f32:$rs2))]>; + [(set f64:$rd, (fextend f32:$rs2))], + IIC_fpu_stod>; def FSTOQ : F3_3u<2, 0b110100, 0b011001101, (outs QFPRegs:$rd), (ins FPRegs:$rs2), "fstoq $rs2, $rd", @@ -961,7 +1141,8 @@ def FSTOQ : F3_3u<2, 0b110100, 0b011001101, def FDTOS : F3_3u<2, 0b110100, 0b011000110, (outs FPRegs:$rd), (ins DFPRegs:$rs2), "fdtos $rs2, $rd", - [(set f32:$rd, (fround f64:$rs2))]>; + [(set f32:$rd, (fround f64:$rs2))], + IIC_fpu_fast_instr>; def FDTOQ : F3_3u<2, 0b110100, 0b011001110, (outs QFPRegs:$rd), (ins DFPRegs:$rs2), "fdtoq $rs2, $rd", @@ -985,22 +1166,29 @@ def FMOVS : F3_3u<2, 0b110100, 0b000000001, def FNEGS : F3_3u<2, 0b110100, 0b000000101, (outs FPRegs:$rd), (ins FPRegs:$rs2), "fnegs $rs2, $rd", - [(set f32:$rd, (fneg f32:$rs2))]>; + [(set f32:$rd, (fneg f32:$rs2))], + IIC_fpu_negs>; def FABSS : F3_3u<2, 0b110100, 0b000001001, (outs FPRegs:$rd), (ins FPRegs:$rs2), "fabss $rs2, $rd", - [(set f32:$rd, (fabs f32:$rs2))]>; + [(set f32:$rd, (fabs f32:$rs2))], + IIC_fpu_abs>; // 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", - [(set f32:$rd, (fsqrt f32:$rs2))]>; + [(set f32:$rd, (fsqrt f32:$rs2))], + IIC_fpu_sqrts>; def FSQRTD : F3_3u<2, 0b110100, 0b000101010, (outs DFPRegs:$rd), (ins DFPRegs:$rs2), "fsqrtd $rs2, $rd", - [(set f64:$rd, (fsqrt f64:$rs2))]>; + [(set f64:$rd, (fsqrt f64:$rs2))], + IIC_fpu_sqrtd>; def FSQRTQ : F3_3u<2, 0b110100, 0b000101011, (outs QFPRegs:$rd), (ins QFPRegs:$rs2), "fsqrtq $rs2, $rd", @@ -1013,11 +1201,13 @@ def FSQRTQ : F3_3u<2, 0b110100, 0b000101011, def FADDS : F3_3<2, 0b110100, 0b001000001, (outs FPRegs:$rd), (ins FPRegs:$rs1, FPRegs:$rs2), "fadds $rs1, $rs2, $rd", - [(set f32:$rd, (fadd f32:$rs1, f32:$rs2))]>; + [(set f32:$rd, (fadd f32:$rs1, f32:$rs2))], + IIC_fpu_fast_instr>; def FADDD : F3_3<2, 0b110100, 0b001000010, (outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2), "faddd $rs1, $rs2, $rd", - [(set f64:$rd, (fadd f64:$rs1, f64:$rs2))]>; + [(set f64:$rd, (fadd f64:$rs1, f64:$rs2))], + IIC_fpu_fast_instr>; def FADDQ : F3_3<2, 0b110100, 0b001000011, (outs QFPRegs:$rd), (ins QFPRegs:$rs1, QFPRegs:$rs2), "faddq $rs1, $rs2, $rd", @@ -1027,11 +1217,13 @@ def FADDQ : F3_3<2, 0b110100, 0b001000011, def FSUBS : F3_3<2, 0b110100, 0b001000101, (outs FPRegs:$rd), (ins FPRegs:$rs1, FPRegs:$rs2), "fsubs $rs1, $rs2, $rd", - [(set f32:$rd, (fsub f32:$rs1, f32:$rs2))]>; + [(set f32:$rd, (fsub f32:$rs1, f32:$rs2))], + IIC_fpu_fast_instr>; def FSUBD : F3_3<2, 0b110100, 0b001000110, (outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2), "fsubd $rs1, $rs2, $rd", - [(set f64:$rd, (fsub f64:$rs1, f64:$rs2))]>; + [(set f64:$rd, (fsub f64:$rs1, f64:$rs2))], + IIC_fpu_fast_instr>; def FSUBQ : F3_3<2, 0b110100, 0b001000111, (outs QFPRegs:$rd), (ins QFPRegs:$rs1, QFPRegs:$rs2), "fsubq $rs1, $rs2, $rd", @@ -1040,25 +1232,32 @@ 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", - [(set f32:$rd, (fmul f32:$rs1, f32:$rs2))]>; + [(set f32:$rd, (fmul f32:$rs1, f32:$rs2))], + IIC_fpu_muls>; def FMULD : F3_3<2, 0b110100, 0b001001010, (outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2), "fmuld $rs1, $rs2, $rd", - [(set f64:$rd, (fmul f64:$rs1, f64:$rs2))]>; + [(set f64:$rd, (fmul f64:$rs1, f64:$rs2))], + IIC_fpu_muld>; def FMULQ : F3_3<2, 0b110100, 0b001001011, (outs QFPRegs:$rd), (ins QFPRegs:$rs1, QFPRegs:$rs2), "fmulq $rs1, $rs2, $rd", [(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", [(set f64:$rd, (fmul (fextend f32:$rs1), - (fextend f32:$rs2)))]>; + (fextend f32:$rs2)))], + IIC_fpu_muld>; def FDMULQ : F3_3<2, 0b110100, 0b001101110, (outs QFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2), "fdmulq $rs1, $rs2, $rd", @@ -1066,14 +1265,18 @@ 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", - [(set f32:$rd, (fdiv f32:$rs1, f32:$rs2))]>; + [(set f32:$rd, (fdiv f32:$rs1, f32:$rs2))], + IIC_fpu_divs>; def FDIVD : F3_3<2, 0b110100, 0b001001110, (outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2), "fdivd $rs1, $rs2, $rd", - [(set f64:$rd, (fdiv f64:$rs1, f64:$rs2))]>; + [(set f64:$rd, (fdiv f64:$rs1, f64:$rs2))], + IIC_fpu_divd>; def FDIVQ : F3_3<2, 0b110100, 0b001001111, (outs QFPRegs:$rd), (ins QFPRegs:$rs1, QFPRegs:$rs2), "fdivq $rs1, $rs2, $rd", @@ -1091,11 +1294,13 @@ let Defs = [FCC0], rd = 0, isCodeGenOnly = 1 in { def FCMPS : F3_3c<2, 0b110101, 0b001010001, (outs), (ins FPRegs:$rs1, FPRegs:$rs2), "fcmps $rs1, $rs2", - [(SPcmpfcc f32:$rs1, f32:$rs2)]>; + [(SPcmpfcc f32:$rs1, f32:$rs2)], + IIC_fpu_fast_instr>; def FCMPD : F3_3c<2, 0b110101, 0b001010010, (outs), (ins DFPRegs:$rs1, DFPRegs:$rs2), "fcmpd $rs1, $rs2", - [(SPcmpfcc f64:$rs1, f64:$rs2)]>; + [(SPcmpfcc f64:$rs1, f64:$rs2)], + IIC_fpu_fast_instr>; def FCMPQ : F3_3c<2, 0b110101, 0b001010011, (outs), (ins QFPRegs:$rs1, QFPRegs:$rs2), "fcmpq $rs1, $rs2", @@ -1125,7 +1330,8 @@ let Uses = [O6], isCall = 1, hasDelaySlot = 1 in def TLS_CALL : InstSP<(outs), (ins calltarget:$disp, TLSSym:$sym, variable_ops), "call $disp, $sym", - [(tlscall texternalsym:$disp, tglobaltlsaddr:$sym)]> { + [(tlscall texternalsym:$disp, tglobaltlsaddr:$sym)], + IIC_jmp_or_call> { bits<30> disp; let op = 1; let Inst{29-0} = disp; @@ -1303,19 +1509,60 @@ let Predicates = [HasV9], hasSideEffects = 1, rd = 0, rs1 = 0b01111 in def MEMBARi : F3_2<2, 0b101000, (outs), (ins simm13Op:$simm13), "membar $simm13", []>; -// TODO: Should add a CASArr variant. In fact, the CAS instruction, -// unlike other instructions, only comes in a form which requires an -// ASI be provided. The ASI value hardcoded here is ASI_PRIMARY, the -// default unprivileged ASI for SparcV9. (Also of note: some modern -// SparcV8 implementations provide CASA as an extension, but require -// the use of SparcV8's default ASI, 0xA ("User Data") instead.) +// The CAS instruction, unlike other instructions, only comes in a +// form which requires an ASI be provided. The ASI value hardcoded +// here is ASI_PRIMARY, the default unprivileged ASI for SparcV9. let Predicates = [HasV9], Constraints = "$swap = $rd", asi = 0b10000000 in def CASrr: F3_1_asi<3, 0b111100, (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2, IntRegs:$swap), "cas [$rs1], $rs2, $rd", [(set i32:$rd, - (atomic_cmp_swap iPTR:$rs1, i32:$rs2, i32:$swap))]>; + (atomic_cmp_swap_32 iPTR:$rs1, i32:$rs2, i32:$swap))]>; + + +// CASA is supported as an instruction on some LEON3 and all LEON4 processors. +// This version can be automatically lowered from C code, selecting ASI 10 +let Predicates = [HasLeonCASA], Constraints = "$swap = $rd", asi = 0b00001010 in + def CASAasi10: F3_1_asi<3, 0b111100, + (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2, + IntRegs:$swap), + "casa [$rs1] 10, $rs2, $rd", + [(set i32:$rd, + (atomic_cmp_swap_32 iPTR:$rs1, i32:$rs2, i32:$swap))]>; + +// CASA supported on some LEON3 and all LEON4 processors. Same pattern as +// CASrr, above, but with a different ASI. This version is supported for +// inline assembly lowering only. +let Predicates = [HasLeonCASA], Constraints = "$swap = $rd" in + def CASArr: F3_1_asi<3, 0b111100, + (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2, + IntRegs:$swap, i8imm:$asi), + "casa [$rs1] $asi, $rs2, $rd", []>; + +// TODO: Add DAG sequence to lower these instructions. Currently, only provided +// as inline assembler-supported instructions. +let Predicates = [HasUMAC_SMAC], Defs = [Y, ASR18], Uses = [Y, ASR18] in { + def SMACrr : F3_1<2, 0b111111, + (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2, ASRRegs:$asr18), + "smac $rs1, $rs2, $rd", + [], IIC_smac_umac>; + + def SMACri : F3_2<2, 0b111111, + (outs IntRegs:$rd), (ins IntRegs:$rs1, simm13Op:$simm13, ASRRegs:$asr18), + "smac $rs1, $simm13, $rd", + [], IIC_smac_umac>; + + def UMACrr : F3_1<2, 0b111110, + (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2, ASRRegs:$asr18), + "umac $rs1, $rs2, $rd", + [], IIC_smac_umac>; + + def UMACri : F3_2<2, 0b111110, + (outs IntRegs:$rd), (ins IntRegs:$rs1, simm13Op:$simm13, ASRRegs:$asr18), + "umac $rs1, $simm13, $rd", + [], IIC_smac_umac>; +} let Defs = [ICC] in { defm TADDCC : F3_12np<"taddcc", 0b100000>; @@ -1411,13 +1658,21 @@ def : Pat<(store (i32 0), ADDRri:$dst), (STri ADDRri:$dst, (i32 G0))>; let Predicates = [HasNoV9] in def : Pat<(atomic_fence imm, imm), (STBAR)>; -// atomic_load_32 addr -> load addr -def : Pat<(i32 (atomic_load ADDRrr:$src)), (LDrr ADDRrr:$src)>; -def : Pat<(i32 (atomic_load ADDRri:$src)), (LDri ADDRri:$src)>; - -// atomic_store_32 val, addr -> store val, addr -def : Pat<(atomic_store ADDRrr:$dst, i32:$val), (STrr ADDRrr:$dst, $val)>; -def : Pat<(atomic_store ADDRri:$dst, i32:$val), (STri ADDRri:$dst, $val)>; +// atomic_load addr -> load addr +def : Pat<(i32 (atomic_load_8 ADDRrr:$src)), (LDUBrr ADDRrr:$src)>; +def : Pat<(i32 (atomic_load_8 ADDRri:$src)), (LDUBri ADDRri:$src)>; +def : Pat<(i32 (atomic_load_16 ADDRrr:$src)), (LDUHrr ADDRrr:$src)>; +def : Pat<(i32 (atomic_load_16 ADDRri:$src)), (LDUHri ADDRri:$src)>; +def : Pat<(i32 (atomic_load_32 ADDRrr:$src)), (LDrr ADDRrr:$src)>; +def : Pat<(i32 (atomic_load_32 ADDRri:$src)), (LDri ADDRri:$src)>; + +// atomic_store val, addr -> store val, addr +def : Pat<(atomic_store_8 ADDRrr:$dst, i32:$val), (STBrr ADDRrr:$dst, $val)>; +def : Pat<(atomic_store_8 ADDRri:$dst, i32:$val), (STBri ADDRri:$dst, $val)>; +def : Pat<(atomic_store_16 ADDRrr:$dst, i32:$val), (STHrr ADDRrr:$dst, $val)>; +def : Pat<(atomic_store_16 ADDRri:$dst, i32:$val), (STHri ADDRri:$dst, $val)>; +def : Pat<(atomic_store_32 ADDRrr:$dst, i32:$val), (STrr ADDRrr:$dst, $val)>; +def : Pat<(atomic_store_32 ADDRri:$dst, i32:$val), (STri ADDRri:$dst, $val)>; // extract_vector def : Pat<(extractelt (v2i32 IntPair:$Rn), 0), diff --git a/lib/Target/Sparc/SparcMCInstLower.cpp b/lib/Target/Sparc/SparcMCInstLower.cpp index b084d0021ba0..a3cedcbf9dd1 100644 --- a/lib/Target/Sparc/SparcMCInstLower.cpp +++ b/lib/Target/Sparc/SparcMCInstLower.cpp @@ -14,7 +14,6 @@ #include "Sparc.h" #include "MCTargetDesc/SparcMCExpr.h" -#include "llvm/ADT/SmallString.h" #include "llvm/CodeGen/AsmPrinter.h" #include "llvm/CodeGen/MachineFunction.h" #include "llvm/CodeGen/MachineInstr.h" diff --git a/lib/Target/Sparc/SparcRegisterInfo.cpp b/lib/Target/Sparc/SparcRegisterInfo.cpp index da31783ba248..37a1fdf4d770 100644 --- a/lib/Target/Sparc/SparcRegisterInfo.cpp +++ b/lib/Target/Sparc/SparcRegisterInfo.cpp @@ -105,13 +105,9 @@ SparcRegisterInfo::getPointerRegClass(const MachineFunction &MF, return Subtarget.is64Bit() ? &SP::I64RegsRegClass : &SP::IntRegsRegClass; } -static void replaceFI(MachineFunction &MF, - MachineBasicBlock::iterator II, - MachineInstr &MI, - DebugLoc dl, - unsigned FIOperandNum, int Offset, - unsigned FramePtr) -{ +static void replaceFI(MachineFunction &MF, MachineBasicBlock::iterator II, + MachineInstr &MI, const DebugLoc &dl, + unsigned FIOperandNum, int Offset, unsigned FramePtr) { // Replace frame index with a frame pointer reference. if (Offset >= -4096 && Offset <= 4095) { // If the offset is small enough to fit in the immediate field, directly diff --git a/lib/Target/Sparc/SparcRegisterInfo.h b/lib/Target/Sparc/SparcRegisterInfo.h index 32075b1df410..2ac51263957e 100644 --- a/lib/Target/Sparc/SparcRegisterInfo.h +++ b/lib/Target/Sparc/SparcRegisterInfo.h @@ -39,9 +39,6 @@ struct SparcRegisterInfo : public SparcGenRegisterInfo { int SPAdj, unsigned FIOperandNum, RegScavenger *RS = nullptr) const override; - void processFunctionBeforeFrameFinalized(MachineFunction &MF, - RegScavenger *RS = nullptr) const; - unsigned getFrameRegister(const MachineFunction &MF) const override; bool canRealignStack(const MachineFunction &MF) const override; diff --git a/lib/Target/Sparc/SparcRegisterInfo.td b/lib/Target/Sparc/SparcRegisterInfo.td index cca9463562a4..d1ef3b19dca7 100644 --- a/lib/Target/Sparc/SparcRegisterInfo.td +++ b/lib/Target/Sparc/SparcRegisterInfo.td @@ -62,6 +62,12 @@ foreach I = 0-3 in def FSR : SparcCtrlReg<0, "FSR">; // Floating-point state register. +def FQ : SparcCtrlReg<0, "FQ">; // Floating-point deferred-trap queue. + +def CPSR : SparcCtrlReg<0, "CPSR">; // Co-processor state register. + +def CPQ : SparcCtrlReg<0, "CPQ">; // Co-processor queue. + // Y register def Y : SparcCtrlReg<0, "Y">, DwarfRegNum<[64]>; // Ancillary state registers (implementation defined) @@ -204,6 +210,40 @@ def D13 : Rd<26, "F26", [F26, F27]>, DwarfRegNum<[85]>; def D14 : Rd<28, "F28", [F28, F29]>, DwarfRegNum<[86]>; def D15 : Rd<30, "F30", [F30, F31]>, DwarfRegNum<[87]>; +// Co-processor registers +def C0 : Ri< 0, "C0">; +def C1 : Ri< 1, "C1">; +def C2 : Ri< 2, "C2">; +def C3 : Ri< 3, "C3">; +def C4 : Ri< 4, "C4">; +def C5 : Ri< 5, "C5">; +def C6 : Ri< 6, "C6">; +def C7 : Ri< 7, "C7">; +def C8 : Ri< 8, "C8">; +def C9 : Ri< 9, "C9">; +def C10 : Ri< 10, "C10">; +def C11 : Ri< 11, "C11">; +def C12 : Ri< 12, "C12">; +def C13 : Ri< 13, "C13">; +def C14 : Ri< 14, "C14">; +def C15 : Ri< 15, "C15">; +def C16 : Ri< 16, "C16">; +def C17 : Ri< 17, "C17">; +def C18 : Ri< 18, "C18">; +def C19 : Ri< 19, "C19">; +def C20 : Ri< 20, "C20">; +def C21 : Ri< 21, "C21">; +def C22 : Ri< 22, "C22">; +def C23 : Ri< 23, "C23">; +def C24 : Ri< 24, "C24">; +def C25 : Ri< 25, "C25">; +def C26 : Ri< 26, "C26">; +def C27 : Ri< 27, "C27">; +def C28 : Ri< 28, "C28">; +def C29 : Ri< 29, "C29">; +def C30 : Ri< 30, "C30">; +def C31 : Ri< 31, "C31">; + // Unaliased double precision floating point registers. // FIXME: Define DwarfRegNum for these registers. def D16 : SparcReg< 1, "F32">; @@ -259,6 +299,24 @@ def I2_I3 : Rdi<26, "I2", [I2, I3]>; def I4_I5 : Rdi<28, "I4", [I4, I5]>; def I6_I7 : Rdi<30, "I6", [I6, I7]>; +// Aliases of the co-processor registers used for LDD/STD double-word operations +def C0_C1 : Rdi<0, "C0", [C0, C1]>; +def C2_C3 : Rdi<2, "C2", [C2, C3]>; +def C4_C5 : Rdi<4, "C4", [C4, C5]>; +def C6_C7 : Rdi<6, "C6", [C6, C7]>; +def C8_C9 : Rdi<8, "C8", [C8, C9]>; +def C10_C11 : Rdi<10, "C10", [C10, C11]>; +def C12_C13 : Rdi<12, "C12", [C12, C13]>; +def C14_C15 : Rdi<14, "C14", [C14, C15]>; +def C16_C17 : Rdi<16, "C16", [C16, C17]>; +def C18_C19 : Rdi<18, "C18", [C18, C19]>; +def C20_C21 : Rdi<20, "C20", [C20, C21]>; +def C22_C23 : Rdi<22, "C22", [C22, C23]>; +def C24_C25 : Rdi<24, "C24", [C24, C25]>; +def C26_C27 : Rdi<26, "C26", [C26, C27]>; +def C28_C29 : Rdi<28, "C28", [C28, C29]>; +def C30_C31 : Rdi<30, "C30", [C30, C31]>; + // Register classes. // // FIXME: the register order should be defined in terms of the preferred @@ -273,6 +331,7 @@ def IntRegs : RegisterClass<"SP", [i32, i64], 32, (sequence "L%u", 0, 7), (sequence "O%u", 0, 7))>; + // Should be in the same order as IntRegs. def IntPair : RegisterClass<"SP", [v2i32], 64, (add I0_I1, I2_I3, I4_I5, I6_I7, @@ -296,10 +355,21 @@ def QFPRegs : RegisterClass<"SP", [f128], 128, (sequence "Q%u", 0, 15)>; // Floating point control register classes. def FCCRegs : RegisterClass<"SP", [i1], 1, (sequence "FCC%u", 0, 3)>; -// Ancillary state registers -def ASRRegs : RegisterClass<"SP", [i32], 32, - (add Y, (sequence "ASR%u", 1, 31))> { - let isAllocatable = 0; +let isAllocatable = 0 in { + // Ancillary state registers + def ASRRegs : RegisterClass<"SP", [i32], 32, + (add Y, (sequence "ASR%u", 1, 31))>; + + // This register class should not be used to hold i64 values. + def CoprocRegs : RegisterClass<"SP", [i32], 32, + (add (sequence "C%u", 0, 31))>; + + // Should be in the same order as CoprocRegs. + def CoprocPair : RegisterClass<"SP", [v2i32], 64, + (add C0_C1, C2_C3, C4_C5, C6_C7, + C8_C9, C10_C11, C12_C13, C14_C15, + C16_C17, C18_C19, C20_C21, C22_C23, + C24_C25, C26_C27, C28_C29, C30_C31)>; } // Privileged Registers diff --git a/lib/Target/Sparc/SparcSchedule.td b/lib/Target/Sparc/SparcSchedule.td new file mode 100755 index 000000000000..f243546b029b --- /dev/null +++ b/lib/Target/Sparc/SparcSchedule.td @@ -0,0 +1,124 @@ +//===-- SparcSchedule.td - Describe the Sparc Itineries ----*- tablegen -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// +// +// +//===----------------------------------------------------------------------===// + +def IIC_iu_or_fpu_instr : InstrItinClass; +def IIC_iu_instr : InstrItinClass; +def IIC_fpu_normal_instr : InstrItinClass; +def IIC_fpu_fast_instr : InstrItinClass; +def IIC_jmp_or_call : InstrItinClass; +def IIC_ldd : InstrItinClass; +def IIC_st : InstrItinClass; +def IIC_std : InstrItinClass; +def IIC_iu_smul : InstrItinClass; +def IIC_iu_umul : InstrItinClass; +def IIC_iu_div : InstrItinClass; +def IIC_ticc : InstrItinClass; +def IIC_ldstub : InstrItinClass; +def IIC_fpu_muls : InstrItinClass; +def IIC_fpu_muld : InstrItinClass; +def IIC_fpu_divs : InstrItinClass; +def IIC_fpu_divd : InstrItinClass; +def IIC_fpu_sqrts : InstrItinClass; +def IIC_fpu_sqrtd : InstrItinClass; +def IIC_fpu_abs : InstrItinClass; +def IIC_fpu_movs : InstrItinClass; +def IIC_fpu_negs : InstrItinClass; +def IIC_smac_umac : InstrItinClass; +def IIC_fpu_stod : InstrItinClass; + +def LEONIU : FuncUnit; // integer unit +def LEONFPU : FuncUnit; // floating-point unit + +// Ref: http://www.atmel.com/Images/doc4226.pdf + +def LEON2Itineraries : ProcessorItineraries< +[LEONIU, LEONFPU], [], [ + InstrItinData<IIC_iu_or_fpu_instr, [InstrStage<1, [LEONIU, LEONFPU]>], [1, 1]>, + InstrItinData<IIC_iu_instr, [InstrStage<1, [LEONIU]>], [1, 1]>, + InstrItinData<IIC_fpu_normal_instr, [InstrStage<1, [LEONFPU]>], [7, 1]>, + InstrItinData<IIC_fpu_fast_instr, [InstrStage<1, [LEONFPU]>], [7, 1]>, + InstrItinData<IIC_jmp_or_call, [InstrStage<1, [LEONIU, LEONFPU]>], [2, 1]>, + InstrItinData<IIC_ldd, [InstrStage<1, [LEONIU, LEONFPU]>], [2, 1]>, + InstrItinData<IIC_st, [InstrStage<1, [LEONIU, LEONFPU]>], [2, 1]>, + InstrItinData<IIC_std, [InstrStage<1, [LEONIU, LEONFPU]>], [3, 1]>, + InstrItinData<IIC_iu_smul, [InstrStage<1, [LEONIU]>], [5, 1]>, + InstrItinData<IIC_iu_umul, [InstrStage<1, [LEONIU]>], [5, 1]>, + InstrItinData<IIC_iu_div, [InstrStage<1, [LEONIU]>], [35, 1]>, + InstrItinData<IIC_ticc, [InstrStage<1, [LEONIU, LEONFPU]>], [4, 1]>, + InstrItinData<IIC_ldstub, [InstrStage<1, [LEONIU, LEONFPU]>], [3, 1]>, + InstrItinData<IIC_fpu_muls, [InstrStage<1, [LEONFPU]>], [16, 1]>, + InstrItinData<IIC_fpu_muld, [InstrStage<1, [LEONFPU]>], [21, 1]>, + InstrItinData<IIC_fpu_divs, [InstrStage<1, [LEONFPU]>], [20, 1]>, + InstrItinData<IIC_fpu_divd, [InstrStage<1, [LEONFPU]>], [36, 1]>, + InstrItinData<IIC_fpu_sqrts, [InstrStage<1, [LEONFPU]>], [37, 1]>, + InstrItinData<IIC_fpu_sqrtd, [InstrStage<1, [LEONFPU]>], [65, 1]>, + InstrItinData<IIC_fpu_abs, [InstrStage<1, [LEONFPU]>], [2, 1]>, + InstrItinData<IIC_fpu_movs, [InstrStage<1, [LEONFPU]>], [2, 1]>, + InstrItinData<IIC_fpu_negs, [InstrStage<1, [LEONFPU]>], [2, 1]>, + InstrItinData<IIC_fpu_stod, [InstrStage<1, [LEONFPU]>], [2, 1]> +]>; + +def LEON3Itineraries : ProcessorItineraries< +[LEONIU, LEONFPU], [], [ + InstrItinData<IIC_iu_or_fpu_instr, [InstrStage<1, [LEONIU, LEONFPU]>], [1, 1]>, + InstrItinData<IIC_iu_instr, [InstrStage<1, [LEONIU]>], [1, 1]>, + InstrItinData<IIC_fpu_normal_instr, [InstrStage<1, [LEONFPU]>], [7, 1]>, + InstrItinData<IIC_fpu_fast_instr, [InstrStage<1, [LEONFPU]>], [4, 1]>, + InstrItinData<IIC_jmp_or_call, [InstrStage<1, [LEONIU, LEONFPU]>], [3, 1]>, + InstrItinData<IIC_ldd, [InstrStage<1, [LEONIU, LEONFPU]>], [2, 1]>, + InstrItinData<IIC_st, [InstrStage<1, [LEONIU, LEONFPU]>], [4, 1]>, + InstrItinData<IIC_std, [InstrStage<1, [LEONIU, LEONFPU]>], [5, 1]>, + InstrItinData<IIC_iu_smul, [InstrStage<1, [LEONIU]>], [1, 1]>, + InstrItinData<IIC_iu_umul, [InstrStage<1, [LEONIU]>], [4, 1]>, + InstrItinData<IIC_iu_div, [InstrStage<1, [LEONIU]>], [35, 1]>, + InstrItinData<IIC_smac_umac, [InstrStage<1, [LEONIU]>], [2, 1]>, + InstrItinData<IIC_ticc, [InstrStage<1, [LEONIU, LEONFPU]>], [5, 1]>, + InstrItinData<IIC_ldstub, [InstrStage<1, [LEONIU, LEONFPU]>], [3, 1]>, + InstrItinData<IIC_fpu_muls, [InstrStage<1, [LEONFPU]>], [4, 1]>, + InstrItinData<IIC_fpu_muld, [InstrStage<1, [LEONFPU]>], [4, 1]>, + InstrItinData<IIC_fpu_divs, [InstrStage<1, [LEONFPU]>], [16, 1]>, + InstrItinData<IIC_fpu_divd, [InstrStage<1, [LEONFPU]>], [17, 1]>, + InstrItinData<IIC_fpu_sqrts, [InstrStage<1, [LEONFPU]>], [24, 1]>, + InstrItinData<IIC_fpu_sqrtd, [InstrStage<1, [LEONFPU]>], [25, 1]>, + InstrItinData<IIC_fpu_abs, [InstrStage<1, [LEONFPU]>], [2, 1]>, + InstrItinData<IIC_fpu_movs, [InstrStage<1, [LEONFPU]>], [2, 1]>, + InstrItinData<IIC_fpu_negs, [InstrStage<1, [LEONFPU]>], [2, 1]>, + InstrItinData<IIC_fpu_stod, [InstrStage<1, [LEONFPU]>], [4, 1]> +]>; + +def LEON4Itineraries : ProcessorItineraries< +[LEONIU, LEONFPU], [], [ + InstrItinData<IIC_iu_or_fpu_instr, [InstrStage<1, [LEONIU, LEONFPU]>], [1, 1]>, + InstrItinData<IIC_iu_instr, [InstrStage<1, [LEONIU]>], [1, 1]>, + InstrItinData<IIC_fpu_normal_instr, [InstrStage<1, [LEONFPU]>], [7, 1]>, + InstrItinData<IIC_fpu_fast_instr, [InstrStage<1, [LEONFPU]>], [4, 1]>, + InstrItinData<IIC_jmp_or_call, [InstrStage<1, [LEONIU, LEONFPU]>], [3, 1]>, + InstrItinData<IIC_ldd, [InstrStage<1, [LEONIU, LEONFPU]>], [1, 1]>, + InstrItinData<IIC_st, [InstrStage<1, [LEONIU, LEONFPU]>], [1, 1]>, + InstrItinData<IIC_std, [InstrStage<1, [LEONIU, LEONFPU]>], [1, 1]>, + InstrItinData<IIC_iu_smul, [InstrStage<1, [LEONIU]>], [1, 1]>, + InstrItinData<IIC_iu_umul, [InstrStage<1, [LEONIU]>], [4, 1]>, + InstrItinData<IIC_iu_div, [InstrStage<1, [LEONIU]>], [35, 1]>, + InstrItinData<IIC_smac_umac, [InstrStage<1, [LEONIU]>], [2, 1]>, + InstrItinData<IIC_ticc, [InstrStage<1, [LEONIU, LEONFPU]>], [5, 1]>, + InstrItinData<IIC_ldstub, [InstrStage<1, [LEONIU, LEONFPU]>], [3, 1]>, + InstrItinData<IIC_fpu_muls, [InstrStage<1, [LEONFPU]>], [4, 1]>, + InstrItinData<IIC_fpu_muld, [InstrStage<1, [LEONFPU]>], [4, 1]>, + InstrItinData<IIC_fpu_divs, [InstrStage<1, [LEONFPU]>], [16, 1]>, + InstrItinData<IIC_fpu_divd, [InstrStage<1, [LEONFPU]>], [17, 1]>, + InstrItinData<IIC_fpu_sqrts, [InstrStage<1, [LEONFPU]>], [24, 1]>, + InstrItinData<IIC_fpu_sqrtd, [InstrStage<1, [LEONFPU]>], [25, 1]>, + InstrItinData<IIC_fpu_abs, [InstrStage<1, [LEONFPU]>], [2, 1]>, + InstrItinData<IIC_fpu_movs, [InstrStage<1, [LEONFPU]>], [2, 1]>, + InstrItinData<IIC_fpu_negs, [InstrStage<1, [LEONFPU]>], [2, 1]>, + InstrItinData<IIC_fpu_stod, [InstrStage<1, [LEONFPU]>], [4, 1]> +]>; diff --git a/lib/Target/Sparc/SparcSubtarget.cpp b/lib/Target/Sparc/SparcSubtarget.cpp index d701594d27af..a6a4dc54faed 100644 --- a/lib/Target/Sparc/SparcSubtarget.cpp +++ b/lib/Target/Sparc/SparcSubtarget.cpp @@ -29,10 +29,27 @@ void SparcSubtarget::anchor() { } SparcSubtarget &SparcSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS) { IsV9 = false; + IsLeon = false; V8DeprecatedInsts = false; IsVIS = false; HasHardQuad = false; UsePopc = false; + UseSoftFloat = false; + + // Leon features + HasLeonCasa = false; + HasUmacSmac = false; + PerformSDIVReplace = false; + FixCallImmediates = false; + IgnoreZeroFlag = false; + InsertNOPDoublePrecision = false; + FixFSMULD = false; + ReplaceFMULS = false; + PreventRoundChange = false; + FixAllFDIVSQRT = false; + InsertNOPLoad = false; + FlushCacheLineSWAP = false; + InsertNOPsLoadStore = false; // Determine default and user specified characteristics std::string CPUName = CPU; @@ -50,9 +67,9 @@ SparcSubtarget &SparcSubtarget::initializeSubtargetDependencies(StringRef CPU, } SparcSubtarget::SparcSubtarget(const Triple &TT, const std::string &CPU, - const std::string &FS, TargetMachine &TM, + const std::string &FS, const TargetMachine &TM, bool is64Bit) - : SparcGenSubtargetInfo(TT, CPU, FS), Is64Bit(is64Bit), + : SparcGenSubtargetInfo(TT, CPU, FS), TargetTriple(TT), Is64Bit(is64Bit), InstrInfo(initializeSubtargetDependencies(CPU, FS)), TLInfo(TM, *this), FrameLowering(*this) {} @@ -64,7 +81,7 @@ int SparcSubtarget::getAdjustedFrameSize(int frameSize) const { frameSize += 128; // Frames with calls must also reserve space for 6 outgoing arguments // whether they are used or not. LowerCall_64 takes care of that. - frameSize = RoundUpToAlignment(frameSize, 16); + frameSize = alignTo(frameSize, 16); } else { // Emit the correct save instruction based on the number of bytes in // the frame. Minimum stack frame size according to V8 ABI is: @@ -77,7 +94,7 @@ int SparcSubtarget::getAdjustedFrameSize(int frameSize) const { // Round up to next doubleword boundary -- a double-word boundary // is required by the ABI. - frameSize = RoundUpToAlignment(frameSize, 8); + frameSize = alignTo(frameSize, 8); } return frameSize; } diff --git a/lib/Target/Sparc/SparcSubtarget.h b/lib/Target/Sparc/SparcSubtarget.h index e2fd2f04528a..42d693699994 100644 --- a/lib/Target/Sparc/SparcSubtarget.h +++ b/lib/Target/Sparc/SparcSubtarget.h @@ -15,11 +15,11 @@ #define LLVM_LIB_TARGET_SPARC_SPARCSUBTARGET_H #include "SparcFrameLowering.h" -#include "SparcInstrInfo.h" #include "SparcISelLowering.h" +#include "SparcInstrInfo.h" +#include "llvm/CodeGen/SelectionDAGTargetInfo.h" #include "llvm/IR/DataLayout.h" #include "llvm/Target/TargetFrameLowering.h" -#include "llvm/Target/TargetSelectionDAGInfo.h" #include "llvm/Target/TargetSubtargetInfo.h" #include <string> @@ -30,21 +30,41 @@ namespace llvm { class StringRef; class SparcSubtarget : public SparcGenSubtargetInfo { + Triple TargetTriple; virtual void anchor(); bool IsV9; + bool IsLeon; bool V8DeprecatedInsts; bool IsVIS, IsVIS2, IsVIS3; bool Is64Bit; bool HasHardQuad; bool UsePopc; + bool UseSoftFloat; + + // LEON features + bool HasUmacSmac; + bool HasLeonCasa; + bool InsertNOPLoad; + bool FixFSMULD; + bool ReplaceFMULS; + bool FixAllFDIVSQRT; + bool UseSoftFpu; + bool PerformSDIVReplace; + bool FixCallImmediates; + bool IgnoreZeroFlag; + bool InsertNOPDoublePrecision; + bool PreventRoundChange; + bool FlushCacheLineSWAP; + bool InsertNOPsLoadStore; + SparcInstrInfo InstrInfo; SparcTargetLowering TLInfo; - TargetSelectionDAGInfo TSInfo; + SelectionDAGTargetInfo TSInfo; SparcFrameLowering FrameLowering; public: SparcSubtarget(const Triple &TT, const std::string &CPU, - const std::string &FS, TargetMachine &TM, bool is64bit); + const std::string &FS, const TargetMachine &TM, bool is64bit); const SparcInstrInfo *getInstrInfo() const override { return &InstrInfo; } const TargetFrameLowering *getFrameLowering() const override { @@ -56,19 +76,37 @@ public: const SparcTargetLowering *getTargetLowering() const override { return &TLInfo; } - const TargetSelectionDAGInfo *getSelectionDAGInfo() const override { + const SelectionDAGTargetInfo *getSelectionDAGInfo() const override { return &TSInfo; } bool enableMachineScheduler() const override; bool isV9() const { return IsV9; } + bool isLeon() const { return IsLeon; } bool isVIS() const { return IsVIS; } bool isVIS2() const { return IsVIS2; } bool isVIS3() const { return IsVIS3; } bool useDeprecatedV8Instructions() const { return V8DeprecatedInsts; } bool hasHardQuad() const { return HasHardQuad; } bool usePopc() const { return UsePopc; } + bool useSoftFloat() const { return UseSoftFloat; } + + // Leon options + bool useSoftFpu() const { return UseSoftFpu; } + bool hasLeonCasa() const { return HasLeonCasa; } + bool hasUmacSmac() const { return HasUmacSmac; } + bool performSDIVReplace() const { return PerformSDIVReplace; } + bool fixCallImmediates() const { return FixCallImmediates; } + bool ignoreZeroFlag() const { return IgnoreZeroFlag; } + bool insertNOPDoublePrecision() const { return InsertNOPDoublePrecision; } + bool fixFSMULD() const { return FixFSMULD; } + bool replaceFMULS() const { return ReplaceFMULS; } + bool preventRoundChange() const { return PreventRoundChange; } + bool fixAllFDIVSQRT() const { return FixAllFDIVSQRT; } + bool flushCacheLineSWAP() const { return FlushCacheLineSWAP; } + bool insertNOPsLoadStore() const { return InsertNOPsLoadStore; } + bool insertNOPLoad() const { return InsertNOPLoad; } /// ParseSubtargetFeatures - Parses features string setting specified /// subtarget options. Definition of function is auto generated by tblgen. @@ -87,6 +125,8 @@ public: /// returns adjusted framesize which includes space for register window /// spills and arguments. int getAdjustedFrameSize(int stackSize) const; + + bool isTargetLinux() const { return TargetTriple.isOSLinux(); } }; } // end namespace llvm diff --git a/lib/Target/Sparc/SparcTargetMachine.cpp b/lib/Target/Sparc/SparcTargetMachine.cpp index 725d7f047c47..17fe86a70844 100644 --- a/lib/Target/Sparc/SparcTargetMachine.cpp +++ b/lib/Target/Sparc/SparcTargetMachine.cpp @@ -13,7 +13,9 @@ #include "SparcTargetMachine.h" #include "SparcTargetObjectFile.h" #include "Sparc.h" +#include "LeonPasses.h" #include "llvm/CodeGen/Passes.h" +#include "llvm/CodeGen/TargetPassConfig.h" #include "llvm/IR/LegacyPassManager.h" #include "llvm/Support/TargetRegistry.h" using namespace llvm; @@ -52,28 +54,68 @@ static std::string computeDataLayout(const Triple &T, bool is64Bit) { return Ret; } -/// SparcTargetMachine ctor - Create an ILP32 architecture model -/// +static Reloc::Model getEffectiveRelocModel(Optional<Reloc::Model> RM) { + if (!RM.hasValue()) + return Reloc::Static; + return *RM; +} + +/// Create an ILP32 architecture model SparcTargetMachine::SparcTargetMachine(const Target &T, const Triple &TT, StringRef CPU, StringRef FS, const TargetOptions &Options, - Reloc::Model RM, CodeModel::Model CM, + Optional<Reloc::Model> RM, + CodeModel::Model CM, CodeGenOpt::Level OL, bool is64bit) : LLVMTargetMachine(T, computeDataLayout(TT, is64bit), TT, CPU, FS, Options, - RM, CM, OL), + getEffectiveRelocModel(RM), CM, OL), TLOF(make_unique<SparcELFTargetObjectFile>()), - Subtarget(TT, CPU, FS, *this, is64bit) { + Subtarget(TT, CPU, FS, *this, is64bit), is64Bit(is64bit) { initAsmInfo(); } SparcTargetMachine::~SparcTargetMachine() {} +const SparcSubtarget * +SparcTargetMachine::getSubtargetImpl(const Function &F) const { + Attribute CPUAttr = F.getFnAttribute("target-cpu"); + Attribute FSAttr = F.getFnAttribute("target-features"); + + std::string CPU = !CPUAttr.hasAttribute(Attribute::None) + ? CPUAttr.getValueAsString().str() + : TargetCPU; + std::string FS = !FSAttr.hasAttribute(Attribute::None) + ? FSAttr.getValueAsString().str() + : TargetFS; + + // FIXME: This is related to the code below to reset the target options, + // we need to know whether or not the soft float flag is set on the + // function, so we can enable it as a subtarget feature. + bool softFloat = + F.hasFnAttribute("use-soft-float") && + F.getFnAttribute("use-soft-float").getValueAsString() == "true"; + + if (softFloat) + FS += FS.empty() ? "+soft-float" : ",+soft-float"; + + auto &I = SubtargetMap[CPU + FS]; + if (!I) { + // This needs to be done before we create a new subtarget since any + // creation will depend on the TM and the code generation flags on the + // function that reside in TargetOptions. + resetTargetOptions(F); + I = llvm::make_unique<SparcSubtarget>(TargetTriple, CPU, FS, *this, + this->is64Bit); + } + return I.get(); +} + namespace { /// Sparc Code Generator Pass Configuration Options. class SparcPassConfig : public TargetPassConfig { public: SparcPassConfig(SparcTargetMachine *TM, PassManagerBase &PM) - : TargetPassConfig(TM, PM) {} + : TargetPassConfig(TM, PM) {} SparcTargetMachine &getSparcTargetMachine() const { return getTM<SparcTargetMachine>(); @@ -100,25 +142,62 @@ bool SparcPassConfig::addInstSelector() { return false; } -void SparcPassConfig::addPreEmitPass(){ +void SparcPassConfig::addPreEmitPass() { addPass(createSparcDelaySlotFillerPass(getSparcTargetMachine())); + if (this->getSparcTargetMachine().getSubtargetImpl()->ignoreZeroFlag()) { + addPass(new IgnoreZeroFlag(getSparcTargetMachine())); + } + 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())); + } + if (this->getSparcTargetMachine().getSubtargetImpl()->flushCacheLineSWAP()) { + addPass(new FlushCacheLineSWAP(getSparcTargetMachine())); + } + if (this->getSparcTargetMachine() + .getSubtargetImpl() + ->insertNOPDoublePrecision()) { + addPass(new InsertNOPDoublePrecision(getSparcTargetMachine())); + } } -void SparcV8TargetMachine::anchor() { } +void SparcV8TargetMachine::anchor() {} SparcV8TargetMachine::SparcV8TargetMachine(const Target &T, const Triple &TT, StringRef CPU, StringRef FS, const TargetOptions &Options, - Reloc::Model RM, CodeModel::Model CM, + Optional<Reloc::Model> RM, + CodeModel::Model CM, CodeGenOpt::Level OL) : SparcTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, false) {} -void SparcV9TargetMachine::anchor() { } +void SparcV9TargetMachine::anchor() {} SparcV9TargetMachine::SparcV9TargetMachine(const Target &T, const Triple &TT, StringRef CPU, StringRef FS, const TargetOptions &Options, - Reloc::Model RM, CodeModel::Model CM, + Optional<Reloc::Model> RM, + CodeModel::Model CM, CodeGenOpt::Level OL) : SparcTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, true) {} @@ -127,6 +206,7 @@ void SparcelTargetMachine::anchor() {} SparcelTargetMachine::SparcelTargetMachine(const Target &T, const Triple &TT, StringRef CPU, StringRef FS, const TargetOptions &Options, - Reloc::Model RM, CodeModel::Model CM, + Optional<Reloc::Model> RM, + CodeModel::Model CM, CodeGenOpt::Level OL) : SparcTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, false) {} diff --git a/lib/Target/Sparc/SparcTargetMachine.h b/lib/Target/Sparc/SparcTargetMachine.h index 903c2d15629f..48193fe095be 100644 --- a/lib/Target/Sparc/SparcTargetMachine.h +++ b/lib/Target/Sparc/SparcTargetMachine.h @@ -23,16 +23,17 @@ namespace llvm { class SparcTargetMachine : public LLVMTargetMachine { std::unique_ptr<TargetLoweringObjectFile> TLOF; SparcSubtarget Subtarget; + bool is64Bit; + mutable StringMap<std::unique_ptr<SparcSubtarget>> SubtargetMap; public: SparcTargetMachine(const Target &T, const Triple &TT, StringRef CPU, StringRef FS, const TargetOptions &Options, - Reloc::Model RM, CodeModel::Model CM, CodeGenOpt::Level OL, - bool is64bit); + Optional<Reloc::Model> RM, CodeModel::Model CM, + CodeGenOpt::Level OL, bool is64bit); ~SparcTargetMachine() override; - const SparcSubtarget *getSubtargetImpl(const Function &) const override { - return &Subtarget; - } + const SparcSubtarget *getSubtargetImpl() const { return &Subtarget; } + const SparcSubtarget *getSubtargetImpl(const Function &) const override; // Pass Pipeline Configuration TargetPassConfig *createPassConfig(PassManagerBase &PM) override; @@ -41,25 +42,25 @@ public: } }; -/// SparcV8TargetMachine - Sparc 32-bit target machine +/// Sparc 32-bit target machine /// class SparcV8TargetMachine : public SparcTargetMachine { virtual void anchor(); public: SparcV8TargetMachine(const Target &T, const Triple &TT, StringRef CPU, StringRef FS, const TargetOptions &Options, - Reloc::Model RM, CodeModel::Model CM, + Optional<Reloc::Model> RM, CodeModel::Model CM, CodeGenOpt::Level OL); }; -/// SparcV9TargetMachine - Sparc 64-bit target machine +/// Sparc 64-bit target machine /// class SparcV9TargetMachine : public SparcTargetMachine { virtual void anchor(); public: SparcV9TargetMachine(const Target &T, const Triple &TT, StringRef CPU, StringRef FS, const TargetOptions &Options, - Reloc::Model RM, CodeModel::Model CM, + Optional<Reloc::Model> RM, CodeModel::Model CM, CodeGenOpt::Level OL); }; @@ -69,7 +70,7 @@ class SparcelTargetMachine : public SparcTargetMachine { public: SparcelTargetMachine(const Target &T, const Triple &TT, StringRef CPU, StringRef FS, const TargetOptions &Options, - Reloc::Model RM, CodeModel::Model CM, + Optional<Reloc::Model> RM, CodeModel::Model CM, CodeGenOpt::Level OL); }; diff --git a/lib/Target/Sparc/TargetInfo/Makefile b/lib/Target/Sparc/TargetInfo/Makefile deleted file mode 100644 index 641ed87160c7..000000000000 --- a/lib/Target/Sparc/TargetInfo/Makefile +++ /dev/null @@ -1,15 +0,0 @@ -##===- lib/Target/Sparc/TargetInfo/Makefile ----------------*- Makefile -*-===## -# -# The LLVM Compiler Infrastructure -# -# This file is distributed under the University of Illinois Open Source -# License. See LICENSE.TXT for details. -# -##===----------------------------------------------------------------------===## -LEVEL = ../../../.. -LIBRARYNAME = LLVMSparcInfo - -# Hack: we need to include 'main' target directory to grab private headers -CPPFLAGS = -I$(PROJ_OBJ_DIR)/.. -I$(PROJ_SRC_DIR)/.. - -include $(LEVEL)/Makefile.common |