summaryrefslogtreecommitdiffstats
path: root/contrib/llvm/lib/Target/Sparc
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm/lib/Target/Sparc')
-rw-r--r--contrib/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp1055
-rw-r--r--contrib/llvm/lib/Target/Sparc/DelaySlotFiller.cpp495
-rw-r--r--contrib/llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp497
-rw-r--r--contrib/llvm/lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp178
-rw-r--r--contrib/llvm/lib/Target/Sparc/InstPrinter/SparcInstPrinter.h58
-rw-r--r--contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp304
-rw-r--r--contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp139
-rw-r--r--contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h97
-rw-r--r--contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp70
-rw-r--r--contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h37
-rw-r--r--contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp219
-rw-r--r--contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp221
-rw-r--r--contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h112
-rw-r--r--contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp184
-rw-r--r--contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h60
-rw-r--r--contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcTargetStreamer.cpp46
-rw-r--r--contrib/llvm/lib/Target/Sparc/Sparc.h134
-rw-r--r--contrib/llvm/lib/Target/Sparc/Sparc.td106
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp449
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcCallingConv.td139
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcFrameLowering.cpp260
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcFrameLowering.h60
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcISelDAGToDAG.cpp226
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcISelLowering.cpp3226
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcISelLowering.h180
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcInstr64Bit.td574
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcInstrAliases.td337
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcInstrFormats.td341
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcInstrInfo.cpp445
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcInstrInfo.h101
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcInstrInfo.td1306
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcInstrVIS.td263
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcMCInstLower.cpp109
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcMachineFunctionInfo.cpp14
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcMachineFunctionInfo.h56
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp213
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcRegisterInfo.h51
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcRegisterInfo.td252
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcSelectionDAGInfo.cpp24
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcSelectionDAGInfo.h31
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcSubtarget.cpp83
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcSubtarget.h93
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcTargetMachine.cpp132
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcTargetMachine.h78
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.cpp43
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.h35
-rw-r--r--contrib/llvm/lib/Target/Sparc/SparcTargetStreamer.h49
-rw-r--r--contrib/llvm/lib/Target/Sparc/TargetInfo/SparcTargetInfo.cpp26
48 files changed, 13208 insertions, 0 deletions
diff --git a/contrib/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp b/contrib/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
new file mode 100644
index 0000000..4a33f7f
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
@@ -0,0 +1,1055 @@
+//===-- SparcAsmParser.cpp - Parse Sparc assembly to MCInst instructions --===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MCTargetDesc/SparcMCTargetDesc.h"
+#include "MCTargetDesc/SparcMCExpr.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/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;
+
+// The generated AsmMatcher SparcGenAsmMatcher uses "Sparc" as the target
+// namespace. But SPARC backend uses "SP" as its namespace.
+namespace llvm {
+ namespace Sparc {
+ using namespace SP;
+ }
+}
+
+namespace {
+class SparcOperand;
+class SparcAsmParser : public MCTargetAsmParser {
+
+ MCSubtargetInfo &STI;
+ MCAsmParser &Parser;
+
+ /// @name Auto-generated Match Functions
+ /// {
+
+#define GET_ASSEMBLER_HEADER
+#include "SparcGenAsmMatcher.inc"
+
+ /// }
+
+ // public interface of the MCTargetAsmParser.
+ bool MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
+ OperandVector &Operands, MCStreamer &Out,
+ uint64_t &ErrorInfo,
+ bool MatchingInlineAsm) override;
+ bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc) override;
+ bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
+ SMLoc NameLoc, OperandVector &Operands) override;
+ bool ParseDirective(AsmToken DirectiveID) override;
+
+ unsigned validateTargetOperandClass(MCParsedAsmOperand &Op,
+ unsigned Kind) override;
+
+ // Custom parse functions for Sparc specific operands.
+ OperandMatchResultTy parseMEMOperand(OperandVector &Operands);
+
+ OperandMatchResultTy parseOperand(OperandVector &Operands, StringRef Name);
+
+ OperandMatchResultTy
+ parseSparcAsmOperand(std::unique_ptr<SparcOperand> &Operand,
+ bool isCall = false);
+
+ OperandMatchResultTy parseBranchModifiers(OperandVector &Operands);
+
+ // returns true if Tok is matched to a register and returns register in RegNo.
+ bool matchRegisterName(const AsmToken &Tok, unsigned &RegNo,
+ unsigned &RegKind);
+
+ bool matchSparcAsmModifiers(const MCExpr *&EVal, SMLoc &EndLoc);
+ bool parseDirectiveWord(unsigned Size, SMLoc L);
+
+ bool is64Bit() const {
+ return STI.getTargetTriple().getArchName().startswith("sparcv9");
+ }
+
+ void expandSET(MCInst &Inst, SMLoc IDLoc,
+ SmallVectorImpl<MCInst> &Instructions);
+
+public:
+ SparcAsmParser(MCSubtargetInfo &sti, MCAsmParser &parser,
+ const MCInstrInfo &MII,
+ const MCTargetOptions &Options)
+ : MCTargetAsmParser(), STI(sti), Parser(parser) {
+ // Initialize the set of available features.
+ setAvailableFeatures(ComputeAvailableFeatures(STI.getFeatureBits()));
+ }
+
+};
+
+ static unsigned IntRegs[32] = {
+ Sparc::G0, Sparc::G1, Sparc::G2, Sparc::G3,
+ Sparc::G4, Sparc::G5, Sparc::G6, Sparc::G7,
+ Sparc::O0, Sparc::O1, Sparc::O2, Sparc::O3,
+ Sparc::O4, Sparc::O5, Sparc::O6, Sparc::O7,
+ Sparc::L0, Sparc::L1, Sparc::L2, Sparc::L3,
+ Sparc::L4, Sparc::L5, Sparc::L6, Sparc::L7,
+ Sparc::I0, Sparc::I1, Sparc::I2, Sparc::I3,
+ Sparc::I4, Sparc::I5, Sparc::I6, Sparc::I7 };
+
+ static unsigned FloatRegs[32] = {
+ Sparc::F0, Sparc::F1, Sparc::F2, Sparc::F3,
+ Sparc::F4, Sparc::F5, Sparc::F6, Sparc::F7,
+ Sparc::F8, Sparc::F9, Sparc::F10, Sparc::F11,
+ Sparc::F12, Sparc::F13, Sparc::F14, Sparc::F15,
+ Sparc::F16, Sparc::F17, Sparc::F18, Sparc::F19,
+ Sparc::F20, Sparc::F21, Sparc::F22, Sparc::F23,
+ Sparc::F24, Sparc::F25, Sparc::F26, Sparc::F27,
+ Sparc::F28, Sparc::F29, Sparc::F30, Sparc::F31 };
+
+ static unsigned DoubleRegs[32] = {
+ Sparc::D0, Sparc::D1, Sparc::D2, Sparc::D3,
+ Sparc::D4, Sparc::D5, Sparc::D6, Sparc::D7,
+ Sparc::D8, Sparc::D7, Sparc::D8, Sparc::D9,
+ Sparc::D12, Sparc::D13, Sparc::D14, Sparc::D15,
+ Sparc::D16, Sparc::D17, Sparc::D18, Sparc::D19,
+ Sparc::D20, Sparc::D21, Sparc::D22, Sparc::D23,
+ Sparc::D24, Sparc::D25, Sparc::D26, Sparc::D27,
+ Sparc::D28, Sparc::D29, Sparc::D30, Sparc::D31 };
+
+ static unsigned QuadFPRegs[32] = {
+ Sparc::Q0, Sparc::Q1, Sparc::Q2, Sparc::Q3,
+ Sparc::Q4, Sparc::Q5, Sparc::Q6, Sparc::Q7,
+ Sparc::Q8, Sparc::Q9, Sparc::Q10, Sparc::Q11,
+ Sparc::Q12, Sparc::Q13, Sparc::Q14, Sparc::Q15 };
+
+ static unsigned ASRRegs[32] = {
+ SP::Y, SP::ASR1, SP::ASR2, SP::ASR3,
+ SP::ASR4, SP::ASR5, SP::ASR6, SP::ASR7,
+ SP::ASR8, SP::ASR9, SP::ASR10, SP::ASR11,
+ SP::ASR12, SP::ASR13, SP::ASR14, SP::ASR15,
+ SP::ASR16, SP::ASR17, SP::ASR18, SP::ASR19,
+ SP::ASR20, SP::ASR21, SP::ASR22, SP::ASR23,
+ SP::ASR24, SP::ASR25, SP::ASR26, SP::ASR27,
+ SP::ASR28, SP::ASR29, SP::ASR30, SP::ASR31};
+
+/// SparcOperand - Instances of this class represent a parsed Sparc machine
+/// instruction.
+class SparcOperand : public MCParsedAsmOperand {
+public:
+ enum RegisterKind {
+ rk_None,
+ rk_IntReg,
+ rk_FloatReg,
+ rk_DoubleReg,
+ rk_QuadReg,
+ rk_Special,
+ };
+
+private:
+ enum KindTy {
+ k_Token,
+ k_Register,
+ k_Immediate,
+ k_MemoryReg,
+ k_MemoryImm
+ } Kind;
+
+ SMLoc StartLoc, EndLoc;
+
+ struct Token {
+ const char *Data;
+ unsigned Length;
+ };
+
+ struct RegOp {
+ unsigned RegNum;
+ RegisterKind Kind;
+ };
+
+ struct ImmOp {
+ const MCExpr *Val;
+ };
+
+ struct MemOp {
+ unsigned Base;
+ unsigned OffsetReg;
+ const MCExpr *Off;
+ };
+
+ union {
+ struct Token Tok;
+ struct RegOp Reg;
+ struct ImmOp Imm;
+ struct MemOp Mem;
+ };
+public:
+ SparcOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {}
+
+ bool isToken() const override { return Kind == k_Token; }
+ bool isReg() const override { return Kind == k_Register; }
+ bool isImm() const override { return Kind == k_Immediate; }
+ bool isMem() const override { return isMEMrr() || isMEMri(); }
+ bool isMEMrr() const { return Kind == k_MemoryReg; }
+ bool isMEMri() const { return Kind == k_MemoryImm; }
+
+ bool isFloatReg() const {
+ return (Kind == k_Register && Reg.Kind == rk_FloatReg);
+ }
+
+ bool isFloatOrDoubleReg() const {
+ return (Kind == k_Register && (Reg.Kind == rk_FloatReg
+ || Reg.Kind == rk_DoubleReg));
+ }
+
+
+ StringRef getToken() const {
+ assert(Kind == k_Token && "Invalid access!");
+ return StringRef(Tok.Data, Tok.Length);
+ }
+
+ unsigned getReg() const override {
+ assert((Kind == k_Register) && "Invalid access!");
+ return Reg.RegNum;
+ }
+
+ const MCExpr *getImm() const {
+ assert((Kind == k_Immediate) && "Invalid access!");
+ return Imm.Val;
+ }
+
+ unsigned getMemBase() const {
+ assert((Kind == k_MemoryReg || Kind == k_MemoryImm) && "Invalid access!");
+ return Mem.Base;
+ }
+
+ unsigned getMemOffsetReg() const {
+ assert((Kind == k_MemoryReg) && "Invalid access!");
+ return Mem.OffsetReg;
+ }
+
+ const MCExpr *getMemOff() const {
+ assert((Kind == k_MemoryImm) && "Invalid access!");
+ return Mem.Off;
+ }
+
+ /// getStartLoc - Get the location of the first token of this operand.
+ SMLoc getStartLoc() const override {
+ return StartLoc;
+ }
+ /// getEndLoc - Get the location of the last token of this operand.
+ SMLoc getEndLoc() const override {
+ return EndLoc;
+ }
+
+ void print(raw_ostream &OS) const override {
+ switch (Kind) {
+ case k_Token: OS << "Token: " << getToken() << "\n"; break;
+ case k_Register: OS << "Reg: #" << getReg() << "\n"; break;
+ case k_Immediate: OS << "Imm: " << getImm() << "\n"; break;
+ case k_MemoryReg: OS << "Mem: " << getMemBase() << "+"
+ << getMemOffsetReg() << "\n"; break;
+ case k_MemoryImm: assert(getMemOff() != nullptr);
+ OS << "Mem: " << getMemBase()
+ << "+" << *getMemOff()
+ << "\n"; break;
+ }
+ }
+
+ void addRegOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ Inst.addOperand(MCOperand::createReg(getReg()));
+ }
+
+ void addImmOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 1 && "Invalid number of operands!");
+ const MCExpr *Expr = getImm();
+ addExpr(Inst, Expr);
+ }
+
+ void addExpr(MCInst &Inst, const MCExpr *Expr) const{
+ // Add as immediate when possible. Null MCExpr = 0.
+ if (!Expr)
+ Inst.addOperand(MCOperand::createImm(0));
+ else if (const MCConstantExpr *CE = dyn_cast<MCConstantExpr>(Expr))
+ Inst.addOperand(MCOperand::createImm(CE->getValue()));
+ else
+ Inst.addOperand(MCOperand::createExpr(Expr));
+ }
+
+ void addMEMrrOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 2 && "Invalid number of operands!");
+
+ Inst.addOperand(MCOperand::createReg(getMemBase()));
+
+ assert(getMemOffsetReg() != 0 && "Invalid offset");
+ Inst.addOperand(MCOperand::createReg(getMemOffsetReg()));
+ }
+
+ void addMEMriOperands(MCInst &Inst, unsigned N) const {
+ assert(N == 2 && "Invalid number of operands!");
+
+ Inst.addOperand(MCOperand::createReg(getMemBase()));
+
+ const MCExpr *Expr = getMemOff();
+ addExpr(Inst, Expr);
+ }
+
+ static std::unique_ptr<SparcOperand> CreateToken(StringRef Str, SMLoc S) {
+ auto Op = make_unique<SparcOperand>(k_Token);
+ Op->Tok.Data = Str.data();
+ Op->Tok.Length = Str.size();
+ Op->StartLoc = S;
+ Op->EndLoc = S;
+ return Op;
+ }
+
+ static std::unique_ptr<SparcOperand> CreateReg(unsigned RegNum, unsigned Kind,
+ SMLoc S, SMLoc E) {
+ auto Op = make_unique<SparcOperand>(k_Register);
+ Op->Reg.RegNum = RegNum;
+ Op->Reg.Kind = (SparcOperand::RegisterKind)Kind;
+ Op->StartLoc = S;
+ Op->EndLoc = E;
+ return Op;
+ }
+
+ static std::unique_ptr<SparcOperand> CreateImm(const MCExpr *Val, SMLoc S,
+ SMLoc E) {
+ auto Op = make_unique<SparcOperand>(k_Immediate);
+ Op->Imm.Val = Val;
+ Op->StartLoc = S;
+ Op->EndLoc = E;
+ return Op;
+ }
+
+ static bool MorphToDoubleReg(SparcOperand &Op) {
+ unsigned Reg = Op.getReg();
+ assert(Op.Reg.Kind == rk_FloatReg);
+ unsigned regIdx = Reg - Sparc::F0;
+ if (regIdx % 2 || regIdx > 31)
+ return false;
+ Op.Reg.RegNum = DoubleRegs[regIdx / 2];
+ Op.Reg.Kind = rk_DoubleReg;
+ return true;
+ }
+
+ static bool MorphToQuadReg(SparcOperand &Op) {
+ unsigned Reg = Op.getReg();
+ unsigned regIdx = 0;
+ switch (Op.Reg.Kind) {
+ default: llvm_unreachable("Unexpected register kind!");
+ case rk_FloatReg:
+ regIdx = Reg - Sparc::F0;
+ if (regIdx % 4 || regIdx > 31)
+ return false;
+ Reg = QuadFPRegs[regIdx / 4];
+ break;
+ case rk_DoubleReg:
+ regIdx = Reg - Sparc::D0;
+ if (regIdx % 2 || regIdx > 31)
+ return false;
+ Reg = QuadFPRegs[regIdx / 2];
+ break;
+ }
+ Op.Reg.RegNum = Reg;
+ Op.Reg.Kind = rk_QuadReg;
+ return true;
+ }
+
+ static std::unique_ptr<SparcOperand>
+ MorphToMEMrr(unsigned Base, std::unique_ptr<SparcOperand> Op) {
+ unsigned offsetReg = Op->getReg();
+ Op->Kind = k_MemoryReg;
+ Op->Mem.Base = Base;
+ Op->Mem.OffsetReg = offsetReg;
+ Op->Mem.Off = nullptr;
+ return Op;
+ }
+
+ static std::unique_ptr<SparcOperand>
+ CreateMEMr(unsigned Base, SMLoc S, SMLoc E) {
+ auto Op = make_unique<SparcOperand>(k_MemoryReg);
+ Op->Mem.Base = Base;
+ Op->Mem.OffsetReg = Sparc::G0; // always 0
+ Op->Mem.Off = nullptr;
+ Op->StartLoc = S;
+ Op->EndLoc = E;
+ return Op;
+ }
+
+ static std::unique_ptr<SparcOperand>
+ MorphToMEMri(unsigned Base, std::unique_ptr<SparcOperand> Op) {
+ const MCExpr *Imm = Op->getImm();
+ Op->Kind = k_MemoryImm;
+ Op->Mem.Base = Base;
+ Op->Mem.OffsetReg = 0;
+ Op->Mem.Off = Imm;
+ return Op;
+ }
+};
+
+} // end namespace
+
+void SparcAsmParser::expandSET(MCInst &Inst, SMLoc IDLoc,
+ SmallVectorImpl<MCInst> &Instructions) {
+ MCOperand MCRegOp = Inst.getOperand(0);
+ MCOperand MCValOp = Inst.getOperand(1);
+ assert(MCRegOp.isReg());
+ assert(MCValOp.isImm() || MCValOp.isExpr());
+
+ // the imm operand can be either an expression or an immediate.
+ bool IsImm = Inst.getOperand(1).isImm();
+ uint64_t ImmValue = IsImm ? MCValOp.getImm() : 0;
+ const MCExpr *ValExpr;
+ if (IsImm)
+ ValExpr = MCConstantExpr::create(ImmValue, getContext());
+ else
+ ValExpr = MCValOp.getExpr();
+
+ MCOperand PrevReg = MCOperand::createReg(Sparc::G0);
+
+ if (!IsImm || (ImmValue & ~0x1fff)) {
+ MCInst TmpInst;
+ const MCExpr *Expr =
+ SparcMCExpr::create(SparcMCExpr::VK_Sparc_HI, ValExpr, getContext());
+ TmpInst.setLoc(IDLoc);
+ TmpInst.setOpcode(SP::SETHIi);
+ TmpInst.addOperand(MCRegOp);
+ TmpInst.addOperand(MCOperand::createExpr(Expr));
+ Instructions.push_back(TmpInst);
+ PrevReg = MCRegOp;
+ }
+
+ if (!IsImm || ((ImmValue & 0x1fff) != 0 || ImmValue == 0)) {
+ MCInst TmpInst;
+ const MCExpr *Expr =
+ SparcMCExpr::create(SparcMCExpr::VK_Sparc_LO, ValExpr, getContext());
+ TmpInst.setLoc(IDLoc);
+ TmpInst.setOpcode(SP::ORri);
+ TmpInst.addOperand(MCRegOp);
+ TmpInst.addOperand(PrevReg);
+ TmpInst.addOperand(MCOperand::createExpr(Expr));
+ Instructions.push_back(TmpInst);
+ }
+}
+
+bool SparcAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
+ OperandVector &Operands,
+ MCStreamer &Out,
+ uint64_t &ErrorInfo,
+ bool MatchingInlineAsm) {
+ MCInst Inst;
+ SmallVector<MCInst, 8> Instructions;
+ unsigned MatchResult = MatchInstructionImpl(Operands, Inst, ErrorInfo,
+ MatchingInlineAsm);
+ switch (MatchResult) {
+ case Match_Success: {
+ switch (Inst.getOpcode()) {
+ default:
+ Inst.setLoc(IDLoc);
+ Instructions.push_back(Inst);
+ break;
+ case SP::SET:
+ expandSET(Inst, IDLoc, Instructions);
+ break;
+ }
+
+ for (const MCInst &I : Instructions) {
+ Out.EmitInstruction(I, STI);
+ }
+ return false;
+ }
+
+ case Match_MissingFeature:
+ return Error(IDLoc,
+ "instruction requires a CPU feature not currently enabled");
+
+ case Match_InvalidOperand: {
+ SMLoc ErrorLoc = IDLoc;
+ if (ErrorInfo != ~0ULL) {
+ if (ErrorInfo >= Operands.size())
+ return Error(IDLoc, "too few operands for instruction");
+
+ ErrorLoc = ((SparcOperand &)*Operands[ErrorInfo]).getStartLoc();
+ if (ErrorLoc == SMLoc())
+ ErrorLoc = IDLoc;
+ }
+
+ return Error(ErrorLoc, "invalid operand for instruction");
+ }
+ case Match_MnemonicFail:
+ return Error(IDLoc, "invalid instruction mnemonic");
+ }
+ llvm_unreachable("Implement any new match types added!");
+}
+
+bool SparcAsmParser::
+ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc)
+{
+ const AsmToken &Tok = Parser.getTok();
+ StartLoc = Tok.getLoc();
+ EndLoc = Tok.getEndLoc();
+ RegNo = 0;
+ if (getLexer().getKind() != AsmToken::Percent)
+ return false;
+ Parser.Lex();
+ unsigned regKind = SparcOperand::rk_None;
+ if (matchRegisterName(Tok, RegNo, regKind)) {
+ Parser.Lex();
+ return false;
+ }
+
+ return Error(StartLoc, "invalid register name");
+}
+
+static void applyMnemonicAliases(StringRef &Mnemonic, uint64_t Features,
+ unsigned VariantID);
+
+bool SparcAsmParser::ParseInstruction(ParseInstructionInfo &Info,
+ StringRef Name, SMLoc NameLoc,
+ OperandVector &Operands) {
+
+ // First operand in MCInst is instruction mnemonic.
+ Operands.push_back(SparcOperand::CreateToken(Name, NameLoc));
+
+ // apply mnemonic aliases, if any, so that we can parse operands correctly.
+ applyMnemonicAliases(Name, getAvailableFeatures(), 0);
+
+ if (getLexer().isNot(AsmToken::EndOfStatement)) {
+ // Read the first operand.
+ if (getLexer().is(AsmToken::Comma)) {
+ if (parseBranchModifiers(Operands) != MatchOperand_Success) {
+ SMLoc Loc = getLexer().getLoc();
+ Parser.eatToEndOfStatement();
+ return Error(Loc, "unexpected token");
+ }
+ }
+ if (parseOperand(Operands, Name) != MatchOperand_Success) {
+ SMLoc Loc = getLexer().getLoc();
+ Parser.eatToEndOfStatement();
+ return Error(Loc, "unexpected token");
+ }
+
+ while (getLexer().is(AsmToken::Comma)) {
+ Parser.Lex(); // Eat the comma.
+ // Parse and remember the operand.
+ if (parseOperand(Operands, Name) != MatchOperand_Success) {
+ SMLoc Loc = getLexer().getLoc();
+ Parser.eatToEndOfStatement();
+ return Error(Loc, "unexpected token");
+ }
+ }
+ }
+ if (getLexer().isNot(AsmToken::EndOfStatement)) {
+ SMLoc Loc = getLexer().getLoc();
+ Parser.eatToEndOfStatement();
+ return Error(Loc, "unexpected token");
+ }
+ Parser.Lex(); // Consume the EndOfStatement.
+ return false;
+}
+
+bool SparcAsmParser::
+ParseDirective(AsmToken DirectiveID)
+{
+ StringRef IDVal = DirectiveID.getString();
+
+ if (IDVal == ".byte")
+ return parseDirectiveWord(1, DirectiveID.getLoc());
+
+ if (IDVal == ".half")
+ return parseDirectiveWord(2, DirectiveID.getLoc());
+
+ if (IDVal == ".word")
+ return parseDirectiveWord(4, DirectiveID.getLoc());
+
+ if (IDVal == ".nword")
+ return parseDirectiveWord(is64Bit() ? 8 : 4, DirectiveID.getLoc());
+
+ if (is64Bit() && IDVal == ".xword")
+ return parseDirectiveWord(8, DirectiveID.getLoc());
+
+ if (IDVal == ".register") {
+ // For now, ignore .register directive.
+ Parser.eatToEndOfStatement();
+ return false;
+ }
+
+ // Let the MC layer to handle other directives.
+ return true;
+}
+
+bool SparcAsmParser:: parseDirectiveWord(unsigned Size, SMLoc L) {
+ if (getLexer().isNot(AsmToken::EndOfStatement)) {
+ for (;;) {
+ const MCExpr *Value;
+ if (getParser().parseExpression(Value))
+ return true;
+
+ getParser().getStreamer().EmitValue(Value, Size);
+
+ if (getLexer().is(AsmToken::EndOfStatement))
+ break;
+
+ // FIXME: Improve diagnostic.
+ if (getLexer().isNot(AsmToken::Comma))
+ return Error(L, "unexpected token in directive");
+ Parser.Lex();
+ }
+ }
+ Parser.Lex();
+ return false;
+}
+
+SparcAsmParser::OperandMatchResultTy
+SparcAsmParser::parseMEMOperand(OperandVector &Operands) {
+
+ SMLoc S, E;
+ unsigned BaseReg = 0;
+
+ if (ParseRegister(BaseReg, S, E)) {
+ return MatchOperand_NoMatch;
+ }
+
+ switch (getLexer().getKind()) {
+ default: return MatchOperand_NoMatch;
+
+ case AsmToken::Comma:
+ case AsmToken::RBrac:
+ case AsmToken::EndOfStatement:
+ Operands.push_back(SparcOperand::CreateMEMr(BaseReg, S, E));
+ return MatchOperand_Success;
+
+ case AsmToken:: Plus:
+ Parser.Lex(); // Eat the '+'
+ break;
+ case AsmToken::Minus:
+ break;
+ }
+
+ std::unique_ptr<SparcOperand> Offset;
+ OperandMatchResultTy ResTy = parseSparcAsmOperand(Offset);
+ if (ResTy != MatchOperand_Success || !Offset)
+ return MatchOperand_NoMatch;
+
+ Operands.push_back(
+ Offset->isImm() ? SparcOperand::MorphToMEMri(BaseReg, std::move(Offset))
+ : SparcOperand::MorphToMEMrr(BaseReg, std::move(Offset)));
+
+ return MatchOperand_Success;
+}
+
+SparcAsmParser::OperandMatchResultTy
+SparcAsmParser::parseOperand(OperandVector &Operands, StringRef Mnemonic) {
+
+ OperandMatchResultTy ResTy = MatchOperandParserImpl(Operands, Mnemonic);
+
+ // If there wasn't a custom match, try the generic matcher below. Otherwise,
+ // there was a match, but an error occurred, in which case, just return that
+ // the operand parsing failed.
+ if (ResTy == MatchOperand_Success || ResTy == MatchOperand_ParseFail)
+ return ResTy;
+
+ if (getLexer().is(AsmToken::LBrac)) {
+ // Memory operand
+ Operands.push_back(SparcOperand::CreateToken("[",
+ Parser.getTok().getLoc()));
+ Parser.Lex(); // Eat the [
+
+ if (Mnemonic == "cas" || Mnemonic == "casx") {
+ SMLoc S = Parser.getTok().getLoc();
+ if (getLexer().getKind() != AsmToken::Percent)
+ return MatchOperand_NoMatch;
+ Parser.Lex(); // eat %
+
+ unsigned RegNo, RegKind;
+ if (!matchRegisterName(Parser.getTok(), RegNo, RegKind))
+ return MatchOperand_NoMatch;
+
+ Parser.Lex(); // Eat the identifier token.
+ SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer()-1);
+ Operands.push_back(SparcOperand::CreateReg(RegNo, RegKind, S, E));
+ ResTy = MatchOperand_Success;
+ } else {
+ ResTy = parseMEMOperand(Operands);
+ }
+
+ if (ResTy != MatchOperand_Success)
+ return ResTy;
+
+ if (!getLexer().is(AsmToken::RBrac))
+ return MatchOperand_ParseFail;
+
+ Operands.push_back(SparcOperand::CreateToken("]",
+ Parser.getTok().getLoc()));
+ Parser.Lex(); // Eat the ]
+
+ // Parse an optional address-space identifier after the address.
+ if (getLexer().is(AsmToken::Integer)) {
+ std::unique_ptr<SparcOperand> Op;
+ ResTy = parseSparcAsmOperand(Op, false);
+ if (ResTy != MatchOperand_Success || !Op)
+ return MatchOperand_ParseFail;
+ Operands.push_back(std::move(Op));
+ }
+ return MatchOperand_Success;
+ }
+
+ std::unique_ptr<SparcOperand> Op;
+
+ ResTy = parseSparcAsmOperand(Op, (Mnemonic == "call"));
+ if (ResTy != MatchOperand_Success || !Op)
+ return MatchOperand_ParseFail;
+
+ // Push the parsed operand into the list of operands
+ Operands.push_back(std::move(Op));
+
+ return MatchOperand_Success;
+}
+
+SparcAsmParser::OperandMatchResultTy
+SparcAsmParser::parseSparcAsmOperand(std::unique_ptr<SparcOperand> &Op,
+ bool isCall) {
+
+ SMLoc S = Parser.getTok().getLoc();
+ SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
+ const MCExpr *EVal;
+
+ Op = nullptr;
+ switch (getLexer().getKind()) {
+ default: break;
+
+ case AsmToken::Percent:
+ Parser.Lex(); // Eat the '%'.
+ unsigned RegNo;
+ unsigned RegKind;
+ if (matchRegisterName(Parser.getTok(), RegNo, RegKind)) {
+ StringRef name = Parser.getTok().getString();
+ Parser.Lex(); // Eat the identifier token.
+ E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
+ switch (RegNo) {
+ default:
+ Op = SparcOperand::CreateReg(RegNo, RegKind, S, E);
+ break;
+ case Sparc::PSR:
+ Op = SparcOperand::CreateToken("%psr", S);
+ break;
+ case Sparc::WIM:
+ Op = SparcOperand::CreateToken("%wim", S);
+ break;
+ case Sparc::TBR:
+ Op = SparcOperand::CreateToken("%tbr", S);
+ break;
+ case Sparc::ICC:
+ if (name == "xcc")
+ Op = SparcOperand::CreateToken("%xcc", S);
+ else
+ Op = SparcOperand::CreateToken("%icc", S);
+ break;
+ }
+ break;
+ }
+ if (matchSparcAsmModifiers(EVal, E)) {
+ E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
+ Op = SparcOperand::CreateImm(EVal, S, E);
+ }
+ break;
+
+ case AsmToken::Minus:
+ case AsmToken::Integer:
+ case AsmToken::LParen:
+ if (!getParser().parseExpression(EVal, E))
+ Op = SparcOperand::CreateImm(EVal, S, E);
+ break;
+
+ case AsmToken::Identifier: {
+ StringRef Identifier;
+ if (!getParser().parseIdentifier(Identifier)) {
+ E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
+ MCSymbol *Sym = getContext().getOrCreateSymbol(Identifier);
+
+ const MCExpr *Res = MCSymbolRefExpr::create(Sym, MCSymbolRefExpr::VK_None,
+ getContext());
+ if (isCall &&
+ getContext().getObjectFileInfo()->getRelocM() == Reloc::PIC_)
+ Res = SparcMCExpr::create(SparcMCExpr::VK_Sparc_WPLT30, Res,
+ getContext());
+ Op = SparcOperand::CreateImm(Res, S, E);
+ }
+ break;
+ }
+ }
+ return (Op) ? MatchOperand_Success : MatchOperand_ParseFail;
+}
+
+SparcAsmParser::OperandMatchResultTy
+SparcAsmParser::parseBranchModifiers(OperandVector &Operands) {
+
+ // parse (,a|,pn|,pt)+
+
+ while (getLexer().is(AsmToken::Comma)) {
+
+ Parser.Lex(); // Eat the comma
+
+ if (!getLexer().is(AsmToken::Identifier))
+ return MatchOperand_ParseFail;
+ StringRef modName = Parser.getTok().getString();
+ if (modName == "a" || modName == "pn" || modName == "pt") {
+ Operands.push_back(SparcOperand::CreateToken(modName,
+ Parser.getTok().getLoc()));
+ Parser.Lex(); // eat the identifier.
+ }
+ }
+ return MatchOperand_Success;
+}
+
+bool SparcAsmParser::matchRegisterName(const AsmToken &Tok,
+ unsigned &RegNo,
+ unsigned &RegKind)
+{
+ int64_t intVal = 0;
+ RegNo = 0;
+ RegKind = SparcOperand::rk_None;
+ if (Tok.is(AsmToken::Identifier)) {
+ StringRef name = Tok.getString();
+
+ // %fp
+ if (name.equals("fp")) {
+ RegNo = Sparc::I6;
+ RegKind = SparcOperand::rk_IntReg;
+ return true;
+ }
+ // %sp
+ if (name.equals("sp")) {
+ RegNo = Sparc::O6;
+ RegKind = SparcOperand::rk_IntReg;
+ return true;
+ }
+
+ if (name.equals("y")) {
+ RegNo = Sparc::Y;
+ RegKind = SparcOperand::rk_Special;
+ return true;
+ }
+
+ if (name.substr(0, 3).equals_lower("asr")
+ && !name.substr(3).getAsInteger(10, intVal)
+ && intVal > 0 && intVal < 32) {
+ RegNo = ASRRegs[intVal];
+ RegKind = SparcOperand::rk_Special;
+ return true;
+ }
+
+ if (name.equals("icc")) {
+ RegNo = Sparc::ICC;
+ RegKind = SparcOperand::rk_Special;
+ return true;
+ }
+
+ if (name.equals("psr")) {
+ RegNo = Sparc::PSR;
+ RegKind = SparcOperand::rk_Special;
+ return true;
+ }
+
+ if (name.equals("wim")) {
+ RegNo = Sparc::WIM;
+ RegKind = SparcOperand::rk_Special;
+ return true;
+ }
+
+ if (name.equals("tbr")) {
+ RegNo = Sparc::TBR;
+ RegKind = SparcOperand::rk_Special;
+ return true;
+ }
+
+ if (name.equals("xcc")) {
+ // FIXME:: check 64bit.
+ RegNo = Sparc::ICC;
+ RegKind = SparcOperand::rk_Special;
+ return true;
+ }
+
+ // %fcc0 - %fcc3
+ if (name.substr(0, 3).equals_lower("fcc")
+ && !name.substr(3).getAsInteger(10, intVal)
+ && intVal < 4) {
+ // FIXME: check 64bit and handle %fcc1 - %fcc3
+ RegNo = Sparc::FCC0 + intVal;
+ RegKind = SparcOperand::rk_Special;
+ return true;
+ }
+
+ // %g0 - %g7
+ if (name.substr(0, 1).equals_lower("g")
+ && !name.substr(1).getAsInteger(10, intVal)
+ && intVal < 8) {
+ RegNo = IntRegs[intVal];
+ RegKind = SparcOperand::rk_IntReg;
+ return true;
+ }
+ // %o0 - %o7
+ if (name.substr(0, 1).equals_lower("o")
+ && !name.substr(1).getAsInteger(10, intVal)
+ && intVal < 8) {
+ RegNo = IntRegs[8 + intVal];
+ RegKind = SparcOperand::rk_IntReg;
+ return true;
+ }
+ if (name.substr(0, 1).equals_lower("l")
+ && !name.substr(1).getAsInteger(10, intVal)
+ && intVal < 8) {
+ RegNo = IntRegs[16 + intVal];
+ RegKind = SparcOperand::rk_IntReg;
+ return true;
+ }
+ if (name.substr(0, 1).equals_lower("i")
+ && !name.substr(1).getAsInteger(10, intVal)
+ && intVal < 8) {
+ RegNo = IntRegs[24 + intVal];
+ RegKind = SparcOperand::rk_IntReg;
+ return true;
+ }
+ // %f0 - %f31
+ if (name.substr(0, 1).equals_lower("f")
+ && !name.substr(1, 2).getAsInteger(10, intVal) && intVal < 32) {
+ RegNo = FloatRegs[intVal];
+ RegKind = SparcOperand::rk_FloatReg;
+ return true;
+ }
+ // %f32 - %f62
+ if (name.substr(0, 1).equals_lower("f")
+ && !name.substr(1, 2).getAsInteger(10, intVal)
+ && intVal >= 32 && intVal <= 62 && (intVal % 2 == 0)) {
+ // FIXME: Check V9
+ RegNo = DoubleRegs[intVal/2];
+ RegKind = SparcOperand::rk_DoubleReg;
+ return true;
+ }
+
+ // %r0 - %r31
+ if (name.substr(0, 1).equals_lower("r")
+ && !name.substr(1, 2).getAsInteger(10, intVal) && intVal < 31) {
+ RegNo = IntRegs[intVal];
+ RegKind = SparcOperand::rk_IntReg;
+ return true;
+ }
+ }
+ return false;
+}
+
+// Determine if an expression contains a reference to the symbol
+// "_GLOBAL_OFFSET_TABLE_".
+static bool hasGOTReference(const MCExpr *Expr) {
+ switch (Expr->getKind()) {
+ case MCExpr::Target:
+ if (const SparcMCExpr *SE = dyn_cast<SparcMCExpr>(Expr))
+ return hasGOTReference(SE->getSubExpr());
+ break;
+
+ case MCExpr::Constant:
+ break;
+
+ case MCExpr::Binary: {
+ const MCBinaryExpr *BE = cast<MCBinaryExpr>(Expr);
+ return hasGOTReference(BE->getLHS()) || hasGOTReference(BE->getRHS());
+ }
+
+ case MCExpr::SymbolRef: {
+ const MCSymbolRefExpr &SymRef = *cast<MCSymbolRefExpr>(Expr);
+ return (SymRef.getSymbol().getName() == "_GLOBAL_OFFSET_TABLE_");
+ }
+
+ case MCExpr::Unary:
+ return hasGOTReference(cast<MCUnaryExpr>(Expr)->getSubExpr());
+ }
+ return false;
+}
+
+bool SparcAsmParser::matchSparcAsmModifiers(const MCExpr *&EVal,
+ SMLoc &EndLoc)
+{
+ AsmToken Tok = Parser.getTok();
+ if (!Tok.is(AsmToken::Identifier))
+ return false;
+
+ StringRef name = Tok.getString();
+
+ SparcMCExpr::VariantKind VK = SparcMCExpr::parseVariantKind(name);
+
+ if (VK == SparcMCExpr::VK_Sparc_None)
+ return false;
+
+ Parser.Lex(); // Eat the identifier.
+ if (Parser.getTok().getKind() != AsmToken::LParen)
+ return false;
+
+ Parser.Lex(); // Eat the LParen token.
+ const MCExpr *subExpr;
+ if (Parser.parseParenExpression(subExpr, EndLoc))
+ return false;
+
+ bool isPIC = getContext().getObjectFileInfo()->getRelocM() == Reloc::PIC_;
+
+ // Ugly: if a sparc assembly expression says "%hi(...)" but the
+ // expression within contains _GLOBAL_OFFSET_TABLE_, it REALLY means
+ // %pc22. Same with %lo -> %pc10. Worse, if it doesn't contain that,
+ // the meaning depends on whether the assembler was invoked with
+ // -KPIC or not: if so, it really means %got22/%got10; if not, it
+ // actually means what it said! Sigh, historical mistakes...
+
+ switch(VK) {
+ default: break;
+ case SparcMCExpr::VK_Sparc_LO:
+ VK = (hasGOTReference(subExpr)
+ ? SparcMCExpr::VK_Sparc_PC10
+ : (isPIC ? SparcMCExpr::VK_Sparc_GOT10 : VK));
+ break;
+ case SparcMCExpr::VK_Sparc_HI:
+ VK = (hasGOTReference(subExpr)
+ ? SparcMCExpr::VK_Sparc_PC22
+ : (isPIC ? SparcMCExpr::VK_Sparc_GOT22 : VK));
+ break;
+ }
+
+ EVal = SparcMCExpr::create(VK, subExpr, getContext());
+ return true;
+}
+
+extern "C" void LLVMInitializeSparcAsmParser() {
+ RegisterMCAsmParser<SparcAsmParser> A(TheSparcTarget);
+ RegisterMCAsmParser<SparcAsmParser> B(TheSparcV9Target);
+ RegisterMCAsmParser<SparcAsmParser> C(TheSparcelTarget);
+}
+
+#define GET_REGISTER_MATCHER
+#define GET_MATCHER_IMPLEMENTATION
+#include "SparcGenAsmMatcher.inc"
+
+unsigned SparcAsmParser::validateTargetOperandClass(MCParsedAsmOperand &GOp,
+ unsigned Kind) {
+ SparcOperand &Op = (SparcOperand &)GOp;
+ if (Op.isFloatOrDoubleReg()) {
+ switch (Kind) {
+ default: break;
+ case MCK_DFPRegs:
+ if (!Op.isFloatReg() || SparcOperand::MorphToDoubleReg(Op))
+ return MCTargetAsmParser::Match_Success;
+ break;
+ case MCK_QFPRegs:
+ if (SparcOperand::MorphToQuadReg(Op))
+ return MCTargetAsmParser::Match_Success;
+ break;
+ }
+ }
+ return Match_InvalidOperand;
+}
diff --git a/contrib/llvm/lib/Target/Sparc/DelaySlotFiller.cpp b/contrib/llvm/lib/Target/Sparc/DelaySlotFiller.cpp
new file mode 100644
index 0000000..38bff44
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/DelaySlotFiller.cpp
@@ -0,0 +1,495 @@
+//===-- DelaySlotFiller.cpp - SPARC delay slot filler ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This is a simple local pass that attempts to fill delay slots with useful
+// instructions. If no instructions can be moved into the delay slot, then a
+// NOP is placed.
+//===----------------------------------------------------------------------===//
+
+#include "Sparc.h"
+#include "SparcSubtarget.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Target/TargetInstrInfo.h"
+#include "llvm/Target/TargetMachine.h"
+#include "llvm/Target/TargetRegisterInfo.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "delay-slot-filler"
+
+STATISTIC(FilledSlots, "Number of delay slots filled");
+
+static cl::opt<bool> DisableDelaySlotFiller(
+ "disable-sparc-delay-filler",
+ cl::init(false),
+ cl::desc("Disable the Sparc delay slot filler."),
+ cl::Hidden);
+
+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) {}
+
+ const char *getPassName() const override {
+ return "SPARC Delay Slot Filler";
+ }
+
+ bool runOnMachineBasicBlock(MachineBasicBlock &MBB);
+ bool runOnMachineFunction(MachineFunction &F) override {
+ bool Changed = false;
+ Subtarget = &F.getSubtarget<SparcSubtarget>();
+
+ // This pass invalidates liveness information when it reorders
+ // instructions to fill delay slot.
+ F.getRegInfo().invalidateLiveness();
+
+ for (MachineFunction::iterator FI = F.begin(), FE = F.end();
+ FI != FE; ++FI)
+ Changed |= runOnMachineBasicBlock(*FI);
+ return Changed;
+ }
+
+ void insertCallDefsUses(MachineBasicBlock::iterator MI,
+ SmallSet<unsigned, 32>& RegDefs,
+ SmallSet<unsigned, 32>& RegUses);
+
+ void insertDefsUses(MachineBasicBlock::iterator MI,
+ SmallSet<unsigned, 32>& RegDefs,
+ SmallSet<unsigned, 32>& RegUses);
+
+ bool IsRegInSet(SmallSet<unsigned, 32>& RegSet,
+ unsigned Reg);
+
+ bool delayHasHazard(MachineBasicBlock::iterator candidate,
+ bool &sawLoad, bool &sawStore,
+ SmallSet<unsigned, 32> &RegDefs,
+ SmallSet<unsigned, 32> &RegUses);
+
+ MachineBasicBlock::iterator
+ findDelayInstr(MachineBasicBlock &MBB, MachineBasicBlock::iterator slot);
+
+ bool needsUnimp(MachineBasicBlock::iterator I, unsigned &StructSize);
+
+ bool tryCombineRestoreWithPrevInst(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI);
+
+ };
+ char Filler::ID = 0;
+} // end of anonymous namespace
+
+/// createSparcDelaySlotFillerPass - Returns a pass that fills in delay
+/// slots in Sparc MachineFunctions
+///
+FunctionPass *llvm::createSparcDelaySlotFillerPass(TargetMachine &tm) {
+ return new Filler(tm);
+}
+
+
+/// runOnMachineBasicBlock - Fill in delay slots for the given basic block.
+/// We assume there is only one delay slot per delayed instruction.
+///
+bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
+ bool Changed = false;
+ Subtarget = &MBB.getParent()->getSubtarget<SparcSubtarget>();
+ const TargetInstrInfo *TII = Subtarget->getInstrInfo();
+
+ for (MachineBasicBlock::iterator I = MBB.begin(); I != MBB.end(); ) {
+ MachineBasicBlock::iterator MI = I;
+ ++I;
+
+ // If MI is restore, try combining it with previous inst.
+ if (!DisableDelaySlotFiller &&
+ (MI->getOpcode() == SP::RESTORErr
+ || MI->getOpcode() == SP::RESTOREri)) {
+ Changed |= tryCombineRestoreWithPrevInst(MBB, MI);
+ continue;
+ }
+
+ if (!Subtarget->isV9() &&
+ (MI->getOpcode() == SP::FCMPS || MI->getOpcode() == SP::FCMPD
+ || MI->getOpcode() == SP::FCMPQ)) {
+ BuildMI(MBB, I, MI->getDebugLoc(), TII->get(SP::NOP));
+ Changed = true;
+ continue;
+ }
+
+ // If MI has no delay slot, skip.
+ if (!MI->hasDelaySlot())
+ continue;
+
+ MachineBasicBlock::iterator D = MBB.end();
+
+ if (!DisableDelaySlotFiller)
+ D = findDelayInstr(MBB, MI);
+
+ ++FilledSlots;
+ Changed = true;
+
+ if (D == MBB.end())
+ BuildMI(MBB, I, MI->getDebugLoc(), TII->get(SP::NOP));
+ else
+ MBB.splice(I, &MBB, D);
+
+ unsigned structSize = 0;
+ if (needsUnimp(MI, structSize)) {
+ MachineBasicBlock::iterator J = MI;
+ ++J; // skip the delay filler.
+ assert (J != MBB.end() && "MI needs a delay instruction.");
+ BuildMI(MBB, ++J, MI->getDebugLoc(),
+ TII->get(SP::UNIMP)).addImm(structSize);
+ // Bundle the delay filler and unimp with the instruction.
+ MIBundleBuilder(MBB, MachineBasicBlock::iterator(MI), J);
+ } else {
+ MIBundleBuilder(MBB, MachineBasicBlock::iterator(MI), I);
+ }
+ }
+ return Changed;
+}
+
+MachineBasicBlock::iterator
+Filler::findDelayInstr(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator slot)
+{
+ SmallSet<unsigned, 32> RegDefs;
+ SmallSet<unsigned, 32> RegUses;
+ bool sawLoad = false;
+ bool sawStore = false;
+
+ if (slot == MBB.begin())
+ return MBB.end();
+
+ if (slot->getOpcode() == SP::RET || slot->getOpcode() == SP::TLS_CALL)
+ return MBB.end();
+
+ if (slot->getOpcode() == SP::RETL) {
+ MachineBasicBlock::iterator J = slot;
+ --J;
+
+ if (J->getOpcode() == SP::RESTORErr
+ || J->getOpcode() == SP::RESTOREri) {
+ // change retl to ret.
+ slot->setDesc(Subtarget->getInstrInfo()->get(SP::RET));
+ return J;
+ }
+ }
+
+ // Call's delay filler can def some of call's uses.
+ if (slot->isCall())
+ insertCallDefsUses(slot, RegDefs, RegUses);
+ else
+ insertDefsUses(slot, RegDefs, RegUses);
+
+ bool done = false;
+
+ MachineBasicBlock::iterator I = slot;
+
+ while (!done) {
+ done = (I == MBB.begin());
+
+ if (!done)
+ --I;
+
+ // skip debug value
+ if (I->isDebugValue())
+ continue;
+
+ if (I->hasUnmodeledSideEffects() || I->isInlineAsm() || I->isPosition() ||
+ I->hasDelaySlot() || I->isBundledWithSucc())
+ break;
+
+ if (delayHasHazard(I, sawLoad, sawStore, RegDefs, RegUses)) {
+ insertDefsUses(I, RegDefs, RegUses);
+ continue;
+ }
+
+ return I;
+ }
+ return MBB.end();
+}
+
+bool Filler::delayHasHazard(MachineBasicBlock::iterator candidate,
+ bool &sawLoad,
+ bool &sawStore,
+ SmallSet<unsigned, 32> &RegDefs,
+ SmallSet<unsigned, 32> &RegUses)
+{
+
+ if (candidate->isImplicitDef() || candidate->isKill())
+ return true;
+
+ if (candidate->mayLoad()) {
+ sawLoad = true;
+ if (sawStore)
+ return true;
+ }
+
+ if (candidate->mayStore()) {
+ if (sawStore)
+ return true;
+ sawStore = true;
+ if (sawLoad)
+ return true;
+ }
+
+ for (unsigned i = 0, e = candidate->getNumOperands(); i!= e; ++i) {
+ const MachineOperand &MO = candidate->getOperand(i);
+ if (!MO.isReg())
+ continue; // skip
+
+ unsigned Reg = MO.getReg();
+
+ if (MO.isDef()) {
+ // check whether Reg is defined or used before delay slot.
+ if (IsRegInSet(RegDefs, Reg) || IsRegInSet(RegUses, Reg))
+ return true;
+ }
+ if (MO.isUse()) {
+ // check whether Reg is defined before delay slot.
+ if (IsRegInSet(RegDefs, Reg))
+ return true;
+ }
+ }
+ return false;
+}
+
+
+void Filler::insertCallDefsUses(MachineBasicBlock::iterator MI,
+ SmallSet<unsigned, 32>& RegDefs,
+ SmallSet<unsigned, 32>& RegUses)
+{
+ // Call defines o7, which is visible to the instruction in delay slot.
+ RegDefs.insert(SP::O7);
+
+ switch(MI->getOpcode()) {
+ default: llvm_unreachable("Unknown opcode.");
+ case SP::CALL: break;
+ case SP::CALLrr:
+ case SP::CALLri:
+ assert(MI->getNumOperands() >= 2);
+ const MachineOperand &Reg = MI->getOperand(0);
+ assert(Reg.isReg() && "CALL first operand is not a register.");
+ assert(Reg.isUse() && "CALL first operand is not a use.");
+ RegUses.insert(Reg.getReg());
+
+ const MachineOperand &RegOrImm = MI->getOperand(1);
+ if (RegOrImm.isImm())
+ 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());
+ break;
+ }
+}
+
+// Insert Defs and Uses of MI into the sets RegDefs and RegUses.
+void Filler::insertDefsUses(MachineBasicBlock::iterator MI,
+ SmallSet<unsigned, 32>& RegDefs,
+ SmallSet<unsigned, 32>& RegUses)
+{
+ for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
+ const MachineOperand &MO = MI->getOperand(i);
+ if (!MO.isReg())
+ continue;
+
+ unsigned Reg = MO.getReg();
+ if (Reg == 0)
+ continue;
+ if (MO.isDef())
+ RegDefs.insert(Reg);
+ if (MO.isUse()) {
+ // Implicit register uses of retl are return values and
+ // retl does not use them.
+ if (MO.isImplicit() && MI->getOpcode() == SP::RETL)
+ continue;
+ RegUses.insert(Reg);
+ }
+ }
+}
+
+// returns true if the Reg or its alias is in the RegSet.
+bool Filler::IsRegInSet(SmallSet<unsigned, 32>& RegSet, unsigned Reg)
+{
+ // Check Reg and all aliased Registers.
+ for (MCRegAliasIterator AI(Reg, Subtarget->getRegisterInfo(), true);
+ AI.isValid(); ++AI)
+ if (RegSet.count(*AI))
+ return true;
+ return false;
+}
+
+bool Filler::needsUnimp(MachineBasicBlock::iterator I, unsigned &StructSize)
+{
+ if (!I->isCall())
+ return false;
+
+ unsigned structSizeOpNum = 0;
+ switch (I->getOpcode()) {
+ default: llvm_unreachable("Unknown call opcode.");
+ case SP::CALL: structSizeOpNum = 1; break;
+ case SP::CALLrr:
+ case SP::CALLri: structSizeOpNum = 2; break;
+ case SP::TLS_CALL: return false;
+ }
+
+ const MachineOperand &MO = I->getOperand(structSizeOpNum);
+ if (!MO.isImm())
+ return false;
+ StructSize = MO.getImm();
+ return true;
+}
+
+static bool combineRestoreADD(MachineBasicBlock::iterator RestoreMI,
+ MachineBasicBlock::iterator AddMI,
+ const TargetInstrInfo *TII)
+{
+ // Before: add <op0>, <op1>, %i[0-7]
+ // restore %g0, %g0, %i[0-7]
+ //
+ // After : restore <op0>, <op1>, %o[0-7]
+
+ unsigned reg = AddMI->getOperand(0).getReg();
+ if (reg < SP::I0 || reg > SP::I7)
+ return false;
+
+ // Erase RESTORE.
+ RestoreMI->eraseFromParent();
+
+ // Change ADD to RESTORE.
+ AddMI->setDesc(TII->get((AddMI->getOpcode() == SP::ADDrr)
+ ? SP::RESTORErr
+ : SP::RESTOREri));
+
+ // Map the destination register.
+ AddMI->getOperand(0).setReg(reg - SP::I0 + SP::O0);
+
+ return true;
+}
+
+static bool combineRestoreOR(MachineBasicBlock::iterator RestoreMI,
+ MachineBasicBlock::iterator OrMI,
+ const TargetInstrInfo *TII)
+{
+ // Before: or <op0>, <op1>, %i[0-7]
+ // restore %g0, %g0, %i[0-7]
+ // and <op0> or <op1> is zero,
+ //
+ // After : restore <op0>, <op1>, %o[0-7]
+
+ unsigned reg = OrMI->getOperand(0).getReg();
+ if (reg < SP::I0 || reg > SP::I7)
+ return false;
+
+ // check whether it is a copy.
+ if (OrMI->getOpcode() == SP::ORrr
+ && OrMI->getOperand(1).getReg() != SP::G0
+ && OrMI->getOperand(2).getReg() != SP::G0)
+ return false;
+
+ if (OrMI->getOpcode() == SP::ORri
+ && OrMI->getOperand(1).getReg() != SP::G0
+ && (!OrMI->getOperand(2).isImm() || OrMI->getOperand(2).getImm() != 0))
+ return false;
+
+ // Erase RESTORE.
+ RestoreMI->eraseFromParent();
+
+ // Change OR to RESTORE.
+ OrMI->setDesc(TII->get((OrMI->getOpcode() == SP::ORrr)
+ ? SP::RESTORErr
+ : SP::RESTOREri));
+
+ // Map the destination register.
+ OrMI->getOperand(0).setReg(reg - SP::I0 + SP::O0);
+
+ return true;
+}
+
+static bool combineRestoreSETHIi(MachineBasicBlock::iterator RestoreMI,
+ MachineBasicBlock::iterator SetHiMI,
+ const TargetInstrInfo *TII)
+{
+ // Before: sethi imm3, %i[0-7]
+ // restore %g0, %g0, %g0
+ //
+ // After : restore %g0, (imm3<<10), %o[0-7]
+
+ unsigned reg = SetHiMI->getOperand(0).getReg();
+ if (reg < SP::I0 || reg > SP::I7)
+ return false;
+
+ if (!SetHiMI->getOperand(1).isImm())
+ return false;
+
+ int64_t imm = SetHiMI->getOperand(1).getImm();
+
+ // Is it a 3 bit immediate?
+ if (!isInt<3>(imm))
+ return false;
+
+ // Make it a 13 bit immediate.
+ imm = (imm << 10) & 0x1FFF;
+
+ assert(RestoreMI->getOpcode() == SP::RESTORErr);
+
+ RestoreMI->setDesc(TII->get(SP::RESTOREri));
+
+ RestoreMI->getOperand(0).setReg(reg - SP::I0 + SP::O0);
+ RestoreMI->getOperand(1).setReg(SP::G0);
+ RestoreMI->getOperand(2).ChangeToImmediate(imm);
+
+
+ // Erase the original SETHI.
+ SetHiMI->eraseFromParent();
+
+ return true;
+}
+
+bool Filler::tryCombineRestoreWithPrevInst(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI)
+{
+ // No previous instruction.
+ if (MBBI == MBB.begin())
+ return false;
+
+ // assert that MBBI is a "restore %g0, %g0, %g0".
+ assert(MBBI->getOpcode() == SP::RESTORErr
+ && MBBI->getOperand(0).getReg() == SP::G0
+ && MBBI->getOperand(1).getReg() == SP::G0
+ && MBBI->getOperand(2).getReg() == SP::G0);
+
+ MachineBasicBlock::iterator PrevInst = std::prev(MBBI);
+
+ // It cannot be combined with a bundled instruction.
+ if (PrevInst->isBundledWithSucc())
+ return false;
+
+ const TargetInstrInfo *TII = Subtarget->getInstrInfo();
+
+ switch (PrevInst->getOpcode()) {
+ default: break;
+ case SP::ADDrr:
+ case SP::ADDri: return combineRestoreADD(MBBI, PrevInst, TII); break;
+ case SP::ORrr:
+ case SP::ORri: return combineRestoreOR(MBBI, PrevInst, TII); break;
+ case SP::SETHIi: return combineRestoreSETHIi(MBBI, PrevInst, TII); break;
+ }
+ // It cannot combine with the previous instruction.
+ return false;
+}
diff --git a/contrib/llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp b/contrib/llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp
new file mode 100644
index 0000000..59f011a
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp
@@ -0,0 +1,497 @@
+//===- SparcDisassembler.cpp - Disassembler for Sparc -----------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is part of the Sparc Disassembler.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sparc.h"
+#include "SparcRegisterInfo.h"
+#include "SparcSubtarget.h"
+#include "llvm/MC/MCDisassembler.h"
+#include "llvm/MC/MCFixedLenDisassembler.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/Support/TargetRegistry.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "sparc-disassembler"
+
+typedef MCDisassembler::DecodeStatus DecodeStatus;
+
+namespace {
+
+/// A disassembler class for Sparc.
+class SparcDisassembler : public MCDisassembler {
+public:
+ SparcDisassembler(const MCSubtargetInfo &STI, MCContext &Ctx)
+ : MCDisassembler(STI, Ctx) {}
+ virtual ~SparcDisassembler() {}
+
+ DecodeStatus getInstruction(MCInst &Instr, uint64_t &Size,
+ ArrayRef<uint8_t> Bytes, uint64_t Address,
+ raw_ostream &VStream,
+ raw_ostream &CStream) const override;
+};
+} // namespace
+
+namespace llvm {
+extern Target TheSparcTarget, TheSparcV9Target, TheSparcelTarget;
+}
+
+static MCDisassembler *createSparcDisassembler(const Target &T,
+ const MCSubtargetInfo &STI,
+ MCContext &Ctx) {
+ return new SparcDisassembler(STI, Ctx);
+}
+
+
+extern "C" void LLVMInitializeSparcDisassembler() {
+ // Register the disassembler.
+ TargetRegistry::RegisterMCDisassembler(TheSparcTarget,
+ createSparcDisassembler);
+ TargetRegistry::RegisterMCDisassembler(TheSparcV9Target,
+ createSparcDisassembler);
+ TargetRegistry::RegisterMCDisassembler(TheSparcelTarget,
+ createSparcDisassembler);
+}
+
+static const unsigned IntRegDecoderTable[] = {
+ SP::G0, SP::G1, SP::G2, SP::G3,
+ SP::G4, SP::G5, SP::G6, SP::G7,
+ SP::O0, SP::O1, SP::O2, SP::O3,
+ SP::O4, SP::O5, SP::O6, SP::O7,
+ SP::L0, SP::L1, SP::L2, SP::L3,
+ SP::L4, SP::L5, SP::L6, SP::L7,
+ SP::I0, SP::I1, SP::I2, SP::I3,
+ SP::I4, SP::I5, SP::I6, SP::I7 };
+
+static const unsigned FPRegDecoderTable[] = {
+ SP::F0, SP::F1, SP::F2, SP::F3,
+ SP::F4, SP::F5, SP::F6, SP::F7,
+ SP::F8, SP::F9, SP::F10, SP::F11,
+ SP::F12, SP::F13, SP::F14, SP::F15,
+ SP::F16, SP::F17, SP::F18, SP::F19,
+ SP::F20, SP::F21, SP::F22, SP::F23,
+ SP::F24, SP::F25, SP::F26, SP::F27,
+ SP::F28, SP::F29, SP::F30, SP::F31 };
+
+static const unsigned DFPRegDecoderTable[] = {
+ SP::D0, SP::D16, SP::D1, SP::D17,
+ SP::D2, SP::D18, SP::D3, SP::D19,
+ SP::D4, SP::D20, SP::D5, SP::D21,
+ SP::D6, SP::D22, SP::D7, SP::D23,
+ SP::D8, SP::D24, SP::D9, SP::D25,
+ SP::D10, SP::D26, SP::D11, SP::D27,
+ SP::D12, SP::D28, SP::D13, SP::D29,
+ SP::D14, SP::D30, SP::D15, SP::D31 };
+
+static const unsigned QFPRegDecoderTable[] = {
+ SP::Q0, SP::Q8, ~0U, ~0U,
+ SP::Q1, SP::Q9, ~0U, ~0U,
+ SP::Q2, SP::Q10, ~0U, ~0U,
+ SP::Q3, SP::Q11, ~0U, ~0U,
+ SP::Q4, SP::Q12, ~0U, ~0U,
+ SP::Q5, SP::Q13, ~0U, ~0U,
+ SP::Q6, SP::Q14, ~0U, ~0U,
+ SP::Q7, SP::Q15, ~0U, ~0U } ;
+
+static const unsigned FCCRegDecoderTable[] = {
+ SP::FCC0, SP::FCC1, SP::FCC2, SP::FCC3 };
+
+static const unsigned ASRRegDecoderTable[] = {
+ SP::Y, SP::ASR1, SP::ASR2, SP::ASR3,
+ SP::ASR4, SP::ASR5, SP::ASR6, SP::ASR7,
+ SP::ASR8, SP::ASR9, SP::ASR10, SP::ASR11,
+ SP::ASR12, SP::ASR13, SP::ASR14, SP::ASR15,
+ SP::ASR16, SP::ASR17, SP::ASR18, SP::ASR19,
+ SP::ASR20, SP::ASR21, SP::ASR22, SP::ASR23,
+ SP::ASR24, SP::ASR25, SP::ASR26, SP::ASR27,
+ SP::ASR28, SP::ASR29, SP::ASR30, SP::ASR31};
+
+static DecodeStatus DecodeIntRegsRegisterClass(MCInst &Inst,
+ unsigned RegNo,
+ uint64_t Address,
+ const void *Decoder) {
+ if (RegNo > 31)
+ return MCDisassembler::Fail;
+ unsigned Reg = IntRegDecoderTable[RegNo];
+ Inst.addOperand(MCOperand::createReg(Reg));
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus DecodeI64RegsRegisterClass(MCInst &Inst,
+ unsigned RegNo,
+ uint64_t Address,
+ const void *Decoder) {
+ if (RegNo > 31)
+ return MCDisassembler::Fail;
+ unsigned Reg = IntRegDecoderTable[RegNo];
+ Inst.addOperand(MCOperand::createReg(Reg));
+ return MCDisassembler::Success;
+}
+
+
+static DecodeStatus DecodeFPRegsRegisterClass(MCInst &Inst,
+ unsigned RegNo,
+ uint64_t Address,
+ const void *Decoder) {
+ if (RegNo > 31)
+ return MCDisassembler::Fail;
+ unsigned Reg = FPRegDecoderTable[RegNo];
+ Inst.addOperand(MCOperand::createReg(Reg));
+ return MCDisassembler::Success;
+}
+
+
+static DecodeStatus DecodeDFPRegsRegisterClass(MCInst &Inst,
+ unsigned RegNo,
+ uint64_t Address,
+ const void *Decoder) {
+ if (RegNo > 31)
+ return MCDisassembler::Fail;
+ unsigned Reg = DFPRegDecoderTable[RegNo];
+ Inst.addOperand(MCOperand::createReg(Reg));
+ return MCDisassembler::Success;
+}
+
+
+static DecodeStatus DecodeQFPRegsRegisterClass(MCInst &Inst,
+ unsigned RegNo,
+ uint64_t Address,
+ const void *Decoder) {
+ if (RegNo > 31)
+ return MCDisassembler::Fail;
+
+ unsigned Reg = QFPRegDecoderTable[RegNo];
+ if (Reg == ~0U)
+ return MCDisassembler::Fail;
+ Inst.addOperand(MCOperand::createReg(Reg));
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus DecodeFCCRegsRegisterClass(MCInst &Inst, unsigned RegNo,
+ uint64_t Address,
+ const void *Decoder) {
+ if (RegNo > 3)
+ return MCDisassembler::Fail;
+ Inst.addOperand(MCOperand::createReg(FCCRegDecoderTable[RegNo]));
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus DecodeASRRegsRegisterClass(MCInst &Inst, unsigned RegNo,
+ uint64_t Address,
+ const void *Decoder) {
+ if (RegNo > 31)
+ return MCDisassembler::Fail;
+ Inst.addOperand(MCOperand::createReg(ASRRegDecoderTable[RegNo]));
+ return MCDisassembler::Success;
+}
+
+
+static DecodeStatus DecodeLoadInt(MCInst &Inst, unsigned insn, uint64_t Address,
+ const void *Decoder);
+static DecodeStatus DecodeLoadFP(MCInst &Inst, unsigned insn, uint64_t Address,
+ const void *Decoder);
+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 DecodeStoreInt(MCInst &Inst, unsigned insn,
+ uint64_t Address, const void *Decoder);
+static DecodeStatus DecodeStoreFP(MCInst &Inst, unsigned insn,
+ uint64_t Address, const void *Decoder);
+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 DecodeCall(MCInst &Inst, unsigned insn,
+ uint64_t Address, const void *Decoder);
+static DecodeStatus DecodeSIMM13(MCInst &Inst, unsigned insn,
+ uint64_t Address, const void *Decoder);
+static DecodeStatus DecodeJMPL(MCInst &Inst, unsigned insn, uint64_t Address,
+ const void *Decoder);
+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);
+
+#include "SparcGenDisassemblerTables.inc"
+
+/// Read four bytes from the ArrayRef and return 32 bit word.
+static DecodeStatus readInstruction32(ArrayRef<uint8_t> Bytes, uint64_t Address,
+ uint64_t &Size, uint32_t &Insn,
+ bool IsLittleEndian) {
+ // We want to read exactly 4 Bytes of data.
+ if (Bytes.size() < 4) {
+ Size = 0;
+ return MCDisassembler::Fail;
+ }
+
+ Insn = IsLittleEndian
+ ? (Bytes[0] << 0) | (Bytes[1] << 8) | (Bytes[2] << 16) |
+ (Bytes[3] << 24)
+ : (Bytes[3] << 0) | (Bytes[2] << 8) | (Bytes[1] << 16) |
+ (Bytes[0] << 24);
+
+ return MCDisassembler::Success;
+}
+
+DecodeStatus SparcDisassembler::getInstruction(MCInst &Instr, uint64_t &Size,
+ ArrayRef<uint8_t> Bytes,
+ uint64_t Address,
+ raw_ostream &VStream,
+ raw_ostream &CStream) const {
+ uint32_t Insn;
+ bool isLittleEndian = getContext().getAsmInfo()->isLittleEndian();
+ DecodeStatus Result =
+ readInstruction32(Bytes, Address, Size, Insn, isLittleEndian);
+ if (Result == MCDisassembler::Fail)
+ return MCDisassembler::Fail;
+
+ // Calling the auto-generated decoder function.
+ Result =
+ decodeInstruction(DecoderTableSparc32, Instr, Insn, Address, this, STI);
+
+ if (Result != MCDisassembler::Fail) {
+ Size = 4;
+ return Result;
+ }
+
+ return MCDisassembler::Fail;
+}
+
+
+typedef DecodeStatus (*DecodeFunc)(MCInst &MI, unsigned insn, uint64_t Address,
+ const void *Decoder);
+
+static DecodeStatus DecodeMem(MCInst &MI, unsigned insn, uint64_t Address,
+ const void *Decoder,
+ bool isLoad, DecodeFunc DecodeRD) {
+ unsigned rd = fieldFromInstruction(insn, 25, 5);
+ unsigned rs1 = fieldFromInstruction(insn, 14, 5);
+ bool isImm = fieldFromInstruction(insn, 13, 1);
+ bool hasAsi = fieldFromInstruction(insn, 23, 1); // (in op3 field)
+ unsigned asi = fieldFromInstruction(insn, 5, 8);
+ unsigned rs2 = 0;
+ unsigned simm13 = 0;
+ if (isImm)
+ simm13 = SignExtend32<13>(fieldFromInstruction(insn, 0, 13));
+ else
+ rs2 = fieldFromInstruction(insn, 0, 5);
+
+ DecodeStatus status;
+ if (isLoad) {
+ status = DecodeRD(MI, rd, Address, Decoder);
+ if (status != MCDisassembler::Success)
+ return status;
+ }
+
+ // Decode rs1.
+ status = DecodeIntRegsRegisterClass(MI, rs1, Address, Decoder);
+ if (status != MCDisassembler::Success)
+ return status;
+
+ // Decode imm|rs2.
+ if (isImm)
+ MI.addOperand(MCOperand::createImm(simm13));
+ else {
+ status = DecodeIntRegsRegisterClass(MI, rs2, Address, Decoder);
+ if (status != MCDisassembler::Success)
+ return status;
+ }
+
+ if (hasAsi)
+ MI.addOperand(MCOperand::createImm(asi));
+
+ if (!isLoad) {
+ status = DecodeRD(MI, rd, Address, Decoder);
+ if (status != MCDisassembler::Success)
+ return status;
+ }
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus DecodeLoadInt(MCInst &Inst, unsigned insn, uint64_t Address,
+ const void *Decoder) {
+ return DecodeMem(Inst, insn, Address, Decoder, true,
+ DecodeIntRegsRegisterClass);
+}
+
+static DecodeStatus DecodeLoadFP(MCInst &Inst, unsigned insn, uint64_t Address,
+ const void *Decoder) {
+ return DecodeMem(Inst, insn, Address, Decoder, true,
+ DecodeFPRegsRegisterClass);
+}
+
+static DecodeStatus DecodeLoadDFP(MCInst &Inst, unsigned insn, uint64_t Address,
+ const void *Decoder) {
+ return DecodeMem(Inst, insn, Address, Decoder, true,
+ DecodeDFPRegsRegisterClass);
+}
+
+static DecodeStatus DecodeLoadQFP(MCInst &Inst, unsigned insn, uint64_t Address,
+ const void *Decoder) {
+ return DecodeMem(Inst, insn, Address, Decoder, true,
+ DecodeQFPRegsRegisterClass);
+}
+
+static DecodeStatus DecodeStoreInt(MCInst &Inst, unsigned insn,
+ uint64_t Address, const void *Decoder) {
+ return DecodeMem(Inst, insn, Address, Decoder, false,
+ DecodeIntRegsRegisterClass);
+}
+
+static DecodeStatus DecodeStoreFP(MCInst &Inst, unsigned insn, uint64_t Address,
+ const void *Decoder) {
+ return DecodeMem(Inst, insn, Address, Decoder, false,
+ DecodeFPRegsRegisterClass);
+}
+
+static DecodeStatus DecodeStoreDFP(MCInst &Inst, unsigned insn,
+ uint64_t Address, const void *Decoder) {
+ return DecodeMem(Inst, insn, Address, Decoder, false,
+ DecodeDFPRegsRegisterClass);
+}
+
+static DecodeStatus DecodeStoreQFP(MCInst &Inst, unsigned insn,
+ uint64_t Address, const void *Decoder) {
+ return DecodeMem(Inst, insn, Address, Decoder, false,
+ DecodeQFPRegsRegisterClass);
+}
+
+static bool tryAddingSymbolicOperand(int64_t Value, bool isBranch,
+ uint64_t Address, uint64_t Offset,
+ uint64_t Width, MCInst &MI,
+ const void *Decoder) {
+ const MCDisassembler *Dis = static_cast<const MCDisassembler*>(Decoder);
+ return Dis->tryAddingSymbolicOperand(MI, Value, Address, isBranch,
+ Offset, Width);
+}
+
+static DecodeStatus DecodeCall(MCInst &MI, unsigned insn,
+ uint64_t Address, const void *Decoder) {
+ unsigned tgt = fieldFromInstruction(insn, 0, 30);
+ tgt <<= 2;
+ if (!tryAddingSymbolicOperand(tgt+Address, false, Address,
+ 0, 30, MI, Decoder))
+ MI.addOperand(MCOperand::createImm(tgt));
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus DecodeSIMM13(MCInst &MI, unsigned insn,
+ uint64_t Address, const void *Decoder) {
+ unsigned tgt = SignExtend32<13>(fieldFromInstruction(insn, 0, 13));
+ MI.addOperand(MCOperand::createImm(tgt));
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus DecodeJMPL(MCInst &MI, unsigned insn, uint64_t Address,
+ const void *Decoder) {
+
+ unsigned rd = fieldFromInstruction(insn, 25, 5);
+ unsigned rs1 = fieldFromInstruction(insn, 14, 5);
+ unsigned isImm = fieldFromInstruction(insn, 13, 1);
+ unsigned rs2 = 0;
+ unsigned simm13 = 0;
+ if (isImm)
+ simm13 = SignExtend32<13>(fieldFromInstruction(insn, 0, 13));
+ else
+ rs2 = fieldFromInstruction(insn, 0, 5);
+
+ // Decode RD.
+ DecodeStatus status = DecodeIntRegsRegisterClass(MI, rd, Address, Decoder);
+ if (status != MCDisassembler::Success)
+ return status;
+
+ // Decode RS1.
+ status = DecodeIntRegsRegisterClass(MI, rs1, Address, Decoder);
+ if (status != MCDisassembler::Success)
+ return status;
+
+ // Decode RS1 | SIMM13.
+ if (isImm)
+ MI.addOperand(MCOperand::createImm(simm13));
+ else {
+ status = DecodeIntRegsRegisterClass(MI, rs2, Address, Decoder);
+ if (status != MCDisassembler::Success)
+ return status;
+ }
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus DecodeReturn(MCInst &MI, unsigned insn, uint64_t Address,
+ const void *Decoder) {
+
+ unsigned rs1 = fieldFromInstruction(insn, 14, 5);
+ unsigned isImm = fieldFromInstruction(insn, 13, 1);
+ unsigned rs2 = 0;
+ unsigned simm13 = 0;
+ if (isImm)
+ simm13 = SignExtend32<13>(fieldFromInstruction(insn, 0, 13));
+ else
+ rs2 = fieldFromInstruction(insn, 0, 5);
+
+ // Decode RS1.
+ DecodeStatus status = DecodeIntRegsRegisterClass(MI, rs1, Address, Decoder);
+ if (status != MCDisassembler::Success)
+ return status;
+
+ // Decode RS2 | SIMM13.
+ if (isImm)
+ MI.addOperand(MCOperand::createImm(simm13));
+ else {
+ status = DecodeIntRegsRegisterClass(MI, rs2, Address, Decoder);
+ if (status != MCDisassembler::Success)
+ return status;
+ }
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus DecodeSWAP(MCInst &MI, unsigned insn, uint64_t Address,
+ const void *Decoder) {
+
+ unsigned rd = fieldFromInstruction(insn, 25, 5);
+ unsigned rs1 = fieldFromInstruction(insn, 14, 5);
+ unsigned isImm = fieldFromInstruction(insn, 13, 1);
+ bool hasAsi = fieldFromInstruction(insn, 23, 1); // (in op3 field)
+ unsigned asi = fieldFromInstruction(insn, 5, 8);
+ unsigned rs2 = 0;
+ unsigned simm13 = 0;
+ if (isImm)
+ simm13 = SignExtend32<13>(fieldFromInstruction(insn, 0, 13));
+ else
+ rs2 = fieldFromInstruction(insn, 0, 5);
+
+ // Decode RD.
+ DecodeStatus status = DecodeIntRegsRegisterClass(MI, rd, Address, Decoder);
+ if (status != MCDisassembler::Success)
+ return status;
+
+ // Decode RS1.
+ status = DecodeIntRegsRegisterClass(MI, rs1, Address, Decoder);
+ if (status != MCDisassembler::Success)
+ return status;
+
+ // Decode RS1 | SIMM13.
+ if (isImm)
+ MI.addOperand(MCOperand::createImm(simm13));
+ else {
+ status = DecodeIntRegsRegisterClass(MI, rs2, Address, Decoder);
+ if (status != MCDisassembler::Success)
+ return status;
+ }
+
+ if (hasAsi)
+ MI.addOperand(MCOperand::createImm(asi));
+
+ return MCDisassembler::Success;
+}
diff --git a/contrib/llvm/lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp b/contrib/llvm/lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp
new file mode 100644
index 0000000..5d714fe
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp
@@ -0,0 +1,178 @@
+//===-- SparcInstPrinter.cpp - Convert Sparc MCInst to assembly syntax -----==//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class prints an Sparc MCInst to a .s file.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SparcInstPrinter.h"
+#include "Sparc.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace llvm;
+
+#define DEBUG_TYPE "asm-printer"
+
+// The generated AsmMatcher SparcGenAsmWriter uses "Sparc" as the target
+// namespace. But SPARC backend uses "SP" as its namespace.
+namespace llvm {
+namespace Sparc {
+ using namespace SP;
+}
+}
+
+#define GET_INSTRUCTION_NAME
+#define PRINT_ALIAS_INSTR
+#include "SparcGenAsmWriter.inc"
+
+bool SparcInstPrinter::isV9(const MCSubtargetInfo &STI) const {
+ return (STI.getFeatureBits()[Sparc::FeatureV9]) != 0;
+}
+
+void SparcInstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const
+{
+ OS << '%' << StringRef(getRegisterName(RegNo)).lower();
+}
+
+void SparcInstPrinter::printInst(const MCInst *MI, raw_ostream &O,
+ StringRef Annot, const MCSubtargetInfo &STI) {
+ if (!printAliasInstr(MI, STI, O) && !printSparcAliasInstr(MI, STI, O))
+ printInstruction(MI, STI, O);
+ printAnnotation(O, Annot);
+}
+
+bool SparcInstPrinter::printSparcAliasInstr(const MCInst *MI,
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
+ switch (MI->getOpcode()) {
+ default: return false;
+ case SP::JMPLrr:
+ case SP::JMPLri: {
+ if (MI->getNumOperands() != 3)
+ return false;
+ if (!MI->getOperand(0).isReg())
+ return false;
+ switch (MI->getOperand(0).getReg()) {
+ default: return false;
+ case SP::G0: // jmp $addr | ret | retl
+ if (MI->getOperand(2).isImm() &&
+ MI->getOperand(2).getImm() == 8) {
+ switch(MI->getOperand(1).getReg()) {
+ default: break;
+ case SP::I7: O << "\tret"; return true;
+ case SP::O7: O << "\tretl"; return true;
+ }
+ }
+ O << "\tjmp "; printMemOperand(MI, 1, STI, O);
+ return true;
+ case SP::O7: // call $addr
+ O << "\tcall "; printMemOperand(MI, 1, STI, O);
+ return true;
+ }
+ }
+ case SP::V9FCMPS: case SP::V9FCMPD: case SP::V9FCMPQ:
+ case SP::V9FCMPES: case SP::V9FCMPED: case SP::V9FCMPEQ: {
+ if (isV9(STI)
+ || (MI->getNumOperands() != 3)
+ || (!MI->getOperand(0).isReg())
+ || (MI->getOperand(0).getReg() != SP::FCC0))
+ return false;
+ // if V8, skip printing %fcc0.
+ switch(MI->getOpcode()) {
+ default:
+ case SP::V9FCMPS: O << "\tfcmps "; break;
+ case SP::V9FCMPD: O << "\tfcmpd "; break;
+ case SP::V9FCMPQ: O << "\tfcmpq "; break;
+ case SP::V9FCMPES: O << "\tfcmpes "; break;
+ case SP::V9FCMPED: O << "\tfcmped "; break;
+ case SP::V9FCMPEQ: O << "\tfcmpeq "; break;
+ }
+ printOperand(MI, 1, STI, O);
+ O << ", ";
+ printOperand(MI, 2, STI, O);
+ return true;
+ }
+ }
+}
+
+void SparcInstPrinter::printOperand(const MCInst *MI, int opNum,
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
+ const MCOperand &MO = MI->getOperand (opNum);
+
+ if (MO.isReg()) {
+ printRegName(O, MO.getReg());
+ return ;
+ }
+
+ if (MO.isImm()) {
+ O << (int)MO.getImm();
+ return;
+ }
+
+ assert(MO.isExpr() && "Unknown operand kind in printOperand");
+ MO.getExpr()->print(O, &MAI);
+}
+
+void SparcInstPrinter::printMemOperand(const MCInst *MI, int opNum,
+ const MCSubtargetInfo &STI,
+ raw_ostream &O, const char *Modifier) {
+ printOperand(MI, opNum, STI, O);
+
+ // If this is an ADD operand, emit it like normal operands.
+ if (Modifier && !strcmp(Modifier, "arith")) {
+ O << ", ";
+ printOperand(MI, opNum+1, STI, O);
+ return;
+ }
+ const MCOperand &MO = MI->getOperand(opNum+1);
+
+ if (MO.isReg() && MO.getReg() == SP::G0)
+ return; // don't print "+%g0"
+ if (MO.isImm() && MO.getImm() == 0)
+ return; // don't print "+0"
+
+ O << "+";
+
+ printOperand(MI, opNum+1, STI, O);
+}
+
+void SparcInstPrinter::printCCOperand(const MCInst *MI, int opNum,
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
+ int CC = (int)MI->getOperand(opNum).getImm();
+ switch (MI->getOpcode()) {
+ default: break;
+ case SP::FBCOND:
+ case SP::FBCONDA:
+ case SP::BPFCC:
+ case SP::BPFCCA:
+ case SP::BPFCCNT:
+ case SP::BPFCCANT:
+ case SP::MOVFCCrr: case SP::V9MOVFCCrr:
+ case SP::MOVFCCri: case SP::V9MOVFCCri:
+ case SP::FMOVS_FCC: case SP::V9FMOVS_FCC:
+ case SP::FMOVD_FCC: case SP::V9FMOVD_FCC:
+ case SP::FMOVQ_FCC: case SP::V9FMOVQ_FCC:
+ // Make sure CC is a fp conditional flag.
+ CC = (CC < 16) ? (CC + 16) : CC;
+ break;
+ }
+ O << SPARCCondCodeToString((SPCC::CondCodes)CC);
+}
+
+bool SparcInstPrinter::printGetPCX(const MCInst *MI, unsigned opNum,
+ const MCSubtargetInfo &STI,
+ raw_ostream &O) {
+ llvm_unreachable("FIXME: Implement SparcInstPrinter::printGetPCX.");
+ return true;
+}
diff --git a/contrib/llvm/lib/Target/Sparc/InstPrinter/SparcInstPrinter.h b/contrib/llvm/lib/Target/Sparc/InstPrinter/SparcInstPrinter.h
new file mode 100644
index 0000000..0b01b88
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/InstPrinter/SparcInstPrinter.h
@@ -0,0 +1,58 @@
+//===-- SparcInstPrinter.h - Convert Sparc MCInst to assembly syntax ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This class prints an Sparc MCInst to a .s file.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_SPARC_INSTPRINTER_SPARCINSTPRINTER_H
+#define LLVM_LIB_TARGET_SPARC_INSTPRINTER_SPARCINSTPRINTER_H
+
+#include "llvm/MC/MCInstPrinter.h"
+#include "llvm/MC/MCSubtargetInfo.h"
+
+namespace llvm {
+
+class MCOperand;
+
+class SparcInstPrinter : public MCInstPrinter {
+public:
+ SparcInstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII,
+ const MCRegisterInfo &MRI)
+ : MCInstPrinter(MAI, MII, MRI) {}
+
+ void printRegName(raw_ostream &OS, unsigned RegNo) const override;
+ void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot,
+ const MCSubtargetInfo &STI) override;
+ bool printSparcAliasInstr(const MCInst *MI, const MCSubtargetInfo &STI,
+ raw_ostream &OS);
+ bool isV9(const MCSubtargetInfo &STI) const;
+
+ // Autogenerated by tblgen.
+ void printInstruction(const MCInst *MI, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ bool printAliasInstr(const MCInst *MI, const MCSubtargetInfo &STI,
+ raw_ostream &O);
+ void printCustomAliasOperand(const MCInst *MI, unsigned OpIdx,
+ unsigned PrintMethodIdx,
+ const MCSubtargetInfo &STI, raw_ostream &O);
+ static const char *getRegisterName(unsigned RegNo);
+
+ void printOperand(const MCInst *MI, int opNum, const MCSubtargetInfo &STI,
+ raw_ostream &OS);
+ void printMemOperand(const MCInst *MI, int opNum, const MCSubtargetInfo &STI,
+ raw_ostream &OS, const char *Modifier = nullptr);
+ void printCCOperand(const MCInst *MI, int opNum, const MCSubtargetInfo &STI,
+ raw_ostream &OS);
+ bool printGetPCX(const MCInst *MI, unsigned OpNo, const MCSubtargetInfo &STI,
+ raw_ostream &OS);
+};
+} // end namespace llvm
+
+#endif
diff --git a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
new file mode 100644
index 0000000..d1d7aaa
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
@@ -0,0 +1,304 @@
+//===-- SparcAsmBackend.cpp - Sparc Assembler Backend ---------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/MC/MCAsmBackend.h"
+#include "MCTargetDesc/SparcFixupKinds.h"
+#include "MCTargetDesc/SparcMCTargetDesc.h"
+#include "llvm/MC/MCELFObjectWriter.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCFixupKindInfo.h"
+#include "llvm/MC/MCObjectWriter.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/Support/TargetRegistry.h"
+
+using namespace llvm;
+
+static unsigned adjustFixupValue(unsigned Kind, uint64_t Value) {
+ switch (Kind) {
+ default:
+ llvm_unreachable("Unknown fixup kind!");
+ case FK_Data_1:
+ case FK_Data_2:
+ case FK_Data_4:
+ case FK_Data_8:
+ return Value;
+
+ case Sparc::fixup_sparc_wplt30:
+ case Sparc::fixup_sparc_call30:
+ return (Value >> 2) & 0x3fffffff;
+
+ case Sparc::fixup_sparc_br22:
+ return (Value >> 2) & 0x3fffff;
+
+ case Sparc::fixup_sparc_br19:
+ return (Value >> 2) & 0x7ffff;
+
+ case Sparc::fixup_sparc_br16_2:
+ return (Value >> 2) & 0xc000;
+
+ case Sparc::fixup_sparc_br16_14:
+ return (Value >> 2) & 0x3fff;
+
+ case Sparc::fixup_sparc_pc22:
+ case Sparc::fixup_sparc_got22:
+ case Sparc::fixup_sparc_tls_gd_hi22:
+ case Sparc::fixup_sparc_tls_ldm_hi22:
+ case Sparc::fixup_sparc_tls_ie_hi22:
+ case Sparc::fixup_sparc_hi22:
+ return (Value >> 10) & 0x3fffff;
+
+ case Sparc::fixup_sparc_pc10:
+ case Sparc::fixup_sparc_got10:
+ case Sparc::fixup_sparc_tls_gd_lo10:
+ case Sparc::fixup_sparc_tls_ldm_lo10:
+ case Sparc::fixup_sparc_tls_ie_lo10:
+ case Sparc::fixup_sparc_lo10:
+ return Value & 0x3ff;
+
+ case Sparc::fixup_sparc_tls_ldo_hix22:
+ case Sparc::fixup_sparc_tls_le_hix22:
+ return (~Value >> 10) & 0x3fffff;
+
+ case Sparc::fixup_sparc_tls_ldo_lox10:
+ case Sparc::fixup_sparc_tls_le_lox10:
+ return (~(~Value & 0x3ff)) & 0x1fff;
+
+ case Sparc::fixup_sparc_h44:
+ return (Value >> 22) & 0x3fffff;
+
+ case Sparc::fixup_sparc_m44:
+ return (Value >> 12) & 0x3ff;
+
+ case Sparc::fixup_sparc_l44:
+ return Value & 0xfff;
+
+ case Sparc::fixup_sparc_hh:
+ return (Value >> 42) & 0x3fffff;
+
+ case Sparc::fixup_sparc_hm:
+ return (Value >> 32) & 0x3ff;
+
+ case Sparc::fixup_sparc_tls_gd_add:
+ case Sparc::fixup_sparc_tls_gd_call:
+ case Sparc::fixup_sparc_tls_ldm_add:
+ case Sparc::fixup_sparc_tls_ldm_call:
+ case Sparc::fixup_sparc_tls_ldo_add:
+ case Sparc::fixup_sparc_tls_ie_ld:
+ case Sparc::fixup_sparc_tls_ie_ldx:
+ case Sparc::fixup_sparc_tls_ie_add:
+ return 0;
+ }
+}
+
+namespace {
+ class SparcAsmBackend : public MCAsmBackend {
+ protected:
+ const Target &TheTarget;
+ bool IsLittleEndian;
+ bool Is64Bit;
+
+ public:
+ SparcAsmBackend(const Target &T)
+ : MCAsmBackend(), TheTarget(T),
+ IsLittleEndian(StringRef(TheTarget.getName()) == "sparcel"),
+ Is64Bit(StringRef(TheTarget.getName()) == "sparcv9") {}
+
+ unsigned getNumFixupKinds() const override {
+ return Sparc::NumTargetFixupKinds;
+ }
+
+ const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const override {
+ const static MCFixupKindInfo InfosBE[Sparc::NumTargetFixupKinds] = {
+ // name offset bits flags
+ { "fixup_sparc_call30", 2, 30, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_sparc_br22", 10, 22, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_sparc_br19", 13, 19, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_sparc_br16_2", 10, 2, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_sparc_br16_14", 18, 14, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_sparc_hi22", 10, 22, 0 },
+ { "fixup_sparc_lo10", 22, 10, 0 },
+ { "fixup_sparc_h44", 10, 22, 0 },
+ { "fixup_sparc_m44", 22, 10, 0 },
+ { "fixup_sparc_l44", 20, 12, 0 },
+ { "fixup_sparc_hh", 10, 22, 0 },
+ { "fixup_sparc_hm", 22, 10, 0 },
+ { "fixup_sparc_pc22", 10, 22, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_sparc_pc10", 22, 10, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_sparc_got22", 10, 22, 0 },
+ { "fixup_sparc_got10", 22, 10, 0 },
+ { "fixup_sparc_wplt30", 2, 30, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_sparc_tls_gd_hi22", 10, 22, 0 },
+ { "fixup_sparc_tls_gd_lo10", 22, 10, 0 },
+ { "fixup_sparc_tls_gd_add", 0, 0, 0 },
+ { "fixup_sparc_tls_gd_call", 0, 0, 0 },
+ { "fixup_sparc_tls_ldm_hi22", 10, 22, 0 },
+ { "fixup_sparc_tls_ldm_lo10", 22, 10, 0 },
+ { "fixup_sparc_tls_ldm_add", 0, 0, 0 },
+ { "fixup_sparc_tls_ldm_call", 0, 0, 0 },
+ { "fixup_sparc_tls_ldo_hix22", 10, 22, 0 },
+ { "fixup_sparc_tls_ldo_lox10", 22, 10, 0 },
+ { "fixup_sparc_tls_ldo_add", 0, 0, 0 },
+ { "fixup_sparc_tls_ie_hi22", 10, 22, 0 },
+ { "fixup_sparc_tls_ie_lo10", 22, 10, 0 },
+ { "fixup_sparc_tls_ie_ld", 0, 0, 0 },
+ { "fixup_sparc_tls_ie_ldx", 0, 0, 0 },
+ { "fixup_sparc_tls_ie_add", 0, 0, 0 },
+ { "fixup_sparc_tls_le_hix22", 0, 0, 0 },
+ { "fixup_sparc_tls_le_lox10", 0, 0, 0 }
+ };
+
+ const static MCFixupKindInfo InfosLE[Sparc::NumTargetFixupKinds] = {
+ // name offset bits flags
+ { "fixup_sparc_call30", 0, 30, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_sparc_br22", 0, 22, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_sparc_br19", 0, 19, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_sparc_br16_2", 20, 2, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_sparc_br16_14", 0, 14, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_sparc_hi22", 0, 22, 0 },
+ { "fixup_sparc_lo10", 0, 10, 0 },
+ { "fixup_sparc_h44", 0, 22, 0 },
+ { "fixup_sparc_m44", 0, 10, 0 },
+ { "fixup_sparc_l44", 0, 12, 0 },
+ { "fixup_sparc_hh", 0, 22, 0 },
+ { "fixup_sparc_hm", 0, 10, 0 },
+ { "fixup_sparc_pc22", 0, 22, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_sparc_pc10", 0, 10, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_sparc_got22", 0, 22, 0 },
+ { "fixup_sparc_got10", 0, 10, 0 },
+ { "fixup_sparc_wplt30", 0, 30, MCFixupKindInfo::FKF_IsPCRel },
+ { "fixup_sparc_tls_gd_hi22", 0, 22, 0 },
+ { "fixup_sparc_tls_gd_lo10", 0, 10, 0 },
+ { "fixup_sparc_tls_gd_add", 0, 0, 0 },
+ { "fixup_sparc_tls_gd_call", 0, 0, 0 },
+ { "fixup_sparc_tls_ldm_hi22", 0, 22, 0 },
+ { "fixup_sparc_tls_ldm_lo10", 0, 10, 0 },
+ { "fixup_sparc_tls_ldm_add", 0, 0, 0 },
+ { "fixup_sparc_tls_ldm_call", 0, 0, 0 },
+ { "fixup_sparc_tls_ldo_hix22", 0, 22, 0 },
+ { "fixup_sparc_tls_ldo_lox10", 0, 10, 0 },
+ { "fixup_sparc_tls_ldo_add", 0, 0, 0 },
+ { "fixup_sparc_tls_ie_hi22", 0, 22, 0 },
+ { "fixup_sparc_tls_ie_lo10", 0, 10, 0 },
+ { "fixup_sparc_tls_ie_ld", 0, 0, 0 },
+ { "fixup_sparc_tls_ie_ldx", 0, 0, 0 },
+ { "fixup_sparc_tls_ie_add", 0, 0, 0 },
+ { "fixup_sparc_tls_le_hix22", 0, 0, 0 },
+ { "fixup_sparc_tls_le_lox10", 0, 0, 0 }
+ };
+
+ if (Kind < FirstTargetFixupKind)
+ return MCAsmBackend::getFixupKindInfo(Kind);
+
+ assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
+ "Invalid kind!");
+ if (IsLittleEndian)
+ return InfosLE[Kind - FirstTargetFixupKind];
+
+ return InfosBE[Kind - FirstTargetFixupKind];
+ }
+
+ void processFixupValue(const MCAssembler &Asm, const MCAsmLayout &Layout,
+ const MCFixup &Fixup, const MCFragment *DF,
+ const MCValue &Target, uint64_t &Value,
+ bool &IsResolved) override {
+ switch ((Sparc::Fixups)Fixup.getKind()) {
+ default: break;
+ case Sparc::fixup_sparc_wplt30:
+ if (Target.getSymA()->getSymbol().isTemporary())
+ return;
+ case Sparc::fixup_sparc_tls_gd_hi22:
+ case Sparc::fixup_sparc_tls_gd_lo10:
+ case Sparc::fixup_sparc_tls_gd_add:
+ case Sparc::fixup_sparc_tls_gd_call:
+ case Sparc::fixup_sparc_tls_ldm_hi22:
+ case Sparc::fixup_sparc_tls_ldm_lo10:
+ case Sparc::fixup_sparc_tls_ldm_add:
+ case Sparc::fixup_sparc_tls_ldm_call:
+ case Sparc::fixup_sparc_tls_ldo_hix22:
+ case Sparc::fixup_sparc_tls_ldo_lox10:
+ case Sparc::fixup_sparc_tls_ldo_add:
+ case Sparc::fixup_sparc_tls_ie_hi22:
+ case Sparc::fixup_sparc_tls_ie_lo10:
+ case Sparc::fixup_sparc_tls_ie_ld:
+ case Sparc::fixup_sparc_tls_ie_ldx:
+ case Sparc::fixup_sparc_tls_ie_add:
+ case Sparc::fixup_sparc_tls_le_hix22:
+ case Sparc::fixup_sparc_tls_le_lox10: IsResolved = false; break;
+ }
+ }
+
+ bool mayNeedRelaxation(const MCInst &Inst) const override {
+ // FIXME.
+ return false;
+ }
+
+ /// fixupNeedsRelaxation - Target specific predicate for whether a given
+ /// fixup requires the associated instruction to be relaxed.
+ bool fixupNeedsRelaxation(const MCFixup &Fixup,
+ uint64_t Value,
+ const MCRelaxableFragment *DF,
+ const MCAsmLayout &Layout) const override {
+ // FIXME.
+ llvm_unreachable("fixupNeedsRelaxation() unimplemented");
+ return false;
+ }
+ void relaxInstruction(const MCInst &Inst, MCInst &Res) const override {
+ // FIXME.
+ llvm_unreachable("relaxInstruction() unimplemented");
+ }
+
+ bool writeNopData(uint64_t Count, MCObjectWriter *OW) const override {
+ // Cannot emit NOP with size not multiple of 32 bits.
+ if (Count % 4 != 0)
+ return false;
+
+ uint64_t NumNops = Count / 4;
+ for (uint64_t i = 0; i != NumNops; ++i)
+ OW->write32(0x01000000);
+
+ return true;
+ }
+ };
+
+ class ELFSparcAsmBackend : public SparcAsmBackend {
+ Triple::OSType OSType;
+ public:
+ ELFSparcAsmBackend(const Target &T, Triple::OSType OSType) :
+ SparcAsmBackend(T), OSType(OSType) { }
+
+ void applyFixup(const MCFixup &Fixup, char *Data, unsigned DataSize,
+ uint64_t Value, bool IsPCRel) const override {
+
+ Value = adjustFixupValue(Fixup.getKind(), Value);
+ if (!Value) return; // Doesn't change encoding.
+
+ unsigned Offset = Fixup.getOffset();
+
+ // For each byte of the fragment that the fixup touches, mask in the bits
+ // from the fixup value. The Value has been "split up" into the
+ // appropriate bitfields above.
+ for (unsigned i = 0; i != 4; ++i) {
+ unsigned Idx = IsLittleEndian ? i : 3 - i;
+ Data[Offset + Idx] |= uint8_t((Value >> (i * 8)) & 0xff);
+ }
+ }
+
+ MCObjectWriter *createObjectWriter(raw_pwrite_stream &OS) const override {
+ uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(OSType);
+ return createSparcELFObjectWriter(OS, Is64Bit, IsLittleEndian, OSABI);
+ }
+ };
+
+} // end anonymous namespace
+
+MCAsmBackend *llvm::createSparcAsmBackend(const Target &T,
+ const MCRegisterInfo &MRI,
+ const Triple &TT, StringRef CPU) {
+ return new ELFSparcAsmBackend(T, TT.getOS());
+}
diff --git a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
new file mode 100644
index 0000000..800a5f2
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcELFObjectWriter.cpp
@@ -0,0 +1,139 @@
+//===-- SparcELFObjectWriter.cpp - Sparc ELF Writer -----------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "MCTargetDesc/SparcFixupKinds.h"
+#include "MCTargetDesc/SparcMCExpr.h"
+#include "MCTargetDesc/SparcMCTargetDesc.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/MC/MCELFObjectWriter.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCValue.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm;
+
+namespace {
+ class SparcELFObjectWriter : public MCELFObjectTargetWriter {
+ public:
+ SparcELFObjectWriter(bool Is64Bit, uint8_t OSABI)
+ : MCELFObjectTargetWriter(Is64Bit, OSABI,
+ Is64Bit ? ELF::EM_SPARCV9 : ELF::EM_SPARC,
+ /*HasRelocationAddend*/ true) {}
+
+ ~SparcELFObjectWriter() override {}
+
+ protected:
+ unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup,
+ bool IsPCRel) const override;
+
+ bool needsRelocateWithSymbol(const MCSymbol &Sym,
+ unsigned Type) const override;
+
+ };
+} // namespace
+
+unsigned SparcELFObjectWriter::GetRelocType(const MCValue &Target,
+ const MCFixup &Fixup,
+ bool IsPCRel) const {
+
+ if (const SparcMCExpr *SExpr = dyn_cast<SparcMCExpr>(Fixup.getValue())) {
+ if (SExpr->getKind() == SparcMCExpr::VK_Sparc_R_DISP32)
+ return ELF::R_SPARC_DISP32;
+ }
+
+ if (IsPCRel) {
+ switch((unsigned)Fixup.getKind()) {
+ default:
+ llvm_unreachable("Unimplemented fixup -> relocation");
+ case FK_Data_1: return ELF::R_SPARC_DISP8;
+ case FK_Data_2: return ELF::R_SPARC_DISP16;
+ case FK_Data_4: return ELF::R_SPARC_DISP32;
+ case FK_Data_8: return ELF::R_SPARC_DISP64;
+ case Sparc::fixup_sparc_call30: return ELF::R_SPARC_WDISP30;
+ case Sparc::fixup_sparc_br22: return ELF::R_SPARC_WDISP22;
+ case Sparc::fixup_sparc_br19: return ELF::R_SPARC_WDISP19;
+ case Sparc::fixup_sparc_pc22: return ELF::R_SPARC_PC22;
+ case Sparc::fixup_sparc_pc10: return ELF::R_SPARC_PC10;
+ case Sparc::fixup_sparc_wplt30: return ELF::R_SPARC_WPLT30;
+ }
+ }
+
+ switch((unsigned)Fixup.getKind()) {
+ default:
+ llvm_unreachable("Unimplemented fixup -> relocation");
+ case FK_Data_1: return ELF::R_SPARC_8;
+ case FK_Data_2: return ((Fixup.getOffset() % 2)
+ ? ELF::R_SPARC_UA16
+ : ELF::R_SPARC_16);
+ case FK_Data_4: return ((Fixup.getOffset() % 4)
+ ? ELF::R_SPARC_UA32
+ : ELF::R_SPARC_32);
+ case FK_Data_8: return ((Fixup.getOffset() % 8)
+ ? ELF::R_SPARC_UA64
+ : ELF::R_SPARC_64);
+ case Sparc::fixup_sparc_hi22: return ELF::R_SPARC_HI22;
+ case Sparc::fixup_sparc_lo10: return ELF::R_SPARC_LO10;
+ case Sparc::fixup_sparc_h44: return ELF::R_SPARC_H44;
+ case Sparc::fixup_sparc_m44: return ELF::R_SPARC_M44;
+ case Sparc::fixup_sparc_l44: return ELF::R_SPARC_L44;
+ case Sparc::fixup_sparc_hh: return ELF::R_SPARC_HH22;
+ case Sparc::fixup_sparc_hm: return ELF::R_SPARC_HM10;
+ case Sparc::fixup_sparc_got22: return ELF::R_SPARC_GOT22;
+ case Sparc::fixup_sparc_got10: return ELF::R_SPARC_GOT10;
+ case Sparc::fixup_sparc_tls_gd_hi22: return ELF::R_SPARC_TLS_GD_HI22;
+ case Sparc::fixup_sparc_tls_gd_lo10: return ELF::R_SPARC_TLS_GD_LO10;
+ case Sparc::fixup_sparc_tls_gd_add: return ELF::R_SPARC_TLS_GD_ADD;
+ case Sparc::fixup_sparc_tls_gd_call: return ELF::R_SPARC_TLS_GD_CALL;
+ case Sparc::fixup_sparc_tls_ldm_hi22: return ELF::R_SPARC_TLS_LDM_HI22;
+ case Sparc::fixup_sparc_tls_ldm_lo10: return ELF::R_SPARC_TLS_LDM_LO10;
+ case Sparc::fixup_sparc_tls_ldm_add: return ELF::R_SPARC_TLS_LDM_ADD;
+ case Sparc::fixup_sparc_tls_ldm_call: return ELF::R_SPARC_TLS_LDM_CALL;
+ case Sparc::fixup_sparc_tls_ldo_hix22: return ELF::R_SPARC_TLS_LDO_HIX22;
+ case Sparc::fixup_sparc_tls_ldo_lox10: return ELF::R_SPARC_TLS_LDO_LOX10;
+ case Sparc::fixup_sparc_tls_ldo_add: return ELF::R_SPARC_TLS_LDO_ADD;
+ case Sparc::fixup_sparc_tls_ie_hi22: return ELF::R_SPARC_TLS_IE_HI22;
+ case Sparc::fixup_sparc_tls_ie_lo10: return ELF::R_SPARC_TLS_IE_LO10;
+ case Sparc::fixup_sparc_tls_ie_ld: return ELF::R_SPARC_TLS_IE_LD;
+ case Sparc::fixup_sparc_tls_ie_ldx: return ELF::R_SPARC_TLS_IE_LDX;
+ case Sparc::fixup_sparc_tls_ie_add: return ELF::R_SPARC_TLS_IE_ADD;
+ case Sparc::fixup_sparc_tls_le_hix22: return ELF::R_SPARC_TLS_LE_HIX22;
+ case Sparc::fixup_sparc_tls_le_lox10: return ELF::R_SPARC_TLS_LE_LOX10;
+ }
+
+ return ELF::R_SPARC_NONE;
+}
+
+bool SparcELFObjectWriter::needsRelocateWithSymbol(const MCSymbol &Sym,
+ unsigned Type) const {
+ switch (Type) {
+ default:
+ return false;
+
+ // All relocations that use a GOT need a symbol, not an offset, as
+ // the offset of the symbol within the section is irrelevant to
+ // where the GOT entry is. Don't need to list all the TLS entries,
+ // as they're all marked as requiring a symbol anyways.
+ case ELF::R_SPARC_GOT10:
+ case ELF::R_SPARC_GOT13:
+ case ELF::R_SPARC_GOT22:
+ case ELF::R_SPARC_GOTDATA_HIX22:
+ case ELF::R_SPARC_GOTDATA_LOX10:
+ case ELF::R_SPARC_GOTDATA_OP_HIX22:
+ case ELF::R_SPARC_GOTDATA_OP_LOX10:
+ return true;
+ }
+}
+
+MCObjectWriter *llvm::createSparcELFObjectWriter(raw_pwrite_stream &OS,
+ bool Is64Bit,
+ bool IsLittleEndian,
+ uint8_t OSABI) {
+ MCELFObjectTargetWriter *MOTW = new SparcELFObjectWriter(Is64Bit, OSABI);
+ return createELFObjectWriter(MOTW, OS, IsLittleEndian);
+}
diff --git a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h
new file mode 100644
index 0000000..34c58da
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h
@@ -0,0 +1,97 @@
+//===-- SparcFixupKinds.h - Sparc Specific Fixup Entries --------*- C++ -*-===//
+//
+// 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_MCTARGETDESC_SPARCFIXUPKINDS_H
+#define LLVM_LIB_TARGET_SPARC_MCTARGETDESC_SPARCFIXUPKINDS_H
+
+#include "llvm/MC/MCFixup.h"
+
+namespace llvm {
+ namespace Sparc {
+ enum Fixups {
+ // fixup_sparc_call30 - 30-bit PC relative relocation for call
+ fixup_sparc_call30 = FirstTargetFixupKind,
+
+ /// fixup_sparc_br22 - 22-bit PC relative relocation for
+ /// branches
+ fixup_sparc_br22,
+
+ /// fixup_sparc_br19 - 19-bit PC relative relocation for
+ /// branches on icc/xcc
+ fixup_sparc_br19,
+
+ /// fixup_sparc_bpr - 16-bit fixup for bpr
+ fixup_sparc_br16_2,
+ fixup_sparc_br16_14,
+
+ /// fixup_sparc_hi22 - 22-bit fixup corresponding to %hi(foo)
+ /// for sethi
+ fixup_sparc_hi22,
+
+ /// fixup_sparc_lo10 - 10-bit fixup corresponding to %lo(foo)
+ fixup_sparc_lo10,
+
+ /// fixup_sparc_h44 - 22-bit fixup corresponding to %h44(foo)
+ fixup_sparc_h44,
+
+ /// fixup_sparc_m44 - 10-bit fixup corresponding to %m44(foo)
+ fixup_sparc_m44,
+
+ /// fixup_sparc_l44 - 12-bit fixup corresponding to %l44(foo)
+ fixup_sparc_l44,
+
+ /// fixup_sparc_hh - 22-bit fixup corresponding to %hh(foo)
+ fixup_sparc_hh,
+
+ /// fixup_sparc_hm - 10-bit fixup corresponding to %hm(foo)
+ fixup_sparc_hm,
+
+ /// fixup_sparc_pc22 - 22-bit fixup corresponding to %pc22(foo)
+ fixup_sparc_pc22,
+
+ /// fixup_sparc_pc10 - 10-bit fixup corresponding to %pc10(foo)
+ fixup_sparc_pc10,
+
+ /// fixup_sparc_got22 - 22-bit fixup corresponding to %got22(foo)
+ fixup_sparc_got22,
+
+ /// fixup_sparc_got10 - 10-bit fixup corresponding to %got10(foo)
+ fixup_sparc_got10,
+
+ /// fixup_sparc_wplt30
+ fixup_sparc_wplt30,
+
+ /// fixups for Thread Local Storage
+ fixup_sparc_tls_gd_hi22,
+ fixup_sparc_tls_gd_lo10,
+ fixup_sparc_tls_gd_add,
+ fixup_sparc_tls_gd_call,
+ fixup_sparc_tls_ldm_hi22,
+ fixup_sparc_tls_ldm_lo10,
+ fixup_sparc_tls_ldm_add,
+ fixup_sparc_tls_ldm_call,
+ fixup_sparc_tls_ldo_hix22,
+ fixup_sparc_tls_ldo_lox10,
+ fixup_sparc_tls_ldo_add,
+ fixup_sparc_tls_ie_hi22,
+ fixup_sparc_tls_ie_lo10,
+ fixup_sparc_tls_ie_ld,
+ fixup_sparc_tls_ie_ldx,
+ fixup_sparc_tls_ie_add,
+ fixup_sparc_tls_le_hix22,
+ fixup_sparc_tls_le_lox10,
+
+ // Marker
+ LastTargetFixupKind,
+ NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind
+ };
+ } // namespace Sparc
+} // namespace llvm
+
+#endif
diff --git a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp
new file mode 100644
index 0000000..280c6d7
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.cpp
@@ -0,0 +1,70 @@
+//===-- SparcMCAsmInfo.cpp - Sparc asm properties -------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the declarations of the SparcMCAsmInfo properties.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SparcMCAsmInfo.h"
+#include "SparcMCExpr.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/MC/MCStreamer.h"
+
+using namespace llvm;
+
+void SparcELFMCAsmInfo::anchor() {}
+
+SparcELFMCAsmInfo::SparcELFMCAsmInfo(const Triple &TheTriple) {
+ bool isV9 = (TheTriple.getArch() == Triple::sparcv9);
+ IsLittleEndian = (TheTriple.getArch() == Triple::sparcel);
+
+ if (isV9) {
+ PointerSize = CalleeSaveStackSlotSize = 8;
+ }
+
+ Data16bitsDirective = "\t.half\t";
+ Data32bitsDirective = "\t.word\t";
+ // .xword is only supported by V9.
+ Data64bitsDirective = (isV9) ? "\t.xword\t" : nullptr;
+ ZeroDirective = "\t.skip\t";
+ CommentString = "!";
+ SupportsDebugInformation = true;
+
+ ExceptionsType = ExceptionHandling::DwarfCFI;
+
+ SunStyleELFSectionSwitchSyntax = true;
+ UsesELFSectionDirectiveForBSS = true;
+
+ UseIntegratedAssembler = true;
+}
+
+const MCExpr*
+SparcELFMCAsmInfo::getExprForPersonalitySymbol(const MCSymbol *Sym,
+ unsigned Encoding,
+ MCStreamer &Streamer) const {
+ if (Encoding & dwarf::DW_EH_PE_pcrel) {
+ MCContext &Ctx = Streamer.getContext();
+ return SparcMCExpr::create(SparcMCExpr::VK_Sparc_R_DISP32,
+ MCSymbolRefExpr::create(Sym, Ctx), Ctx);
+ }
+
+ return MCAsmInfo::getExprForPersonalitySymbol(Sym, Encoding, Streamer);
+}
+
+const MCExpr*
+SparcELFMCAsmInfo::getExprForFDESymbol(const MCSymbol *Sym,
+ unsigned Encoding,
+ MCStreamer &Streamer) const {
+ if (Encoding & dwarf::DW_EH_PE_pcrel) {
+ MCContext &Ctx = Streamer.getContext();
+ return SparcMCExpr::create(SparcMCExpr::VK_Sparc_R_DISP32,
+ MCSymbolRefExpr::create(Sym, Ctx), Ctx);
+ }
+ return MCAsmInfo::getExprForFDESymbol(Sym, Encoding, Streamer);
+}
diff --git a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h
new file mode 100644
index 0000000..12386f1
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCAsmInfo.h
@@ -0,0 +1,37 @@
+//===-- SparcMCAsmInfo.h - Sparc asm properties ----------------*- C++ -*--===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the declaration of the SparcMCAsmInfo class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_SPARC_MCTARGETDESC_SPARCMCASMINFO_H
+#define LLVM_LIB_TARGET_SPARC_MCTARGETDESC_SPARCMCASMINFO_H
+
+#include "llvm/MC/MCAsmInfoELF.h"
+
+namespace llvm {
+class Triple;
+
+class SparcELFMCAsmInfo : public MCAsmInfoELF {
+ void anchor() override;
+public:
+ explicit SparcELFMCAsmInfo(const Triple &TheTriple);
+ const MCExpr*
+ getExprForPersonalitySymbol(const MCSymbol *Sym, unsigned Encoding,
+ MCStreamer &Streamer) const override;
+ const MCExpr* getExprForFDESymbol(const MCSymbol *Sym,
+ unsigned Encoding,
+ MCStreamer &Streamer) const override;
+
+};
+
+} // namespace llvm
+
+#endif
diff --git a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp
new file mode 100644
index 0000000..9171d4d
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCCodeEmitter.cpp
@@ -0,0 +1,219 @@
+//===-- SparcMCCodeEmitter.cpp - Convert Sparc code to machine code -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the SparcMCCodeEmitter class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SparcMCExpr.h"
+#include "MCTargetDesc/SparcFixupKinds.h"
+#include "SparcMCTargetDesc.h"
+#include "llvm/ADT/Statistic.h"
+#include "llvm/MC/MCCodeEmitter.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "mccodeemitter"
+
+STATISTIC(MCNumEmitted, "Number of MC instructions emitted");
+
+namespace {
+class SparcMCCodeEmitter : public MCCodeEmitter {
+ SparcMCCodeEmitter(const SparcMCCodeEmitter &) = delete;
+ void operator=(const SparcMCCodeEmitter &) = delete;
+ MCContext &Ctx;
+
+public:
+ SparcMCCodeEmitter(MCContext &ctx): Ctx(ctx) {}
+
+ ~SparcMCCodeEmitter() override {}
+
+ void encodeInstruction(const MCInst &MI, raw_ostream &OS,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const override;
+
+ // getBinaryCodeForInstr - TableGen'erated function for getting the
+ // binary encoding for an instruction.
+ uint64_t getBinaryCodeForInstr(const MCInst &MI,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
+ /// getMachineOpValue - Return binary encoding of operand. If the machine
+ /// operand requires relocation, record the relocation and return zero.
+ unsigned getMachineOpValue(const MCInst &MI, const MCOperand &MO,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
+ unsigned getCallTargetOpValue(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+ unsigned getBranchTargetOpValue(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+ unsigned getBranchPredTargetOpValue(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+ unsigned getBranchOnRegTargetOpValue(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const;
+
+};
+} // end anonymous namespace
+
+MCCodeEmitter *llvm::createSparcMCCodeEmitter(const MCInstrInfo &MCII,
+ const MCRegisterInfo &MRI,
+ MCContext &Ctx) {
+ return new SparcMCCodeEmitter(Ctx);
+}
+
+void SparcMCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ unsigned Bits = getBinaryCodeForInstr(MI, Fixups, STI);
+
+ if (Ctx.getAsmInfo()->isLittleEndian()) {
+ // Output the bits in little-endian byte order.
+ support::endian::Writer<support::little>(OS).write<uint32_t>(Bits);
+ } else {
+ // Output the bits in big-endian byte order.
+ support::endian::Writer<support::big>(OS).write<uint32_t>(Bits);
+ }
+ unsigned tlsOpNo = 0;
+ switch (MI.getOpcode()) {
+ default: break;
+ case SP::TLS_CALL: tlsOpNo = 1; break;
+ case SP::TLS_ADDrr:
+ case SP::TLS_ADDXrr:
+ case SP::TLS_LDrr:
+ case SP::TLS_LDXrr: tlsOpNo = 3; break;
+ }
+ if (tlsOpNo != 0) {
+ const MCOperand &MO = MI.getOperand(tlsOpNo);
+ uint64_t op = getMachineOpValue(MI, MO, Fixups, STI);
+ assert(op == 0 && "Unexpected operand value!");
+ (void)op; // suppress warning.
+ }
+
+ ++MCNumEmitted; // Keep track of the # of mi's emitted.
+}
+
+
+unsigned SparcMCCodeEmitter::
+getMachineOpValue(const MCInst &MI, const MCOperand &MO,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+
+ if (MO.isReg())
+ return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg());
+
+ if (MO.isImm())
+ return MO.getImm();
+
+ assert(MO.isExpr());
+ const MCExpr *Expr = MO.getExpr();
+ if (const SparcMCExpr *SExpr = dyn_cast<SparcMCExpr>(Expr)) {
+ MCFixupKind Kind = (MCFixupKind)SExpr->getFixupKind();
+ Fixups.push_back(MCFixup::create(0, Expr, Kind));
+ return 0;
+ }
+
+ int64_t Res;
+ if (Expr->evaluateAsAbsolute(Res))
+ return Res;
+
+ llvm_unreachable("Unhandled expression!");
+ return 0;
+}
+
+unsigned SparcMCCodeEmitter::
+getCallTargetOpValue(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ const MCOperand &MO = MI.getOperand(OpNo);
+ if (MO.isReg() || MO.isImm())
+ return getMachineOpValue(MI, MO, Fixups, STI);
+
+ if (MI.getOpcode() == SP::TLS_CALL) {
+ // No fixups for __tls_get_addr. Will emit for fixups for tls_symbol in
+ // encodeInstruction.
+#ifndef NDEBUG
+ // Verify that the callee is actually __tls_get_addr.
+ const SparcMCExpr *SExpr = dyn_cast<SparcMCExpr>(MO.getExpr());
+ assert(SExpr && SExpr->getSubExpr()->getKind() == MCExpr::SymbolRef &&
+ "Unexpected expression in TLS_CALL");
+ const MCSymbolRefExpr *SymExpr = cast<MCSymbolRefExpr>(SExpr->getSubExpr());
+ assert(SymExpr->getSymbol().getName() == "__tls_get_addr" &&
+ "Unexpected function for TLS_CALL");
+#endif
+ return 0;
+ }
+
+ MCFixupKind fixupKind = (MCFixupKind)Sparc::fixup_sparc_call30;
+
+ if (const SparcMCExpr *SExpr = dyn_cast<SparcMCExpr>(MO.getExpr())) {
+ if (SExpr->getKind() == SparcMCExpr::VK_Sparc_WPLT30)
+ fixupKind = (MCFixupKind)Sparc::fixup_sparc_wplt30;
+ }
+
+ Fixups.push_back(MCFixup::create(0, MO.getExpr(), fixupKind));
+
+ return 0;
+}
+
+unsigned SparcMCCodeEmitter::
+getBranchTargetOpValue(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ const MCOperand &MO = MI.getOperand(OpNo);
+ if (MO.isReg() || MO.isImm())
+ return getMachineOpValue(MI, MO, Fixups, STI);
+
+ Fixups.push_back(MCFixup::create(0, MO.getExpr(),
+ (MCFixupKind)Sparc::fixup_sparc_br22));
+ return 0;
+}
+
+unsigned SparcMCCodeEmitter::
+getBranchPredTargetOpValue(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ const MCOperand &MO = MI.getOperand(OpNo);
+ if (MO.isReg() || MO.isImm())
+ return getMachineOpValue(MI, MO, Fixups, STI);
+
+ Fixups.push_back(MCFixup::create(0, MO.getExpr(),
+ (MCFixupKind)Sparc::fixup_sparc_br19));
+ return 0;
+}
+unsigned SparcMCCodeEmitter::
+getBranchOnRegTargetOpValue(const MCInst &MI, unsigned OpNo,
+ SmallVectorImpl<MCFixup> &Fixups,
+ const MCSubtargetInfo &STI) const {
+ const MCOperand &MO = MI.getOperand(OpNo);
+ if (MO.isReg() || MO.isImm())
+ return getMachineOpValue(MI, MO, Fixups, STI);
+
+ Fixups.push_back(MCFixup::create(0, MO.getExpr(),
+ (MCFixupKind)Sparc::fixup_sparc_br16_2));
+ Fixups.push_back(MCFixup::create(0, MO.getExpr(),
+ (MCFixupKind)Sparc::fixup_sparc_br16_14));
+
+ return 0;
+}
+
+
+
+#include "SparcGenMCCodeEmitter.inc"
diff --git a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
new file mode 100644
index 0000000..e85a8cd
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
@@ -0,0 +1,221 @@
+//===-- SparcMCExpr.cpp - Sparc specific MC expression classes --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the implementation of the assembly expression modifiers
+// accepted by the Sparc architecture (e.g. "%hi", "%lo", ...).
+//
+//===----------------------------------------------------------------------===//
+
+#include "SparcMCExpr.h"
+#include "llvm/MC/MCAssembler.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCObjectStreamer.h"
+#include "llvm/MC/MCSymbolELF.h"
+#include "llvm/Object/ELF.h"
+
+
+using namespace llvm;
+
+#define DEBUG_TYPE "sparcmcexpr"
+
+const SparcMCExpr*
+SparcMCExpr::create(VariantKind Kind, const MCExpr *Expr,
+ MCContext &Ctx) {
+ return new (Ctx) SparcMCExpr(Kind, Expr);
+}
+
+void SparcMCExpr::printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const {
+
+ bool closeParen = printVariantKind(OS, Kind);
+
+ const MCExpr *Expr = getSubExpr();
+ Expr->print(OS, MAI);
+
+ if (closeParen)
+ OS << ')';
+}
+
+bool SparcMCExpr::printVariantKind(raw_ostream &OS, VariantKind Kind)
+{
+ bool closeParen = true;
+ switch (Kind) {
+ case VK_Sparc_None: closeParen = false; break;
+ case VK_Sparc_LO: OS << "%lo("; break;
+ case VK_Sparc_HI: OS << "%hi("; break;
+ case VK_Sparc_H44: OS << "%h44("; break;
+ case VK_Sparc_M44: OS << "%m44("; break;
+ case VK_Sparc_L44: OS << "%l44("; break;
+ case VK_Sparc_HH: OS << "%hh("; break;
+ case VK_Sparc_HM: OS << "%hm("; break;
+ // FIXME: use %pc22/%pc10, if system assembler supports them.
+ case VK_Sparc_PC22: OS << "%hi("; break;
+ case VK_Sparc_PC10: OS << "%lo("; break;
+ // FIXME: use %got22/%got10, if system assembler supports them.
+ case VK_Sparc_GOT22: OS << "%hi("; break;
+ case VK_Sparc_GOT10: OS << "%lo("; break;
+ case VK_Sparc_WPLT30: closeParen = false; break;
+ case VK_Sparc_R_DISP32: OS << "%r_disp32("; break;
+ case VK_Sparc_TLS_GD_HI22: OS << "%tgd_hi22("; break;
+ case VK_Sparc_TLS_GD_LO10: OS << "%tgd_lo10("; break;
+ case VK_Sparc_TLS_GD_ADD: OS << "%tgd_add("; break;
+ case VK_Sparc_TLS_GD_CALL: OS << "%tgd_call("; break;
+ case VK_Sparc_TLS_LDM_HI22: OS << "%tldm_hi22("; break;
+ case VK_Sparc_TLS_LDM_LO10: OS << "%tldm_lo10("; break;
+ case VK_Sparc_TLS_LDM_ADD: OS << "%tldm_add("; break;
+ case VK_Sparc_TLS_LDM_CALL: OS << "%tldm_call("; break;
+ case VK_Sparc_TLS_LDO_HIX22: OS << "%tldo_hix22("; break;
+ case VK_Sparc_TLS_LDO_LOX10: OS << "%tldo_lox10("; break;
+ case VK_Sparc_TLS_LDO_ADD: OS << "%tldo_add("; break;
+ case VK_Sparc_TLS_IE_HI22: OS << "%tie_hi22("; break;
+ case VK_Sparc_TLS_IE_LO10: OS << "%tie_lo10("; break;
+ case VK_Sparc_TLS_IE_LD: OS << "%tie_ld("; break;
+ case VK_Sparc_TLS_IE_LDX: OS << "%tie_ldx("; break;
+ case VK_Sparc_TLS_IE_ADD: OS << "%tie_add("; break;
+ case VK_Sparc_TLS_LE_HIX22: OS << "%tle_hix22("; break;
+ case VK_Sparc_TLS_LE_LOX10: OS << "%tle_lox10("; break;
+ }
+ return closeParen;
+}
+
+SparcMCExpr::VariantKind SparcMCExpr::parseVariantKind(StringRef name)
+{
+ return StringSwitch<SparcMCExpr::VariantKind>(name)
+ .Case("lo", VK_Sparc_LO)
+ .Case("hi", VK_Sparc_HI)
+ .Case("h44", VK_Sparc_H44)
+ .Case("m44", VK_Sparc_M44)
+ .Case("l44", VK_Sparc_L44)
+ .Case("hh", VK_Sparc_HH)
+ .Case("hm", VK_Sparc_HM)
+ .Case("pc22", VK_Sparc_PC22)
+ .Case("pc10", VK_Sparc_PC10)
+ .Case("got22", VK_Sparc_GOT22)
+ .Case("got10", VK_Sparc_GOT10)
+ .Case("r_disp32", VK_Sparc_R_DISP32)
+ .Case("tgd_hi22", VK_Sparc_TLS_GD_HI22)
+ .Case("tgd_lo10", VK_Sparc_TLS_GD_LO10)
+ .Case("tgd_add", VK_Sparc_TLS_GD_ADD)
+ .Case("tgd_call", VK_Sparc_TLS_GD_CALL)
+ .Case("tldm_hi22", VK_Sparc_TLS_LDM_HI22)
+ .Case("tldm_lo10", VK_Sparc_TLS_LDM_LO10)
+ .Case("tldm_add", VK_Sparc_TLS_LDM_ADD)
+ .Case("tldm_call", VK_Sparc_TLS_LDM_CALL)
+ .Case("tldo_hix22", VK_Sparc_TLS_LDO_HIX22)
+ .Case("tldo_lox10", VK_Sparc_TLS_LDO_LOX10)
+ .Case("tldo_add", VK_Sparc_TLS_LDO_ADD)
+ .Case("tie_hi22", VK_Sparc_TLS_IE_HI22)
+ .Case("tie_lo10", VK_Sparc_TLS_IE_LO10)
+ .Case("tie_ld", VK_Sparc_TLS_IE_LD)
+ .Case("tie_ldx", VK_Sparc_TLS_IE_LDX)
+ .Case("tie_add", VK_Sparc_TLS_IE_ADD)
+ .Case("tle_hix22", VK_Sparc_TLS_LE_HIX22)
+ .Case("tle_lox10", VK_Sparc_TLS_LE_LOX10)
+ .Default(VK_Sparc_None);
+}
+
+Sparc::Fixups SparcMCExpr::getFixupKind(SparcMCExpr::VariantKind Kind) {
+ switch (Kind) {
+ default: llvm_unreachable("Unhandled SparcMCExpr::VariantKind");
+ case VK_Sparc_LO: return Sparc::fixup_sparc_lo10;
+ case VK_Sparc_HI: return Sparc::fixup_sparc_hi22;
+ case VK_Sparc_H44: return Sparc::fixup_sparc_h44;
+ case VK_Sparc_M44: return Sparc::fixup_sparc_m44;
+ case VK_Sparc_L44: return Sparc::fixup_sparc_l44;
+ case VK_Sparc_HH: return Sparc::fixup_sparc_hh;
+ case VK_Sparc_HM: return Sparc::fixup_sparc_hm;
+ case VK_Sparc_PC22: return Sparc::fixup_sparc_pc22;
+ case VK_Sparc_PC10: return Sparc::fixup_sparc_pc10;
+ case VK_Sparc_GOT22: return Sparc::fixup_sparc_got22;
+ case VK_Sparc_GOT10: return Sparc::fixup_sparc_got10;
+ case VK_Sparc_WPLT30: return Sparc::fixup_sparc_wplt30;
+ case VK_Sparc_TLS_GD_HI22: return Sparc::fixup_sparc_tls_gd_hi22;
+ case VK_Sparc_TLS_GD_LO10: return Sparc::fixup_sparc_tls_gd_lo10;
+ case VK_Sparc_TLS_GD_ADD: return Sparc::fixup_sparc_tls_gd_add;
+ case VK_Sparc_TLS_GD_CALL: return Sparc::fixup_sparc_tls_gd_call;
+ case VK_Sparc_TLS_LDM_HI22: return Sparc::fixup_sparc_tls_ldm_hi22;
+ case VK_Sparc_TLS_LDM_LO10: return Sparc::fixup_sparc_tls_ldm_lo10;
+ case VK_Sparc_TLS_LDM_ADD: return Sparc::fixup_sparc_tls_ldm_add;
+ case VK_Sparc_TLS_LDM_CALL: return Sparc::fixup_sparc_tls_ldm_call;
+ case VK_Sparc_TLS_LDO_HIX22: return Sparc::fixup_sparc_tls_ldo_hix22;
+ case VK_Sparc_TLS_LDO_LOX10: return Sparc::fixup_sparc_tls_ldo_lox10;
+ case VK_Sparc_TLS_LDO_ADD: return Sparc::fixup_sparc_tls_ldo_add;
+ case VK_Sparc_TLS_IE_HI22: return Sparc::fixup_sparc_tls_ie_hi22;
+ case VK_Sparc_TLS_IE_LO10: return Sparc::fixup_sparc_tls_ie_lo10;
+ case VK_Sparc_TLS_IE_LD: return Sparc::fixup_sparc_tls_ie_ld;
+ case VK_Sparc_TLS_IE_LDX: return Sparc::fixup_sparc_tls_ie_ldx;
+ case VK_Sparc_TLS_IE_ADD: return Sparc::fixup_sparc_tls_ie_add;
+ case VK_Sparc_TLS_LE_HIX22: return Sparc::fixup_sparc_tls_le_hix22;
+ case VK_Sparc_TLS_LE_LOX10: return Sparc::fixup_sparc_tls_le_lox10;
+ }
+}
+
+bool
+SparcMCExpr::evaluateAsRelocatableImpl(MCValue &Res,
+ const MCAsmLayout *Layout,
+ const MCFixup *Fixup) const {
+ return getSubExpr()->evaluateAsRelocatable(Res, Layout, Fixup);
+}
+
+static void fixELFSymbolsInTLSFixupsImpl(const MCExpr *Expr, MCAssembler &Asm) {
+ switch (Expr->getKind()) {
+ case MCExpr::Target:
+ llvm_unreachable("Can't handle nested target expr!");
+ break;
+
+ case MCExpr::Constant:
+ break;
+
+ case MCExpr::Binary: {
+ const MCBinaryExpr *BE = cast<MCBinaryExpr>(Expr);
+ fixELFSymbolsInTLSFixupsImpl(BE->getLHS(), Asm);
+ fixELFSymbolsInTLSFixupsImpl(BE->getRHS(), Asm);
+ break;
+ }
+
+ case MCExpr::SymbolRef: {
+ const MCSymbolRefExpr &SymRef = *cast<MCSymbolRefExpr>(Expr);
+ cast<MCSymbolELF>(SymRef.getSymbol()).setType(ELF::STT_TLS);
+ break;
+ }
+
+ case MCExpr::Unary:
+ fixELFSymbolsInTLSFixupsImpl(cast<MCUnaryExpr>(Expr)->getSubExpr(), Asm);
+ break;
+ }
+
+}
+
+void SparcMCExpr::fixELFSymbolsInTLSFixups(MCAssembler &Asm) const {
+ switch(getKind()) {
+ default: return;
+ case VK_Sparc_TLS_GD_HI22:
+ case VK_Sparc_TLS_GD_LO10:
+ case VK_Sparc_TLS_GD_ADD:
+ case VK_Sparc_TLS_GD_CALL:
+ case VK_Sparc_TLS_LDM_HI22:
+ case VK_Sparc_TLS_LDM_LO10:
+ case VK_Sparc_TLS_LDM_ADD:
+ case VK_Sparc_TLS_LDM_CALL:
+ case VK_Sparc_TLS_LDO_HIX22:
+ case VK_Sparc_TLS_LDO_LOX10:
+ case VK_Sparc_TLS_LDO_ADD:
+ case VK_Sparc_TLS_IE_HI22:
+ case VK_Sparc_TLS_IE_LO10:
+ case VK_Sparc_TLS_IE_LD:
+ case VK_Sparc_TLS_IE_LDX:
+ case VK_Sparc_TLS_IE_ADD:
+ case VK_Sparc_TLS_LE_HIX22:
+ case VK_Sparc_TLS_LE_LOX10: break;
+ }
+ fixELFSymbolsInTLSFixupsImpl(getSubExpr(), Asm);
+}
+
+void SparcMCExpr::visitUsedExpr(MCStreamer &Streamer) const {
+ Streamer.visitUsedExpr(*getSubExpr());
+}
diff --git a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h
new file mode 100644
index 0000000..d08ad86
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h
@@ -0,0 +1,112 @@
+//====- SparcMCExpr.h - Sparc specific MC expression classes --*- C++ -*-=====//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file describes Sparc-specific MCExprs, used for modifiers like
+// "%hi" or "%lo" etc.,
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_SPARC_MCTARGETDESC_SPARCMCEXPR_H
+#define LLVM_LIB_TARGET_SPARC_MCTARGETDESC_SPARCMCEXPR_H
+
+#include "SparcFixupKinds.h"
+#include "llvm/MC/MCExpr.h"
+
+namespace llvm {
+
+class StringRef;
+class SparcMCExpr : public MCTargetExpr {
+public:
+ enum VariantKind {
+ VK_Sparc_None,
+ VK_Sparc_LO,
+ VK_Sparc_HI,
+ VK_Sparc_H44,
+ VK_Sparc_M44,
+ VK_Sparc_L44,
+ VK_Sparc_HH,
+ VK_Sparc_HM,
+ VK_Sparc_PC22,
+ VK_Sparc_PC10,
+ VK_Sparc_GOT22,
+ VK_Sparc_GOT10,
+ VK_Sparc_WPLT30,
+ VK_Sparc_R_DISP32,
+ VK_Sparc_TLS_GD_HI22,
+ VK_Sparc_TLS_GD_LO10,
+ VK_Sparc_TLS_GD_ADD,
+ VK_Sparc_TLS_GD_CALL,
+ VK_Sparc_TLS_LDM_HI22,
+ VK_Sparc_TLS_LDM_LO10,
+ VK_Sparc_TLS_LDM_ADD,
+ VK_Sparc_TLS_LDM_CALL,
+ VK_Sparc_TLS_LDO_HIX22,
+ VK_Sparc_TLS_LDO_LOX10,
+ VK_Sparc_TLS_LDO_ADD,
+ VK_Sparc_TLS_IE_HI22,
+ VK_Sparc_TLS_IE_LO10,
+ VK_Sparc_TLS_IE_LD,
+ VK_Sparc_TLS_IE_LDX,
+ VK_Sparc_TLS_IE_ADD,
+ VK_Sparc_TLS_LE_HIX22,
+ VK_Sparc_TLS_LE_LOX10
+ };
+
+private:
+ const VariantKind Kind;
+ const MCExpr *Expr;
+
+ explicit SparcMCExpr(VariantKind Kind, const MCExpr *Expr)
+ : Kind(Kind), Expr(Expr) {}
+
+public:
+ /// @name Construction
+ /// @{
+
+ static const SparcMCExpr *create(VariantKind Kind, const MCExpr *Expr,
+ MCContext &Ctx);
+ /// @}
+ /// @name Accessors
+ /// @{
+
+ /// getOpcode - Get the kind of this expression.
+ VariantKind getKind() const { return Kind; }
+
+ /// getSubExpr - Get the child of this expression.
+ const MCExpr *getSubExpr() const { return Expr; }
+
+ /// getFixupKind - Get the fixup kind of this expression.
+ Sparc::Fixups getFixupKind() const { return getFixupKind(Kind); }
+
+ /// @}
+ void printImpl(raw_ostream &OS, const MCAsmInfo *MAI) const override;
+ bool evaluateAsRelocatableImpl(MCValue &Res,
+ const MCAsmLayout *Layout,
+ const MCFixup *Fixup) const override;
+ void visitUsedExpr(MCStreamer &Streamer) const override;
+ MCSection *findAssociatedSection() const override {
+ return getSubExpr()->findAssociatedSection();
+ }
+
+ void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const override;
+
+ static bool classof(const MCExpr *E) {
+ return E->getKind() == MCExpr::Target;
+ }
+
+ static bool classof(const SparcMCExpr *) { return true; }
+
+ static VariantKind parseVariantKind(StringRef name);
+ static bool printVariantKind(raw_ostream &OS, VariantKind Kind);
+ static Sparc::Fixups getFixupKind(VariantKind Kind);
+};
+
+} // end namespace llvm.
+
+#endif
diff --git a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp
new file mode 100644
index 0000000..91d2eee
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.cpp
@@ -0,0 +1,184 @@
+//===-- SparcMCTargetDesc.cpp - Sparc Target Descriptions -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides Sparc specific target descriptions.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SparcMCTargetDesc.h"
+#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"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/TargetRegistry.h"
+
+using namespace llvm;
+
+#define GET_INSTRINFO_MC_DESC
+#include "SparcGenInstrInfo.inc"
+
+#define GET_SUBTARGETINFO_MC_DESC
+#include "SparcGenSubtargetInfo.inc"
+
+#define GET_REGINFO_MC_DESC
+#include "SparcGenRegisterInfo.inc"
+
+static MCAsmInfo *createSparcMCAsmInfo(const MCRegisterInfo &MRI,
+ const Triple &TT) {
+ MCAsmInfo *MAI = new SparcELFMCAsmInfo(TT);
+ unsigned Reg = MRI.getDwarfRegNum(SP::O6, true);
+ MCCFIInstruction Inst = MCCFIInstruction::createDefCfa(nullptr, Reg, 0);
+ MAI->addInitialFrameState(Inst);
+ return MAI;
+}
+
+static MCAsmInfo *createSparcV9MCAsmInfo(const MCRegisterInfo &MRI,
+ const Triple &TT) {
+ MCAsmInfo *MAI = new SparcELFMCAsmInfo(TT);
+ unsigned Reg = MRI.getDwarfRegNum(SP::O6, true);
+ MCCFIInstruction Inst = MCCFIInstruction::createDefCfa(nullptr, Reg, 2047);
+ MAI->addInitialFrameState(Inst);
+ return MAI;
+}
+
+static MCInstrInfo *createSparcMCInstrInfo() {
+ MCInstrInfo *X = new MCInstrInfo();
+ InitSparcMCInstrInfo(X);
+ return X;
+}
+
+static MCRegisterInfo *createSparcMCRegisterInfo(StringRef TT) {
+ MCRegisterInfo *X = new MCRegisterInfo();
+ InitSparcMCRegisterInfo(X, SP::O7);
+ return X;
+}
+
+static MCSubtargetInfo *
+createSparcMCSubtargetInfo(const Triple &TT, StringRef CPU, StringRef FS) {
+ MCSubtargetInfo *X = new MCSubtargetInfo();
+ if (CPU.empty())
+ CPU = (TT.getArch() == Triple::sparcv9) ? "v9" : "v8";
+ InitSparcMCSubtargetInfo(X, TT, CPU, FS);
+ return X;
+}
+
+// Code models. Some only make sense for 64-bit code.
+//
+// SunCC Reloc CodeModel Constraints
+// abs32 Static Small text+data+bss linked below 2^32 bytes
+// abs44 Static Medium text+data+bss linked below 2^44 bytes
+// abs64 Static Large text smaller than 2^31 bytes
+// pic13 PIC_ Small GOT < 2^13 bytes
+// pic32 PIC_ Medium GOT < 2^32 bytes
+//
+// All code models require that the text segment is smaller than 2GB.
+
+static MCCodeGenInfo *createSparcMCCodeGenInfo(StringRef TT, Reloc::Model RM,
+ CodeModel::Model CM,
+ CodeGenOpt::Level OL) {
+ MCCodeGenInfo *X = new MCCodeGenInfo();
+
+ // The default 32-bit code model is abs32/pic32 and the default 32-bit
+ // code model for JIT is abs32.
+ switch (CM) {
+ default: break;
+ case CodeModel::Default:
+ case CodeModel::JITDefault: CM = CodeModel::Small; break;
+ }
+
+ X->initMCCodeGenInfo(RM, CM, OL);
+ return X;
+}
+
+static MCCodeGenInfo *createSparcV9MCCodeGenInfo(StringRef TT, Reloc::Model RM,
+ CodeModel::Model CM,
+ CodeGenOpt::Level OL) {
+ MCCodeGenInfo *X = new MCCodeGenInfo();
+
+ // The default 64-bit code model is abs44/pic32 and the default 64-bit
+ // code model for JIT is abs64.
+ switch (CM) {
+ default: break;
+ case CodeModel::Default:
+ CM = RM == Reloc::PIC_ ? CodeModel::Small : CodeModel::Medium;
+ break;
+ case CodeModel::JITDefault:
+ CM = CodeModel::Large;
+ break;
+ }
+
+ X->initMCCodeGenInfo(RM, CM, OL);
+ return X;
+}
+
+static MCTargetStreamer *
+createObjectTargetStreamer(MCStreamer &S, const MCSubtargetInfo &STI) {
+ return new SparcTargetELFStreamer(S);
+}
+
+static MCTargetStreamer *createTargetAsmStreamer(MCStreamer &S,
+ formatted_raw_ostream &OS,
+ MCInstPrinter *InstPrint,
+ bool isVerboseAsm) {
+ return new SparcTargetAsmStreamer(S, OS);
+}
+
+static MCInstPrinter *createSparcMCInstPrinter(const Triple &T,
+ unsigned SyntaxVariant,
+ const MCAsmInfo &MAI,
+ const MCInstrInfo &MII,
+ const MCRegisterInfo &MRI) {
+ return new SparcInstPrinter(MAI, MII, MRI);
+}
+
+extern "C" void LLVMInitializeSparcTargetMC() {
+ // Register the MC asm info.
+ RegisterMCAsmInfoFn X(TheSparcTarget, createSparcMCAsmInfo);
+ RegisterMCAsmInfoFn Y(TheSparcV9Target, createSparcV9MCAsmInfo);
+ RegisterMCAsmInfoFn Z(TheSparcelTarget, createSparcMCAsmInfo);
+
+ for (Target *T : {&TheSparcTarget, &TheSparcV9Target, &TheSparcelTarget}) {
+ // Register the MC instruction info.
+ TargetRegistry::RegisterMCInstrInfo(*T, createSparcMCInstrInfo);
+
+ // Register the MC register info.
+ TargetRegistry::RegisterMCRegInfo(*T, createSparcMCRegisterInfo);
+
+ // Register the MC subtarget info.
+ TargetRegistry::RegisterMCSubtargetInfo(*T, createSparcMCSubtargetInfo);
+
+ // Register the MC Code Emitter.
+ TargetRegistry::RegisterMCCodeEmitter(*T, createSparcMCCodeEmitter);
+
+ // Register the asm backend.
+ TargetRegistry::RegisterMCAsmBackend(*T, createSparcAsmBackend);
+
+ // Register the object target streamer.
+ TargetRegistry::RegisterObjectTargetStreamer(*T,
+ createObjectTargetStreamer);
+
+ // Register the asm streamer.
+ TargetRegistry::RegisterAsmTargetStreamer(*T, createTargetAsmStreamer);
+
+ // Register the MCInstPrinter
+ TargetRegistry::RegisterMCInstPrinter(*T, createSparcMCInstPrinter);
+ }
+
+ // Register the MC codegen info.
+ TargetRegistry::RegisterMCCodeGenInfo(TheSparcTarget,
+ createSparcMCCodeGenInfo);
+ TargetRegistry::RegisterMCCodeGenInfo(TheSparcV9Target,
+ createSparcV9MCCodeGenInfo);
+ TargetRegistry::RegisterMCCodeGenInfo(TheSparcelTarget,
+ createSparcMCCodeGenInfo);
+}
diff --git a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h
new file mode 100644
index 0000000..8f62de4
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCTargetDesc.h
@@ -0,0 +1,60 @@
+//===-- SparcMCTargetDesc.h - Sparc Target Descriptions ---------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides Sparc specific target descriptions.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_SPARC_MCTARGETDESC_SPARCMCTARGETDESC_H
+#define LLVM_LIB_TARGET_SPARC_MCTARGETDESC_SPARCMCTARGETDESC_H
+
+#include "llvm/Support/DataTypes.h"
+
+namespace llvm {
+class MCAsmBackend;
+class MCCodeEmitter;
+class MCContext;
+class MCInstrInfo;
+class MCObjectWriter;
+class MCRegisterInfo;
+class MCSubtargetInfo;
+class Target;
+class Triple;
+class StringRef;
+class raw_pwrite_stream;
+class raw_ostream;
+
+extern Target TheSparcTarget;
+extern Target TheSparcV9Target;
+extern Target TheSparcelTarget;
+
+MCCodeEmitter *createSparcMCCodeEmitter(const MCInstrInfo &MCII,
+ const MCRegisterInfo &MRI,
+ MCContext &Ctx);
+MCAsmBackend *createSparcAsmBackend(const Target &T, const MCRegisterInfo &MRI,
+ const Triple &TT, StringRef CPU);
+MCObjectWriter *createSparcELFObjectWriter(raw_pwrite_stream &OS, bool Is64Bit,
+ bool IsLIttleEndian, uint8_t OSABI);
+} // namespace llvm
+
+// Defines symbolic names for Sparc registers. This defines a mapping from
+// register name to register number.
+//
+#define GET_REGINFO_ENUM
+#include "SparcGenRegisterInfo.inc"
+
+// Defines symbolic names for the Sparc instructions.
+//
+#define GET_INSTRINFO_ENUM
+#include "SparcGenInstrInfo.inc"
+
+#define GET_SUBTARGETINFO_ENUM
+#include "SparcGenSubtargetInfo.inc"
+
+#endif
diff --git a/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcTargetStreamer.cpp b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcTargetStreamer.cpp
new file mode 100644
index 0000000..94af791
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcTargetStreamer.cpp
@@ -0,0 +1,46 @@
+//===-- SparcTargetStreamer.cpp - Sparc Target Streamer Methods -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file provides Sparc specific target streamer methods.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SparcTargetStreamer.h"
+#include "InstPrinter/SparcInstPrinter.h"
+#include "llvm/Support/FormattedStream.h"
+
+using namespace llvm;
+
+// pin vtable to this file
+SparcTargetStreamer::SparcTargetStreamer(MCStreamer &S) : MCTargetStreamer(S) {}
+
+void SparcTargetStreamer::anchor() {}
+
+SparcTargetAsmStreamer::SparcTargetAsmStreamer(MCStreamer &S,
+ formatted_raw_ostream &OS)
+ : SparcTargetStreamer(S), OS(OS) {}
+
+void SparcTargetAsmStreamer::emitSparcRegisterIgnore(unsigned reg) {
+ OS << "\t.register "
+ << "%" << StringRef(SparcInstPrinter::getRegisterName(reg)).lower()
+ << ", #ignore\n";
+}
+
+void SparcTargetAsmStreamer::emitSparcRegisterScratch(unsigned reg) {
+ OS << "\t.register "
+ << "%" << StringRef(SparcInstPrinter::getRegisterName(reg)).lower()
+ << ", #scratch\n";
+}
+
+SparcTargetELFStreamer::SparcTargetELFStreamer(MCStreamer &S)
+ : SparcTargetStreamer(S) {}
+
+MCELFStreamer &SparcTargetELFStreamer::getStreamer() {
+ return static_cast<MCELFStreamer &>(Streamer);
+}
diff --git a/contrib/llvm/lib/Target/Sparc/Sparc.h b/contrib/llvm/lib/Target/Sparc/Sparc.h
new file mode 100644
index 0000000..133af86
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/Sparc.h
@@ -0,0 +1,134 @@
+//===-- Sparc.h - Top-level interface for Sparc representation --*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the entry points for global functions defined in the LLVM
+// Sparc back-end.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_SPARC_SPARC_H
+#define LLVM_LIB_TARGET_SPARC_SPARC_H
+
+#include "MCTargetDesc/SparcMCTargetDesc.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Target/TargetMachine.h"
+
+namespace llvm {
+ class FunctionPass;
+ class SparcTargetMachine;
+ class formatted_raw_ostream;
+ class AsmPrinter;
+ class MCInst;
+ class MachineInstr;
+
+ FunctionPass *createSparcISelDag(SparcTargetMachine &TM);
+ FunctionPass *createSparcDelaySlotFillerPass(TargetMachine &TM);
+
+ void LowerSparcMachineInstrToMCInst(const MachineInstr *MI,
+ MCInst &OutMI,
+ AsmPrinter &AP);
+} // namespace llvm
+
+namespace llvm {
+ // Enums corresponding to Sparc condition codes, both icc's and fcc's. These
+ // values must be kept in sync with the ones in the .td file.
+ namespace SPCC {
+ enum CondCodes {
+ ICC_A = 8 , // Always
+ ICC_N = 0 , // Never
+ ICC_NE = 9 , // Not Equal
+ ICC_E = 1 , // Equal
+ ICC_G = 10 , // Greater
+ ICC_LE = 2 , // Less or Equal
+ ICC_GE = 11 , // Greater or Equal
+ ICC_L = 3 , // Less
+ ICC_GU = 12 , // Greater Unsigned
+ ICC_LEU = 4 , // Less or Equal Unsigned
+ ICC_CC = 13 , // Carry Clear/Great or Equal Unsigned
+ ICC_CS = 5 , // Carry Set/Less Unsigned
+ ICC_POS = 14 , // Positive
+ ICC_NEG = 6 , // Negative
+ ICC_VC = 15 , // Overflow Clear
+ ICC_VS = 7 , // Overflow Set
+
+ FCC_A = 8+16, // Always
+ FCC_N = 0+16, // Never
+ FCC_U = 7+16, // Unordered
+ FCC_G = 6+16, // Greater
+ FCC_UG = 5+16, // Unordered or Greater
+ FCC_L = 4+16, // Less
+ FCC_UL = 3+16, // Unordered or Less
+ FCC_LG = 2+16, // Less or Greater
+ FCC_NE = 1+16, // Not Equal
+ FCC_E = 9+16, // Equal
+ FCC_UE = 10+16, // Unordered or Equal
+ FCC_GE = 11+16, // Greater or Equal
+ 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
+ };
+ } // namespace SPCC
+
+ inline static const char *SPARCCondCodeToString(SPCC::CondCodes CC) {
+ switch (CC) {
+ case SPCC::ICC_A: return "a";
+ case SPCC::ICC_N: return "n";
+ case SPCC::ICC_NE: return "ne";
+ case SPCC::ICC_E: return "e";
+ case SPCC::ICC_G: return "g";
+ case SPCC::ICC_LE: return "le";
+ case SPCC::ICC_GE: return "ge";
+ case SPCC::ICC_L: return "l";
+ case SPCC::ICC_GU: return "gu";
+ case SPCC::ICC_LEU: return "leu";
+ case SPCC::ICC_CC: return "cc";
+ case SPCC::ICC_CS: return "cs";
+ case SPCC::ICC_POS: return "pos";
+ case SPCC::ICC_NEG: return "neg";
+ case SPCC::ICC_VC: return "vc";
+ case SPCC::ICC_VS: return "vs";
+ case SPCC::FCC_A: return "a";
+ case SPCC::FCC_N: return "n";
+ case SPCC::FCC_U: return "u";
+ case SPCC::FCC_G: return "g";
+ case SPCC::FCC_UG: return "ug";
+ case SPCC::FCC_L: return "l";
+ case SPCC::FCC_UL: return "ul";
+ case SPCC::FCC_LG: return "lg";
+ case SPCC::FCC_NE: return "ne";
+ case SPCC::FCC_E: return "e";
+ case SPCC::FCC_UE: return "ue";
+ case SPCC::FCC_GE: return "ge";
+ case SPCC::FCC_UGE: return "uge";
+ case SPCC::FCC_LE: return "le";
+ case SPCC::FCC_ULE: return "ule";
+ case SPCC::FCC_O: return "o";
+ }
+ llvm_unreachable("Invalid cond code");
+ }
+
+ inline static unsigned HI22(int64_t imm) {
+ return (unsigned)((imm >> 10) & ((1 << 22)-1));
+ }
+
+ inline static unsigned LO10(int64_t imm) {
+ return (unsigned)(imm & 0x3FF);
+ }
+
+ inline static unsigned HIX22(int64_t imm) {
+ return HI22(~imm);
+ }
+
+ inline static unsigned LOX10(int64_t imm) {
+ return ~LO10(~imm);
+ }
+
+} // end namespace llvm
+#endif
diff --git a/contrib/llvm/lib/Target/Sparc/Sparc.td b/contrib/llvm/lib/Target/Sparc/Sparc.td
new file mode 100644
index 0000000..c34122e
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/Sparc.td
@@ -0,0 +1,106 @@
+//===-- Sparc.td - Describe the Sparc Target Machine -------*- tablegen -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Target-independent interfaces which we are implementing
+//===----------------------------------------------------------------------===//
+
+include "llvm/Target/Target.td"
+
+//===----------------------------------------------------------------------===//
+// SPARC Subtarget features.
+//
+
+def FeatureV9
+ : SubtargetFeature<"v9", "IsV9", "true",
+ "Enable SPARC-V9 instructions">;
+def FeatureV8Deprecated
+ : SubtargetFeature<"deprecated-v8", "V8DeprecatedInsts", "true",
+ "Enable deprecated V8 instructions in V9 mode">;
+def FeatureVIS
+ : SubtargetFeature<"vis", "IsVIS", "true",
+ "Enable UltraSPARC Visual Instruction Set extensions">;
+def FeatureVIS2
+ : SubtargetFeature<"vis2", "IsVIS2", "true",
+ "Enable Visual Instruction Set extensions II">;
+def FeatureVIS3
+ : SubtargetFeature<"vis3", "IsVIS3", "true",
+ "Enable Visual Instruction Set extensions III">;
+
+def FeatureHardQuad
+ : SubtargetFeature<"hard-quad-float", "HasHardQuad", "true",
+ "Enable quad-word floating point instructions">;
+
+def UsePopc : SubtargetFeature<"popc", "UsePopc", "true",
+ "Use the popc (population count) instruction">;
+
+//===----------------------------------------------------------------------===//
+// Register File, Calling Conv, Instruction Descriptions
+//===----------------------------------------------------------------------===//
+
+include "SparcRegisterInfo.td"
+include "SparcCallingConv.td"
+include "SparcInstrInfo.td"
+
+def SparcInstrInfo : InstrInfo;
+
+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]>;
+
+
+//===----------------------------------------------------------------------===//
+// Declare the target which we are implementing
+//===----------------------------------------------------------------------===//
+
+def SparcAsmWriter : AsmWriter {
+ string AsmWriterClassName = "InstPrinter";
+ int PassSubtarget = 1;
+ int Variant = 0;
+}
+
+def Sparc : Target {
+ // Pull in Instruction Info:
+ let InstructionSet = SparcInstrInfo;
+ let AssemblyParsers = [SparcAsmParser];
+ let AssemblyWriters = [SparcAsmWriter];
+}
diff --git a/contrib/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp b/contrib/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp
new file mode 100644
index 0000000..c5f046b
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/SparcAsmPrinter.cpp
@@ -0,0 +1,449 @@
+//===-- SparcAsmPrinter.cpp - Sparc LLVM assembly writer ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains a printer that converts from our internal representation
+// of machine-dependent LLVM code to GAS-format SPARC assembly language.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sparc.h"
+#include "InstPrinter/SparcInstPrinter.h"
+#include "MCTargetDesc/SparcMCExpr.h"
+#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"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
+#include "llvm/IR/Mangler.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCInst.h"
+#include "llvm/MC/MCStreamer.h"
+#include "llvm/MC/MCSymbol.h"
+#include "llvm/Support/TargetRegistry.h"
+#include "llvm/Support/raw_ostream.h"
+using namespace llvm;
+
+#define DEBUG_TYPE "asm-printer"
+
+namespace {
+ class SparcAsmPrinter : public AsmPrinter {
+ SparcTargetStreamer &getTargetStreamer() {
+ return static_cast<SparcTargetStreamer &>(
+ *OutStreamer->getTargetStreamer());
+ }
+ public:
+ explicit SparcAsmPrinter(TargetMachine &TM,
+ std::unique_ptr<MCStreamer> Streamer)
+ : AsmPrinter(TM, std::move(Streamer)) {}
+
+ const char *getPassName() const override {
+ return "Sparc Assembly Printer";
+ }
+
+ 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;
+
+ static const char *getRegisterName(unsigned RegNo) {
+ return SparcInstPrinter::getRegisterName(RegNo);
+ }
+
+ bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
+ unsigned AsmVariant, const char *ExtraCode,
+ raw_ostream &O) override;
+ bool PrintAsmMemoryOperand(const MachineInstr *MI, unsigned OpNo,
+ unsigned AsmVariant, const char *ExtraCode,
+ raw_ostream &O) override;
+
+ void LowerGETPCXAndEmitMCInsts(const MachineInstr *MI,
+ const MCSubtargetInfo &STI);
+
+ };
+} // end of anonymous namespace
+
+static MCOperand createSparcMCOperand(SparcMCExpr::VariantKind Kind,
+ MCSymbol *Sym, MCContext &OutContext) {
+ const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::create(Sym,
+ OutContext);
+ const SparcMCExpr *expr = SparcMCExpr::create(Kind, MCSym, OutContext);
+ return MCOperand::createExpr(expr);
+
+}
+static MCOperand createPCXCallOP(MCSymbol *Label,
+ MCContext &OutContext) {
+ return createSparcMCOperand(SparcMCExpr::VK_Sparc_None, Label, OutContext);
+}
+
+static MCOperand createPCXRelExprOp(SparcMCExpr::VariantKind Kind,
+ MCSymbol *GOTLabel, MCSymbol *StartLabel,
+ MCSymbol *CurLabel,
+ MCContext &OutContext)
+{
+ const MCSymbolRefExpr *GOT = MCSymbolRefExpr::create(GOTLabel, OutContext);
+ const MCSymbolRefExpr *Start = MCSymbolRefExpr::create(StartLabel,
+ OutContext);
+ const MCSymbolRefExpr *Cur = MCSymbolRefExpr::create(CurLabel,
+ OutContext);
+
+ const MCBinaryExpr *Sub = MCBinaryExpr::createSub(Cur, Start, OutContext);
+ const MCBinaryExpr *Add = MCBinaryExpr::createAdd(GOT, Sub, OutContext);
+ const SparcMCExpr *expr = SparcMCExpr::create(Kind,
+ Add, OutContext);
+ return MCOperand::createExpr(expr);
+}
+
+static void EmitCall(MCStreamer &OutStreamer,
+ MCOperand &Callee,
+ const MCSubtargetInfo &STI)
+{
+ MCInst CallInst;
+ CallInst.setOpcode(SP::CALL);
+ CallInst.addOperand(Callee);
+ OutStreamer.EmitInstruction(CallInst, STI);
+}
+
+static void EmitSETHI(MCStreamer &OutStreamer,
+ MCOperand &Imm, MCOperand &RD,
+ const MCSubtargetInfo &STI)
+{
+ MCInst SETHIInst;
+ SETHIInst.setOpcode(SP::SETHIi);
+ SETHIInst.addOperand(RD);
+ SETHIInst.addOperand(Imm);
+ OutStreamer.EmitInstruction(SETHIInst, STI);
+}
+
+static void EmitBinary(MCStreamer &OutStreamer, unsigned Opcode,
+ MCOperand &RS1, MCOperand &Src2, MCOperand &RD,
+ const MCSubtargetInfo &STI)
+{
+ MCInst Inst;
+ Inst.setOpcode(Opcode);
+ Inst.addOperand(RD);
+ Inst.addOperand(RS1);
+ Inst.addOperand(Src2);
+ OutStreamer.EmitInstruction(Inst, STI);
+}
+
+static void EmitOR(MCStreamer &OutStreamer,
+ MCOperand &RS1, MCOperand &Imm, MCOperand &RD,
+ const MCSubtargetInfo &STI) {
+ EmitBinary(OutStreamer, SP::ORri, RS1, Imm, RD, STI);
+}
+
+static void EmitADD(MCStreamer &OutStreamer,
+ MCOperand &RS1, MCOperand &RS2, MCOperand &RD,
+ const MCSubtargetInfo &STI) {
+ EmitBinary(OutStreamer, SP::ADDrr, RS1, RS2, RD, STI);
+}
+
+static void EmitSHL(MCStreamer &OutStreamer,
+ MCOperand &RS1, MCOperand &Imm, MCOperand &RD,
+ const MCSubtargetInfo &STI) {
+ EmitBinary(OutStreamer, SP::SLLri, RS1, Imm, RD, STI);
+}
+
+
+static void EmitHiLo(MCStreamer &OutStreamer, MCSymbol *GOTSym,
+ SparcMCExpr::VariantKind HiKind,
+ SparcMCExpr::VariantKind LoKind,
+ MCOperand &RD,
+ MCContext &OutContext,
+ const MCSubtargetInfo &STI) {
+
+ MCOperand hi = createSparcMCOperand(HiKind, GOTSym, OutContext);
+ MCOperand lo = createSparcMCOperand(LoKind, GOTSym, OutContext);
+ EmitSETHI(OutStreamer, hi, RD, STI);
+ EmitOR(OutStreamer, RD, lo, RD, STI);
+}
+
+void SparcAsmPrinter::LowerGETPCXAndEmitMCInsts(const MachineInstr *MI,
+ const MCSubtargetInfo &STI)
+{
+ MCSymbol *GOTLabel =
+ OutContext.getOrCreateSymbol(Twine("_GLOBAL_OFFSET_TABLE_"));
+
+ const MachineOperand &MO = MI->getOperand(0);
+ assert(MO.getReg() != SP::O7 &&
+ "%o7 is assigned as destination for getpcx!");
+
+ MCOperand MCRegOP = MCOperand::createReg(MO.getReg());
+
+
+ if (TM.getRelocationModel() != Reloc::PIC_) {
+ // Just load the address of GOT to MCRegOP.
+ switch(TM.getCodeModel()) {
+ default:
+ llvm_unreachable("Unsupported absolute code model");
+ case CodeModel::Small:
+ EmitHiLo(*OutStreamer, GOTLabel,
+ SparcMCExpr::VK_Sparc_HI, SparcMCExpr::VK_Sparc_LO,
+ MCRegOP, OutContext, STI);
+ break;
+ case CodeModel::Medium: {
+ EmitHiLo(*OutStreamer, GOTLabel,
+ SparcMCExpr::VK_Sparc_H44, SparcMCExpr::VK_Sparc_M44,
+ MCRegOP, OutContext, STI);
+ MCOperand imm = MCOperand::createExpr(MCConstantExpr::create(12,
+ OutContext));
+ EmitSHL(*OutStreamer, MCRegOP, imm, MCRegOP, STI);
+ MCOperand lo = createSparcMCOperand(SparcMCExpr::VK_Sparc_L44,
+ GOTLabel, OutContext);
+ EmitOR(*OutStreamer, MCRegOP, lo, MCRegOP, STI);
+ break;
+ }
+ case CodeModel::Large: {
+ EmitHiLo(*OutStreamer, GOTLabel,
+ SparcMCExpr::VK_Sparc_HH, SparcMCExpr::VK_Sparc_HM,
+ MCRegOP, OutContext, STI);
+ MCOperand imm = MCOperand::createExpr(MCConstantExpr::create(32,
+ OutContext));
+ EmitSHL(*OutStreamer, MCRegOP, imm, MCRegOP, STI);
+ // Use register %o7 to load the lower 32 bits.
+ MCOperand RegO7 = MCOperand::createReg(SP::O7);
+ EmitHiLo(*OutStreamer, GOTLabel,
+ SparcMCExpr::VK_Sparc_HI, SparcMCExpr::VK_Sparc_LO,
+ RegO7, OutContext, STI);
+ EmitADD(*OutStreamer, MCRegOP, RegO7, MCRegOP, STI);
+ }
+ }
+ return;
+ }
+
+ MCSymbol *StartLabel = OutContext.createTempSymbol();
+ MCSymbol *EndLabel = OutContext.createTempSymbol();
+ MCSymbol *SethiLabel = OutContext.createTempSymbol();
+
+ MCOperand RegO7 = MCOperand::createReg(SP::O7);
+
+ // <StartLabel>:
+ // call <EndLabel>
+ // <SethiLabel>:
+ // sethi %hi(_GLOBAL_OFFSET_TABLE_+(<SethiLabel>-<StartLabel>)), <MO>
+ // <EndLabel>:
+ // or <MO>, %lo(_GLOBAL_OFFSET_TABLE_+(<EndLabel>-<StartLabel>))), <MO>
+ // add <MO>, %o7, <MO>
+
+ OutStreamer->EmitLabel(StartLabel);
+ MCOperand Callee = createPCXCallOP(EndLabel, OutContext);
+ EmitCall(*OutStreamer, Callee, STI);
+ OutStreamer->EmitLabel(SethiLabel);
+ MCOperand hiImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_PC22,
+ GOTLabel, StartLabel, SethiLabel,
+ OutContext);
+ EmitSETHI(*OutStreamer, hiImm, MCRegOP, STI);
+ OutStreamer->EmitLabel(EndLabel);
+ MCOperand loImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_PC10,
+ GOTLabel, StartLabel, EndLabel,
+ OutContext);
+ EmitOR(*OutStreamer, MCRegOP, loImm, MCRegOP, STI);
+ EmitADD(*OutStreamer, MCRegOP, RegO7, MCRegOP, STI);
+}
+
+void SparcAsmPrinter::EmitInstruction(const MachineInstr *MI)
+{
+
+ switch (MI->getOpcode()) {
+ default: break;
+ case TargetOpcode::DBG_VALUE:
+ // FIXME: Debug Value.
+ return;
+ case SP::GETPCX:
+ LowerGETPCXAndEmitMCInsts(MI, getSubtargetInfo());
+ return;
+ }
+ MachineBasicBlock::const_instr_iterator I = MI;
+ MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();
+ do {
+ MCInst TmpInst;
+ LowerSparcMachineInstrToMCInst(I, TmpInst, *this);
+ EmitToStreamer(*OutStreamer, TmpInst);
+ } while ((++I != E) && I->isInsideBundle()); // Delay slot check.
+}
+
+void SparcAsmPrinter::EmitFunctionBodyStart() {
+ if (!MF->getSubtarget<SparcSubtarget>().is64Bit())
+ return;
+
+ const MachineRegisterInfo &MRI = MF->getRegInfo();
+ const unsigned globalRegs[] = { SP::G2, SP::G3, SP::G6, SP::G7, 0 };
+ for (unsigned i = 0; globalRegs[i] != 0; ++i) {
+ unsigned reg = globalRegs[i];
+ if (MRI.use_empty(reg))
+ continue;
+
+ if (reg == SP::G6 || reg == SP::G7)
+ getTargetStreamer().emitSparcRegisterIgnore(reg);
+ else
+ getTargetStreamer().emitSparcRegisterScratch(reg);
+ }
+}
+
+void SparcAsmPrinter::printOperand(const MachineInstr *MI, int opNum,
+ raw_ostream &O) {
+ const DataLayout *DL = TM.getDataLayout();
+ const MachineOperand &MO = MI->getOperand (opNum);
+ SparcMCExpr::VariantKind TF = (SparcMCExpr::VariantKind) MO.getTargetFlags();
+
+#ifndef NDEBUG
+ // Verify the target flags.
+ if (MO.isGlobal() || MO.isSymbol() || MO.isCPI()) {
+ if (MI->getOpcode() == SP::CALL)
+ assert(TF == SparcMCExpr::VK_Sparc_None &&
+ "Cannot handle target flags on call address");
+ else if (MI->getOpcode() == SP::SETHIi || MI->getOpcode() == SP::SETHIXi)
+ assert((TF == SparcMCExpr::VK_Sparc_HI
+ || TF == SparcMCExpr::VK_Sparc_H44
+ || TF == SparcMCExpr::VK_Sparc_HH
+ || TF == SparcMCExpr::VK_Sparc_TLS_GD_HI22
+ || TF == SparcMCExpr::VK_Sparc_TLS_LDM_HI22
+ || TF == SparcMCExpr::VK_Sparc_TLS_LDO_HIX22
+ || TF == SparcMCExpr::VK_Sparc_TLS_IE_HI22
+ || TF == SparcMCExpr::VK_Sparc_TLS_LE_HIX22) &&
+ "Invalid target flags for address operand on sethi");
+ else if (MI->getOpcode() == SP::TLS_CALL)
+ assert((TF == SparcMCExpr::VK_Sparc_None
+ || TF == SparcMCExpr::VK_Sparc_TLS_GD_CALL
+ || TF == SparcMCExpr::VK_Sparc_TLS_LDM_CALL) &&
+ "Cannot handle target flags on tls call address");
+ else if (MI->getOpcode() == SP::TLS_ADDrr)
+ assert((TF == SparcMCExpr::VK_Sparc_TLS_GD_ADD
+ || TF == SparcMCExpr::VK_Sparc_TLS_LDM_ADD
+ || TF == SparcMCExpr::VK_Sparc_TLS_LDO_ADD
+ || TF == SparcMCExpr::VK_Sparc_TLS_IE_ADD) &&
+ "Cannot handle target flags on add for TLS");
+ else if (MI->getOpcode() == SP::TLS_LDrr)
+ assert(TF == SparcMCExpr::VK_Sparc_TLS_IE_LD &&
+ "Cannot handle target flags on ld for TLS");
+ else if (MI->getOpcode() == SP::TLS_LDXrr)
+ assert(TF == SparcMCExpr::VK_Sparc_TLS_IE_LDX &&
+ "Cannot handle target flags on ldx for TLS");
+ else if (MI->getOpcode() == SP::XORri || MI->getOpcode() == SP::XORXri)
+ assert((TF == SparcMCExpr::VK_Sparc_TLS_LDO_LOX10
+ || TF == SparcMCExpr::VK_Sparc_TLS_LE_LOX10) &&
+ "Cannot handle target flags on xor for TLS");
+ else
+ assert((TF == SparcMCExpr::VK_Sparc_LO
+ || TF == SparcMCExpr::VK_Sparc_M44
+ || TF == SparcMCExpr::VK_Sparc_L44
+ || TF == SparcMCExpr::VK_Sparc_HM
+ || TF == SparcMCExpr::VK_Sparc_TLS_GD_LO10
+ || TF == SparcMCExpr::VK_Sparc_TLS_LDM_LO10
+ || TF == SparcMCExpr::VK_Sparc_TLS_IE_LO10 ) &&
+ "Invalid target flags for small address operand");
+ }
+#endif
+
+
+ bool CloseParen = SparcMCExpr::printVariantKind(O, TF);
+
+ switch (MO.getType()) {
+ case MachineOperand::MO_Register:
+ O << "%" << StringRef(getRegisterName(MO.getReg())).lower();
+ break;
+
+ case MachineOperand::MO_Immediate:
+ O << (int)MO.getImm();
+ break;
+ case MachineOperand::MO_MachineBasicBlock:
+ MO.getMBB()->getSymbol()->print(O, MAI);
+ return;
+ case MachineOperand::MO_GlobalAddress:
+ getSymbol(MO.getGlobal())->print(O, MAI);
+ break;
+ case MachineOperand::MO_BlockAddress:
+ O << GetBlockAddressSymbol(MO.getBlockAddress())->getName();
+ break;
+ case MachineOperand::MO_ExternalSymbol:
+ O << MO.getSymbolName();
+ break;
+ case MachineOperand::MO_ConstantPoolIndex:
+ O << DL->getPrivateGlobalPrefix() << "CPI" << getFunctionNumber() << "_"
+ << MO.getIndex();
+ break;
+ default:
+ llvm_unreachable("<unknown operand type>");
+ }
+ if (CloseParen) O << ")";
+}
+
+void SparcAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum,
+ raw_ostream &O, const char *Modifier) {
+ printOperand(MI, opNum, O);
+
+ // If this is an ADD operand, emit it like normal operands.
+ if (Modifier && !strcmp(Modifier, "arith")) {
+ O << ", ";
+ printOperand(MI, opNum+1, O);
+ return;
+ }
+
+ if (MI->getOperand(opNum+1).isReg() &&
+ MI->getOperand(opNum+1).getReg() == SP::G0)
+ return; // don't print "+%g0"
+ if (MI->getOperand(opNum+1).isImm() &&
+ MI->getOperand(opNum+1).getImm() == 0)
+ return; // don't print "+0"
+
+ O << "+";
+ printOperand(MI, opNum+1, O);
+}
+
+/// PrintAsmOperand - Print out an operand for an inline asm expression.
+///
+bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
+ unsigned AsmVariant,
+ const char *ExtraCode,
+ raw_ostream &O) {
+ if (ExtraCode && ExtraCode[0]) {
+ if (ExtraCode[1] != 0) return true; // Unknown modifier.
+
+ switch (ExtraCode[0]) {
+ default:
+ // See if this is a generic print operand
+ return AsmPrinter::PrintAsmOperand(MI, OpNo, AsmVariant, ExtraCode, O);
+ case 'r':
+ break;
+ }
+ }
+
+ printOperand(MI, OpNo, O);
+
+ return false;
+}
+
+bool SparcAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
+ unsigned OpNo, unsigned AsmVariant,
+ const char *ExtraCode,
+ raw_ostream &O) {
+ if (ExtraCode && ExtraCode[0])
+ return true; // Unknown modifier
+
+ O << '[';
+ printMemOperand(MI, OpNo, O);
+ O << ']';
+
+ return false;
+}
+
+// Force static initialization.
+extern "C" void LLVMInitializeSparcAsmPrinter() {
+ RegisterAsmPrinter<SparcAsmPrinter> X(TheSparcTarget);
+ RegisterAsmPrinter<SparcAsmPrinter> Y(TheSparcV9Target);
+ RegisterAsmPrinter<SparcAsmPrinter> Z(TheSparcelTarget);
+}
diff --git a/contrib/llvm/lib/Target/Sparc/SparcCallingConv.td b/contrib/llvm/lib/Target/Sparc/SparcCallingConv.td
new file mode 100644
index 0000000..dfaaabf
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/SparcCallingConv.td
@@ -0,0 +1,139 @@
+//===-- SparcCallingConv.td - Calling Conventions Sparc ----*- tablegen -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This describes the calling conventions for the Sparc architectures.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// SPARC v8 32-bit.
+//===----------------------------------------------------------------------===//
+
+def CC_Sparc32 : CallingConv<[
+ // Custom assign SRet to [sp+64].
+ CCIfSRet<CCCustom<"CC_Sparc_Assign_SRet">>,
+ // i32 f32 arguments get passed in integer registers if there is space.
+ CCIfType<[i32, f32], CCAssignToReg<[I0, I1, I2, I3, I4, I5]>>,
+ // f64 arguments are split and passed through registers or through stack.
+ CCIfType<[f64], CCCustom<"CC_Sparc_Assign_f64">>,
+
+ // Alternatively, they are assigned to the stack in 4-byte aligned units.
+ CCAssignToStack<4, 4>
+]>;
+
+def RetCC_Sparc32 : CallingConv<[
+ CCIfType<[i32], CCAssignToReg<[I0, I1, I2, I3, I4, I5]>>,
+ CCIfType<[f32], CCAssignToReg<[F0, F1, F2, F3]>>,
+ CCIfType<[f64], CCAssignToReg<[D0, D1]>>
+]>;
+
+
+//===----------------------------------------------------------------------===//
+// SPARC v9 64-bit.
+//===----------------------------------------------------------------------===//
+//
+// The 64-bit ABI conceptually assigns all function arguments to a parameter
+// array starting at [%fp+BIAS+128] in the callee's stack frame. All arguments
+// occupy a multiple of 8 bytes in the array. Integer arguments are extended to
+// 64 bits by the caller. Floats are right-aligned in their 8-byte slot, the
+// first 4 bytes in the slot are undefined.
+//
+// The integer registers %i0 to %i5 shadow the first 48 bytes of the parameter
+// array at fixed offsets. Integer arguments are promoted to registers when
+// possible.
+//
+// The floating point registers %f0 to %f31 shadow the first 128 bytes of the
+// parameter array at fixed offsets. Float and double parameters are promoted
+// to these registers when possible.
+//
+// Structs up to 16 bytes in size are passed by value. They are right-aligned
+// in one or two 8-byte slots in the parameter array. Struct members are
+// promoted to both floating point and integer registers when possible. A
+// struct containing two floats would thus be passed in %f0 and %f1, while two
+// float function arguments would occupy 8 bytes each, and be passed in %f1 and
+// %f3.
+//
+// When a struct { int, float } is passed by value, the int goes in the high
+// bits of an integer register while the float goes in a floating point
+// register.
+//
+// The difference is encoded in LLVM IR using the inreg atttribute on function
+// arguments:
+//
+// C: void f(float, float);
+// IR: declare void f(float %f1, float %f3)
+//
+// C: void f(struct { float f0, f1; });
+// IR: declare void f(float inreg %f0, float inreg %f1)
+//
+// C: void f(int, float);
+// IR: declare void f(int signext %i0, float %f3)
+//
+// C: void f(struct { int i0high; float f1; });
+// IR: declare void f(i32 inreg %i0high, float inreg %f1)
+//
+// Two ints in a struct are simply coerced to i64:
+//
+// C: void f(struct { int i0high, i0low; });
+// IR: declare void f(i64 %i0.coerced)
+//
+// The frontend and backend divide the task of producing ABI compliant code for
+// C functions. The C frontend will:
+//
+// - Annotate integer arguments with zeroext or signext attributes.
+//
+// - Split structs into one or two 64-bit sized chunks, or 32-bit chunks with
+// inreg attributes.
+//
+// - Pass structs larger than 16 bytes indirectly with an explicit pointer
+// argument. The byval attribute is not used.
+//
+// The backend will:
+//
+// - Assign all arguments to 64-bit aligned stack slots, 32-bits for inreg.
+//
+// - Promote to integer or floating point registers depending on type.
+//
+// Function return values are passed exactly like function arguments, except a
+// struct up to 32 bytes in size can be returned in registers.
+
+// Function arguments AND most return values.
+def CC_Sparc64 : CallingConv<[
+ // The frontend uses the inreg flag to indicate i32 and float arguments from
+ // structs. These arguments are not promoted to 64 bits, but they can still
+ // be assigned to integer and float registers.
+ CCIfInReg<CCIfType<[i32, f32], CCCustom<"CC_Sparc64_Half">>>,
+
+ // All integers are promoted to i64 by the caller.
+ CCIfType<[i32], CCPromoteToType<i64>>,
+
+ // Custom assignment is required because stack space is reserved for all
+ // arguments whether they are passed in registers or not.
+ CCCustom<"CC_Sparc64_Full">
+]>;
+
+def RetCC_Sparc64 : CallingConv<[
+ // A single f32 return value always goes in %f0. The ABI doesn't specify what
+ // happens to multiple f32 return values outside a struct.
+ CCIfType<[f32], CCCustom<"CC_Sparc64_Half">>,
+
+ // Otherwise, return values are passed exactly like arguments.
+ CCDelegateTo<CC_Sparc64>
+]>;
+
+// Callee-saved registers are handled by the register window mechanism.
+def CSR : CalleeSavedRegs<(add)> {
+ let OtherPreserved = (add (sequence "I%u", 0, 7),
+ (sequence "L%u", 0, 7));
+}
+
+// Callee-saved registers for calls with ReturnsTwice attribute.
+def RTCSR : CalleeSavedRegs<(add)> {
+ let OtherPreserved = (add I6, I7);
+}
diff --git a/contrib/llvm/lib/Target/Sparc/SparcFrameLowering.cpp b/contrib/llvm/lib/Target/Sparc/SparcFrameLowering.cpp
new file mode 100644
index 0000000..bccc6bd
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/SparcFrameLowering.cpp
@@ -0,0 +1,260 @@
+//===-- SparcFrameLowering.cpp - Sparc Frame Information ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the Sparc implementation of TargetFrameLowering class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SparcFrameLowering.h"
+#include "SparcInstrInfo.h"
+#include "SparcMachineFunctionInfo.h"
+#include "SparcSubtarget.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineModuleInfo.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/IR/Function.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Target/TargetOptions.h"
+
+using namespace llvm;
+
+static cl::opt<bool>
+DisableLeafProc("disable-sparc-leaf-proc",
+ cl::init(false),
+ cl::desc("Disable Sparc leaf procedure optimization."),
+ cl::Hidden);
+
+SparcFrameLowering::SparcFrameLowering(const SparcSubtarget &ST)
+ : TargetFrameLowering(TargetFrameLowering::StackGrowsDown,
+ ST.is64Bit() ? 16 : 8, 0, ST.is64Bit() ? 16 : 8) {}
+
+void SparcFrameLowering::emitSPAdjustment(MachineFunction &MF,
+ MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI,
+ int NumBytes,
+ unsigned ADDrr,
+ unsigned ADDri) const {
+
+ DebugLoc dl = (MBBI != MBB.end()) ? MBBI->getDebugLoc() : DebugLoc();
+ const SparcInstrInfo &TII =
+ *static_cast<const SparcInstrInfo *>(MF.getSubtarget().getInstrInfo());
+
+ if (NumBytes >= -4096 && NumBytes < 4096) {
+ BuildMI(MBB, MBBI, dl, TII.get(ADDri), SP::O6)
+ .addReg(SP::O6).addImm(NumBytes);
+ return;
+ }
+
+ // Emit this the hard way. This clobbers G1 which we always know is
+ // available here.
+ if (NumBytes >= 0) {
+ // Emit nonnegative numbers with sethi + or.
+ // sethi %hi(NumBytes), %g1
+ // or %g1, %lo(NumBytes), %g1
+ // add %sp, %g1, %sp
+ BuildMI(MBB, MBBI, dl, TII.get(SP::SETHIi), SP::G1)
+ .addImm(HI22(NumBytes));
+ BuildMI(MBB, MBBI, dl, TII.get(SP::ORri), SP::G1)
+ .addReg(SP::G1).addImm(LO10(NumBytes));
+ BuildMI(MBB, MBBI, dl, TII.get(ADDrr), SP::O6)
+ .addReg(SP::O6).addReg(SP::G1);
+ return ;
+ }
+
+ // Emit negative numbers with sethi + xor.
+ // sethi %hix(NumBytes), %g1
+ // xor %g1, %lox(NumBytes), %g1
+ // add %sp, %g1, %sp
+ BuildMI(MBB, MBBI, dl, TII.get(SP::SETHIi), SP::G1)
+ .addImm(HIX22(NumBytes));
+ BuildMI(MBB, MBBI, dl, TII.get(SP::XORri), SP::G1)
+ .addReg(SP::G1).addImm(LOX10(NumBytes));
+ BuildMI(MBB, MBBI, dl, TII.get(ADDrr), SP::O6)
+ .addReg(SP::O6).addReg(SP::G1);
+}
+
+void SparcFrameLowering::emitPrologue(MachineFunction &MF,
+ MachineBasicBlock &MBB) const {
+ SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>();
+
+ assert(&MF.front() == &MBB && "Shrink-wrapping not yet supported");
+ MachineFrameInfo *MFI = MF.getFrameInfo();
+ const SparcInstrInfo &TII =
+ *static_cast<const SparcInstrInfo *>(MF.getSubtarget().getInstrInfo());
+ MachineBasicBlock::iterator MBBI = MBB.begin();
+ DebugLoc dl = MBBI != MBB.end() ? MBBI->getDebugLoc() : DebugLoc();
+
+ // Get the number of bytes to allocate from the FrameInfo
+ int NumBytes = (int) MFI->getStackSize();
+
+ unsigned SAVEri = SP::SAVEri;
+ unsigned SAVErr = SP::SAVErr;
+ if (FuncInfo->isLeafProc()) {
+ if (NumBytes == 0)
+ return;
+ SAVEri = SP::ADDri;
+ SAVErr = SP::ADDrr;
+ }
+ NumBytes = -MF.getSubtarget<SparcSubtarget>().getAdjustedFrameSize(NumBytes);
+ emitSPAdjustment(MF, MBB, MBBI, NumBytes, SAVErr, SAVEri);
+
+ MachineModuleInfo &MMI = MF.getMMI();
+ const MCRegisterInfo *MRI = MMI.getContext().getRegisterInfo();
+ unsigned regFP = MRI->getDwarfRegNum(SP::I6, true);
+
+ // Emit ".cfi_def_cfa_register 30".
+ unsigned CFIIndex =
+ MMI.addFrameInst(MCCFIInstruction::createDefCfaRegister(nullptr, regFP));
+ BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
+ .addCFIIndex(CFIIndex);
+
+ // Emit ".cfi_window_save".
+ CFIIndex = MMI.addFrameInst(MCCFIInstruction::createWindowSave(nullptr));
+ BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
+ .addCFIIndex(CFIIndex);
+
+ unsigned regInRA = MRI->getDwarfRegNum(SP::I7, true);
+ unsigned regOutRA = MRI->getDwarfRegNum(SP::O7, true);
+ // Emit ".cfi_register 15, 31".
+ CFIIndex = MMI.addFrameInst(
+ MCCFIInstruction::createRegister(nullptr, regOutRA, regInRA));
+ BuildMI(MBB, MBBI, dl, TII.get(TargetOpcode::CFI_INSTRUCTION))
+ .addCFIIndex(CFIIndex);
+}
+
+void SparcFrameLowering::
+eliminateCallFramePseudoInstr(MachineFunction &MF, MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I) const {
+ if (!hasReservedCallFrame(MF)) {
+ MachineInstr &MI = *I;
+ int Size = MI.getOperand(0).getImm();
+ if (MI.getOpcode() == SP::ADJCALLSTACKDOWN)
+ Size = -Size;
+
+ if (Size)
+ emitSPAdjustment(MF, MBB, I, Size, SP::ADDrr, SP::ADDri);
+ }
+ MBB.erase(I);
+}
+
+
+void SparcFrameLowering::emitEpilogue(MachineFunction &MF,
+ MachineBasicBlock &MBB) const {
+ SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>();
+ MachineBasicBlock::iterator MBBI = MBB.getLastNonDebugInstr();
+ const SparcInstrInfo &TII =
+ *static_cast<const SparcInstrInfo *>(MF.getSubtarget().getInstrInfo());
+ DebugLoc dl = MBBI->getDebugLoc();
+ assert(MBBI->getOpcode() == SP::RETL &&
+ "Can only put epilog before 'retl' instruction!");
+ if (!FuncInfo->isLeafProc()) {
+ BuildMI(MBB, MBBI, dl, TII.get(SP::RESTORErr), SP::G0).addReg(SP::G0)
+ .addReg(SP::G0);
+ return;
+ }
+ MachineFrameInfo *MFI = MF.getFrameInfo();
+
+ int NumBytes = (int) MFI->getStackSize();
+ if (NumBytes == 0)
+ return;
+
+ NumBytes = MF.getSubtarget<SparcSubtarget>().getAdjustedFrameSize(NumBytes);
+ emitSPAdjustment(MF, MBB, MBBI, NumBytes, SP::ADDrr, SP::ADDri);
+}
+
+bool SparcFrameLowering::hasReservedCallFrame(const MachineFunction &MF) const {
+ // Reserve call frame if there are no variable sized objects on the stack.
+ return !MF.getFrameInfo()->hasVarSizedObjects();
+}
+
+// hasFP - Return true if the specified function should have a dedicated frame
+// pointer register. This is true if the function has variable sized allocas or
+// if frame pointer elimination is disabled.
+bool SparcFrameLowering::hasFP(const MachineFunction &MF) const {
+ const MachineFrameInfo *MFI = MF.getFrameInfo();
+ return MF.getTarget().Options.DisableFramePointerElim(MF) ||
+ MFI->hasVarSizedObjects() || MFI->isFrameAddressTaken();
+}
+
+
+static bool LLVM_ATTRIBUTE_UNUSED verifyLeafProcRegUse(MachineRegisterInfo *MRI)
+{
+
+ for (unsigned reg = SP::I0; reg <= SP::I7; ++reg)
+ if (MRI->isPhysRegUsed(reg))
+ return false;
+
+ for (unsigned reg = SP::L0; reg <= SP::L7; ++reg)
+ if (MRI->isPhysRegUsed(reg))
+ return false;
+
+ return true;
+}
+
+bool SparcFrameLowering::isLeafProc(MachineFunction &MF) const
+{
+
+ MachineRegisterInfo &MRI = MF.getRegInfo();
+ MachineFrameInfo *MFI = MF.getFrameInfo();
+
+ return !(MFI->hasCalls() // has calls
+ || MRI.isPhysRegUsed(SP::L0) // Too many registers needed
+ || MRI.isPhysRegUsed(SP::O6) // %SP is used
+ || hasFP(MF)); // need %FP
+}
+
+void SparcFrameLowering::remapRegsForLeafProc(MachineFunction &MF) const {
+
+ MachineRegisterInfo &MRI = MF.getRegInfo();
+
+ // Remap %i[0-7] to %o[0-7].
+ for (unsigned reg = SP::I0; reg <= SP::I7; ++reg) {
+ if (!MRI.isPhysRegUsed(reg))
+ continue;
+ unsigned mapped_reg = (reg - SP::I0 + SP::O0);
+ assert(!MRI.isPhysRegUsed(mapped_reg));
+
+ // Replace I register with O register.
+ MRI.replaceRegWith(reg, mapped_reg);
+
+ // Mark the reg unused.
+ MRI.setPhysRegUnused(reg);
+ }
+
+ // Rewrite MBB's Live-ins.
+ for (MachineFunction::iterator MBB = MF.begin(), E = MF.end();
+ MBB != E; ++MBB) {
+ for (unsigned reg = SP::I0; reg <= SP::I7; ++reg) {
+ if (!MBB->isLiveIn(reg))
+ continue;
+ MBB->removeLiveIn(reg);
+ MBB->addLiveIn(reg - SP::I0 + SP::O0);
+ }
+ }
+
+ assert(verifyLeafProcRegUse(&MRI));
+#ifdef XDEBUG
+ MF.verify(0, "After LeafProc Remapping");
+#endif
+}
+
+void SparcFrameLowering::processFunctionBeforeCalleeSavedScan
+ (MachineFunction &MF, RegScavenger *RS) const {
+
+ if (!DisableLeafProc && isLeafProc(MF)) {
+ SparcMachineFunctionInfo *MFI = MF.getInfo<SparcMachineFunctionInfo>();
+ MFI->setLeafProc(true);
+
+ remapRegsForLeafProc(MF);
+ }
+
+}
diff --git a/contrib/llvm/lib/Target/Sparc/SparcFrameLowering.h b/contrib/llvm/lib/Target/Sparc/SparcFrameLowering.h
new file mode 100644
index 0000000..3d73bbd
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/SparcFrameLowering.h
@@ -0,0 +1,60 @@
+//===-- SparcFrameLowering.h - Define frame lowering for Sparc --*- C++ -*-===//
+//
+// 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_SPARCFRAMELOWERING_H
+#define LLVM_LIB_TARGET_SPARC_SPARCFRAMELOWERING_H
+
+#include "Sparc.h"
+#include "llvm/Target/TargetFrameLowering.h"
+
+namespace llvm {
+
+class SparcSubtarget;
+class SparcFrameLowering : public TargetFrameLowering {
+public:
+ explicit SparcFrameLowering(const SparcSubtarget &ST);
+
+ /// emitProlog/emitEpilog - These methods insert prolog and epilog code into
+ /// the function.
+ void emitPrologue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
+ void emitEpilogue(MachineFunction &MF, MachineBasicBlock &MBB) const override;
+
+ void
+ eliminateCallFramePseudoInstr(MachineFunction &MF,
+ MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I) const override;
+
+ bool hasReservedCallFrame(const MachineFunction &MF) const override;
+ bool hasFP(const MachineFunction &MF) const override;
+ void processFunctionBeforeCalleeSavedScan(MachineFunction &MF,
+ RegScavenger *RS = nullptr) const override;
+
+private:
+ // Remap input registers to output registers for leaf procedure.
+ void remapRegsForLeafProc(MachineFunction &MF) const;
+
+ // Returns true if MF is a leaf procedure.
+ bool isLeafProc(MachineFunction &MF) const;
+
+
+ // Emits code for adjusting SP in function prologue/epilogue.
+ void emitSPAdjustment(MachineFunction &MF,
+ MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI,
+ int NumBytes, unsigned ADDrr, unsigned ADDri) const;
+
+};
+
+} // namespace llvm
+
+#endif
diff --git a/contrib/llvm/lib/Target/Sparc/SparcISelDAGToDAG.cpp b/contrib/llvm/lib/Target/Sparc/SparcISelDAGToDAG.cpp
new file mode 100644
index 0000000..9c594a9
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/SparcISelDAGToDAG.cpp
@@ -0,0 +1,226 @@
+//===-- SparcISelDAGToDAG.cpp - A dag to dag inst selector for Sparc ------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines an instruction selector for the SPARC target.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SparcTargetMachine.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"
+using namespace llvm;
+
+//===----------------------------------------------------------------------===//
+// Instruction Selector Implementation
+//===----------------------------------------------------------------------===//
+
+//===--------------------------------------------------------------------===//
+/// SparcDAGToDAGISel - SPARC specific code to select SPARC machine
+/// instructions for SelectionDAG operations.
+///
+namespace {
+class SparcDAGToDAGISel : public SelectionDAGISel {
+ /// Subtarget - Keep a pointer to the Sparc Subtarget around so that we can
+ /// make the right decision when generating code for different targets.
+ const SparcSubtarget *Subtarget;
+public:
+ explicit SparcDAGToDAGISel(SparcTargetMachine &tm) : SelectionDAGISel(tm) {}
+
+ bool runOnMachineFunction(MachineFunction &MF) override {
+ Subtarget = &MF.getSubtarget<SparcSubtarget>();
+ return SelectionDAGISel::runOnMachineFunction(MF);
+ }
+
+ SDNode *Select(SDNode *N) override;
+
+ // Complex Pattern Selectors.
+ bool SelectADDRrr(SDValue N, SDValue &R1, SDValue &R2);
+ bool SelectADDRri(SDValue N, SDValue &Base, SDValue &Offset);
+
+ /// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
+ /// inline asm expressions.
+ bool SelectInlineAsmMemoryOperand(const SDValue &Op,
+ unsigned ConstraintID,
+ std::vector<SDValue> &OutOps) override;
+
+ const char *getPassName() const override {
+ return "SPARC DAG->DAG Pattern Instruction Selection";
+ }
+
+ // Include the pieces autogenerated from the target description.
+#include "SparcGenDAGISel.inc"
+
+private:
+ SDNode* getGlobalBaseReg();
+};
+} // end anonymous namespace
+
+SDNode* SparcDAGToDAGISel::getGlobalBaseReg() {
+ unsigned GlobalBaseReg = Subtarget->getInstrInfo()->getGlobalBaseReg(MF);
+ return CurDAG->getRegister(GlobalBaseReg, TLI->getPointerTy()).getNode();
+}
+
+bool SparcDAGToDAGISel::SelectADDRri(SDValue Addr,
+ SDValue &Base, SDValue &Offset) {
+ if (FrameIndexSDNode *FIN = dyn_cast<FrameIndexSDNode>(Addr)) {
+ Base = CurDAG->getTargetFrameIndex(FIN->getIndex(), TLI->getPointerTy());
+ Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
+ return true;
+ }
+ if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
+ Addr.getOpcode() == ISD::TargetGlobalAddress ||
+ Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
+ return false; // direct calls.
+
+ if (Addr.getOpcode() == ISD::ADD) {
+ if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1))) {
+ if (isInt<13>(CN->getSExtValue())) {
+ if (FrameIndexSDNode *FIN =
+ dyn_cast<FrameIndexSDNode>(Addr.getOperand(0))) {
+ // Constant offset from frame ref.
+ Base =
+ CurDAG->getTargetFrameIndex(FIN->getIndex(), TLI->getPointerTy());
+ } else {
+ Base = Addr.getOperand(0);
+ }
+ Offset = CurDAG->getTargetConstant(CN->getZExtValue(), SDLoc(Addr),
+ MVT::i32);
+ return true;
+ }
+ }
+ if (Addr.getOperand(0).getOpcode() == SPISD::Lo) {
+ Base = Addr.getOperand(1);
+ Offset = Addr.getOperand(0).getOperand(0);
+ return true;
+ }
+ if (Addr.getOperand(1).getOpcode() == SPISD::Lo) {
+ Base = Addr.getOperand(0);
+ Offset = Addr.getOperand(1).getOperand(0);
+ return true;
+ }
+ }
+ Base = Addr;
+ Offset = CurDAG->getTargetConstant(0, SDLoc(Addr), MVT::i32);
+ return true;
+}
+
+bool SparcDAGToDAGISel::SelectADDRrr(SDValue Addr, SDValue &R1, SDValue &R2) {
+ if (Addr.getOpcode() == ISD::FrameIndex) return false;
+ if (Addr.getOpcode() == ISD::TargetExternalSymbol ||
+ Addr.getOpcode() == ISD::TargetGlobalAddress ||
+ Addr.getOpcode() == ISD::TargetGlobalTLSAddress)
+ return false; // direct calls.
+
+ if (Addr.getOpcode() == ISD::ADD) {
+ if (ConstantSDNode *CN = dyn_cast<ConstantSDNode>(Addr.getOperand(1)))
+ if (isInt<13>(CN->getSExtValue()))
+ return false; // Let the reg+imm pattern catch this!
+ if (Addr.getOperand(0).getOpcode() == SPISD::Lo ||
+ Addr.getOperand(1).getOpcode() == SPISD::Lo)
+ return false; // Let the reg+imm pattern catch this!
+ R1 = Addr.getOperand(0);
+ R2 = Addr.getOperand(1);
+ return true;
+ }
+
+ R1 = Addr;
+ R2 = CurDAG->getRegister(SP::G0, TLI->getPointerTy());
+ return true;
+}
+
+SDNode *SparcDAGToDAGISel::Select(SDNode *N) {
+ SDLoc dl(N);
+ if (N->isMachineOpcode()) {
+ N->setNodeId(-1);
+ return nullptr; // Already selected.
+ }
+
+ switch (N->getOpcode()) {
+ default: break;
+ case SPISD::GLOBAL_BASE_REG:
+ return getGlobalBaseReg();
+
+ case ISD::SDIV:
+ case ISD::UDIV: {
+ // sdivx / udivx handle 64-bit divides.
+ if (N->getValueType(0) == MVT::i64)
+ break;
+ // FIXME: should use a custom expander to expose the SRA to the dag.
+ SDValue DivLHS = N->getOperand(0);
+ SDValue DivRHS = N->getOperand(1);
+
+ // Set the Y register to the high-part.
+ SDValue TopPart;
+ if (N->getOpcode() == ISD::SDIV) {
+ TopPart = SDValue(CurDAG->getMachineNode(SP::SRAri, dl, MVT::i32, DivLHS,
+ CurDAG->getTargetConstant(31, dl, MVT::i32)),
+ 0);
+ } else {
+ TopPart = CurDAG->getRegister(SP::G0, MVT::i32);
+ }
+ TopPart = SDValue(CurDAG->getMachineNode(SP::WRASRrr, dl, MVT::i32,
+ TopPart,
+ CurDAG->getRegister(SP::G0, MVT::i32)), 0);
+ TopPart = CurDAG->getCopyToReg(TopPart, dl, SP::Y, TopPart, SDValue()).getValue(1);
+
+ // 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);
+ }
+ case ISD::MULHU:
+ case ISD::MULHS: {
+ // FIXME: Handle mul by immediate.
+ SDValue MulLHS = N->getOperand(0);
+ SDValue MulRHS = N->getOperand(1);
+ unsigned Opcode = N->getOpcode() == ISD::MULHU ? SP::UMULrr : SP::SMULrr;
+ SDNode *Mul = CurDAG->getMachineNode(Opcode, dl, MVT::i32, MVT::Glue,
+ MulLHS, MulRHS);
+ // The high part is in the Y register.
+ return CurDAG->SelectNodeTo(N, SP::RDASR, MVT::i32,
+ CurDAG->getRegister(SP::Y, MVT::i32),
+ SDValue(Mul, 1));
+ }
+ }
+
+ return SelectCode(N);
+}
+
+
+/// SelectInlineAsmMemoryOperand - Implement addressing mode selection for
+/// inline asm expressions.
+bool
+SparcDAGToDAGISel::SelectInlineAsmMemoryOperand(const SDValue &Op,
+ unsigned ConstraintID,
+ std::vector<SDValue> &OutOps) {
+ SDValue Op0, Op1;
+ switch (ConstraintID) {
+ default: return true;
+ case InlineAsm::Constraint_i:
+ case InlineAsm::Constraint_m: // memory
+ if (!SelectADDRrr(Op, Op0, Op1))
+ SelectADDRri(Op, Op0, Op1);
+ break;
+ }
+
+ OutOps.push_back(Op0);
+ OutOps.push_back(Op1);
+ return false;
+}
+
+/// createSparcISelDag - This pass converts a legalized DAG into a
+/// SPARC-specific DAG, ready for instruction scheduling.
+///
+FunctionPass *llvm::createSparcISelDag(SparcTargetMachine &TM) {
+ return new SparcDAGToDAGISel(TM);
+}
diff --git a/contrib/llvm/lib/Target/Sparc/SparcISelLowering.cpp b/contrib/llvm/lib/Target/Sparc/SparcISelLowering.cpp
new file mode 100644
index 0000000..0481676
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/SparcISelLowering.cpp
@@ -0,0 +1,3226 @@
+//===-- SparcISelLowering.cpp - Sparc DAG Lowering Implementation ---------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the interfaces that Sparc uses to lower LLVM code into a
+// selection DAG.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SparcISelLowering.h"
+#include "MCTargetDesc/SparcMCExpr.h"
+#include "SparcMachineFunctionInfo.h"
+#include "SparcRegisterInfo.h"
+#include "SparcTargetMachine.h"
+#include "SparcTargetObjectFile.h"
+#include "llvm/CodeGen/CallingConvLower.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/CodeGen/SelectionDAG.h"
+#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
+#include "llvm/IR/DerivedTypes.h"
+#include "llvm/IR/Function.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/ErrorHandling.h"
+using namespace llvm;
+
+
+//===----------------------------------------------------------------------===//
+// Calling Convention Implementation
+//===----------------------------------------------------------------------===//
+
+static bool CC_Sparc_Assign_SRet(unsigned &ValNo, MVT &ValVT,
+ MVT &LocVT, CCValAssign::LocInfo &LocInfo,
+ ISD::ArgFlagsTy &ArgFlags, CCState &State)
+{
+ assert (ArgFlags.isSRet());
+
+ // Assign SRet argument.
+ State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT,
+ 0,
+ LocVT, LocInfo));
+ return true;
+}
+
+static bool CC_Sparc_Assign_f64(unsigned &ValNo, MVT &ValVT,
+ MVT &LocVT, CCValAssign::LocInfo &LocInfo,
+ ISD::ArgFlagsTy &ArgFlags, CCState &State)
+{
+ static const MCPhysReg RegList[] = {
+ SP::I0, SP::I1, SP::I2, SP::I3, SP::I4, SP::I5
+ };
+ // Try to get first reg.
+ if (unsigned Reg = State.AllocateReg(RegList)) {
+ State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
+ } else {
+ // Assign whole thing in stack.
+ State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT,
+ State.AllocateStack(8,4),
+ LocVT, LocInfo));
+ return true;
+ }
+
+ // Try to get second reg.
+ if (unsigned Reg = State.AllocateReg(RegList))
+ State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg, LocVT, LocInfo));
+ else
+ State.addLoc(CCValAssign::getCustomMem(ValNo, ValVT,
+ State.AllocateStack(4,4),
+ LocVT, LocInfo));
+ return true;
+}
+
+// Allocate a full-sized argument for the 64-bit ABI.
+static bool CC_Sparc64_Full(unsigned &ValNo, MVT &ValVT,
+ MVT &LocVT, CCValAssign::LocInfo &LocInfo,
+ ISD::ArgFlagsTy &ArgFlags, CCState &State) {
+ assert((LocVT == MVT::f32 || LocVT == MVT::f128
+ || LocVT.getSizeInBits() == 64) &&
+ "Can't handle non-64 bits locations");
+
+ // Stack space is allocated for all arguments starting from [%fp+BIAS+128].
+ unsigned size = (LocVT == MVT::f128) ? 16 : 8;
+ unsigned alignment = (LocVT == MVT::f128) ? 16 : 8;
+ unsigned Offset = State.AllocateStack(size, alignment);
+ unsigned Reg = 0;
+
+ if (LocVT == MVT::i64 && Offset < 6*8)
+ // Promote integers to %i0-%i5.
+ Reg = SP::I0 + Offset/8;
+ else if (LocVT == MVT::f64 && Offset < 16*8)
+ // Promote doubles to %d0-%d30. (Which LLVM calls D0-D15).
+ Reg = SP::D0 + Offset/8;
+ else if (LocVT == MVT::f32 && Offset < 16*8)
+ // Promote floats to %f1, %f3, ...
+ Reg = SP::F1 + Offset/4;
+ else if (LocVT == MVT::f128 && Offset < 16*8)
+ // Promote long doubles to %q0-%q28. (Which LLVM calls Q0-Q7).
+ Reg = SP::Q0 + Offset/16;
+
+ // Promote to register when possible, otherwise use the stack slot.
+ if (Reg) {
+ State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
+ return true;
+ }
+
+ // This argument goes on the stack in an 8-byte slot.
+ // When passing floats, LocVT is smaller than 8 bytes. Adjust the offset to
+ // the right-aligned float. The first 4 bytes of the stack slot are undefined.
+ if (LocVT == MVT::f32)
+ Offset += 4;
+
+ State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo));
+ return true;
+}
+
+// Allocate a half-sized argument for the 64-bit ABI.
+//
+// This is used when passing { float, int } structs by value in registers.
+static bool CC_Sparc64_Half(unsigned &ValNo, MVT &ValVT,
+ MVT &LocVT, CCValAssign::LocInfo &LocInfo,
+ ISD::ArgFlagsTy &ArgFlags, CCState &State) {
+ assert(LocVT.getSizeInBits() == 32 && "Can't handle non-32 bits locations");
+ unsigned Offset = State.AllocateStack(4, 4);
+
+ if (LocVT == MVT::f32 && Offset < 16*8) {
+ // Promote floats to %f0-%f31.
+ State.addLoc(CCValAssign::getReg(ValNo, ValVT, SP::F0 + Offset/4,
+ LocVT, LocInfo));
+ return true;
+ }
+
+ if (LocVT == MVT::i32 && Offset < 6*8) {
+ // Promote integers to %i0-%i5, using half the register.
+ unsigned Reg = SP::I0 + Offset/8;
+ LocVT = MVT::i64;
+ LocInfo = CCValAssign::AExt;
+
+ // Set the Custom bit if this i32 goes in the high bits of a register.
+ if (Offset % 8 == 0)
+ State.addLoc(CCValAssign::getCustomReg(ValNo, ValVT, Reg,
+ LocVT, LocInfo));
+ else
+ State.addLoc(CCValAssign::getReg(ValNo, ValVT, Reg, LocVT, LocInfo));
+ return true;
+ }
+
+ State.addLoc(CCValAssign::getMem(ValNo, ValVT, Offset, LocVT, LocInfo));
+ return true;
+}
+
+#include "SparcGenCallingConv.inc"
+
+// The calling conventions in SparcCallingConv.td are described in terms of the
+// 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");
+ 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,
+ const SmallVectorImpl<ISD::OutputArg> &Outs,
+ const SmallVectorImpl<SDValue> &OutVals,
+ 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,
+ const SmallVectorImpl<ISD::OutputArg> &Outs,
+ const SmallVectorImpl<SDValue> &OutVals,
+ SDLoc DL, SelectionDAG &DAG) const {
+ MachineFunction &MF = DAG.getMachineFunction();
+
+ // CCValAssign - represent the assignment of the return value to locations.
+ SmallVector<CCValAssign, 16> RVLocs;
+
+ // CCState - Info about the registers and stack slot.
+ CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
+ *DAG.getContext());
+
+ // Analyze return values.
+ CCInfo.AnalyzeReturn(Outs, RetCC_Sparc32);
+
+ SDValue Flag;
+ SmallVector<SDValue, 4> RetOps(1, Chain);
+ // Make room for the return address offset.
+ RetOps.push_back(SDValue());
+
+ // Copy the result values into the output registers.
+ for (unsigned i = 0; i != RVLocs.size(); ++i) {
+ CCValAssign &VA = RVLocs[i];
+ assert(VA.isRegLoc() && "Can only return in registers!");
+
+ Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(),
+ OutVals[i], Flag);
+
+ // Guarantee that all emitted copies are stuck together with flags.
+ Flag = Chain.getValue(1);
+ RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
+ }
+
+ unsigned RetAddrOffset = 8; // Call Inst + Delay Slot
+ // If the function returns a struct, copy the SRetReturnReg to I0
+ if (MF.getFunction()->hasStructRetAttr()) {
+ SparcMachineFunctionInfo *SFI = MF.getInfo<SparcMachineFunctionInfo>();
+ unsigned Reg = SFI->getSRetReturnReg();
+ if (!Reg)
+ llvm_unreachable("sret virtual register not created in the entry block");
+ SDValue Val = DAG.getCopyFromReg(Chain, DL, Reg, getPointerTy());
+ Chain = DAG.getCopyToReg(Chain, DL, SP::I0, Val, Flag);
+ Flag = Chain.getValue(1);
+ RetOps.push_back(DAG.getRegister(SP::I0, getPointerTy()));
+ RetAddrOffset = 12; // CallInst + Delay Slot + Unimp
+ }
+
+ RetOps[0] = Chain; // Update chain.
+ RetOps[1] = DAG.getConstant(RetAddrOffset, DL, MVT::i32);
+
+ // Add the flag if we have it.
+ if (Flag.getNode())
+ RetOps.push_back(Flag);
+
+ return DAG.getNode(SPISD::RET_FLAG, DL, MVT::Other, RetOps);
+}
+
+// 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,
+ const SmallVectorImpl<ISD::OutputArg> &Outs,
+ const SmallVectorImpl<SDValue> &OutVals,
+ SDLoc DL, SelectionDAG &DAG) const {
+ // CCValAssign - represent the assignment of the return value to locations.
+ SmallVector<CCValAssign, 16> RVLocs;
+
+ // CCState - Info about the registers and stack slot.
+ CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), RVLocs,
+ *DAG.getContext());
+
+ // Analyze return values.
+ CCInfo.AnalyzeReturn(Outs, RetCC_Sparc64);
+
+ SDValue Flag;
+ SmallVector<SDValue, 4> RetOps(1, Chain);
+
+ // The second operand on the return instruction is the return address offset.
+ // The return address is always %i7+8 with the 64-bit ABI.
+ RetOps.push_back(DAG.getConstant(8, DL, MVT::i32));
+
+ // Copy the result values into the output registers.
+ for (unsigned i = 0; i != RVLocs.size(); ++i) {
+ CCValAssign &VA = RVLocs[i];
+ assert(VA.isRegLoc() && "Can only return in registers!");
+ SDValue OutVal = OutVals[i];
+
+ // Integer return values must be sign or zero extended by the callee.
+ switch (VA.getLocInfo()) {
+ case CCValAssign::Full: break;
+ case CCValAssign::SExt:
+ OutVal = DAG.getNode(ISD::SIGN_EXTEND, DL, VA.getLocVT(), OutVal);
+ break;
+ case CCValAssign::ZExt:
+ OutVal = DAG.getNode(ISD::ZERO_EXTEND, DL, VA.getLocVT(), OutVal);
+ break;
+ case CCValAssign::AExt:
+ OutVal = DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), OutVal);
+ break;
+ default:
+ llvm_unreachable("Unknown loc info!");
+ }
+
+ // The custom bit on an i32 return value indicates that it should be passed
+ // in the high bits of the register.
+ if (VA.getValVT() == MVT::i32 && VA.needsCustom()) {
+ OutVal = DAG.getNode(ISD::SHL, DL, MVT::i64, OutVal,
+ DAG.getConstant(32, DL, MVT::i32));
+
+ // The next value may go in the low bits of the same register.
+ // Handle both at once.
+ if (i+1 < RVLocs.size() && RVLocs[i+1].getLocReg() == VA.getLocReg()) {
+ SDValue NV = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i64, OutVals[i+1]);
+ OutVal = DAG.getNode(ISD::OR, DL, MVT::i64, OutVal, NV);
+ // Skip the next value, it's already done.
+ ++i;
+ }
+ }
+
+ Chain = DAG.getCopyToReg(Chain, DL, VA.getLocReg(), OutVal, Flag);
+
+ // Guarantee that all emitted copies are stuck together with flags.
+ Flag = Chain.getValue(1);
+ RetOps.push_back(DAG.getRegister(VA.getLocReg(), VA.getLocVT()));
+ }
+
+ RetOps[0] = Chain; // Update chain.
+
+ // Add the flag if we have it.
+ if (Flag.getNode())
+ RetOps.push_back(Flag);
+
+ 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 {
+ if (Subtarget->is64Bit())
+ return LowerFormalArguments_64(Chain, CallConv, IsVarArg, Ins,
+ DL, DAG, InVals);
+ return LowerFormalArguments_32(Chain, CallConv, IsVarArg, Ins,
+ DL, DAG, InVals);
+}
+
+/// 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 {
+ MachineFunction &MF = DAG.getMachineFunction();
+ MachineRegisterInfo &RegInfo = MF.getRegInfo();
+ SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>();
+
+ // Assign locations to all of the incoming arguments.
+ SmallVector<CCValAssign, 16> ArgLocs;
+ CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), ArgLocs,
+ *DAG.getContext());
+ CCInfo.AnalyzeFormalArguments(Ins, CC_Sparc32);
+
+ const unsigned StackOffset = 92;
+
+ unsigned InIdx = 0;
+ for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i, ++InIdx) {
+ CCValAssign &VA = ArgLocs[i];
+
+ if (Ins[InIdx].Flags.isSRet()) {
+ if (InIdx != 0)
+ report_fatal_error("sparc only supports sret on the first parameter");
+ // 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);
+ InVals.push_back(Arg);
+ continue;
+ }
+
+ if (VA.isRegLoc()) {
+ if (VA.needsCustom()) {
+ assert(VA.getLocVT() == MVT::f64);
+ unsigned VRegHi = RegInfo.createVirtualRegister(&SP::IntRegsRegClass);
+ MF.getRegInfo().addLiveIn(VA.getLocReg(), VRegHi);
+ SDValue HiVal = DAG.getCopyFromReg(Chain, dl, VRegHi, MVT::i32);
+
+ assert(i+1 < e);
+ CCValAssign &NextVA = ArgLocs[++i];
+
+ SDValue LoVal;
+ if (NextVA.isMemLoc()) {
+ 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);
+ } else {
+ unsigned loReg = MF.addLiveIn(NextVA.getLocReg(),
+ &SP::IntRegsRegClass);
+ LoVal = DAG.getCopyFromReg(Chain, dl, loReg, MVT::i32);
+ }
+ SDValue WholeValue =
+ DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, LoVal, HiVal);
+ WholeValue = DAG.getNode(ISD::BITCAST, dl, MVT::f64, WholeValue);
+ InVals.push_back(WholeValue);
+ continue;
+ }
+ unsigned VReg = RegInfo.createVirtualRegister(&SP::IntRegsRegClass);
+ MF.getRegInfo().addLiveIn(VA.getLocReg(), VReg);
+ SDValue Arg = DAG.getCopyFromReg(Chain, dl, VReg, MVT::i32);
+ if (VA.getLocVT() == MVT::f32)
+ Arg = DAG.getNode(ISD::BITCAST, dl, MVT::f32, Arg);
+ else if (VA.getLocVT() != MVT::i32) {
+ Arg = DAG.getNode(ISD::AssertSext, dl, MVT::i32, Arg,
+ DAG.getValueType(VA.getLocVT()));
+ Arg = DAG.getNode(ISD::TRUNCATE, dl, VA.getLocVT(), Arg);
+ }
+ InVals.push_back(Arg);
+ continue;
+ }
+
+ assert(VA.isMemLoc());
+
+ unsigned Offset = VA.getLocMemOffset()+StackOffset;
+
+ if (VA.needsCustom()) {
+ assert(VA.getValVT() == MVT::f64);
+ // 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, getPointerTy());
+ SDValue Load = DAG.getLoad(VA.getValVT(), dl, Chain, FIPtr,
+ MachinePointerInfo(),
+ false,false, false, 0);
+ InVals.push_back(Load);
+ continue;
+ }
+
+ int FI = MF.getFrameInfo()->CreateFixedObject(4,
+ Offset,
+ true);
+ SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy());
+ SDValue HiVal = DAG.getLoad(MVT::i32, dl, Chain, FIPtr,
+ MachinePointerInfo(),
+ false, false, false, 0);
+ int FI2 = MF.getFrameInfo()->CreateFixedObject(4,
+ Offset+4,
+ true);
+ SDValue FIPtr2 = DAG.getFrameIndex(FI2, getPointerTy());
+
+ SDValue LoVal = DAG.getLoad(MVT::i32, dl, Chain, FIPtr2,
+ MachinePointerInfo(),
+ false, false, false, 0);
+
+ SDValue WholeValue =
+ DAG.getNode(ISD::BUILD_PAIR, dl, MVT::i64, LoVal, HiVal);
+ WholeValue = DAG.getNode(ISD::BITCAST, dl, MVT::f64, WholeValue);
+ InVals.push_back(WholeValue);
+ continue;
+ }
+
+ int FI = MF.getFrameInfo()->CreateFixedObject(4,
+ Offset,
+ true);
+ SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy());
+ SDValue Load ;
+ if (VA.getValVT() == MVT::i32 || VA.getValVT() == MVT::f32) {
+ Load = DAG.getLoad(VA.getValVT(), dl, Chain, FIPtr,
+ MachinePointerInfo(),
+ false, false, false, 0);
+ } else {
+ ISD::LoadExtType LoadOp = ISD::SEXTLOAD;
+ // Sparc is big endian, so add an offset based on the ObjectVT.
+ unsigned Offset = 4-std::max(1U, VA.getValVT().getSizeInBits()/8);
+ FIPtr = DAG.getNode(ISD::ADD, dl, MVT::i32, FIPtr,
+ DAG.getConstant(Offset, dl, MVT::i32));
+ Load = DAG.getExtLoad(LoadOp, dl, MVT::i32, Chain, FIPtr,
+ MachinePointerInfo(),
+ VA.getValVT(), false, false, false,0);
+ Load = DAG.getNode(ISD::TRUNCATE, dl, VA.getValVT(), Load);
+ }
+ InVals.push_back(Load);
+ }
+
+ if (MF.getFunction()->hasStructRetAttr()) {
+ // Copy the SRet Argument to SRetReturnReg.
+ SparcMachineFunctionInfo *SFI = MF.getInfo<SparcMachineFunctionInfo>();
+ unsigned Reg = SFI->getSRetReturnReg();
+ if (!Reg) {
+ Reg = MF.getRegInfo().createVirtualRegister(&SP::IntRegsRegClass);
+ SFI->setSRetReturnReg(Reg);
+ }
+ SDValue Copy = DAG.getCopyToReg(DAG.getEntryNode(), dl, Reg, InVals[0]);
+ Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, Copy, Chain);
+ }
+
+ // Store remaining ArgRegs to the stack if this is a varargs function.
+ if (isVarArg) {
+ static const MCPhysReg ArgRegs[] = {
+ SP::I0, SP::I1, SP::I2, SP::I3, SP::I4, SP::I5
+ };
+ unsigned NumAllocated = CCInfo.getFirstUnallocated(ArgRegs);
+ const MCPhysReg *CurArgReg = ArgRegs+NumAllocated, *ArgRegEnd = ArgRegs+6;
+ unsigned ArgOffset = CCInfo.getNextStackOffset();
+ if (NumAllocated == 6)
+ ArgOffset += StackOffset;
+ else {
+ assert(!ArgOffset);
+ ArgOffset = 68+4*NumAllocated;
+ }
+
+ // Remember the vararg offset for the va_start implementation.
+ FuncInfo->setVarArgsFrameOffset(ArgOffset);
+
+ std::vector<SDValue> OutChains;
+
+ for (; CurArgReg != ArgRegEnd; ++CurArgReg) {
+ unsigned VReg = RegInfo.createVirtualRegister(&SP::IntRegsRegClass);
+ MF.getRegInfo().addLiveIn(*CurArgReg, VReg);
+ SDValue Arg = DAG.getCopyFromReg(DAG.getRoot(), dl, VReg, MVT::i32);
+
+ int FrameIdx = MF.getFrameInfo()->CreateFixedObject(4, ArgOffset,
+ true);
+ SDValue FIPtr = DAG.getFrameIndex(FrameIdx, MVT::i32);
+
+ OutChains.push_back(DAG.getStore(DAG.getRoot(), dl, Arg, FIPtr,
+ MachinePointerInfo(),
+ false, false, 0));
+ ArgOffset += 4;
+ }
+
+ if (!OutChains.empty()) {
+ OutChains.push_back(Chain);
+ Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, OutChains);
+ }
+ }
+
+ return 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 {
+ MachineFunction &MF = DAG.getMachineFunction();
+
+ // Analyze arguments according to CC_Sparc64.
+ SmallVector<CCValAssign, 16> ArgLocs;
+ CCState CCInfo(CallConv, IsVarArg, DAG.getMachineFunction(), ArgLocs,
+ *DAG.getContext());
+ CCInfo.AnalyzeFormalArguments(Ins, CC_Sparc64);
+
+ // The argument array begins at %fp+BIAS+128, after the register save area.
+ const unsigned ArgArea = 128;
+
+ for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
+ CCValAssign &VA = ArgLocs[i];
+ if (VA.isRegLoc()) {
+ // This argument is passed in a register.
+ // All integer register arguments are promoted by the caller to i64.
+
+ // Create a virtual register for the promoted live-in value.
+ unsigned VReg = MF.addLiveIn(VA.getLocReg(),
+ getRegClassFor(VA.getLocVT()));
+ SDValue Arg = DAG.getCopyFromReg(Chain, DL, VReg, VA.getLocVT());
+
+ // Get the high bits for i32 struct elements.
+ if (VA.getValVT() == MVT::i32 && VA.needsCustom())
+ Arg = DAG.getNode(ISD::SRL, DL, VA.getLocVT(), Arg,
+ DAG.getConstant(32, DL, MVT::i32));
+
+ // The caller promoted the argument, so insert an Assert?ext SDNode so we
+ // won't promote the value again in this function.
+ switch (VA.getLocInfo()) {
+ case CCValAssign::SExt:
+ Arg = DAG.getNode(ISD::AssertSext, DL, VA.getLocVT(), Arg,
+ DAG.getValueType(VA.getValVT()));
+ break;
+ case CCValAssign::ZExt:
+ Arg = DAG.getNode(ISD::AssertZext, DL, VA.getLocVT(), Arg,
+ DAG.getValueType(VA.getValVT()));
+ break;
+ default:
+ break;
+ }
+
+ // Truncate the register down to the argument type.
+ if (VA.isExtInLoc())
+ Arg = DAG.getNode(ISD::TRUNCATE, DL, VA.getValVT(), Arg);
+
+ InVals.push_back(Arg);
+ continue;
+ }
+
+ // The registers are exhausted. This argument was passed on the stack.
+ assert(VA.isMemLoc());
+ // The CC_Sparc64_Full/Half functions compute stack offsets relative to the
+ // beginning of the arguments area at %fp+BIAS+128.
+ unsigned Offset = VA.getLocMemOffset() + ArgArea;
+ unsigned ValSize = VA.getValVT().getSizeInBits() / 8;
+ // Adjust offset for extended arguments, SPARC is big-endian.
+ // The caller will have written the full slot with extended bytes, but we
+ // prefer our own extending loads.
+ 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()),
+ MachinePointerInfo::getFixedStack(FI),
+ false, false, false, 0));
+ }
+
+ if (!IsVarArg)
+ return Chain;
+
+ // This function takes variable arguments, some of which may have been passed
+ // in registers %i0-%i5. Variable floating point arguments are never passed
+ // in floating point registers. They go on %i0-%i5 or on the stack like
+ // integer arguments.
+ //
+ // The va_start intrinsic needs to know the offset to the first variable
+ // argument.
+ unsigned ArgOffset = CCInfo.getNextStackOffset();
+ SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>();
+ // Skip the 128 bytes of register save area.
+ FuncInfo->setVarArgsFrameOffset(ArgOffset + ArgArea +
+ Subtarget->getStackPointerBias());
+
+ // Save the variable arguments that were passed in registers.
+ // The caller is required to reserve stack space for 6 arguments regardless
+ // of how many arguments were actually passed.
+ SmallVector<SDValue, 8> OutChains;
+ for (; ArgOffset < 6*8; ArgOffset += 8) {
+ unsigned VReg = MF.addLiveIn(SP::I0 + ArgOffset/8, &SP::I64RegsRegClass);
+ SDValue VArg = DAG.getCopyFromReg(Chain, DL, VReg, MVT::i64);
+ int FI = MF.getFrameInfo()->CreateFixedObject(8, ArgOffset + ArgArea, true);
+ OutChains.push_back(DAG.getStore(Chain, DL, VArg,
+ DAG.getFrameIndex(FI, getPointerTy()),
+ MachinePointerInfo::getFixedStack(FI),
+ false, false, 0));
+ }
+
+ if (!OutChains.empty())
+ Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, OutChains);
+
+ return Chain;
+}
+
+SDValue
+SparcTargetLowering::LowerCall(TargetLowering::CallLoweringInfo &CLI,
+ SmallVectorImpl<SDValue> &InVals) const {
+ if (Subtarget->is64Bit())
+ return LowerCall_64(CLI, InVals);
+ return LowerCall_32(CLI, InVals);
+}
+
+static bool hasReturnsTwiceAttr(SelectionDAG &DAG, SDValue Callee,
+ ImmutableCallSite *CS) {
+ if (CS)
+ return CS->hasFnAttr(Attribute::ReturnsTwice);
+
+ const Function *CalleeFn = nullptr;
+ if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
+ CalleeFn = dyn_cast<Function>(G->getGlobal());
+ } else if (ExternalSymbolSDNode *E =
+ dyn_cast<ExternalSymbolSDNode>(Callee)) {
+ const Function *Fn = DAG.getMachineFunction().getFunction();
+ const Module *M = Fn->getParent();
+ const char *CalleeName = E->getSymbol();
+ CalleeFn = M->getFunction(CalleeName);
+ }
+
+ if (!CalleeFn)
+ return false;
+ return CalleeFn->hasFnAttribute(Attribute::ReturnsTwice);
+}
+
+// Lower a call for the 32-bit ABI.
+SDValue
+SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI,
+ SmallVectorImpl<SDValue> &InVals) const {
+ SelectionDAG &DAG = CLI.DAG;
+ SDLoc &dl = CLI.DL;
+ SmallVectorImpl<ISD::OutputArg> &Outs = CLI.Outs;
+ SmallVectorImpl<SDValue> &OutVals = CLI.OutVals;
+ SmallVectorImpl<ISD::InputArg> &Ins = CLI.Ins;
+ SDValue Chain = CLI.Chain;
+ SDValue Callee = CLI.Callee;
+ bool &isTailCall = CLI.IsTailCall;
+ CallingConv::ID CallConv = CLI.CallConv;
+ bool isVarArg = CLI.IsVarArg;
+
+ // Sparc target does not yet support tail call optimization.
+ isTailCall = false;
+
+ // Analyze operands of the call, assigning locations to each operand.
+ SmallVector<CCValAssign, 16> ArgLocs;
+ CCState CCInfo(CallConv, isVarArg, DAG.getMachineFunction(), ArgLocs,
+ *DAG.getContext());
+ CCInfo.AnalyzeCallOperands(Outs, CC_Sparc32);
+
+ // Get the size of the outgoing arguments stack space requirement.
+ unsigned ArgsSize = CCInfo.getNextStackOffset();
+
+ // Keep stack frames 8-byte aligned.
+ ArgsSize = (ArgsSize+7) & ~7;
+
+ MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
+
+ // Create local copies for byval args.
+ SmallVector<SDValue, 8> ByValArgs;
+ for (unsigned i = 0, e = Outs.size(); i != e; ++i) {
+ ISD::ArgFlagsTy Flags = Outs[i].Flags;
+ if (!Flags.isByVal())
+ continue;
+
+ SDValue Arg = OutVals[i];
+ unsigned Size = Flags.getByValSize();
+ unsigned Align = Flags.getByValAlign();
+
+ int FI = MFI->CreateStackObject(Size, Align, false);
+ SDValue FIPtr = DAG.getFrameIndex(FI, getPointerTy());
+ 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);
+ }
+
+ Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(ArgsSize, dl, true),
+ dl);
+
+ SmallVector<std::pair<unsigned, SDValue>, 8> RegsToPass;
+ SmallVector<SDValue, 8> MemOpChains;
+
+ const unsigned StackOffset = 92;
+ bool hasStructRetAttr = false;
+ // Walk the register/memloc assignments, inserting copies/loads.
+ for (unsigned i = 0, realArgIdx = 0, byvalArgIdx = 0, e = ArgLocs.size();
+ i != e;
+ ++i, ++realArgIdx) {
+ CCValAssign &VA = ArgLocs[i];
+ SDValue Arg = OutVals[realArgIdx];
+
+ ISD::ArgFlagsTy Flags = Outs[realArgIdx].Flags;
+
+ // Use local copy if it is a byval arg.
+ if (Flags.isByVal())
+ Arg = ByValArgs[byvalArgIdx++];
+
+ // Promote the value if needed.
+ switch (VA.getLocInfo()) {
+ default: llvm_unreachable("Unknown loc info!");
+ case CCValAssign::Full: break;
+ case CCValAssign::SExt:
+ Arg = DAG.getNode(ISD::SIGN_EXTEND, dl, VA.getLocVT(), Arg);
+ break;
+ case CCValAssign::ZExt:
+ Arg = DAG.getNode(ISD::ZERO_EXTEND, dl, VA.getLocVT(), Arg);
+ break;
+ case CCValAssign::AExt:
+ Arg = DAG.getNode(ISD::ANY_EXTEND, dl, VA.getLocVT(), Arg);
+ break;
+ case CCValAssign::BCvt:
+ Arg = DAG.getNode(ISD::BITCAST, dl, VA.getLocVT(), Arg);
+ break;
+ }
+
+ if (Flags.isSRet()) {
+ assert(VA.needsCustom());
+ // store SRet argument in %sp+64
+ 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));
+ hasStructRetAttr = true;
+ continue;
+ }
+
+ if (VA.needsCustom()) {
+ assert(VA.getLocVT() == MVT::f64);
+
+ if (VA.isMemLoc()) {
+ unsigned Offset = VA.getLocMemOffset() + StackOffset;
+ // if it is double-word aligned, just store.
+ if (Offset % 8 == 0) {
+ 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));
+ continue;
+ }
+ }
+
+ SDValue StackPtr = DAG.CreateStackTemporary(MVT::f64, MVT::i32);
+ SDValue Store = DAG.getStore(DAG.getEntryNode(), dl,
+ Arg, StackPtr, MachinePointerInfo(),
+ false, false, 0);
+ // Sparc is big-endian, so the high part comes first.
+ SDValue Hi = DAG.getLoad(MVT::i32, dl, Store, StackPtr,
+ MachinePointerInfo(), false, false, false, 0);
+ // Increment the pointer to the other half.
+ StackPtr = DAG.getNode(ISD::ADD, dl, StackPtr.getValueType(), StackPtr,
+ DAG.getIntPtrConstant(4, dl));
+ // Load the low part.
+ SDValue Lo = DAG.getLoad(MVT::i32, dl, Store, StackPtr,
+ MachinePointerInfo(), false, false, false, 0);
+
+ if (VA.isRegLoc()) {
+ RegsToPass.push_back(std::make_pair(VA.getLocReg(), Hi));
+ assert(i+1 != e);
+ CCValAssign &NextVA = ArgLocs[++i];
+ if (NextVA.isRegLoc()) {
+ RegsToPass.push_back(std::make_pair(NextVA.getLocReg(), Lo));
+ } else {
+ // Store the low part in stack.
+ unsigned Offset = NextVA.getLocMemOffset() + StackOffset;
+ 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, Lo, PtrOff,
+ MachinePointerInfo(),
+ false, false, 0));
+ }
+ } else {
+ unsigned Offset = VA.getLocMemOffset() + StackOffset;
+ // Store the high part.
+ 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, Hi, PtrOff,
+ MachinePointerInfo(),
+ false, false, 0));
+ // Store the low part.
+ PtrOff = DAG.getIntPtrConstant(Offset + 4, dl);
+ PtrOff = DAG.getNode(ISD::ADD, dl, MVT::i32, StackPtr, PtrOff);
+ MemOpChains.push_back(DAG.getStore(Chain, dl, Lo, PtrOff,
+ MachinePointerInfo(),
+ false, false, 0));
+ }
+ continue;
+ }
+
+ // Arguments that can be passed on register must be kept at
+ // RegsToPass vector
+ if (VA.isRegLoc()) {
+ if (VA.getLocVT() != MVT::f32) {
+ RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
+ continue;
+ }
+ Arg = DAG.getNode(ISD::BITCAST, dl, MVT::i32, Arg);
+ RegsToPass.push_back(std::make_pair(VA.getLocReg(), Arg));
+ continue;
+ }
+
+ assert(VA.isMemLoc());
+
+ // Create a store off the stack pointer for this argument.
+ SDValue StackPtr = DAG.getRegister(SP::O6, MVT::i32);
+ 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));
+ }
+
+
+ // Emit all stores, make sure the occur before any copies into physregs.
+ if (!MemOpChains.empty())
+ Chain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, MemOpChains);
+
+ // Build a sequence of copy-to-reg nodes chained together with token
+ // chain and flag operands which copy the outgoing args into registers.
+ // The InFlag in necessary since all emitted instructions must be
+ // stuck together.
+ SDValue InFlag;
+ for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
+ unsigned Reg = toCallerWindow(RegsToPass[i].first);
+ Chain = DAG.getCopyToReg(Chain, dl, Reg, RegsToPass[i].second, InFlag);
+ InFlag = Chain.getValue(1);
+ }
+
+ unsigned SRetArgSize = (hasStructRetAttr)? getSRetArgSize(DAG, Callee):0;
+ bool hasReturnsTwice = hasReturnsTwiceAttr(DAG, Callee, CLI.CS);
+
+ // 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);
+ 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))
+ Callee = DAG.getTargetExternalSymbol(E->getSymbol(), MVT::i32, TF);
+
+ // Returns a chain & a flag for retval copy to use
+ SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
+ SmallVector<SDValue, 8> Ops;
+ Ops.push_back(Chain);
+ Ops.push_back(Callee);
+ if (hasStructRetAttr)
+ Ops.push_back(DAG.getTargetConstant(SRetArgSize, dl, MVT::i32));
+ for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i)
+ Ops.push_back(DAG.getRegister(toCallerWindow(RegsToPass[i].first),
+ RegsToPass[i].second.getValueType()));
+
+ // Add a register mask operand representing the call-preserved registers.
+ const SparcRegisterInfo *TRI = Subtarget->getRegisterInfo();
+ const uint32_t *Mask =
+ ((hasReturnsTwice)
+ ? TRI->getRTCallPreservedMask(CallConv)
+ : TRI->getCallPreservedMask(DAG.getMachineFunction(), CallConv));
+ assert(Mask && "Missing call preserved mask for calling convention");
+ Ops.push_back(DAG.getRegisterMask(Mask));
+
+ if (InFlag.getNode())
+ Ops.push_back(InFlag);
+
+ Chain = DAG.getNode(SPISD::CALL, dl, NodeTys, Ops);
+ InFlag = Chain.getValue(1);
+
+ Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(ArgsSize, dl, true),
+ DAG.getIntPtrConstant(0, dl, true), InFlag, dl);
+ InFlag = Chain.getValue(1);
+
+ // Assign locations to each value returned by this call.
+ SmallVector<CCValAssign, 16> RVLocs;
+ CCState RVInfo(CallConv, isVarArg, DAG.getMachineFunction(), RVLocs,
+ *DAG.getContext());
+
+ RVInfo.AnalyzeCallResult(Ins, RetCC_Sparc32);
+
+ // 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));
+ }
+
+ return Chain;
+}
+
+// This functions returns true if CalleeName is a ABI function that returns
+// a long double (fp128).
+static bool isFP128ABICall(const char *CalleeName)
+{
+ static const char *const ABICalls[] =
+ { "_Q_add", "_Q_sub", "_Q_mul", "_Q_div",
+ "_Q_sqrt", "_Q_neg",
+ "_Q_itoq", "_Q_stoq", "_Q_dtoq", "_Q_utoq",
+ "_Q_lltoq", "_Q_ulltoq",
+ nullptr
+ };
+ for (const char * const *I = ABICalls; *I != nullptr; ++I)
+ if (strcmp(CalleeName, *I) == 0)
+ return true;
+ return false;
+}
+
+unsigned
+SparcTargetLowering::getSRetArgSize(SelectionDAG &DAG, SDValue Callee) const
+{
+ const Function *CalleeFn = nullptr;
+ if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee)) {
+ CalleeFn = dyn_cast<Function>(G->getGlobal());
+ } else if (ExternalSymbolSDNode *E =
+ dyn_cast<ExternalSymbolSDNode>(Callee)) {
+ const Function *Fn = DAG.getMachineFunction().getFunction();
+ const Module *M = Fn->getParent();
+ const char *CalleeName = E->getSymbol();
+ CalleeFn = M->getFunction(CalleeName);
+ if (!CalleeFn && isFP128ABICall(CalleeName))
+ return 16; // Return sizeof(fp128)
+ }
+
+ if (!CalleeFn)
+ return 0;
+
+ assert(CalleeFn->hasStructRetAttr() &&
+ "Callee does not have the StructRet attribute.");
+
+ PointerType *Ty = cast<PointerType>(CalleeFn->arg_begin()->getType());
+ Type *ElementTy = Ty->getElementType();
+ return getDataLayout()->getTypeAllocSize(ElementTy);
+}
+
+
+// Fixup floating point arguments in the ... part of a varargs call.
+//
+// The SPARC v9 ABI requires that floating point arguments are treated the same
+// as integers when calling a varargs function. This does not apply to the
+// fixed arguments that are part of the function's prototype.
+//
+// This function post-processes a CCValAssign array created by
+// AnalyzeCallOperands().
+static void fixupVariableFloatArgs(SmallVectorImpl<CCValAssign> &ArgLocs,
+ ArrayRef<ISD::OutputArg> Outs) {
+ for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
+ const CCValAssign &VA = ArgLocs[i];
+ MVT ValTy = VA.getLocVT();
+ // FIXME: What about f32 arguments? C promotes them to f64 when calling
+ // varargs functions.
+ if (!VA.isRegLoc() || (ValTy != MVT::f64 && ValTy != MVT::f128))
+ continue;
+ // The fixed arguments to a varargs function still go in FP registers.
+ if (Outs[VA.getValNo()].IsFixed)
+ continue;
+
+ // This floating point argument should be reassigned.
+ CCValAssign NewVA;
+
+ // Determine the offset into the argument array.
+ unsigned firstReg = (ValTy == MVT::f64) ? SP::D0 : SP::Q0;
+ unsigned argSize = (ValTy == MVT::f64) ? 8 : 16;
+ unsigned Offset = argSize * (VA.getLocReg() - firstReg);
+ assert(Offset < 16*8 && "Offset out of range, bad register enum?");
+
+ if (Offset < 6*8) {
+ // This argument should go in %i0-%i5.
+ unsigned IReg = SP::I0 + Offset/8;
+ if (ValTy == MVT::f64)
+ // Full register, just bitconvert into i64.
+ NewVA = CCValAssign::getReg(VA.getValNo(), VA.getValVT(),
+ IReg, MVT::i64, CCValAssign::BCvt);
+ else {
+ assert(ValTy == MVT::f128 && "Unexpected type!");
+ // Full register, just bitconvert into i128 -- We will lower this into
+ // two i64s in LowerCall_64.
+ NewVA = CCValAssign::getCustomReg(VA.getValNo(), VA.getValVT(),
+ IReg, MVT::i128, CCValAssign::BCvt);
+ }
+ } else {
+ // This needs to go to memory, we're out of integer registers.
+ NewVA = CCValAssign::getMem(VA.getValNo(), VA.getValVT(),
+ Offset, VA.getLocVT(), VA.getLocInfo());
+ }
+ ArgLocs[i] = NewVA;
+ }
+}
+
+// Lower a call for the 64-bit ABI.
+SDValue
+SparcTargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI,
+ SmallVectorImpl<SDValue> &InVals) const {
+ SelectionDAG &DAG = CLI.DAG;
+ SDLoc DL = CLI.DL;
+ SDValue Chain = CLI.Chain;
+
+ // Sparc target does not yet support tail call optimization.
+ CLI.IsTailCall = false;
+
+ // Analyze operands of the call, assigning locations to each operand.
+ SmallVector<CCValAssign, 16> ArgLocs;
+ CCState CCInfo(CLI.CallConv, CLI.IsVarArg, DAG.getMachineFunction(), ArgLocs,
+ *DAG.getContext());
+ CCInfo.AnalyzeCallOperands(CLI.Outs, CC_Sparc64);
+
+ // Get the size of the outgoing arguments stack space requirement.
+ // The stack offset computed by CC_Sparc64 includes all arguments.
+ // Called functions expect 6 argument words to exist in the stack frame, used
+ // or not.
+ unsigned ArgsSize = std::max(6*8u, CCInfo.getNextStackOffset());
+
+ // Keep stack frames 16-byte aligned.
+ ArgsSize = RoundUpToAlignment(ArgsSize, 16);
+
+ // Varargs calls require special treatment.
+ if (CLI.IsVarArg)
+ fixupVariableFloatArgs(ArgLocs, CLI.Outs);
+
+ // Adjust the stack pointer to make room for the arguments.
+ // FIXME: Use hasReservedCallFrame to avoid %sp adjustments around all calls
+ // with more than 6 arguments.
+ Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(ArgsSize, DL, true),
+ DL);
+
+ // Collect the set of registers to pass to the function and their values.
+ // This will be emitted as a sequence of CopyToReg nodes glued to the call
+ // instruction.
+ SmallVector<std::pair<unsigned, SDValue>, 8> RegsToPass;
+
+ // Collect chains from all the memory opeations that copy arguments to the
+ // stack. They must follow the stack pointer adjustment above and precede the
+ // call instruction itself.
+ SmallVector<SDValue, 8> MemOpChains;
+
+ for (unsigned i = 0, e = ArgLocs.size(); i != e; ++i) {
+ const CCValAssign &VA = ArgLocs[i];
+ SDValue Arg = CLI.OutVals[i];
+
+ // Promote the value if needed.
+ switch (VA.getLocInfo()) {
+ default:
+ llvm_unreachable("Unknown location info!");
+ case CCValAssign::Full:
+ break;
+ case CCValAssign::SExt:
+ Arg = DAG.getNode(ISD::SIGN_EXTEND, DL, VA.getLocVT(), Arg);
+ break;
+ case CCValAssign::ZExt:
+ Arg = DAG.getNode(ISD::ZERO_EXTEND, DL, VA.getLocVT(), Arg);
+ break;
+ case CCValAssign::AExt:
+ Arg = DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), Arg);
+ break;
+ case CCValAssign::BCvt:
+ // fixupVariableFloatArgs() may create bitcasts from f128 to i128. But
+ // SPARC does not support i128 natively. Lower it into two i64, see below.
+ if (!VA.needsCustom() || VA.getValVT() != MVT::f128
+ || VA.getLocVT() != MVT::i128)
+ Arg = DAG.getNode(ISD::BITCAST, DL, VA.getLocVT(), Arg);
+ break;
+ }
+
+ if (VA.isRegLoc()) {
+ if (VA.needsCustom() && VA.getValVT() == MVT::f128
+ && VA.getLocVT() == MVT::i128) {
+ // Store and reload into the interger register reg and reg+1.
+ unsigned Offset = 8 * (VA.getLocReg() - SP::I0);
+ unsigned StackOffset = Offset + Subtarget->getStackPointerBias() + 128;
+ SDValue StackPtr = DAG.getRegister(SP::O6, getPointerTy());
+ SDValue HiPtrOff = DAG.getIntPtrConstant(StackOffset, DL);
+ HiPtrOff = DAG.getNode(ISD::ADD, DL, getPointerTy(), StackPtr,
+ HiPtrOff);
+ SDValue LoPtrOff = DAG.getIntPtrConstant(StackOffset + 8, DL);
+ LoPtrOff = DAG.getNode(ISD::ADD, DL, getPointerTy(), StackPtr,
+ LoPtrOff);
+
+ // Store to %sp+BIAS+128+Offset
+ SDValue Store = DAG.getStore(Chain, DL, Arg, HiPtrOff,
+ MachinePointerInfo(),
+ false, false, 0);
+ // 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);
+ RegsToPass.push_back(std::make_pair(toCallerWindow(VA.getLocReg()),
+ Hi64));
+ RegsToPass.push_back(std::make_pair(toCallerWindow(VA.getLocReg()+1),
+ Lo64));
+ continue;
+ }
+
+ // The custom bit on an i32 return value indicates that it should be
+ // passed in the high bits of the register.
+ if (VA.getValVT() == MVT::i32 && VA.needsCustom()) {
+ Arg = DAG.getNode(ISD::SHL, DL, MVT::i64, Arg,
+ DAG.getConstant(32, DL, MVT::i32));
+
+ // The next value may go in the low bits of the same register.
+ // Handle both at once.
+ if (i+1 < ArgLocs.size() && ArgLocs[i+1].isRegLoc() &&
+ ArgLocs[i+1].getLocReg() == VA.getLocReg()) {
+ SDValue NV = DAG.getNode(ISD::ZERO_EXTEND, DL, MVT::i64,
+ CLI.OutVals[i+1]);
+ Arg = DAG.getNode(ISD::OR, DL, MVT::i64, Arg, NV);
+ // Skip the next value, it's already done.
+ ++i;
+ }
+ }
+ RegsToPass.push_back(std::make_pair(toCallerWindow(VA.getLocReg()), Arg));
+ continue;
+ }
+
+ assert(VA.isMemLoc());
+
+ // Create a store off the stack pointer for this argument.
+ SDValue StackPtr = DAG.getRegister(SP::O6, getPointerTy());
+ // The argument area starts at %fp+BIAS+128 in the callee frame,
+ // %sp+BIAS+128 in ours.
+ SDValue PtrOff = DAG.getIntPtrConstant(VA.getLocMemOffset() +
+ Subtarget->getStackPointerBias() +
+ 128, DL);
+ PtrOff = DAG.getNode(ISD::ADD, DL, getPointerTy(), StackPtr, PtrOff);
+ MemOpChains.push_back(DAG.getStore(Chain, DL, Arg, PtrOff,
+ MachinePointerInfo(),
+ false, false, 0));
+ }
+
+ // Emit all stores, make sure they occur before the call.
+ if (!MemOpChains.empty())
+ Chain = DAG.getNode(ISD::TokenFactor, DL, MVT::Other, MemOpChains);
+
+ // Build a sequence of CopyToReg nodes glued together with token chain and
+ // glue operands which copy the outgoing args into registers. The InGlue is
+ // necessary since all emitted instructions must be stuck together in order
+ // to pass the live physical registers.
+ SDValue InGlue;
+ for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i) {
+ Chain = DAG.getCopyToReg(Chain, DL,
+ RegsToPass[i].first, RegsToPass[i].second, InGlue);
+ InGlue = Chain.getValue(1);
+ }
+
+ // 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.
+ SDValue Callee = CLI.Callee;
+ bool hasReturnsTwice = hasReturnsTwiceAttr(DAG, Callee, CLI.CS);
+ unsigned TF = ((getTargetMachine().getRelocationModel() == Reloc::PIC_)
+ ? SparcMCExpr::VK_Sparc_WPLT30 : 0);
+ if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee))
+ Callee = DAG.getTargetGlobalAddress(G->getGlobal(), DL, getPointerTy(), 0,
+ TF);
+ else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee))
+ Callee = DAG.getTargetExternalSymbol(E->getSymbol(), getPointerTy(), TF);
+
+ // Build the operands for the call instruction itself.
+ SmallVector<SDValue, 8> Ops;
+ Ops.push_back(Chain);
+ Ops.push_back(Callee);
+ for (unsigned i = 0, e = RegsToPass.size(); i != e; ++i)
+ Ops.push_back(DAG.getRegister(RegsToPass[i].first,
+ RegsToPass[i].second.getValueType()));
+
+ // Add a register mask operand representing the call-preserved registers.
+ const SparcRegisterInfo *TRI = Subtarget->getRegisterInfo();
+ const uint32_t *Mask =
+ ((hasReturnsTwice) ? TRI->getRTCallPreservedMask(CLI.CallConv)
+ : TRI->getCallPreservedMask(DAG.getMachineFunction(),
+ CLI.CallConv));
+ assert(Mask && "Missing call preserved mask for calling convention");
+ Ops.push_back(DAG.getRegisterMask(Mask));
+
+ // Make sure the CopyToReg nodes are glued to the call instruction which
+ // consumes the registers.
+ if (InGlue.getNode())
+ Ops.push_back(InGlue);
+
+ // Now the call itself.
+ SDVTList NodeTys = DAG.getVTList(MVT::Other, MVT::Glue);
+ Chain = DAG.getNode(SPISD::CALL, DL, NodeTys, Ops);
+ InGlue = Chain.getValue(1);
+
+ // Revert the stack pointer immediately after the call.
+ Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(ArgsSize, DL, true),
+ DAG.getIntPtrConstant(0, DL, true), InGlue, DL);
+ InGlue = Chain.getValue(1);
+
+ // Now extract the return values. This is more or less the same as
+ // LowerFormalArguments_64.
+
+ // Assign locations to each value returned by this call.
+ SmallVector<CCValAssign, 16> RVLocs;
+ CCState RVInfo(CLI.CallConv, CLI.IsVarArg, DAG.getMachineFunction(), RVLocs,
+ *DAG.getContext());
+
+ // Set inreg flag manually for codegen generated library calls that
+ // return float.
+ if (CLI.Ins.size() == 1 && CLI.Ins[0].VT == MVT::f32 && CLI.CS == nullptr)
+ CLI.Ins[0].Flags.setInReg();
+
+ RVInfo.AnalyzeCallResult(CLI.Ins, RetCC_Sparc64);
+
+ // Copy all of the result registers out of their specified physreg.
+ for (unsigned i = 0; i != RVLocs.size(); ++i) {
+ CCValAssign &VA = RVLocs[i];
+ unsigned Reg = toCallerWindow(VA.getLocReg());
+
+ // When returning 'inreg {i32, i32 }', two consecutive i32 arguments can
+ // reside in the same register in the high and low bits. Reuse the
+ // CopyFromReg previous node to avoid duplicate copies.
+ SDValue RV;
+ if (RegisterSDNode *SrcReg = dyn_cast<RegisterSDNode>(Chain.getOperand(1)))
+ if (SrcReg->getReg() == Reg && Chain->getOpcode() == ISD::CopyFromReg)
+ RV = Chain.getValue(0);
+
+ // But usually we'll create a new CopyFromReg for a different register.
+ if (!RV.getNode()) {
+ RV = DAG.getCopyFromReg(Chain, DL, Reg, RVLocs[i].getLocVT(), InGlue);
+ Chain = RV.getValue(1);
+ InGlue = Chain.getValue(2);
+ }
+
+ // Get the high bits for i32 struct elements.
+ if (VA.getValVT() == MVT::i32 && VA.needsCustom())
+ RV = DAG.getNode(ISD::SRL, DL, VA.getLocVT(), RV,
+ DAG.getConstant(32, DL, MVT::i32));
+
+ // The callee promoted the return value, so insert an Assert?ext SDNode so
+ // we won't promote the value again in this function.
+ switch (VA.getLocInfo()) {
+ case CCValAssign::SExt:
+ RV = DAG.getNode(ISD::AssertSext, DL, VA.getLocVT(), RV,
+ DAG.getValueType(VA.getValVT()));
+ break;
+ case CCValAssign::ZExt:
+ RV = DAG.getNode(ISD::AssertZext, DL, VA.getLocVT(), RV,
+ DAG.getValueType(VA.getValVT()));
+ break;
+ default:
+ break;
+ }
+
+ // Truncate the register down to the return value type.
+ if (VA.isExtInLoc())
+ RV = DAG.getNode(ISD::TRUNCATE, DL, VA.getValVT(), RV);
+
+ InVals.push_back(RV);
+ }
+
+ return Chain;
+}
+
+//===----------------------------------------------------------------------===//
+// TargetLowering Implementation
+//===----------------------------------------------------------------------===//
+
+/// IntCondCCodeToICC - Convert a DAG integer condition code to a SPARC ICC
+/// condition.
+static SPCC::CondCodes IntCondCCodeToICC(ISD::CondCode CC) {
+ switch (CC) {
+ default: llvm_unreachable("Unknown integer condition code!");
+ case ISD::SETEQ: return SPCC::ICC_E;
+ case ISD::SETNE: return SPCC::ICC_NE;
+ case ISD::SETLT: return SPCC::ICC_L;
+ case ISD::SETGT: return SPCC::ICC_G;
+ case ISD::SETLE: return SPCC::ICC_LE;
+ case ISD::SETGE: return SPCC::ICC_GE;
+ case ISD::SETULT: return SPCC::ICC_CS;
+ case ISD::SETULE: return SPCC::ICC_LEU;
+ case ISD::SETUGT: return SPCC::ICC_GU;
+ case ISD::SETUGE: return SPCC::ICC_CC;
+ }
+}
+
+/// FPCondCCodeToFCC - Convert a DAG floatingp oint condition code to a SPARC
+/// FCC condition.
+static SPCC::CondCodes FPCondCCodeToFCC(ISD::CondCode CC) {
+ switch (CC) {
+ default: llvm_unreachable("Unknown fp condition code!");
+ case ISD::SETEQ:
+ case ISD::SETOEQ: return SPCC::FCC_E;
+ case ISD::SETNE:
+ case ISD::SETUNE: return SPCC::FCC_NE;
+ case ISD::SETLT:
+ case ISD::SETOLT: return SPCC::FCC_L;
+ case ISD::SETGT:
+ case ISD::SETOGT: return SPCC::FCC_G;
+ case ISD::SETLE:
+ case ISD::SETOLE: return SPCC::FCC_LE;
+ case ISD::SETGE:
+ case ISD::SETOGE: return SPCC::FCC_GE;
+ case ISD::SETULT: return SPCC::FCC_UL;
+ case ISD::SETULE: return SPCC::FCC_ULE;
+ case ISD::SETUGT: return SPCC::FCC_UG;
+ case ISD::SETUGE: return SPCC::FCC_UGE;
+ case ISD::SETUO: return SPCC::FCC_U;
+ case ISD::SETO: return SPCC::FCC_O;
+ case ISD::SETONE: return SPCC::FCC_LG;
+ case ISD::SETUEQ: return SPCC::FCC_UE;
+ }
+}
+
+SparcTargetLowering::SparcTargetLowering(TargetMachine &TM,
+ const SparcSubtarget &STI)
+ : TargetLowering(TM), Subtarget(&STI) {
+ // 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->is64Bit())
+ addRegisterClass(MVT::i64, &SP::I64RegsRegClass);
+
+ // Turn FP extload into load/fextend
+ for (MVT VT : MVT::fp_valuetypes()) {
+ setLoadExtAction(ISD::EXTLOAD, VT, MVT::f32, Expand);
+ setLoadExtAction(ISD::EXTLOAD, VT, MVT::f64, Expand);
+ }
+
+ // Sparc doesn't have i1 sign extending load
+ for (MVT VT : MVT::integer_valuetypes())
+ setLoadExtAction(ISD::SEXTLOAD, VT, MVT::i1, Promote);
+
+ // Turn FP truncstore into trunc + store.
+ setTruncStoreAction(MVT::f64, MVT::f32, Expand);
+ setTruncStoreAction(MVT::f128, MVT::f32, Expand);
+ setTruncStoreAction(MVT::f128, MVT::f64, Expand);
+
+ // Custom legalize GlobalAddress nodes into LO/HI parts.
+ setOperationAction(ISD::GlobalAddress, getPointerTy(), Custom);
+ setOperationAction(ISD::GlobalTLSAddress, getPointerTy(), Custom);
+ setOperationAction(ISD::ConstantPool, getPointerTy(), Custom);
+ setOperationAction(ISD::BlockAddress, getPointerTy(), Custom);
+
+ // Sparc doesn't have sext_inreg, replace them with shl/sra
+ setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i16, Expand);
+ setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i8 , Expand);
+ setOperationAction(ISD::SIGN_EXTEND_INREG, MVT::i1 , Expand);
+
+ // Sparc has no REM or DIVREM operations.
+ setOperationAction(ISD::UREM, MVT::i32, Expand);
+ setOperationAction(ISD::SREM, MVT::i32, Expand);
+ setOperationAction(ISD::SDIVREM, MVT::i32, Expand);
+ setOperationAction(ISD::UDIVREM, MVT::i32, Expand);
+
+ // ... nor does SparcV9.
+ if (Subtarget->is64Bit()) {
+ setOperationAction(ISD::UREM, MVT::i64, Expand);
+ setOperationAction(ISD::SREM, MVT::i64, Expand);
+ setOperationAction(ISD::SDIVREM, MVT::i64, Expand);
+ setOperationAction(ISD::UDIVREM, MVT::i64, Expand);
+ }
+
+ // Custom expand fp<->sint
+ setOperationAction(ISD::FP_TO_SINT, MVT::i32, Custom);
+ setOperationAction(ISD::SINT_TO_FP, MVT::i32, Custom);
+ setOperationAction(ISD::FP_TO_SINT, MVT::i64, Custom);
+ setOperationAction(ISD::SINT_TO_FP, MVT::i64, Custom);
+
+ // Custom Expand fp<->uint
+ setOperationAction(ISD::FP_TO_UINT, MVT::i32, Custom);
+ setOperationAction(ISD::UINT_TO_FP, MVT::i32, Custom);
+ setOperationAction(ISD::FP_TO_UINT, MVT::i64, Custom);
+ setOperationAction(ISD::UINT_TO_FP, MVT::i64, Custom);
+
+ setOperationAction(ISD::BITCAST, MVT::f32, Expand);
+ setOperationAction(ISD::BITCAST, MVT::i32, Expand);
+
+ // Sparc has no select or setcc: expand to SELECT_CC.
+ setOperationAction(ISD::SELECT, MVT::i32, Expand);
+ setOperationAction(ISD::SELECT, MVT::f32, Expand);
+ setOperationAction(ISD::SELECT, MVT::f64, Expand);
+ setOperationAction(ISD::SELECT, MVT::f128, Expand);
+
+ setOperationAction(ISD::SETCC, MVT::i32, Expand);
+ setOperationAction(ISD::SETCC, MVT::f32, Expand);
+ setOperationAction(ISD::SETCC, MVT::f64, Expand);
+ setOperationAction(ISD::SETCC, MVT::f128, Expand);
+
+ // Sparc doesn't have BRCOND either, it has BR_CC.
+ setOperationAction(ISD::BRCOND, MVT::Other, Expand);
+ setOperationAction(ISD::BRIND, MVT::Other, Expand);
+ setOperationAction(ISD::BR_JT, MVT::Other, Expand);
+ setOperationAction(ISD::BR_CC, MVT::i32, Custom);
+ setOperationAction(ISD::BR_CC, MVT::f32, Custom);
+ setOperationAction(ISD::BR_CC, MVT::f64, Custom);
+ setOperationAction(ISD::BR_CC, MVT::f128, Custom);
+
+ setOperationAction(ISD::SELECT_CC, MVT::i32, Custom);
+ setOperationAction(ISD::SELECT_CC, MVT::f32, Custom);
+ setOperationAction(ISD::SELECT_CC, MVT::f64, Custom);
+ setOperationAction(ISD::SELECT_CC, MVT::f128, Custom);
+
+ if (Subtarget->is64Bit()) {
+ setOperationAction(ISD::ADDC, MVT::i64, Custom);
+ setOperationAction(ISD::ADDE, MVT::i64, Custom);
+ setOperationAction(ISD::SUBC, MVT::i64, Custom);
+ setOperationAction(ISD::SUBE, MVT::i64, Custom);
+ setOperationAction(ISD::BITCAST, MVT::f64, Expand);
+ setOperationAction(ISD::BITCAST, MVT::i64, Expand);
+ setOperationAction(ISD::SELECT, MVT::i64, Expand);
+ setOperationAction(ISD::SETCC, MVT::i64, Expand);
+ setOperationAction(ISD::BR_CC, MVT::i64, Custom);
+ setOperationAction(ISD::SELECT_CC, MVT::i64, Custom);
+
+ 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);
+ setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Custom);
+ }
+
+ // ATOMICs.
+ // FIXME: We insert fences for each atomics and generate sub-optimal code
+ // for PSO/TSO. Also, implement other atomicrmw operations.
+
+ setInsertFencesForAtomic(true);
+
+ 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);
+
+ // Custom Lower Atomic LOAD/STORE
+ setOperationAction(ISD::ATOMIC_LOAD, MVT::i32, Custom);
+ setOperationAction(ISD::ATOMIC_STORE, MVT::i32, Custom);
+
+ if (Subtarget->is64Bit()) {
+ setOperationAction(ISD::ATOMIC_CMP_SWAP, MVT::i64, Legal);
+ setOperationAction(ISD::ATOMIC_SWAP, MVT::i64, Legal);
+ setOperationAction(ISD::ATOMIC_LOAD, MVT::i64, Custom);
+ setOperationAction(ISD::ATOMIC_STORE, MVT::i64, Custom);
+ }
+
+ if (!Subtarget->isV9()) {
+ // SparcV8 does not have FNEGD and FABSD.
+ setOperationAction(ISD::FNEG, MVT::f64, Custom);
+ setOperationAction(ISD::FABS, MVT::f64, Custom);
+ }
+
+ setOperationAction(ISD::FSIN , MVT::f128, Expand);
+ setOperationAction(ISD::FCOS , MVT::f128, Expand);
+ setOperationAction(ISD::FSINCOS, MVT::f128, Expand);
+ setOperationAction(ISD::FREM , MVT::f128, Expand);
+ setOperationAction(ISD::FMA , MVT::f128, Expand);
+ setOperationAction(ISD::FSIN , MVT::f64, Expand);
+ setOperationAction(ISD::FCOS , MVT::f64, Expand);
+ setOperationAction(ISD::FSINCOS, MVT::f64, Expand);
+ setOperationAction(ISD::FREM , MVT::f64, Expand);
+ setOperationAction(ISD::FMA , MVT::f64, Expand);
+ setOperationAction(ISD::FSIN , MVT::f32, Expand);
+ setOperationAction(ISD::FCOS , MVT::f32, Expand);
+ setOperationAction(ISD::FSINCOS, MVT::f32, Expand);
+ 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);
+ setOperationAction(ISD::FCOPYSIGN, MVT::f128, Expand);
+ setOperationAction(ISD::FCOPYSIGN, MVT::f64, Expand);
+ setOperationAction(ISD::FCOPYSIGN, MVT::f32, Expand);
+ setOperationAction(ISD::FPOW , MVT::f128, Expand);
+ setOperationAction(ISD::FPOW , MVT::f64, Expand);
+ setOperationAction(ISD::FPOW , MVT::f32, Expand);
+
+ setOperationAction(ISD::SHL_PARTS, MVT::i32, Expand);
+ setOperationAction(ISD::SRA_PARTS, MVT::i32, Expand);
+ setOperationAction(ISD::SRL_PARTS, MVT::i32, Expand);
+
+ // FIXME: Sparc provides these multiplies, but we don't have them yet.
+ setOperationAction(ISD::UMUL_LOHI, MVT::i32, Expand);
+ setOperationAction(ISD::SMUL_LOHI, MVT::i32, Expand);
+
+ if (Subtarget->is64Bit()) {
+ setOperationAction(ISD::UMUL_LOHI, MVT::i64, Expand);
+ setOperationAction(ISD::SMUL_LOHI, MVT::i64, Expand);
+ setOperationAction(ISD::MULHU, MVT::i64, Expand);
+ setOperationAction(ISD::MULHS, MVT::i64, Expand);
+
+ setOperationAction(ISD::UMULO, MVT::i64, Custom);
+ setOperationAction(ISD::SMULO, MVT::i64, Custom);
+
+ setOperationAction(ISD::SHL_PARTS, MVT::i64, Expand);
+ setOperationAction(ISD::SRA_PARTS, MVT::i64, Expand);
+ setOperationAction(ISD::SRL_PARTS, MVT::i64, Expand);
+ }
+
+ // VASTART needs to be custom lowered to use the VarArgsFrameIndex.
+ setOperationAction(ISD::VASTART , MVT::Other, Custom);
+ // VAARG needs to be lowered to not do unaligned accesses for doubles.
+ setOperationAction(ISD::VAARG , MVT::Other, Custom);
+
+ setOperationAction(ISD::TRAP , MVT::Other, Legal);
+
+ // Use the default implementation.
+ setOperationAction(ISD::VACOPY , MVT::Other, Expand);
+ setOperationAction(ISD::VAEND , MVT::Other, Expand);
+ setOperationAction(ISD::STACKSAVE , MVT::Other, Expand);
+ setOperationAction(ISD::STACKRESTORE , MVT::Other, Expand);
+ setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i32 , Custom);
+
+ setExceptionPointerRegister(SP::I0);
+ setExceptionSelectorRegister(SP::I1);
+
+ setStackPointerRegisterToSaveRestore(SP::O6);
+
+ setOperationAction(ISD::CTPOP, MVT::i32,
+ Subtarget->usePopc() ? Legal : Expand);
+
+ if (Subtarget->isV9() && Subtarget->hasHardQuad()) {
+ setOperationAction(ISD::LOAD, MVT::f128, Legal);
+ setOperationAction(ISD::STORE, MVT::f128, Legal);
+ } else {
+ setOperationAction(ISD::LOAD, MVT::f128, Custom);
+ setOperationAction(ISD::STORE, MVT::f128, Custom);
+ }
+
+ if (Subtarget->hasHardQuad()) {
+ setOperationAction(ISD::FADD, MVT::f128, Legal);
+ setOperationAction(ISD::FSUB, MVT::f128, Legal);
+ setOperationAction(ISD::FMUL, MVT::f128, Legal);
+ setOperationAction(ISD::FDIV, MVT::f128, Legal);
+ setOperationAction(ISD::FSQRT, MVT::f128, Legal);
+ setOperationAction(ISD::FP_EXTEND, MVT::f128, Legal);
+ setOperationAction(ISD::FP_ROUND, MVT::f64, Legal);
+ if (Subtarget->isV9()) {
+ setOperationAction(ISD::FNEG, MVT::f128, Legal);
+ setOperationAction(ISD::FABS, MVT::f128, Legal);
+ } else {
+ setOperationAction(ISD::FNEG, MVT::f128, Custom);
+ setOperationAction(ISD::FABS, MVT::f128, Custom);
+ }
+
+ if (!Subtarget->is64Bit()) {
+ setLibcallName(RTLIB::FPTOSINT_F128_I64, "_Q_qtoll");
+ setLibcallName(RTLIB::FPTOUINT_F128_I64, "_Q_qtoull");
+ setLibcallName(RTLIB::SINTTOFP_I64_F128, "_Q_lltoq");
+ setLibcallName(RTLIB::UINTTOFP_I64_F128, "_Q_ulltoq");
+ }
+
+ } else {
+ // Custom legalize f128 operations.
+
+ setOperationAction(ISD::FADD, MVT::f128, Custom);
+ setOperationAction(ISD::FSUB, MVT::f128, Custom);
+ setOperationAction(ISD::FMUL, MVT::f128, Custom);
+ setOperationAction(ISD::FDIV, MVT::f128, Custom);
+ setOperationAction(ISD::FSQRT, MVT::f128, Custom);
+ setOperationAction(ISD::FNEG, MVT::f128, Custom);
+ setOperationAction(ISD::FABS, MVT::f128, Custom);
+
+ setOperationAction(ISD::FP_EXTEND, MVT::f128, Custom);
+ setOperationAction(ISD::FP_ROUND, MVT::f64, Custom);
+ setOperationAction(ISD::FP_ROUND, MVT::f32, Custom);
+
+ // Setup Runtime library names.
+ if (Subtarget->is64Bit()) {
+ setLibcallName(RTLIB::ADD_F128, "_Qp_add");
+ setLibcallName(RTLIB::SUB_F128, "_Qp_sub");
+ setLibcallName(RTLIB::MUL_F128, "_Qp_mul");
+ setLibcallName(RTLIB::DIV_F128, "_Qp_div");
+ setLibcallName(RTLIB::SQRT_F128, "_Qp_sqrt");
+ setLibcallName(RTLIB::FPTOSINT_F128_I32, "_Qp_qtoi");
+ setLibcallName(RTLIB::FPTOUINT_F128_I32, "_Qp_qtoui");
+ setLibcallName(RTLIB::SINTTOFP_I32_F128, "_Qp_itoq");
+ setLibcallName(RTLIB::UINTTOFP_I32_F128, "_Qp_uitoq");
+ setLibcallName(RTLIB::FPTOSINT_F128_I64, "_Qp_qtox");
+ setLibcallName(RTLIB::FPTOUINT_F128_I64, "_Qp_qtoux");
+ setLibcallName(RTLIB::SINTTOFP_I64_F128, "_Qp_xtoq");
+ setLibcallName(RTLIB::UINTTOFP_I64_F128, "_Qp_uxtoq");
+ setLibcallName(RTLIB::FPEXT_F32_F128, "_Qp_stoq");
+ setLibcallName(RTLIB::FPEXT_F64_F128, "_Qp_dtoq");
+ setLibcallName(RTLIB::FPROUND_F128_F32, "_Qp_qtos");
+ setLibcallName(RTLIB::FPROUND_F128_F64, "_Qp_qtod");
+ } else {
+ setLibcallName(RTLIB::ADD_F128, "_Q_add");
+ setLibcallName(RTLIB::SUB_F128, "_Q_sub");
+ setLibcallName(RTLIB::MUL_F128, "_Q_mul");
+ setLibcallName(RTLIB::DIV_F128, "_Q_div");
+ setLibcallName(RTLIB::SQRT_F128, "_Q_sqrt");
+ setLibcallName(RTLIB::FPTOSINT_F128_I32, "_Q_qtoi");
+ setLibcallName(RTLIB::FPTOUINT_F128_I32, "_Q_qtou");
+ setLibcallName(RTLIB::SINTTOFP_I32_F128, "_Q_itoq");
+ setLibcallName(RTLIB::UINTTOFP_I32_F128, "_Q_utoq");
+ setLibcallName(RTLIB::FPTOSINT_F128_I64, "_Q_qtoll");
+ setLibcallName(RTLIB::FPTOUINT_F128_I64, "_Q_qtoull");
+ setLibcallName(RTLIB::SINTTOFP_I64_F128, "_Q_lltoq");
+ setLibcallName(RTLIB::UINTTOFP_I64_F128, "_Q_ulltoq");
+ setLibcallName(RTLIB::FPEXT_F32_F128, "_Q_stoq");
+ setLibcallName(RTLIB::FPEXT_F64_F128, "_Q_dtoq");
+ setLibcallName(RTLIB::FPROUND_F128_F32, "_Q_qtos");
+ setLibcallName(RTLIB::FPROUND_F128_F64, "_Q_qtod");
+ }
+ }
+
+ setMinFunctionAlignment(2);
+
+ computeRegisterProperties(Subtarget->getRegisterInfo());
+}
+
+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::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";
+ }
+ return nullptr;
+}
+
+EVT SparcTargetLowering::getSetCCResultType(LLVMContext &, EVT VT) const {
+ if (!VT.isVector())
+ return MVT::i32;
+ return VT.changeVectorElementTypeToInteger();
+}
+
+/// isMaskedValueZeroForTargetNode - Return true if 'Op & Mask' is known to
+/// be zero. Op is expected to be a target specific node. Used by DAG
+/// combiner.
+void SparcTargetLowering::computeKnownBitsForTargetNode
+ (const SDValue Op,
+ APInt &KnownZero,
+ APInt &KnownOne,
+ const SelectionDAG &DAG,
+ unsigned Depth) const {
+ APInt KnownZero2, KnownOne2;
+ KnownZero = KnownOne = APInt(KnownZero.getBitWidth(), 0);
+
+ switch (Op.getOpcode()) {
+ default: break;
+ case SPISD::SELECT_ICC:
+ case SPISD::SELECT_XCC:
+ case SPISD::SELECT_FCC:
+ DAG.computeKnownBits(Op.getOperand(1), KnownZero, KnownOne, Depth+1);
+ DAG.computeKnownBits(Op.getOperand(0), KnownZero2, KnownOne2, Depth+1);
+
+ // Only known if known in both the LHS and RHS.
+ KnownOne &= KnownOne2;
+ KnownZero &= KnownZero2;
+ break;
+ }
+}
+
+// Look at LHS/RHS/CC and see if they are a lowered setcc instruction. If so
+// set LHS/RHS and SPCC to the LHS/RHS of the setcc and SPCC to the condition.
+static void LookThroughSetCC(SDValue &LHS, SDValue &RHS,
+ ISD::CondCode CC, unsigned &SPCC) {
+ if (isa<ConstantSDNode>(RHS) &&
+ cast<ConstantSDNode>(RHS)->isNullValue() &&
+ CC == ISD::SETNE &&
+ (((LHS.getOpcode() == SPISD::SELECT_ICC ||
+ LHS.getOpcode() == SPISD::SELECT_XCC) &&
+ LHS.getOperand(3).getOpcode() == SPISD::CMPICC) ||
+ (LHS.getOpcode() == SPISD::SELECT_FCC &&
+ LHS.getOperand(3).getOpcode() == SPISD::CMPFCC)) &&
+ isa<ConstantSDNode>(LHS.getOperand(0)) &&
+ isa<ConstantSDNode>(LHS.getOperand(1)) &&
+ cast<ConstantSDNode>(LHS.getOperand(0))->isOne() &&
+ cast<ConstantSDNode>(LHS.getOperand(1))->isNullValue()) {
+ SDValue CMPCC = LHS.getOperand(3);
+ SPCC = cast<ConstantSDNode>(LHS.getOperand(2))->getZExtValue();
+ LHS = CMPCC.getOperand(0);
+ RHS = CMPCC.getOperand(1);
+ }
+}
+
+// Convert to a target node and set target flags.
+SDValue SparcTargetLowering::withTargetFlags(SDValue Op, unsigned TF,
+ SelectionDAG &DAG) const {
+ if (const GlobalAddressSDNode *GA = dyn_cast<GlobalAddressSDNode>(Op))
+ return DAG.getTargetGlobalAddress(GA->getGlobal(),
+ SDLoc(GA),
+ GA->getValueType(0),
+ GA->getOffset(), TF);
+
+ if (const ConstantPoolSDNode *CP = dyn_cast<ConstantPoolSDNode>(Op))
+ return DAG.getTargetConstantPool(CP->getConstVal(),
+ CP->getValueType(0),
+ CP->getAlignment(),
+ CP->getOffset(), TF);
+
+ if (const BlockAddressSDNode *BA = dyn_cast<BlockAddressSDNode>(Op))
+ return DAG.getTargetBlockAddress(BA->getBlockAddress(),
+ Op.getValueType(),
+ 0,
+ TF);
+
+ if (const ExternalSymbolSDNode *ES = dyn_cast<ExternalSymbolSDNode>(Op))
+ return DAG.getTargetExternalSymbol(ES->getSymbol(),
+ ES->getValueType(0), TF);
+
+ llvm_unreachable("Unhandled address SDNode");
+}
+
+// Split Op into high and low parts according to HiTF and LoTF.
+// Return an ADD node combining the parts.
+SDValue SparcTargetLowering::makeHiLoPair(SDValue Op,
+ unsigned HiTF, unsigned LoTF,
+ SelectionDAG &DAG) const {
+ SDLoc DL(Op);
+ EVT VT = Op.getValueType();
+ SDValue Hi = DAG.getNode(SPISD::Hi, DL, VT, withTargetFlags(Op, HiTF, DAG));
+ SDValue Lo = DAG.getNode(SPISD::Lo, DL, VT, withTargetFlags(Op, LoTF, DAG));
+ return DAG.getNode(ISD::ADD, DL, VT, Hi, Lo);
+}
+
+// Build SDNodes for producing an address from a GlobalAddress, ConstantPool,
+// or ExternalSymbol SDNode.
+SDValue SparcTargetLowering::makeAddress(SDValue Op, SelectionDAG &DAG) const {
+ SDLoc DL(Op);
+ EVT VT = getPointerTy();
+
+ // Handle PIC mode first.
+ if (getTargetMachine().getRelocationModel() == Reloc::PIC_) {
+ // 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);
+ SDValue GlobalBase = DAG.getNode(SPISD::GLOBAL_BASE_REG, DL, VT);
+ SDValue AbsAddr = DAG.getNode(ISD::ADD, DL, VT, GlobalBase, HiLo);
+ // GLOBAL_BASE_REG codegen'ed with call. Inform MFI that this
+ // function has calls.
+ MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
+ MFI->setHasCalls(true);
+ return DAG.getLoad(VT, DL, DAG.getEntryNode(), AbsAddr,
+ MachinePointerInfo::getGOT(), false, false, false, 0);
+ }
+
+ // This is one of the absolute code models.
+ switch(getTargetMachine().getCodeModel()) {
+ default:
+ llvm_unreachable("Unsupported absolute code model");
+ case CodeModel::Small:
+ // abs32.
+ return makeHiLoPair(Op, SparcMCExpr::VK_Sparc_HI,
+ SparcMCExpr::VK_Sparc_LO, DAG);
+ case CodeModel::Medium: {
+ // abs44.
+ SDValue H44 = makeHiLoPair(Op, SparcMCExpr::VK_Sparc_H44,
+ SparcMCExpr::VK_Sparc_M44, DAG);
+ H44 = DAG.getNode(ISD::SHL, DL, VT, H44, DAG.getConstant(12, DL, MVT::i32));
+ SDValue L44 = withTargetFlags(Op, SparcMCExpr::VK_Sparc_L44, DAG);
+ L44 = DAG.getNode(SPISD::Lo, DL, VT, L44);
+ return DAG.getNode(ISD::ADD, DL, VT, H44, L44);
+ }
+ case CodeModel::Large: {
+ // abs64.
+ SDValue Hi = makeHiLoPair(Op, SparcMCExpr::VK_Sparc_HH,
+ SparcMCExpr::VK_Sparc_HM, DAG);
+ Hi = DAG.getNode(ISD::SHL, DL, VT, Hi, DAG.getConstant(32, DL, MVT::i32));
+ SDValue Lo = makeHiLoPair(Op, SparcMCExpr::VK_Sparc_HI,
+ SparcMCExpr::VK_Sparc_LO, DAG);
+ return DAG.getNode(ISD::ADD, DL, VT, Hi, Lo);
+ }
+ }
+}
+
+SDValue SparcTargetLowering::LowerGlobalAddress(SDValue Op,
+ SelectionDAG &DAG) const {
+ return makeAddress(Op, DAG);
+}
+
+SDValue SparcTargetLowering::LowerConstantPool(SDValue Op,
+ SelectionDAG &DAG) const {
+ return makeAddress(Op, DAG);
+}
+
+SDValue SparcTargetLowering::LowerBlockAddress(SDValue Op,
+ SelectionDAG &DAG) const {
+ return makeAddress(Op, DAG);
+}
+
+SDValue SparcTargetLowering::LowerGlobalTLSAddress(SDValue Op,
+ SelectionDAG &DAG) const {
+
+ GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Op);
+ SDLoc DL(GA);
+ const GlobalValue *GV = GA->getGlobal();
+ EVT PtrVT = getPointerTy();
+
+ TLSModel::Model model = getTargetMachine().getTLSModel(GV);
+
+ if (model == TLSModel::GeneralDynamic || model == TLSModel::LocalDynamic) {
+ unsigned HiTF = ((model == TLSModel::GeneralDynamic)
+ ? SparcMCExpr::VK_Sparc_TLS_GD_HI22
+ : SparcMCExpr::VK_Sparc_TLS_LDM_HI22);
+ unsigned LoTF = ((model == TLSModel::GeneralDynamic)
+ ? SparcMCExpr::VK_Sparc_TLS_GD_LO10
+ : SparcMCExpr::VK_Sparc_TLS_LDM_LO10);
+ unsigned addTF = ((model == TLSModel::GeneralDynamic)
+ ? SparcMCExpr::VK_Sparc_TLS_GD_ADD
+ : SparcMCExpr::VK_Sparc_TLS_LDM_ADD);
+ unsigned callTF = ((model == TLSModel::GeneralDynamic)
+ ? SparcMCExpr::VK_Sparc_TLS_GD_CALL
+ : SparcMCExpr::VK_Sparc_TLS_LDM_CALL);
+
+ SDValue HiLo = makeHiLoPair(Op, HiTF, LoTF, DAG);
+ SDValue Base = DAG.getNode(SPISD::GLOBAL_BASE_REG, DL, PtrVT);
+ SDValue Argument = DAG.getNode(SPISD::TLS_ADD, DL, PtrVT, Base, HiLo,
+ withTargetFlags(Op, addTF, DAG));
+
+ SDValue Chain = DAG.getEntryNode();
+ SDValue InFlag;
+
+ Chain = DAG.getCALLSEQ_START(Chain, DAG.getIntPtrConstant(1, DL, true), DL);
+ Chain = DAG.getCopyToReg(Chain, DL, SP::O0, Argument, InFlag);
+ InFlag = Chain.getValue(1);
+ SDValue Callee = DAG.getTargetExternalSymbol("__tls_get_addr", PtrVT);
+ 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);
+ Chain = DAG.getNode(SPISD::TLS_CALL, DL, NodeTys, Ops);
+ InFlag = Chain.getValue(1);
+ Chain = DAG.getCALLSEQ_END(Chain, DAG.getIntPtrConstant(1, DL, true),
+ DAG.getIntPtrConstant(0, DL, true), InFlag, DL);
+ InFlag = Chain.getValue(1);
+ SDValue Ret = DAG.getCopyFromReg(Chain, DL, SP::O0, PtrVT, InFlag);
+
+ if (model != TLSModel::LocalDynamic)
+ return Ret;
+
+ SDValue Hi = DAG.getNode(SPISD::Hi, DL, PtrVT,
+ withTargetFlags(Op, SparcMCExpr::VK_Sparc_TLS_LDO_HIX22, DAG));
+ SDValue Lo = DAG.getNode(SPISD::Lo, DL, PtrVT,
+ withTargetFlags(Op, SparcMCExpr::VK_Sparc_TLS_LDO_LOX10, DAG));
+ HiLo = DAG.getNode(ISD::XOR, DL, PtrVT, Hi, Lo);
+ return DAG.getNode(SPISD::TLS_ADD, DL, PtrVT, Ret, HiLo,
+ withTargetFlags(Op, SparcMCExpr::VK_Sparc_TLS_LDO_ADD, DAG));
+ }
+
+ if (model == TLSModel::InitialExec) {
+ unsigned ldTF = ((PtrVT == MVT::i64)? SparcMCExpr::VK_Sparc_TLS_IE_LDX
+ : SparcMCExpr::VK_Sparc_TLS_IE_LD);
+
+ SDValue Base = DAG.getNode(SPISD::GLOBAL_BASE_REG, DL, PtrVT);
+
+ // GLOBAL_BASE_REG codegen'ed with call. Inform MFI that this
+ // function has calls.
+ MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
+ MFI->setHasCalls(true);
+
+ SDValue TGA = makeHiLoPair(Op,
+ SparcMCExpr::VK_Sparc_TLS_IE_HI22,
+ SparcMCExpr::VK_Sparc_TLS_IE_LO10, DAG);
+ SDValue Ptr = DAG.getNode(ISD::ADD, DL, PtrVT, Base, TGA);
+ SDValue Offset = DAG.getNode(SPISD::TLS_LD,
+ DL, PtrVT, Ptr,
+ withTargetFlags(Op, ldTF, DAG));
+ return DAG.getNode(SPISD::TLS_ADD, DL, PtrVT,
+ DAG.getRegister(SP::G7, PtrVT), Offset,
+ withTargetFlags(Op,
+ SparcMCExpr::VK_Sparc_TLS_IE_ADD, DAG));
+ }
+
+ assert(model == TLSModel::LocalExec);
+ SDValue Hi = DAG.getNode(SPISD::Hi, DL, PtrVT,
+ withTargetFlags(Op, SparcMCExpr::VK_Sparc_TLS_LE_HIX22, DAG));
+ SDValue Lo = DAG.getNode(SPISD::Lo, DL, PtrVT,
+ withTargetFlags(Op, SparcMCExpr::VK_Sparc_TLS_LE_LOX10, DAG));
+ SDValue Offset = DAG.getNode(ISD::XOR, DL, PtrVT, Hi, Lo);
+
+ return DAG.getNode(ISD::ADD, DL, PtrVT,
+ DAG.getRegister(SP::G7, PtrVT), Offset);
+}
+
+SDValue
+SparcTargetLowering::LowerF128_LibCallArg(SDValue Chain, ArgListTy &Args,
+ SDValue Arg, SDLoc DL,
+ SelectionDAG &DAG) const {
+ MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
+ EVT ArgVT = Arg.getValueType();
+ Type *ArgTy = ArgVT.getTypeForEVT(*DAG.getContext());
+
+ ArgListEntry Entry;
+ Entry.Node = Arg;
+ Entry.Ty = ArgTy;
+
+ if (ArgTy->isFP128Ty()) {
+ // 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());
+ Chain = DAG.getStore(Chain,
+ DL,
+ Entry.Node,
+ FIPtr,
+ MachinePointerInfo(),
+ false,
+ false,
+ 8);
+
+ Entry.Node = FIPtr;
+ Entry.Ty = PointerType::getUnqual(ArgTy);
+ }
+ Args.push_back(Entry);
+ return Chain;
+}
+
+SDValue
+SparcTargetLowering::LowerF128Op(SDValue Op, SelectionDAG &DAG,
+ const char *LibFuncName,
+ unsigned numArgs) const {
+
+ ArgListTy Args;
+
+ MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
+
+ SDValue Callee = DAG.getExternalSymbol(LibFuncName, getPointerTy());
+ Type *RetTy = Op.getValueType().getTypeForEVT(*DAG.getContext());
+ Type *RetTyABI = RetTy;
+ SDValue Chain = DAG.getEntryNode();
+ SDValue RetPtr;
+
+ if (RetTy->isFP128Ty()) {
+ // Create a Stack Object to receive the return value of type f128.
+ ArgListEntry Entry;
+ int RetFI = MFI->CreateStackObject(16, 8, false);
+ RetPtr = DAG.getFrameIndex(RetFI, getPointerTy());
+ Entry.Node = RetPtr;
+ Entry.Ty = PointerType::getUnqual(RetTy);
+ if (!Subtarget->is64Bit())
+ Entry.isSRet = true;
+ Entry.isReturned = false;
+ Args.push_back(Entry);
+ RetTyABI = Type::getVoidTy(*DAG.getContext());
+ }
+
+ assert(Op->getNumOperands() >= numArgs && "Not enough operands!");
+ for (unsigned i = 0, e = numArgs; i != e; ++i) {
+ Chain = LowerF128_LibCallArg(Chain, Args, Op.getOperand(i), SDLoc(Op), DAG);
+ }
+ TargetLowering::CallLoweringInfo CLI(DAG);
+ CLI.setDebugLoc(SDLoc(Op)).setChain(Chain)
+ .setCallee(CallingConv::C, RetTyABI, Callee, std::move(Args), 0);
+
+ std::pair<SDValue, SDValue> CallInfo = LowerCallTo(CLI);
+
+ // chain is in second result.
+ if (RetTyABI == RetTy)
+ return CallInfo.first;
+
+ assert (RetTy->isFP128Ty() && "Unexpected return type!");
+
+ Chain = CallInfo.second;
+
+ // Load RetPtr to get the return value.
+ return DAG.getLoad(Op.getValueType(),
+ SDLoc(Op),
+ Chain,
+ RetPtr,
+ MachinePointerInfo(),
+ false, false, false, 8);
+}
+
+SDValue
+SparcTargetLowering::LowerF128Compare(SDValue LHS, SDValue RHS,
+ unsigned &SPCC,
+ SDLoc DL,
+ SelectionDAG &DAG) const {
+
+ const char *LibCall = nullptr;
+ bool is64Bit = Subtarget->is64Bit();
+ switch(SPCC) {
+ default: llvm_unreachable("Unhandled conditional code!");
+ case SPCC::FCC_E : LibCall = is64Bit? "_Qp_feq" : "_Q_feq"; break;
+ case SPCC::FCC_NE : LibCall = is64Bit? "_Qp_fne" : "_Q_fne"; break;
+ case SPCC::FCC_L : LibCall = is64Bit? "_Qp_flt" : "_Q_flt"; break;
+ case SPCC::FCC_G : LibCall = is64Bit? "_Qp_fgt" : "_Q_fgt"; break;
+ case SPCC::FCC_LE : LibCall = is64Bit? "_Qp_fle" : "_Q_fle"; break;
+ case SPCC::FCC_GE : LibCall = is64Bit? "_Qp_fge" : "_Q_fge"; break;
+ case SPCC::FCC_UL :
+ case SPCC::FCC_ULE:
+ case SPCC::FCC_UG :
+ case SPCC::FCC_UGE:
+ case SPCC::FCC_U :
+ case SPCC::FCC_O :
+ case SPCC::FCC_LG :
+ case SPCC::FCC_UE : LibCall = is64Bit? "_Qp_cmp" : "_Q_cmp"; break;
+ }
+
+ SDValue Callee = DAG.getExternalSymbol(LibCall, getPointerTy());
+ Type *RetTy = Type::getInt32Ty(*DAG.getContext());
+ ArgListTy Args;
+ SDValue Chain = DAG.getEntryNode();
+ Chain = LowerF128_LibCallArg(Chain, Args, LHS, DL, DAG);
+ Chain = LowerF128_LibCallArg(Chain, Args, RHS, DL, DAG);
+
+ TargetLowering::CallLoweringInfo CLI(DAG);
+ CLI.setDebugLoc(DL).setChain(Chain)
+ .setCallee(CallingConv::C, RetTy, Callee, std::move(Args), 0);
+
+ std::pair<SDValue, SDValue> CallInfo = LowerCallTo(CLI);
+
+ // result is in first, and chain is in second result.
+ SDValue Result = CallInfo.first;
+
+ switch(SPCC) {
+ default: {
+ SDValue RHS = DAG.getTargetConstant(0, DL, Result.getValueType());
+ SPCC = SPCC::ICC_NE;
+ return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS);
+ }
+ case SPCC::FCC_UL : {
+ SDValue Mask = DAG.getTargetConstant(1, DL, Result.getValueType());
+ Result = DAG.getNode(ISD::AND, DL, Result.getValueType(), Result, Mask);
+ SDValue RHS = DAG.getTargetConstant(0, DL, Result.getValueType());
+ SPCC = SPCC::ICC_NE;
+ return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS);
+ }
+ case SPCC::FCC_ULE: {
+ SDValue RHS = DAG.getTargetConstant(2, DL, Result.getValueType());
+ SPCC = SPCC::ICC_NE;
+ return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS);
+ }
+ case SPCC::FCC_UG : {
+ SDValue RHS = DAG.getTargetConstant(1, DL, Result.getValueType());
+ SPCC = SPCC::ICC_G;
+ return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS);
+ }
+ case SPCC::FCC_UGE: {
+ SDValue RHS = DAG.getTargetConstant(1, DL, Result.getValueType());
+ SPCC = SPCC::ICC_NE;
+ return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS);
+ }
+
+ case SPCC::FCC_U : {
+ SDValue RHS = DAG.getTargetConstant(3, DL, Result.getValueType());
+ SPCC = SPCC::ICC_E;
+ return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS);
+ }
+ case SPCC::FCC_O : {
+ SDValue RHS = DAG.getTargetConstant(3, DL, Result.getValueType());
+ SPCC = SPCC::ICC_NE;
+ return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS);
+ }
+ case SPCC::FCC_LG : {
+ SDValue Mask = DAG.getTargetConstant(3, DL, Result.getValueType());
+ Result = DAG.getNode(ISD::AND, DL, Result.getValueType(), Result, Mask);
+ SDValue RHS = DAG.getTargetConstant(0, DL, Result.getValueType());
+ SPCC = SPCC::ICC_NE;
+ return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS);
+ }
+ case SPCC::FCC_UE : {
+ SDValue Mask = DAG.getTargetConstant(3, DL, Result.getValueType());
+ Result = DAG.getNode(ISD::AND, DL, Result.getValueType(), Result, Mask);
+ SDValue RHS = DAG.getTargetConstant(0, DL, Result.getValueType());
+ SPCC = SPCC::ICC_E;
+ return DAG.getNode(SPISD::CMPICC, DL, MVT::Glue, Result, RHS);
+ }
+ }
+}
+
+static SDValue
+LowerF128_FPEXTEND(SDValue Op, SelectionDAG &DAG,
+ const SparcTargetLowering &TLI) {
+
+ if (Op.getOperand(0).getValueType() == MVT::f64)
+ return TLI.LowerF128Op(Op, DAG,
+ TLI.getLibcallName(RTLIB::FPEXT_F64_F128), 1);
+
+ if (Op.getOperand(0).getValueType() == MVT::f32)
+ return TLI.LowerF128Op(Op, DAG,
+ TLI.getLibcallName(RTLIB::FPEXT_F32_F128), 1);
+
+ llvm_unreachable("fpextend with non-float operand!");
+ return SDValue();
+}
+
+static SDValue
+LowerF128_FPROUND(SDValue Op, SelectionDAG &DAG,
+ const SparcTargetLowering &TLI) {
+ // FP_ROUND on f64 and f32 are legal.
+ if (Op.getOperand(0).getValueType() != MVT::f128)
+ return Op;
+
+ if (Op.getValueType() == MVT::f64)
+ return TLI.LowerF128Op(Op, DAG,
+ TLI.getLibcallName(RTLIB::FPROUND_F128_F64), 1);
+ if (Op.getValueType() == MVT::f32)
+ return TLI.LowerF128Op(Op, DAG,
+ TLI.getLibcallName(RTLIB::FPROUND_F128_F32), 1);
+
+ llvm_unreachable("fpround to non-float!");
+ return SDValue();
+}
+
+static SDValue LowerFP_TO_SINT(SDValue Op, SelectionDAG &DAG,
+ const SparcTargetLowering &TLI,
+ bool hasHardQuad) {
+ SDLoc dl(Op);
+ EVT VT = Op.getValueType();
+ assert(VT == MVT::i32 || VT == MVT::i64);
+
+ // Expand f128 operations to fp128 abi calls.
+ if (Op.getOperand(0).getValueType() == MVT::f128
+ && (!hasHardQuad || !TLI.isTypeLegal(VT))) {
+ const char *libName = TLI.getLibcallName(VT == MVT::i32
+ ? RTLIB::FPTOSINT_F128_I32
+ : RTLIB::FPTOSINT_F128_I64);
+ return TLI.LowerF128Op(Op, DAG, libName, 1);
+ }
+
+ // Expand if the resulting type is illegal.
+ if (!TLI.isTypeLegal(VT))
+ return SDValue();
+
+ // Otherwise, Convert the fp value to integer in an FP register.
+ if (VT == MVT::i32)
+ Op = DAG.getNode(SPISD::FTOI, dl, MVT::f32, Op.getOperand(0));
+ else
+ Op = DAG.getNode(SPISD::FTOX, dl, MVT::f64, Op.getOperand(0));
+
+ return DAG.getNode(ISD::BITCAST, dl, VT, Op);
+}
+
+static SDValue LowerSINT_TO_FP(SDValue Op, SelectionDAG &DAG,
+ const SparcTargetLowering &TLI,
+ bool hasHardQuad) {
+ SDLoc dl(Op);
+ EVT OpVT = Op.getOperand(0).getValueType();
+ assert(OpVT == MVT::i32 || (OpVT == MVT::i64));
+
+ EVT floatVT = (OpVT == MVT::i32) ? MVT::f32 : MVT::f64;
+
+ // Expand f128 operations to fp128 ABI calls.
+ if (Op.getValueType() == MVT::f128
+ && (!hasHardQuad || !TLI.isTypeLegal(OpVT))) {
+ const char *libName = TLI.getLibcallName(OpVT == MVT::i32
+ ? RTLIB::SINTTOFP_I32_F128
+ : RTLIB::SINTTOFP_I64_F128);
+ return TLI.LowerF128Op(Op, DAG, libName, 1);
+ }
+
+ // Expand if the operand type is illegal.
+ if (!TLI.isTypeLegal(OpVT))
+ return SDValue();
+
+ // Otherwise, Convert the int value to FP in an FP register.
+ SDValue Tmp = DAG.getNode(ISD::BITCAST, dl, floatVT, Op.getOperand(0));
+ unsigned opcode = (OpVT == MVT::i32)? SPISD::ITOF : SPISD::XTOF;
+ return DAG.getNode(opcode, dl, Op.getValueType(), Tmp);
+}
+
+static SDValue LowerFP_TO_UINT(SDValue Op, SelectionDAG &DAG,
+ const SparcTargetLowering &TLI,
+ bool hasHardQuad) {
+ SDLoc dl(Op);
+ EVT VT = Op.getValueType();
+
+ // Expand if it does not involve f128 or the target has support for
+ // quad floating point instructions and the resulting type is legal.
+ if (Op.getOperand(0).getValueType() != MVT::f128 ||
+ (hasHardQuad && TLI.isTypeLegal(VT)))
+ return SDValue();
+
+ assert(VT == MVT::i32 || VT == MVT::i64);
+
+ return TLI.LowerF128Op(Op, DAG,
+ TLI.getLibcallName(VT == MVT::i32
+ ? RTLIB::FPTOUINT_F128_I32
+ : RTLIB::FPTOUINT_F128_I64),
+ 1);
+}
+
+static SDValue LowerUINT_TO_FP(SDValue Op, SelectionDAG &DAG,
+ const SparcTargetLowering &TLI,
+ bool hasHardQuad) {
+ SDLoc dl(Op);
+ EVT OpVT = Op.getOperand(0).getValueType();
+ assert(OpVT == MVT::i32 || OpVT == MVT::i64);
+
+ // Expand if it does not involve f128 or the target has support for
+ // quad floating point instructions and the operand type is legal.
+ if (Op.getValueType() != MVT::f128 || (hasHardQuad && TLI.isTypeLegal(OpVT)))
+ return SDValue();
+
+ return TLI.LowerF128Op(Op, DAG,
+ TLI.getLibcallName(OpVT == MVT::i32
+ ? RTLIB::UINTTOFP_I32_F128
+ : RTLIB::UINTTOFP_I64_F128),
+ 1);
+}
+
+static SDValue LowerBR_CC(SDValue Op, SelectionDAG &DAG,
+ const SparcTargetLowering &TLI,
+ bool hasHardQuad) {
+ SDValue Chain = Op.getOperand(0);
+ ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(1))->get();
+ SDValue LHS = Op.getOperand(2);
+ SDValue RHS = Op.getOperand(3);
+ SDValue Dest = Op.getOperand(4);
+ SDLoc dl(Op);
+ unsigned Opc, SPCC = ~0U;
+
+ // If this is a br_cc of a "setcc", and if the setcc got lowered into
+ // an CMP[IF]CC/SELECT_[IF]CC pair, find the original compared values.
+ LookThroughSetCC(LHS, RHS, CC, SPCC);
+
+ // Get the condition flag.
+ SDValue CompareFlag;
+ if (LHS.getValueType().isInteger()) {
+ CompareFlag = DAG.getNode(SPISD::CMPICC, dl, MVT::Glue, LHS, RHS);
+ if (SPCC == ~0U) SPCC = IntCondCCodeToICC(CC);
+ // 32-bit compares use the icc flags, 64-bit uses the xcc flags.
+ Opc = LHS.getValueType() == MVT::i32 ? SPISD::BRICC : SPISD::BRXCC;
+ } else {
+ if (!hasHardQuad && LHS.getValueType() == MVT::f128) {
+ if (SPCC == ~0U) SPCC = FPCondCCodeToFCC(CC);
+ CompareFlag = TLI.LowerF128Compare(LHS, RHS, SPCC, dl, DAG);
+ Opc = SPISD::BRICC;
+ } else {
+ CompareFlag = DAG.getNode(SPISD::CMPFCC, dl, MVT::Glue, LHS, RHS);
+ if (SPCC == ~0U) SPCC = FPCondCCodeToFCC(CC);
+ Opc = SPISD::BRFCC;
+ }
+ }
+ return DAG.getNode(Opc, dl, MVT::Other, Chain, Dest,
+ DAG.getConstant(SPCC, dl, MVT::i32), CompareFlag);
+}
+
+static SDValue LowerSELECT_CC(SDValue Op, SelectionDAG &DAG,
+ const SparcTargetLowering &TLI,
+ bool hasHardQuad) {
+ SDValue LHS = Op.getOperand(0);
+ SDValue RHS = Op.getOperand(1);
+ ISD::CondCode CC = cast<CondCodeSDNode>(Op.getOperand(4))->get();
+ SDValue TrueVal = Op.getOperand(2);
+ SDValue FalseVal = Op.getOperand(3);
+ SDLoc dl(Op);
+ unsigned Opc, SPCC = ~0U;
+
+ // If this is a select_cc of a "setcc", and if the setcc got lowered into
+ // an CMP[IF]CC/SELECT_[IF]CC pair, find the original compared values.
+ LookThroughSetCC(LHS, RHS, CC, SPCC);
+
+ SDValue CompareFlag;
+ if (LHS.getValueType().isInteger()) {
+ CompareFlag = DAG.getNode(SPISD::CMPICC, dl, MVT::Glue, LHS, RHS);
+ Opc = LHS.getValueType() == MVT::i32 ?
+ SPISD::SELECT_ICC : SPISD::SELECT_XCC;
+ if (SPCC == ~0U) SPCC = IntCondCCodeToICC(CC);
+ } else {
+ if (!hasHardQuad && LHS.getValueType() == MVT::f128) {
+ if (SPCC == ~0U) SPCC = FPCondCCodeToFCC(CC);
+ CompareFlag = TLI.LowerF128Compare(LHS, RHS, SPCC, dl, DAG);
+ Opc = SPISD::SELECT_ICC;
+ } else {
+ CompareFlag = DAG.getNode(SPISD::CMPFCC, dl, MVT::Glue, LHS, RHS);
+ Opc = SPISD::SELECT_FCC;
+ if (SPCC == ~0U) SPCC = FPCondCCodeToFCC(CC);
+ }
+ }
+ return DAG.getNode(Opc, dl, TrueVal.getValueType(), TrueVal, FalseVal,
+ DAG.getConstant(SPCC, dl, MVT::i32), CompareFlag);
+}
+
+static SDValue LowerVASTART(SDValue Op, SelectionDAG &DAG,
+ const SparcTargetLowering &TLI) {
+ MachineFunction &MF = DAG.getMachineFunction();
+ SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>();
+
+ // Need frame address to find the address of VarArgsFrameIndex.
+ MF.getFrameInfo()->setFrameAddressIsTaken(true);
+
+ // vastart just stores the address of the VarArgsFrameIndex slot into the
+ // memory location argument.
+ SDLoc DL(Op);
+ SDValue Offset =
+ DAG.getNode(ISD::ADD, DL, TLI.getPointerTy(),
+ DAG.getRegister(SP::I6, TLI.getPointerTy()),
+ 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);
+}
+
+static SDValue LowerVAARG(SDValue Op, SelectionDAG &DAG) {
+ SDNode *Node = Op.getNode();
+ EVT VT = Node->getValueType(0);
+ SDValue InChain = Node->getOperand(0);
+ SDValue VAListPtr = Node->getOperand(1);
+ 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);
+ // 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);
+ // 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);
+}
+
+static SDValue LowerDYNAMIC_STACKALLOC(SDValue Op, SelectionDAG &DAG,
+ const SparcSubtarget *Subtarget) {
+ SDValue Chain = Op.getOperand(0); // Legalize the chain.
+ SDValue Size = Op.getOperand(1); // Legalize the size.
+ EVT VT = Size->getValueType(0);
+ SDLoc dl(Op);
+
+ unsigned SPReg = SP::O6;
+ SDValue SP = DAG.getCopyFromReg(Chain, dl, SPReg, VT);
+ SDValue NewSP = DAG.getNode(ISD::SUB, dl, VT, SP, Size); // Value
+ Chain = DAG.getCopyToReg(SP.getValue(1), dl, SPReg, NewSP); // Output chain
+
+ // The resultant pointer is actually 16 words from the bottom of the stack,
+ // to provide a register spill area.
+ unsigned regSpillArea = Subtarget->is64Bit() ? 128 : 96;
+ regSpillArea += Subtarget->getStackPointerBias();
+
+ SDValue NewVal = DAG.getNode(ISD::ADD, dl, VT, NewSP,
+ DAG.getConstant(regSpillArea, dl, VT));
+ SDValue Ops[2] = { NewVal, Chain };
+ return DAG.getMergeValues(Ops, dl);
+}
+
+
+static SDValue getFLUSHW(SDValue Op, SelectionDAG &DAG) {
+ SDLoc dl(Op);
+ SDValue Chain = DAG.getNode(SPISD::FLUSHW,
+ dl, MVT::Other, DAG.getEntryNode());
+ return Chain;
+}
+
+static SDValue getFRAMEADDR(uint64_t depth, SDValue Op, SelectionDAG &DAG,
+ const SparcSubtarget *Subtarget) {
+ MachineFrameInfo *MFI = DAG.getMachineFunction().getFrameInfo();
+ MFI->setFrameAddressIsTaken(true);
+
+ EVT VT = Op.getValueType();
+ SDLoc dl(Op);
+ unsigned FrameReg = SP::I6;
+ unsigned stackBias = Subtarget->getStackPointerBias();
+
+ SDValue FrameAddr;
+
+ if (depth == 0) {
+ FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl, FrameReg, VT);
+ if (Subtarget->is64Bit())
+ FrameAddr = DAG.getNode(ISD::ADD, dl, VT, FrameAddr,
+ DAG.getIntPtrConstant(stackBias, dl));
+ return FrameAddr;
+ }
+
+ // flush first to make sure the windowed registers' values are in stack
+ SDValue Chain = getFLUSHW(Op, DAG);
+ FrameAddr = DAG.getCopyFromReg(Chain, dl, FrameReg, VT);
+
+ unsigned Offset = (Subtarget->is64Bit()) ? (stackBias + 112) : 56;
+
+ 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);
+ }
+ if (Subtarget->is64Bit())
+ FrameAddr = DAG.getNode(ISD::ADD, dl, VT, FrameAddr,
+ DAG.getIntPtrConstant(stackBias, dl));
+ return FrameAddr;
+}
+
+
+static SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG,
+ const SparcSubtarget *Subtarget) {
+
+ uint64_t depth = Op.getConstantOperandVal(0);
+
+ return getFRAMEADDR(depth, Op, DAG, Subtarget);
+
+}
+
+static SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG,
+ const SparcTargetLowering &TLI,
+ const SparcSubtarget *Subtarget) {
+ MachineFunction &MF = DAG.getMachineFunction();
+ MachineFrameInfo *MFI = MF.getFrameInfo();
+ MFI->setReturnAddressIsTaken(true);
+
+ if (TLI.verifyReturnAddressArgumentIsConstant(Op, DAG))
+ return SDValue();
+
+ EVT VT = Op.getValueType();
+ SDLoc dl(Op);
+ uint64_t depth = Op.getConstantOperandVal(0);
+
+ SDValue RetAddr;
+ if (depth == 0) {
+ unsigned RetReg = MF.addLiveIn(SP::I7,
+ TLI.getRegClassFor(TLI.getPointerTy()));
+ RetAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl, RetReg, VT);
+ return RetAddr;
+ }
+
+ // Need frame address to find return address of the caller.
+ SDValue FrameAddr = getFRAMEADDR(depth - 1, Op, DAG, Subtarget);
+
+ unsigned Offset = (Subtarget->is64Bit()) ? 120 : 60;
+ SDValue Ptr = DAG.getNode(ISD::ADD,
+ dl, VT,
+ FrameAddr,
+ DAG.getIntPtrConstant(Offset, dl));
+ RetAddr = DAG.getLoad(VT, dl, DAG.getEntryNode(), Ptr,
+ MachinePointerInfo(), false, false, false, 0);
+
+ return RetAddr;
+}
+
+static SDValue LowerF64Op(SDValue Op, SelectionDAG &DAG, unsigned opcode)
+{
+ SDLoc dl(Op);
+
+ assert(Op.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);
+ 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);
+
+ SDValue DstReg64 = SDValue(DAG.getMachineNode(TargetOpcode::IMPLICIT_DEF,
+ dl, MVT::f64), 0);
+ DstReg64 = DAG.getTargetInsertSubreg(SP::sub_even, dl, MVT::f64,
+ DstReg64, Hi32);
+ DstReg64 = DAG.getTargetInsertSubreg(SP::sub_odd, dl, MVT::f64,
+ DstReg64, Lo32);
+ return DstReg64;
+}
+
+// Lower a f128 load into two f64 loads.
+static SDValue LowerF128Load(SDValue Op, SelectionDAG &DAG)
+{
+ SDLoc dl(Op);
+ LoadSDNode *LdNode = dyn_cast<LoadSDNode>(Op.getNode());
+ assert(LdNode && LdNode->getOffset().getOpcode() == ISD::UNDEF
+ && "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);
+ 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 SubRegEven = DAG.getTargetConstant(SP::sub_even64, dl, MVT::i32);
+ SDValue SubRegOdd = DAG.getTargetConstant(SP::sub_odd64, dl, MVT::i32);
+
+ SDNode *InFP128 = DAG.getMachineNode(TargetOpcode::IMPLICIT_DEF,
+ dl, MVT::f128);
+ InFP128 = DAG.getMachineNode(TargetOpcode::INSERT_SUBREG, dl,
+ MVT::f128,
+ SDValue(InFP128, 0),
+ Hi64,
+ SubRegEven);
+ InFP128 = DAG.getMachineNode(TargetOpcode::INSERT_SUBREG, dl,
+ MVT::f128,
+ SDValue(InFP128, 0),
+ Lo64,
+ SubRegOdd);
+ SDValue OutChains[2] = { SDValue(Hi64.getNode(), 1),
+ SDValue(Lo64.getNode(), 1) };
+ SDValue OutChain = DAG.getNode(ISD::TokenFactor, dl, MVT::Other, OutChains);
+ SDValue Ops[2] = {SDValue(InFP128,0), OutChain};
+ return DAG.getMergeValues(Ops, dl);
+}
+
+// Lower a f128 store into two f64 stores.
+static SDValue LowerF128Store(SDValue Op, SelectionDAG &DAG) {
+ SDLoc dl(Op);
+ StoreSDNode *StNode = dyn_cast<StoreSDNode>(Op.getNode());
+ assert(StNode && StNode->getOffset().getOpcode() == ISD::UNDEF
+ && "Unexpected node type");
+ SDValue SubRegEven = DAG.getTargetConstant(SP::sub_even64, dl, MVT::i32);
+ SDValue SubRegOdd = DAG.getTargetConstant(SP::sub_odd64, dl, MVT::i32);
+
+ SDNode *Hi64 = DAG.getMachineNode(TargetOpcode::EXTRACT_SUBREG,
+ dl,
+ MVT::f64,
+ StNode->getValue(),
+ SubRegEven);
+ SDNode *Lo64 = DAG.getMachineNode(TargetOpcode::EXTRACT_SUBREG,
+ dl,
+ MVT::f64,
+ StNode->getValue(),
+ SubRegOdd);
+
+ unsigned alignment = StNode->getAlignment();
+ if (alignment > 8)
+ alignment = 8;
+
+ SDValue OutChains[2];
+ OutChains[0] = DAG.getStore(StNode->getChain(),
+ dl,
+ SDValue(Hi64, 0),
+ StNode->getBasePtr(),
+ MachinePointerInfo(),
+ false, false, 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);
+ return DAG.getNode(ISD::TokenFactor, dl, MVT::Other, OutChains);
+}
+
+static SDValue LowerFNEGorFABS(SDValue Op, SelectionDAG &DAG, bool isV9) {
+ assert((Op.getOpcode() == ISD::FNEG || Op.getOpcode() == ISD::FABS)
+ && "invalid opcode");
+
+ if (Op.getValueType() == MVT::f64)
+ return LowerF64Op(Op, 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
+
+ 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());
+
+ SDValue DstReg128 = SDValue(DAG.getMachineNode(TargetOpcode::IMPLICIT_DEF,
+ dl, MVT::f128), 0);
+ DstReg128 = DAG.getTargetInsertSubreg(SP::sub_even64, dl, MVT::f128,
+ DstReg128, Hi64);
+ DstReg128 = DAG.getTargetInsertSubreg(SP::sub_odd64, dl, MVT::f128,
+ DstReg128, Lo64);
+ return DstReg128;
+}
+
+static SDValue LowerADDC_ADDE_SUBC_SUBE(SDValue Op, SelectionDAG &DAG) {
+
+ if (Op.getValueType() != MVT::i64)
+ return Op;
+
+ SDLoc dl(Op);
+ SDValue Src1 = Op.getOperand(0);
+ SDValue Src1Lo = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Src1);
+ SDValue Src1Hi = DAG.getNode(ISD::SRL, dl, MVT::i64, Src1,
+ DAG.getConstant(32, dl, MVT::i64));
+ Src1Hi = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Src1Hi);
+
+ SDValue Src2 = Op.getOperand(1);
+ SDValue Src2Lo = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Src2);
+ SDValue Src2Hi = DAG.getNode(ISD::SRL, dl, MVT::i64, Src2,
+ DAG.getConstant(32, dl, MVT::i64));
+ Src2Hi = DAG.getNode(ISD::TRUNCATE, dl, MVT::i32, Src2Hi);
+
+
+ bool hasChain = false;
+ unsigned hiOpc = Op.getOpcode();
+ switch (Op.getOpcode()) {
+ default: llvm_unreachable("Invalid opcode");
+ case ISD::ADDC: hiOpc = ISD::ADDE; break;
+ case ISD::ADDE: hasChain = true; break;
+ case ISD::SUBC: hiOpc = ISD::SUBE; break;
+ case ISD::SUBE: hasChain = true; break;
+ }
+ SDValue Lo;
+ SDVTList VTs = DAG.getVTList(MVT::i32, MVT::Glue);
+ if (hasChain) {
+ Lo = DAG.getNode(Op.getOpcode(), dl, VTs, Src1Lo, Src2Lo,
+ Op.getOperand(2));
+ } else {
+ Lo = DAG.getNode(Op.getOpcode(), dl, VTs, Src1Lo, Src2Lo);
+ }
+ SDValue Hi = DAG.getNode(hiOpc, dl, VTs, Src1Hi, Src2Hi, Lo.getValue(1));
+ SDValue Carry = Hi.getValue(1);
+
+ Lo = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i64, Lo);
+ Hi = DAG.getNode(ISD::ZERO_EXTEND, dl, MVT::i64, Hi);
+ Hi = DAG.getNode(ISD::SHL, dl, MVT::i64, Hi,
+ DAG.getConstant(32, dl, MVT::i64));
+
+ SDValue Dst = DAG.getNode(ISD::OR, dl, MVT::i64, Hi, Lo);
+ SDValue Ops[2] = { Dst, Carry };
+ return DAG.getMergeValues(Ops, dl);
+}
+
+// Custom lower UMULO/SMULO for SPARC. This code is similar to ExpandNode()
+// in LegalizeDAG.cpp except the order of arguments to the library function.
+static SDValue LowerUMULO_SMULO(SDValue Op, SelectionDAG &DAG,
+ const SparcTargetLowering &TLI)
+{
+ unsigned opcode = Op.getOpcode();
+ assert((opcode == ISD::UMULO || opcode == ISD::SMULO) && "Invalid Opcode.");
+
+ bool isSigned = (opcode == ISD::SMULO);
+ EVT VT = MVT::i64;
+ EVT WideVT = MVT::i128;
+ SDLoc dl(Op);
+ SDValue LHS = Op.getOperand(0);
+
+ if (LHS.getValueType() != VT)
+ return Op;
+
+ SDValue ShiftAmt = DAG.getConstant(63, dl, VT);
+
+ SDValue RHS = Op.getOperand(1);
+ SDValue HiLHS = DAG.getNode(ISD::SRA, dl, VT, LHS, ShiftAmt);
+ SDValue HiRHS = DAG.getNode(ISD::SRA, dl, MVT::i64, RHS, ShiftAmt);
+ SDValue Args[] = { HiLHS, LHS, HiRHS, RHS };
+
+ SDValue MulResult = TLI.makeLibCall(DAG,
+ RTLIB::MUL_I128, WideVT,
+ Args, 4, isSigned, dl).first;
+ SDValue BottomHalf = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, VT,
+ MulResult, DAG.getIntPtrConstant(0, dl));
+ SDValue TopHalf = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, VT,
+ MulResult, DAG.getIntPtrConstant(1, dl));
+ if (isSigned) {
+ SDValue Tmp1 = DAG.getNode(ISD::SRA, dl, VT, BottomHalf, ShiftAmt);
+ TopHalf = DAG.getSetCC(dl, MVT::i32, TopHalf, Tmp1, ISD::SETNE);
+ } else {
+ TopHalf = DAG.getSetCC(dl, MVT::i32, TopHalf, DAG.getConstant(0, dl, VT),
+ ISD::SETNE);
+ }
+ // MulResult is a node with an illegal type. Because such things are not
+ // generally permitted during this phase of legalization, ensure that
+ // nothing is left using the node. The above EXTRACT_ELEMENT nodes should have
+ // been folded.
+ assert(MulResult->use_empty() && "Illegally typed node still in use!");
+
+ SDValue Ops[2] = { BottomHalf, TopHalf } ;
+ return DAG.getMergeValues(Ops, dl);
+}
+
+static SDValue LowerATOMIC_LOAD_STORE(SDValue Op, SelectionDAG &DAG) {
+ // Monotonic load/stores are legal.
+ if (cast<AtomicSDNode>(Op)->getOrdering() <= Monotonic)
+ return Op;
+
+ // Otherwise, expand with a fence.
+ return SDValue();
+}
+
+
+SDValue SparcTargetLowering::
+LowerOperation(SDValue Op, SelectionDAG &DAG) const {
+
+ bool hasHardQuad = Subtarget->hasHardQuad();
+ bool isV9 = Subtarget->isV9();
+
+ switch (Op.getOpcode()) {
+ default: llvm_unreachable("Should not custom lower this!");
+
+ case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG, *this,
+ Subtarget);
+ case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG,
+ Subtarget);
+ case ISD::GlobalTLSAddress: return LowerGlobalTLSAddress(Op, DAG);
+ case ISD::GlobalAddress: return LowerGlobalAddress(Op, DAG);
+ case ISD::BlockAddress: return LowerBlockAddress(Op, DAG);
+ case ISD::ConstantPool: return LowerConstantPool(Op, DAG);
+ case ISD::FP_TO_SINT: return LowerFP_TO_SINT(Op, DAG, *this,
+ hasHardQuad);
+ case ISD::SINT_TO_FP: return LowerSINT_TO_FP(Op, DAG, *this,
+ hasHardQuad);
+ case ISD::FP_TO_UINT: return LowerFP_TO_UINT(Op, DAG, *this,
+ hasHardQuad);
+ case ISD::UINT_TO_FP: return LowerUINT_TO_FP(Op, DAG, *this,
+ hasHardQuad);
+ case ISD::BR_CC: return LowerBR_CC(Op, DAG, *this,
+ hasHardQuad);
+ case ISD::SELECT_CC: return LowerSELECT_CC(Op, DAG, *this,
+ hasHardQuad);
+ case ISD::VASTART: return LowerVASTART(Op, DAG, *this);
+ case ISD::VAARG: return LowerVAARG(Op, DAG);
+ case ISD::DYNAMIC_STACKALLOC: return LowerDYNAMIC_STACKALLOC(Op, DAG,
+ Subtarget);
+
+ case ISD::LOAD: return LowerF128Load(Op, DAG);
+ case ISD::STORE: return LowerF128Store(Op, DAG);
+ case ISD::FADD: return LowerF128Op(Op, DAG,
+ getLibcallName(RTLIB::ADD_F128), 2);
+ case ISD::FSUB: return LowerF128Op(Op, DAG,
+ getLibcallName(RTLIB::SUB_F128), 2);
+ case ISD::FMUL: return LowerF128Op(Op, DAG,
+ getLibcallName(RTLIB::MUL_F128), 2);
+ case ISD::FDIV: return LowerF128Op(Op, DAG,
+ getLibcallName(RTLIB::DIV_F128), 2);
+ case ISD::FSQRT: return LowerF128Op(Op, DAG,
+ getLibcallName(RTLIB::SQRT_F128),1);
+ case ISD::FABS:
+ case ISD::FNEG: return LowerFNEGorFABS(Op, DAG, isV9);
+ case ISD::FP_EXTEND: return LowerF128_FPEXTEND(Op, DAG, *this);
+ case ISD::FP_ROUND: return LowerF128_FPROUND(Op, DAG, *this);
+ case ISD::ADDC:
+ case ISD::ADDE:
+ case ISD::SUBC:
+ case ISD::SUBE: return LowerADDC_ADDE_SUBC_SUBE(Op, DAG);
+ case ISD::UMULO:
+ case ISD::SMULO: return LowerUMULO_SMULO(Op, DAG, *this);
+ case ISD::ATOMIC_LOAD:
+ case ISD::ATOMIC_STORE: return LowerATOMIC_LOAD_STORE(Op, DAG);
+ }
+}
+
+MachineBasicBlock *
+SparcTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI,
+ MachineBasicBlock *BB) const {
+ switch (MI->getOpcode()) {
+ default: llvm_unreachable("Unknown SELECT_CC!");
+ case SP::SELECT_CC_Int_ICC:
+ case SP::SELECT_CC_FP_ICC:
+ case SP::SELECT_CC_DFP_ICC:
+ case SP::SELECT_CC_QFP_ICC:
+ return expandSelectCC(MI, BB, SP::BCOND);
+ case SP::SELECT_CC_Int_FCC:
+ case SP::SELECT_CC_FP_FCC:
+ case SP::SELECT_CC_DFP_FCC:
+ case SP::SELECT_CC_QFP_FCC:
+ return expandSelectCC(MI, BB, SP::FBCOND);
+
+ 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,
+ unsigned BROpcode) const {
+ const TargetInstrInfo &TII = *Subtarget->getInstrInfo();
+ 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
+ // to set, the condition code register to branch on, the true/false values to
+ // select between, and a branch opcode to use.
+ const BasicBlock *LLVM_BB = BB->getBasicBlock();
+ MachineFunction::iterator It = BB;
+ ++It;
+
+ // thisMBB:
+ // ...
+ // TrueVal = ...
+ // [f]bCC copy1MBB
+ // fallthrough --> copy0MBB
+ MachineBasicBlock *thisMBB = BB;
+ MachineFunction *F = BB->getParent();
+ MachineBasicBlock *copy0MBB = F->CreateMachineBasicBlock(LLVM_BB);
+ MachineBasicBlock *sinkMBB = F->CreateMachineBasicBlock(LLVM_BB);
+ F->insert(It, copy0MBB);
+ F->insert(It, sinkMBB);
+
+ // Transfer the remainder of BB and its successor edges to sinkMBB.
+ sinkMBB->splice(sinkMBB->begin(), BB,
+ std::next(MachineBasicBlock::iterator(MI)),
+ BB->end());
+ sinkMBB->transferSuccessorsAndUpdatePHIs(BB);
+
+ // Add the true and fallthrough blocks as its successors.
+ BB->addSuccessor(copy0MBB);
+ BB->addSuccessor(sinkMBB);
+
+ BuildMI(BB, dl, TII.get(BROpcode)).addMBB(sinkMBB).addImm(CC);
+
+ // copy0MBB:
+ // %FalseValue = ...
+ // # fallthrough to sinkMBB
+ BB = copy0MBB;
+
+ // Update machine-CFG edges
+ BB->addSuccessor(sinkMBB);
+
+ // sinkMBB:
+ // %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);
+
+ 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();
+
+ // MI is an atomic read-modify-write instruction of the form:
+ //
+ // rd = atomicrmw<op> addr, rs2
+ //
+ // 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.
+ //
+ // %val0 = load %addr
+ // loop:
+ // %val = phi %val0, %dest
+ // %upd = op %val, %rs2
+ // %dest = cas %addr, %val, %upd
+ // cmp %val, %dest
+ // bne loop
+ // done:
+ //
+ bool is64Bit = SP::I64RegsRegClass.hasSubClassEq(MRI.getRegClass(DestReg));
+ const TargetRegisterClass *ValueRC =
+ is64Bit ? &SP::I64RegsRegClass : &SP::IntRegsRegClass;
+ unsigned Val0Reg = MRI.createVirtualRegister(ValueRC);
+
+ BuildMI(*MBB, MI, DL, TII.get(is64Bit ? SP::LDXri : SP::LDri), Val0Reg)
+ .addReg(AddrReg).addImm(0);
+
+ // Split the basic block MBB before MI and insert the loop block in the hole.
+ MachineFunction::iterator MFI = MBB;
+ 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;
+}
+
+//===----------------------------------------------------------------------===//
+// Sparc Inline Assembly Support
+//===----------------------------------------------------------------------===//
+
+/// getConstraintType - Given a constraint letter, return the type of
+/// constraint it is for this target.
+SparcTargetLowering::ConstraintType
+SparcTargetLowering::getConstraintType(const std::string &Constraint) const {
+ if (Constraint.size() == 1) {
+ switch (Constraint[0]) {
+ default: break;
+ case 'r': return C_RegisterClass;
+ case 'I': // SIMM13
+ return C_Other;
+ }
+ }
+
+ return TargetLowering::getConstraintType(Constraint);
+}
+
+TargetLowering::ConstraintWeight SparcTargetLowering::
+getSingleConstraintMatchWeight(AsmOperandInfo &info,
+ const char *constraint) const {
+ ConstraintWeight weight = CW_Invalid;
+ Value *CallOperandVal = info.CallOperandVal;
+ // If we don't have a value, we can't do a match,
+ // but allow it at the lowest weight.
+ if (!CallOperandVal)
+ return CW_Default;
+
+ // Look at the constraint type.
+ switch (*constraint) {
+ default:
+ weight = TargetLowering::getSingleConstraintMatchWeight(info, constraint);
+ break;
+ case 'I': // SIMM13
+ if (ConstantInt *C = dyn_cast<ConstantInt>(info.CallOperandVal)) {
+ if (isInt<13>(C->getSExtValue()))
+ weight = CW_Constant;
+ }
+ break;
+ }
+ return weight;
+}
+
+/// LowerAsmOperandForConstraint - Lower the specified operand into the Ops
+/// vector. If it is invalid, don't add anything to Ops.
+void SparcTargetLowering::
+LowerAsmOperandForConstraint(SDValue Op,
+ std::string &Constraint,
+ std::vector<SDValue> &Ops,
+ SelectionDAG &DAG) const {
+ SDValue Result(nullptr, 0);
+
+ // Only support length 1 constraints for now.
+ if (Constraint.length() > 1)
+ return;
+
+ char ConstraintLetter = Constraint[0];
+ switch (ConstraintLetter) {
+ default: break;
+ case 'I':
+ if (ConstantSDNode *C = dyn_cast<ConstantSDNode>(Op)) {
+ if (isInt<13>(C->getSExtValue())) {
+ Result = DAG.getTargetConstant(C->getSExtValue(), SDLoc(Op),
+ Op.getValueType());
+ break;
+ }
+ return;
+ }
+ }
+
+ if (Result.getNode()) {
+ Ops.push_back(Result);
+ return;
+ }
+ TargetLowering::LowerAsmOperandForConstraint(Op, Constraint, Ops, DAG);
+}
+
+std::pair<unsigned, const TargetRegisterClass *>
+SparcTargetLowering::getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
+ const std::string &Constraint,
+ MVT VT) const {
+ if (Constraint.size() == 1) {
+ switch (Constraint[0]) {
+ case 'r':
+ return std::make_pair(0U, &SP::IntRegsRegClass);
+ }
+ } else if (!Constraint.empty() && Constraint.size() <= 5
+ && Constraint[0] == '{' && *(Constraint.end()-1) == '}') {
+ // constraint = '{r<d>}'
+ // Remove the braces from around the name.
+ StringRef name(Constraint.data()+1, Constraint.size()-2);
+ // Handle register aliases:
+ // r0-r7 -> g0-g7
+ // r8-r15 -> o0-o7
+ // r16-r23 -> l0-l7
+ // r24-r31 -> i0-i7
+ uint64_t intVal = 0;
+ if (name.substr(0, 1).equals("r")
+ && !name.substr(1).getAsInteger(10, intVal) && intVal <= 31) {
+ const char regTypes[] = { 'g', 'o', 'l', 'i' };
+ char regType = regTypes[intVal/8];
+ char regIdx = '0' + (intVal % 8);
+ char tmp[] = { '{', regType, regIdx, '}', 0 };
+ std::string newConstraint = std::string(tmp);
+ return TargetLowering::getRegForInlineAsmConstraint(TRI, newConstraint,
+ VT);
+ }
+ }
+
+ return TargetLowering::getRegForInlineAsmConstraint(TRI, Constraint, VT);
+}
+
+bool
+SparcTargetLowering::isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const {
+ // The Sparc target isn't yet aware of offsets.
+ return false;
+}
+
+void SparcTargetLowering::ReplaceNodeResults(SDNode *N,
+ SmallVectorImpl<SDValue>& Results,
+ SelectionDAG &DAG) const {
+
+ SDLoc dl(N);
+
+ RTLIB::Libcall libCall = RTLIB::UNKNOWN_LIBCALL;
+
+ switch (N->getOpcode()) {
+ default:
+ llvm_unreachable("Do not know how to custom type legalize this operation!");
+
+ case ISD::FP_TO_SINT:
+ case ISD::FP_TO_UINT:
+ // Custom lower only if it involves f128 or i64.
+ if (N->getOperand(0).getValueType() != MVT::f128
+ || N->getValueType(0) != MVT::i64)
+ return;
+ libCall = ((N->getOpcode() == ISD::FP_TO_SINT)
+ ? RTLIB::FPTOSINT_F128_I64
+ : RTLIB::FPTOUINT_F128_I64);
+
+ Results.push_back(LowerF128Op(SDValue(N, 0),
+ DAG,
+ getLibcallName(libCall),
+ 1));
+ return;
+
+ case ISD::SINT_TO_FP:
+ case ISD::UINT_TO_FP:
+ // Custom lower only if it involves f128 or i64.
+ if (N->getValueType(0) != MVT::f128
+ || N->getOperand(0).getValueType() != MVT::i64)
+ return;
+
+ libCall = ((N->getOpcode() == ISD::SINT_TO_FP)
+ ? RTLIB::SINTTOFP_I64_F128
+ : RTLIB::UINTTOFP_I64_F128);
+
+ Results.push_back(LowerF128Op(SDValue(N, 0),
+ DAG,
+ getLibcallName(libCall),
+ 1));
+ return;
+ }
+}
diff --git a/contrib/llvm/lib/Target/Sparc/SparcISelLowering.h b/contrib/llvm/lib/Target/Sparc/SparcISelLowering.h
new file mode 100644
index 0000000..a4b9c79
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/SparcISelLowering.h
@@ -0,0 +1,180 @@
+//===-- SparcISelLowering.h - Sparc DAG Lowering Interface ------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the interfaces that Sparc uses to lower LLVM code into a
+// selection DAG.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_SPARC_SPARCISELLOWERING_H
+#define LLVM_LIB_TARGET_SPARC_SPARCISELLOWERING_H
+
+#include "Sparc.h"
+#include "llvm/Target/TargetLowering.h"
+
+namespace llvm {
+ class SparcSubtarget;
+
+ namespace SPISD {
+ enum NodeType : unsigned {
+ FIRST_NUMBER = ISD::BUILTIN_OP_END,
+ CMPICC, // Compare two GPR operands, set icc+xcc.
+ CMPFCC, // Compare two FP operands, set fcc.
+ BRICC, // Branch to dest on icc condition
+ BRXCC, // Branch to dest on xcc condition (64-bit only).
+ BRFCC, // Branch to dest on fcc condition
+ SELECT_ICC, // Select between two values using the current ICC flags.
+ SELECT_XCC, // Select between two values using the current XCC flags.
+ SELECT_FCC, // Select between two values using the current FCC flags.
+
+ Hi, Lo, // Hi/Lo operations, typically on a global address.
+
+ FTOI, // FP to Int within a FP register.
+ ITOF, // Int to FP within a FP register.
+ FTOX, // FP to Int64 within a FP register.
+ XTOF, // Int64 to FP within a FP register.
+
+ CALL, // A call instruction.
+ RET_FLAG, // Return with a flag operand.
+ GLOBAL_BASE_REG, // Global base reg for PIC.
+ FLUSHW, // FLUSH register windows to stack.
+
+ TLS_ADD, // For Thread Local Storage (TLS).
+ TLS_LD,
+ TLS_CALL
+ };
+ } // namespace SPISD
+
+ class SparcTargetLowering : public TargetLowering {
+ const SparcSubtarget *Subtarget;
+ public:
+ SparcTargetLowering(TargetMachine &TM, const SparcSubtarget &STI);
+ SDValue LowerOperation(SDValue Op, SelectionDAG &DAG) 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.
+ void computeKnownBitsForTargetNode(const SDValue Op,
+ APInt &KnownZero,
+ APInt &KnownOne,
+ const SelectionDAG &DAG,
+ unsigned Depth = 0) const override;
+
+ MachineBasicBlock *
+ EmitInstrWithCustomInserter(MachineInstr *MI,
+ MachineBasicBlock *MBB) const override;
+
+ const char *getTargetNodeName(unsigned Opcode) const override;
+
+ ConstraintType getConstraintType(const std::string &Constraint) const override;
+ ConstraintWeight
+ getSingleConstraintMatchWeight(AsmOperandInfo &info,
+ const char *constraint) const override;
+ void LowerAsmOperandForConstraint(SDValue Op,
+ std::string &Constraint,
+ std::vector<SDValue> &Ops,
+ SelectionDAG &DAG) const override;
+ std::pair<unsigned, const TargetRegisterClass *>
+ getRegForInlineAsmConstraint(const TargetRegisterInfo *TRI,
+ const std::string &Constraint,
+ MVT VT) const override;
+
+ bool isOffsetFoldingLegal(const GlobalAddressSDNode *GA) const override;
+ MVT getScalarShiftAmountTy(EVT LHSTy) const override { return MVT::i32; }
+
+ /// getSetCCResultType - Return the ISD::SETCC ValueType
+ EVT getSetCCResultType(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,
+ bool isVarArg,
+ const SmallVectorImpl<ISD::InputArg> &Ins,
+ SDLoc dl, SelectionDAG &DAG,
+ SmallVectorImpl<SDValue> &InVals) const;
+ SDValue LowerFormalArguments_64(SDValue Chain,
+ CallingConv::ID CallConv,
+ bool isVarArg,
+ const SmallVectorImpl<ISD::InputArg> &Ins,
+ SDLoc dl, SelectionDAG &DAG,
+ SmallVectorImpl<SDValue> &InVals) const;
+
+ SDValue
+ LowerCall(TargetLowering::CallLoweringInfo &CLI,
+ SmallVectorImpl<SDValue> &InVals) const override;
+ SDValue LowerCall_32(TargetLowering::CallLoweringInfo &CLI,
+ SmallVectorImpl<SDValue> &InVals) const;
+ 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,
+ 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 SmallVectorImpl<ISD::OutputArg> &Outs,
+ const SmallVectorImpl<SDValue> &OutVals,
+ 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;
+
+ 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 LowerF128Op(SDValue Op, SelectionDAG &DAG,
+ const char *LibFuncName,
+ unsigned numArgs) const;
+ SDValue LowerF128Compare(SDValue LHS, SDValue RHS,
+ unsigned &SPCC,
+ SDLoc DL,
+ SelectionDAG &DAG) const;
+
+ bool ShouldShrinkFPConstant(EVT VT) const override {
+ // Do not shrink FP constpool if VT == MVT::f128.
+ // (ldd, call _Q_fdtoq) is more expensive than two ldds.
+ return VT != MVT::f128;
+ }
+
+ void ReplaceNodeResults(SDNode *N,
+ SmallVectorImpl<SDValue>& Results,
+ SelectionDAG &DAG) const override;
+
+ MachineBasicBlock *expandSelectCC(MachineInstr *MI, MachineBasicBlock *BB,
+ unsigned BROpcode) const;
+ MachineBasicBlock *expandAtomicRMW(MachineInstr *MI,
+ MachineBasicBlock *BB,
+ unsigned Opcode,
+ unsigned CondCode = 0) const;
+ };
+} // end namespace llvm
+
+#endif // SPARC_ISELLOWERING_H
diff --git a/contrib/llvm/lib/Target/Sparc/SparcInstr64Bit.td b/contrib/llvm/lib/Target/Sparc/SparcInstr64Bit.td
new file mode 100644
index 0000000..419e8cc
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/SparcInstr64Bit.td
@@ -0,0 +1,574 @@
+//===-- SparcInstr64Bit.td - 64-bit instructions for Sparc Target ---------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains instruction definitions and patterns needed for 64-bit
+// code generation on SPARC v9.
+//
+// Some SPARC v9 instructions are defined in SparcInstrInfo.td because they can
+// also be used in 32-bit code running on a SPARC v9 CPU.
+//
+//===----------------------------------------------------------------------===//
+
+let Predicates = [Is64Bit] in {
+// The same integer registers are used for i32 and i64 values.
+// When registers hold i32 values, the high bits are don't care.
+// This give us free trunc and anyext.
+def : Pat<(i64 (anyext i32:$val)), (COPY_TO_REGCLASS $val, I64Regs)>;
+def : Pat<(i32 (trunc i64:$val)), (COPY_TO_REGCLASS $val, IntRegs)>;
+
+} // Predicates = [Is64Bit]
+
+
+//===----------------------------------------------------------------------===//
+// 64-bit Shift Instructions.
+//===----------------------------------------------------------------------===//
+//
+// The 32-bit shift instructions are still available. The left shift srl
+// instructions shift all 64 bits, but it only accepts a 5-bit shift amount.
+//
+// The srl instructions only shift the low 32 bits and clear the high 32 bits.
+// Finally, sra shifts the low 32 bits and sign-extends to 64 bits.
+
+let Predicates = [Is64Bit] in {
+
+def : Pat<(i64 (zext i32:$val)), (SRLri $val, 0)>;
+def : Pat<(i64 (sext i32:$val)), (SRAri $val, 0)>;
+
+def : Pat<(i64 (and i64:$val, 0xffffffff)), (SRLri $val, 0)>;
+def : Pat<(i64 (sext_inreg i64:$val, i32)), (SRAri $val, 0)>;
+
+defm SLLX : F3_S<"sllx", 0b100101, 1, shl, i64, I64Regs>;
+defm SRLX : F3_S<"srlx", 0b100110, 1, srl, i64, I64Regs>;
+defm SRAX : F3_S<"srax", 0b100111, 1, sra, i64, I64Regs>;
+
+} // Predicates = [Is64Bit]
+
+
+//===----------------------------------------------------------------------===//
+// 64-bit Immediates.
+//===----------------------------------------------------------------------===//
+//
+// All 32-bit immediates can be materialized with sethi+or, but 64-bit
+// immediates may require more code. There may be a point where it is
+// preferable to use a constant pool load instead, depending on the
+// microarchitecture.
+
+// Single-instruction patterns.
+
+// The ALU instructions want their simm13 operands as i32 immediates.
+def as_i32imm : SDNodeXForm<imm, [{
+ return CurDAG->getTargetConstant(N->getSExtValue(), SDLoc(N), MVT::i32);
+}]>;
+def : Pat<(i64 simm13:$val), (ORri (i64 G0), (as_i32imm $val))>;
+def : Pat<(i64 SETHIimm:$val), (SETHIi (HI22 $val))>;
+
+// Double-instruction patterns.
+
+// All unsigned i32 immediates can be handled by sethi+or.
+def uimm32 : PatLeaf<(imm), [{ return isUInt<32>(N->getZExtValue()); }]>;
+def : Pat<(i64 uimm32:$val), (ORri (SETHIi (HI22 $val)), (LO10 $val))>,
+ Requires<[Is64Bit]>;
+
+// All negative i33 immediates can be handled by sethi+xor.
+def nimm33 : PatLeaf<(imm), [{
+ int64_t Imm = N->getSExtValue();
+ return Imm < 0 && isInt<33>(Imm);
+}]>;
+// Bits 10-31 inverted. Same as assembler's %hix.
+def HIX22 : SDNodeXForm<imm, [{
+ uint64_t Val = (~N->getZExtValue() >> 10) & ((1u << 22) - 1);
+ return CurDAG->getTargetConstant(Val, SDLoc(N), MVT::i32);
+}]>;
+// Bits 0-9 with ones in bits 10-31. Same as assembler's %lox.
+def LOX10 : SDNodeXForm<imm, [{
+ return CurDAG->getTargetConstant(~(~N->getZExtValue() & 0x3ff), SDLoc(N),
+ MVT::i32);
+}]>;
+def : Pat<(i64 nimm33:$val), (XORri (SETHIi (HIX22 $val)), (LOX10 $val))>,
+ Requires<[Is64Bit]>;
+
+// More possible patterns:
+//
+// (sllx sethi, n)
+// (sllx simm13, n)
+//
+// 3 instrs:
+//
+// (xor (sllx sethi), simm13)
+// (sllx (xor sethi, simm13))
+//
+// 4 instrs:
+//
+// (or sethi, (sllx sethi))
+// (xnor sethi, (sllx sethi))
+//
+// 5 instrs:
+//
+// (or (sllx sethi), (or sethi, simm13))
+// (xnor (sllx sethi), (or sethi, simm13))
+// (or (sllx sethi), (sllx sethi))
+// (xnor (sllx sethi), (sllx sethi))
+//
+// Worst case is 6 instrs:
+//
+// (or (sllx (or sethi, simmm13)), (or sethi, simm13))
+
+// Bits 42-63, same as assembler's %hh.
+def HH22 : SDNodeXForm<imm, [{
+ uint64_t Val = (N->getZExtValue() >> 42) & ((1u << 22) - 1);
+ return CurDAG->getTargetConstant(Val, SDLoc(N), MVT::i32);
+}]>;
+// Bits 32-41, same as assembler's %hm.
+def HM10 : SDNodeXForm<imm, [{
+ uint64_t Val = (N->getZExtValue() >> 32) & ((1u << 10) - 1);
+ return CurDAG->getTargetConstant(Val, SDLoc(N), MVT::i32);
+}]>;
+def : Pat<(i64 imm:$val),
+ (ORrr (SLLXri (ORri (SETHIi (HH22 $val)), (HM10 $val)), (i32 32)),
+ (ORri (SETHIi (HI22 $val)), (LO10 $val)))>,
+ Requires<[Is64Bit]>;
+
+
+//===----------------------------------------------------------------------===//
+// 64-bit Integer Arithmetic and Logic.
+//===----------------------------------------------------------------------===//
+
+let Predicates = [Is64Bit] in {
+
+// Register-register instructions.
+let isCodeGenOnly = 1 in {
+defm ANDX : F3_12<"and", 0b000001, and, I64Regs, i64, i64imm>;
+defm ORX : F3_12<"or", 0b000010, or, I64Regs, i64, i64imm>;
+defm XORX : F3_12<"xor", 0b000011, xor, I64Regs, i64, i64imm>;
+
+def ANDXNrr : F3_1<2, 0b000101,
+ (outs I64Regs:$dst), (ins I64Regs:$b, I64Regs:$c),
+ "andn $b, $c, $dst",
+ [(set i64:$dst, (and i64:$b, (not i64:$c)))]>;
+def ORXNrr : F3_1<2, 0b000110,
+ (outs I64Regs:$dst), (ins I64Regs:$b, I64Regs:$c),
+ "orn $b, $c, $dst",
+ [(set i64:$dst, (or i64:$b, (not i64:$c)))]>;
+def XNORXrr : F3_1<2, 0b000111,
+ (outs I64Regs:$dst), (ins I64Regs:$b, I64Regs:$c),
+ "xnor $b, $c, $dst",
+ [(set i64:$dst, (not (xor i64:$b, i64:$c)))]>;
+
+defm ADDX : F3_12<"add", 0b000000, add, I64Regs, i64, i64imm>;
+defm SUBX : F3_12<"sub", 0b000100, sub, I64Regs, i64, i64imm>;
+
+def TLS_ADDXrr : F3_1<2, 0b000000, (outs I64Regs:$rd),
+ (ins I64Regs:$rs1, I64Regs:$rs2, TLSSym:$sym),
+ "add $rs1, $rs2, $rd, $sym",
+ [(set i64:$rd,
+ (tlsadd i64:$rs1, i64:$rs2, tglobaltlsaddr:$sym))]>;
+
+// "LEA" form of add
+def LEAX_ADDri : F3_2<2, 0b000000,
+ (outs I64Regs:$dst), (ins MEMri:$addr),
+ "add ${addr:arith}, $dst",
+ [(set iPTR:$dst, ADDRri:$addr)]>;
+}
+
+def : Pat<(SPcmpicc i64:$a, i64:$b), (CMPrr $a, $b)>;
+def : Pat<(SPcmpicc i64:$a, (i64 simm13:$b)), (CMPri $a, (as_i32imm $b))>;
+def : Pat<(ctpop i64:$src), (POPCrr $src)>;
+
+} // Predicates = [Is64Bit]
+
+
+//===----------------------------------------------------------------------===//
+// 64-bit Integer Multiply and Divide.
+//===----------------------------------------------------------------------===//
+
+let Predicates = [Is64Bit] in {
+
+def MULXrr : F3_1<2, 0b001001,
+ (outs I64Regs:$rd), (ins I64Regs:$rs1, I64Regs:$rs2),
+ "mulx $rs1, $rs2, $rd",
+ [(set i64:$rd, (mul i64:$rs1, i64:$rs2))]>;
+def MULXri : F3_2<2, 0b001001,
+ (outs IntRegs:$rd), (ins IntRegs:$rs1, i64imm:$simm13),
+ "mulx $rs1, $simm13, $rd",
+ [(set i64:$rd, (mul i64:$rs1, (i64 simm13:$simm13)))]>;
+
+// Division can trap.
+let hasSideEffects = 1 in {
+def SDIVXrr : F3_1<2, 0b101101,
+ (outs I64Regs:$rd), (ins I64Regs:$rs1, I64Regs:$rs2),
+ "sdivx $rs1, $rs2, $rd",
+ [(set i64:$rd, (sdiv i64:$rs1, i64:$rs2))]>;
+def SDIVXri : F3_2<2, 0b101101,
+ (outs IntRegs:$rd), (ins IntRegs:$rs1, i64imm:$simm13),
+ "sdivx $rs1, $simm13, $rd",
+ [(set i64:$rd, (sdiv i64:$rs1, (i64 simm13:$simm13)))]>;
+
+def UDIVXrr : F3_1<2, 0b001101,
+ (outs I64Regs:$rd), (ins I64Regs:$rs1, I64Regs:$rs2),
+ "udivx $rs1, $rs2, $rd",
+ [(set i64:$rd, (udiv i64:$rs1, i64:$rs2))]>;
+def UDIVXri : F3_2<2, 0b001101,
+ (outs IntRegs:$rd), (ins IntRegs:$rs1, i64imm:$simm13),
+ "udivx $rs1, $simm13, $rd",
+ [(set i64:$rd, (udiv i64:$rs1, (i64 simm13:$simm13)))]>;
+} // hasSideEffects = 1
+
+} // Predicates = [Is64Bit]
+
+
+//===----------------------------------------------------------------------===//
+// 64-bit Loads and Stores.
+//===----------------------------------------------------------------------===//
+//
+// All the 32-bit loads and stores are available. The extending loads are sign
+// or zero-extending to 64 bits. The LDrr and LDri instructions load 32 bits
+// zero-extended to i64. Their mnemonic is lduw in SPARC v9 (Load Unsigned
+// Word).
+//
+// SPARC v9 adds 64-bit loads as well as a sign-extending ldsw i32 loads.
+
+let Predicates = [Is64Bit] in {
+
+// 64-bit loads.
+let DecoderMethod = "DecodeLoadInt" in
+ defm LDX : Load<"ldx", 0b001011, load, I64Regs, i64>;
+
+let mayLoad = 1, isCodeGenOnly = 1, isAsmParserOnly = 1 in
+ def TLS_LDXrr : F3_1<3, 0b001011,
+ (outs IntRegs:$dst), (ins MEMrr:$addr, TLSSym:$sym),
+ "ldx [$addr], $dst, $sym",
+ [(set i64:$dst,
+ (tlsld ADDRrr:$addr, tglobaltlsaddr:$sym))]>;
+
+// Extending loads to i64.
+def : Pat<(i64 (zextloadi1 ADDRrr:$addr)), (LDUBrr ADDRrr:$addr)>;
+def : Pat<(i64 (zextloadi1 ADDRri:$addr)), (LDUBri ADDRri:$addr)>;
+def : Pat<(i64 (extloadi1 ADDRrr:$addr)), (LDUBrr ADDRrr:$addr)>;
+def : Pat<(i64 (extloadi1 ADDRri:$addr)), (LDUBri ADDRri:$addr)>;
+
+def : Pat<(i64 (zextloadi8 ADDRrr:$addr)), (LDUBrr ADDRrr:$addr)>;
+def : Pat<(i64 (zextloadi8 ADDRri:$addr)), (LDUBri ADDRri:$addr)>;
+def : Pat<(i64 (extloadi8 ADDRrr:$addr)), (LDUBrr ADDRrr:$addr)>;
+def : Pat<(i64 (extloadi8 ADDRri:$addr)), (LDUBri ADDRri:$addr)>;
+def : Pat<(i64 (sextloadi8 ADDRrr:$addr)), (LDSBrr ADDRrr:$addr)>;
+def : Pat<(i64 (sextloadi8 ADDRri:$addr)), (LDSBri ADDRri:$addr)>;
+
+def : Pat<(i64 (zextloadi16 ADDRrr:$addr)), (LDUHrr ADDRrr:$addr)>;
+def : Pat<(i64 (zextloadi16 ADDRri:$addr)), (LDUHri ADDRri:$addr)>;
+def : Pat<(i64 (extloadi16 ADDRrr:$addr)), (LDUHrr ADDRrr:$addr)>;
+def : Pat<(i64 (extloadi16 ADDRri:$addr)), (LDUHri ADDRri:$addr)>;
+def : Pat<(i64 (sextloadi16 ADDRrr:$addr)), (LDSHrr ADDRrr:$addr)>;
+def : Pat<(i64 (sextloadi16 ADDRri:$addr)), (LDSHri ADDRri:$addr)>;
+
+def : Pat<(i64 (zextloadi32 ADDRrr:$addr)), (LDrr ADDRrr:$addr)>;
+def : Pat<(i64 (zextloadi32 ADDRri:$addr)), (LDri ADDRri:$addr)>;
+def : Pat<(i64 (extloadi32 ADDRrr:$addr)), (LDrr ADDRrr:$addr)>;
+def : Pat<(i64 (extloadi32 ADDRri:$addr)), (LDri ADDRri:$addr)>;
+
+// Sign-extending load of i32 into i64 is a new SPARC v9 instruction.
+let DecoderMethod = "DecodeLoadInt" in
+ defm LDSW : Load<"ldsw", 0b001000, sextloadi32, I64Regs, i64>;
+
+// 64-bit stores.
+let DecoderMethod = "DecodeStoreInt" in
+ defm STX : Store<"stx", 0b001110, store, I64Regs, i64>;
+
+// Truncating stores from i64 are identical to the i32 stores.
+def : Pat<(truncstorei8 i64:$src, ADDRrr:$addr), (STBrr ADDRrr:$addr, $src)>;
+def : Pat<(truncstorei8 i64:$src, ADDRri:$addr), (STBri ADDRri:$addr, $src)>;
+def : Pat<(truncstorei16 i64:$src, ADDRrr:$addr), (STHrr ADDRrr:$addr, $src)>;
+def : Pat<(truncstorei16 i64:$src, ADDRri:$addr), (STHri ADDRri:$addr, $src)>;
+def : Pat<(truncstorei32 i64:$src, ADDRrr:$addr), (STrr ADDRrr:$addr, $src)>;
+def : Pat<(truncstorei32 i64:$src, ADDRri:$addr), (STri ADDRri:$addr, $src)>;
+
+// store 0, addr -> store %g0, addr
+def : Pat<(store (i64 0), ADDRrr:$dst), (STXrr ADDRrr:$dst, (i64 G0))>;
+def : Pat<(store (i64 0), ADDRri:$dst), (STXri ADDRri:$dst, (i64 G0))>;
+
+} // Predicates = [Is64Bit]
+
+
+//===----------------------------------------------------------------------===//
+// 64-bit Conditionals.
+//===----------------------------------------------------------------------===//
+
+//
+// Flag-setting instructions like subcc and addcc set both icc and xcc flags.
+// The icc flags correspond to the 32-bit result, and the xcc are for the
+// full 64-bit result.
+//
+// We reuse CMPICC SDNodes for compares, but use new BRXCC branch nodes for
+// 64-bit compares. See LowerBR_CC.
+
+let Predicates = [Is64Bit] in {
+
+let Uses = [ICC], cc = 0b10 in
+ defm BPX : IPredBranch<"%xcc", [(SPbrxcc bb:$imm19, imm:$cond)]>;
+
+// Conditional moves on %xcc.
+let Uses = [ICC], Constraints = "$f = $rd" in {
+let intcc = 1, cc = 0b10 in {
+def MOVXCCrr : F4_1<0b101100, (outs IntRegs:$rd),
+ (ins IntRegs:$rs2, IntRegs:$f, CCOp:$cond),
+ "mov$cond %xcc, $rs2, $rd",
+ [(set i32:$rd,
+ (SPselectxcc i32:$rs2, i32:$f, imm:$cond))]>;
+def MOVXCCri : F4_2<0b101100, (outs IntRegs:$rd),
+ (ins i32imm:$simm11, IntRegs:$f, CCOp:$cond),
+ "mov$cond %xcc, $simm11, $rd",
+ [(set i32:$rd,
+ (SPselectxcc simm11:$simm11, i32:$f, imm:$cond))]>;
+} // cc
+
+let intcc = 1, opf_cc = 0b10 in {
+def FMOVS_XCC : F4_3<0b110101, 0b000001, (outs FPRegs:$rd),
+ (ins FPRegs:$rs2, FPRegs:$f, CCOp:$cond),
+ "fmovs$cond %xcc, $rs2, $rd",
+ [(set f32:$rd,
+ (SPselectxcc f32:$rs2, f32:$f, imm:$cond))]>;
+def FMOVD_XCC : F4_3<0b110101, 0b000010, (outs DFPRegs:$rd),
+ (ins DFPRegs:$rs2, DFPRegs:$f, CCOp:$cond),
+ "fmovd$cond %xcc, $rs2, $rd",
+ [(set f64:$rd,
+ (SPselectxcc f64:$rs2, f64:$f, imm:$cond))]>;
+def FMOVQ_XCC : F4_3<0b110101, 0b000011, (outs QFPRegs:$rd),
+ (ins QFPRegs:$rs2, QFPRegs:$f, CCOp:$cond),
+ "fmovq$cond %xcc, $rs2, $rd",
+ [(set f128:$rd,
+ (SPselectxcc f128:$rs2, f128:$f, imm:$cond))]>;
+} // opf_cc
+} // Uses, Constraints
+
+// Branch On integer register with Prediction (BPr).
+let isBranch = 1, isTerminator = 1, hasDelaySlot = 1 in
+multiclass BranchOnReg<bits<3> cond, string OpcStr> {
+ def napt : F2_4<cond, 0, 1, (outs), (ins I64Regs:$rs1, bprtarget16:$imm16),
+ !strconcat(OpcStr, " $rs1, $imm16"), []>;
+ def apt : F2_4<cond, 1, 1, (outs), (ins I64Regs:$rs1, bprtarget16:$imm16),
+ !strconcat(OpcStr, ",a $rs1, $imm16"), []>;
+ def napn : F2_4<cond, 0, 0, (outs), (ins I64Regs:$rs1, bprtarget16:$imm16),
+ !strconcat(OpcStr, ",pn $rs1, $imm16"), []>;
+ def apn : F2_4<cond, 1, 0, (outs), (ins I64Regs:$rs1, bprtarget16:$imm16),
+ !strconcat(OpcStr, ",a,pn $rs1, $imm16"), []>;
+}
+
+multiclass bpr_alias<string OpcStr, Instruction NAPT, Instruction APT> {
+ def : InstAlias<!strconcat(OpcStr, ",pt $rs1, $imm16"),
+ (NAPT I64Regs:$rs1, bprtarget16:$imm16), 0>;
+ def : InstAlias<!strconcat(OpcStr, ",a,pt $rs1, $imm16"),
+ (APT I64Regs:$rs1, bprtarget16:$imm16), 0>;
+}
+
+defm BPZ : BranchOnReg<0b001, "brz">;
+defm BPLEZ : BranchOnReg<0b010, "brlez">;
+defm BPLZ : BranchOnReg<0b011, "brlz">;
+defm BPNZ : BranchOnReg<0b101, "brnz">;
+defm BPGZ : BranchOnReg<0b110, "brgz">;
+defm BPGEZ : BranchOnReg<0b111, "brgez">;
+
+defm : bpr_alias<"brz", BPZnapt, BPZapt >;
+defm : bpr_alias<"brlez", BPLEZnapt, BPLEZapt>;
+defm : bpr_alias<"brlz", BPLZnapt, BPLZapt >;
+defm : bpr_alias<"brnz", BPNZnapt, BPNZapt >;
+defm : bpr_alias<"brgz", BPGZnapt, BPGZapt >;
+defm : bpr_alias<"brgez", BPGEZnapt, BPGEZapt>;
+
+// Move integer register on register condition (MOVr).
+multiclass MOVR< bits<3> rcond, string OpcStr> {
+ def rr : F4_4r<0b101111, 0b00000, rcond, (outs I64Regs:$rd),
+ (ins I64Regs:$rs1, IntRegs:$rs2),
+ !strconcat(OpcStr, " $rs1, $rs2, $rd"), []>;
+
+ def ri : F4_4i<0b101111, rcond, (outs I64Regs:$rd),
+ (ins I64Regs:$rs1, i64imm:$simm10),
+ !strconcat(OpcStr, " $rs1, $simm10, $rd"), []>;
+}
+
+defm MOVRRZ : MOVR<0b001, "movrz">;
+defm MOVRLEZ : MOVR<0b010, "movrlez">;
+defm MOVRLZ : MOVR<0b011, "movrlz">;
+defm MOVRNZ : MOVR<0b101, "movrnz">;
+defm MOVRGZ : MOVR<0b110, "movrgz">;
+defm MOVRGEZ : MOVR<0b111, "movrgez">;
+
+// Move FP register on integer register condition (FMOVr).
+multiclass FMOVR<bits<3> rcond, string OpcStr> {
+
+ def S : F4_4r<0b110101, 0b00101, rcond,
+ (outs FPRegs:$rd), (ins I64Regs:$rs1, FPRegs:$rs2),
+ !strconcat(!strconcat("fmovrs", OpcStr)," $rs1, $rs2, $rd"),
+ []>;
+ def D : F4_4r<0b110101, 0b00110, rcond,
+ (outs FPRegs:$rd), (ins I64Regs:$rs1, FPRegs:$rs2),
+ !strconcat(!strconcat("fmovrd", OpcStr)," $rs1, $rs2, $rd"),
+ []>;
+ def Q : F4_4r<0b110101, 0b00111, rcond,
+ (outs FPRegs:$rd), (ins I64Regs:$rs1, FPRegs:$rs2),
+ !strconcat(!strconcat("fmovrq", OpcStr)," $rs1, $rs2, $rd"),
+ []>, Requires<[HasHardQuad]>;
+}
+
+let Predicates = [HasV9] in {
+ defm FMOVRZ : FMOVR<0b001, "z">;
+ defm FMOVRLEZ : FMOVR<0b010, "lez">;
+ defm FMOVRLZ : FMOVR<0b011, "lz">;
+ defm FMOVRNZ : FMOVR<0b101, "nz">;
+ defm FMOVRGZ : FMOVR<0b110, "gz">;
+ defm FMOVRGEZ : FMOVR<0b111, "gez">;
+}
+
+//===----------------------------------------------------------------------===//
+// 64-bit Floating Point Conversions.
+//===----------------------------------------------------------------------===//
+
+let Predicates = [Is64Bit] in {
+
+def FXTOS : F3_3u<2, 0b110100, 0b010000100,
+ (outs FPRegs:$rd), (ins DFPRegs:$rs2),
+ "fxtos $rs2, $rd",
+ [(set FPRegs:$rd, (SPxtof DFPRegs:$rs2))]>;
+def FXTOD : F3_3u<2, 0b110100, 0b010001000,
+ (outs DFPRegs:$rd), (ins DFPRegs:$rs2),
+ "fxtod $rs2, $rd",
+ [(set DFPRegs:$rd, (SPxtof DFPRegs:$rs2))]>;
+def FXTOQ : F3_3u<2, 0b110100, 0b010001100,
+ (outs QFPRegs:$rd), (ins DFPRegs:$rs2),
+ "fxtoq $rs2, $rd",
+ [(set QFPRegs:$rd, (SPxtof DFPRegs:$rs2))]>,
+ Requires<[HasHardQuad]>;
+
+def FSTOX : F3_3u<2, 0b110100, 0b010000001,
+ (outs DFPRegs:$rd), (ins FPRegs:$rs2),
+ "fstox $rs2, $rd",
+ [(set DFPRegs:$rd, (SPftox FPRegs:$rs2))]>;
+def FDTOX : F3_3u<2, 0b110100, 0b010000010,
+ (outs DFPRegs:$rd), (ins DFPRegs:$rs2),
+ "fdtox $rs2, $rd",
+ [(set DFPRegs:$rd, (SPftox DFPRegs:$rs2))]>;
+def FQTOX : F3_3u<2, 0b110100, 0b010000011,
+ (outs DFPRegs:$rd), (ins QFPRegs:$rs2),
+ "fqtox $rs2, $rd",
+ [(set DFPRegs:$rd, (SPftox QFPRegs:$rs2))]>,
+ Requires<[HasHardQuad]>;
+
+} // Predicates = [Is64Bit]
+
+def : Pat<(SPselectxcc i64:$t, i64:$f, imm:$cond),
+ (MOVXCCrr $t, $f, imm:$cond)>;
+def : Pat<(SPselectxcc (i64 simm11:$t), i64:$f, imm:$cond),
+ (MOVXCCri (as_i32imm $t), $f, imm:$cond)>;
+
+def : Pat<(SPselecticc i64:$t, i64:$f, imm:$cond),
+ (MOVICCrr $t, $f, imm:$cond)>;
+def : Pat<(SPselecticc (i64 simm11:$t), i64:$f, imm:$cond),
+ (MOVICCri (as_i32imm $t), $f, imm:$cond)>;
+
+def : Pat<(SPselectfcc i64:$t, i64:$f, imm:$cond),
+ (MOVFCCrr $t, $f, imm:$cond)>;
+def : Pat<(SPselectfcc (i64 simm11:$t), i64:$f, imm:$cond),
+ (MOVFCCri (as_i32imm $t), $f, imm:$cond)>;
+
+} // Predicates = [Is64Bit]
+
+
+// 64 bit SETHI
+let Predicates = [Is64Bit], isCodeGenOnly = 1 in {
+def SETHIXi : F2_1<0b100,
+ (outs IntRegs:$rd), (ins i64imm:$imm22),
+ "sethi $imm22, $rd",
+ [(set i64:$rd, SETHIimm:$imm22)]>;
+}
+
+// ATOMICS.
+let Predicates = [Is64Bit], Constraints = "$swap = $rd", asi = 0b10000000 in {
+ def CASXrr: F3_1_asi<3, 0b111110,
+ (outs I64Regs:$rd), (ins I64Regs:$rs1, I64Regs:$rs2,
+ I64Regs:$swap),
+ "casx [$rs1], $rs2, $rd",
+ [(set i64:$rd,
+ (atomic_cmp_swap i64:$rs1, i64:$rs2, i64:$swap))]>;
+
+} // Predicates = [Is64Bit], Constraints = ...
+
+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)>;
+
+// 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)>;
+
+} // 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">;
+
+// Global addresses, constant pool entries
+let Predicates = [Is64Bit] in {
+
+def : Pat<(SPhi tglobaladdr:$in), (SETHIi tglobaladdr:$in)>;
+def : Pat<(SPlo tglobaladdr:$in), (ORXri (i64 G0), tglobaladdr:$in)>;
+def : Pat<(SPhi tconstpool:$in), (SETHIi tconstpool:$in)>;
+def : Pat<(SPlo tconstpool:$in), (ORXri (i64 G0), tconstpool:$in)>;
+
+// GlobalTLS addresses
+def : Pat<(SPhi tglobaltlsaddr:$in), (SETHIi tglobaltlsaddr:$in)>;
+def : Pat<(SPlo tglobaltlsaddr:$in), (ORXri (i64 G0), tglobaltlsaddr:$in)>;
+def : Pat<(add (SPhi tglobaltlsaddr:$in1), (SPlo tglobaltlsaddr:$in2)),
+ (ADDXri (SETHIXi tglobaltlsaddr:$in1), (tglobaltlsaddr:$in2))>;
+def : Pat<(xor (SPhi tglobaltlsaddr:$in1), (SPlo tglobaltlsaddr:$in2)),
+ (XORXri (SETHIXi tglobaltlsaddr:$in1), (tglobaltlsaddr:$in2))>;
+
+// Blockaddress
+def : Pat<(SPhi tblockaddress:$in), (SETHIi tblockaddress:$in)>;
+def : Pat<(SPlo tblockaddress:$in), (ORXri (i64 G0), tblockaddress:$in)>;
+
+// Add reg, lo. This is used when taking the addr of a global/constpool entry.
+def : Pat<(add iPTR:$r, (SPlo tglobaladdr:$in)), (ADDXri $r, tglobaladdr:$in)>;
+def : Pat<(add iPTR:$r, (SPlo tconstpool:$in)), (ADDXri $r, tconstpool:$in)>;
+def : Pat<(add iPTR:$r, (SPlo tblockaddress:$in)),
+ (ADDXri $r, tblockaddress:$in)>;
+}
diff --git a/contrib/llvm/lib/Target/Sparc/SparcInstrAliases.td b/contrib/llvm/lib/Target/Sparc/SparcInstrAliases.td
new file mode 100644
index 0000000..670e9e9
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/SparcInstrAliases.td
@@ -0,0 +1,337 @@
+//===-- SparcInstrAliases.td - Instruction Aliases for Sparc Target -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains instruction aliases for Sparc.
+//===----------------------------------------------------------------------===//
+
+// Instruction aliases for conditional moves.
+
+// mov<cond> <ccreg> rs2, rd
+multiclass intcond_mov_alias<string cond, int condVal, string ccreg,
+ Instruction movrr, Instruction movri,
+ Instruction fmovs, Instruction fmovd> {
+
+ // mov<cond> (%icc|%xcc), rs2, rd
+ def : InstAlias<!strconcat(!strconcat(!strconcat("mov", cond), ccreg),
+ ", $rs2, $rd"),
+ (movrr IntRegs:$rd, IntRegs:$rs2, condVal)>;
+
+ // mov<cond> (%icc|%xcc), simm11, rd
+ def : InstAlias<!strconcat(!strconcat(!strconcat("mov", cond), ccreg),
+ ", $simm11, $rd"),
+ (movri IntRegs:$rd, i32imm:$simm11, condVal)>;
+
+ // fmovs<cond> (%icc|%xcc), $rs2, $rd
+ def : InstAlias<!strconcat(!strconcat(!strconcat("fmovs", cond), ccreg),
+ ", $rs2, $rd"),
+ (fmovs FPRegs:$rd, FPRegs:$rs2, condVal)>;
+
+ // fmovd<cond> (%icc|%xcc), $rs2, $rd
+ def : InstAlias<!strconcat(!strconcat(!strconcat("fmovd", cond), ccreg),
+ ", $rs2, $rd"),
+ (fmovd DFPRegs:$rd, DFPRegs:$rs2, condVal)>;
+}
+
+// mov<cond> <ccreg> rs2, rd
+multiclass fpcond_mov_alias<string cond, int condVal,
+ Instruction movrr, Instruction movri,
+ Instruction fmovs, Instruction fmovd> {
+
+ // mov<cond> %fcc[0-3], rs2, rd
+ def : InstAlias<!strconcat(!strconcat("mov", cond), " $cc, $rs2, $rd"),
+ (movrr IntRegs:$rd, FCCRegs:$cc, IntRegs:$rs2, condVal)>;
+
+ // mov<cond> %fcc[0-3], simm11, rd
+ def : InstAlias<!strconcat(!strconcat("mov", cond), " $cc, $simm11, $rd"),
+ (movri IntRegs:$rd, FCCRegs:$cc, i32imm:$simm11, condVal)>;
+
+ // fmovs<cond> %fcc[0-3], $rs2, $rd
+ def : InstAlias<!strconcat(!strconcat("fmovs", cond), " $cc, $rs2, $rd"),
+ (fmovs FPRegs:$rd, FCCRegs:$cc, FPRegs:$rs2, condVal)>;
+
+ // fmovd<cond> %fcc[0-3], $rs2, $rd
+ def : InstAlias<!strconcat(!strconcat("fmovd", cond), " $cc, $rs2, $rd"),
+ (fmovd DFPRegs:$rd, FCCRegs:$cc, DFPRegs:$rs2, condVal)>;
+}
+
+// Instruction aliases for integer conditional branches and moves.
+multiclass int_cond_alias<string cond, int condVal> {
+
+ // b<cond> $imm
+ def : InstAlias<!strconcat(!strconcat("b", cond), " $imm"),
+ (BCOND brtarget:$imm, condVal)>;
+
+ // b<cond>,a $imm
+ def : InstAlias<!strconcat(!strconcat("b", cond), ",a $imm"),
+ (BCONDA brtarget:$imm, condVal)>;
+
+ // b<cond> %icc, $imm
+ def : InstAlias<!strconcat(!strconcat("b", cond), " %icc, $imm"),
+ (BPICC brtarget:$imm, condVal)>, Requires<[HasV9]>;
+
+ // b<cond>,pt %icc, $imm
+ def : InstAlias<!strconcat(!strconcat("b", cond), ",pt %icc, $imm"),
+ (BPICC brtarget:$imm, condVal)>, Requires<[HasV9]>;
+
+ // b<cond>,a %icc, $imm
+ def : InstAlias<!strconcat(!strconcat("b", cond), ",a %icc, $imm"),
+ (BPICCA brtarget:$imm, condVal)>, Requires<[HasV9]>;
+
+ // b<cond>,a,pt %icc, $imm
+ def : InstAlias<!strconcat(!strconcat("b", cond), ",a,pt %icc, $imm"),
+ (BPICCA brtarget:$imm, condVal)>, Requires<[HasV9]>;
+
+ // b<cond>,pn %icc, $imm
+ def : InstAlias<!strconcat(!strconcat("b", cond), ",pn %icc, $imm"),
+ (BPICCNT brtarget:$imm, condVal)>, Requires<[HasV9]>;
+
+ // b<cond>,a,pn %icc, $imm
+ def : InstAlias<!strconcat(!strconcat("b", cond), ",a,pn %icc, $imm"),
+ (BPICCANT brtarget:$imm, condVal)>, Requires<[HasV9]>;
+
+ // b<cond> %xcc, $imm
+ def : InstAlias<!strconcat(!strconcat("b", cond), " %xcc, $imm"),
+ (BPXCC brtarget:$imm, condVal)>, Requires<[Is64Bit]>;
+
+ // b<cond>,pt %xcc, $imm
+ def : InstAlias<!strconcat(!strconcat("b", cond), ",pt %xcc, $imm"),
+ (BPXCC brtarget:$imm, condVal)>, Requires<[Is64Bit]>;
+
+ // b<cond>,a %xcc, $imm
+ def : InstAlias<!strconcat(!strconcat("b", cond), ",a %xcc, $imm"),
+ (BPXCCA brtarget:$imm, condVal)>, Requires<[Is64Bit]>;
+
+ // b<cond>,a,pt %xcc, $imm
+ def : InstAlias<!strconcat(!strconcat("b", cond), ",a,pt %xcc, $imm"),
+ (BPXCCA brtarget:$imm, condVal)>, Requires<[Is64Bit]>;
+
+ // b<cond>,pn %xcc, $imm
+ def : InstAlias<!strconcat(!strconcat("b", cond), ",pn %xcc, $imm"),
+ (BPXCCNT brtarget:$imm, condVal)>, Requires<[Is64Bit]>;
+
+ // b<cond>,a,pn %xcc, $imm
+ def : InstAlias<!strconcat(!strconcat("b", cond), ",a,pn %xcc, $imm"),
+ (BPXCCANT brtarget:$imm, condVal)>, Requires<[Is64Bit]>;
+
+
+ defm : intcond_mov_alias<cond, condVal, " %icc",
+ MOVICCrr, MOVICCri,
+ FMOVS_ICC, FMOVD_ICC>, Requires<[HasV9]>;
+
+ defm : intcond_mov_alias<cond, condVal, " %xcc",
+ MOVXCCrr, MOVXCCri,
+ FMOVS_XCC, FMOVD_XCC>, Requires<[Is64Bit]>;
+
+ // fmovq<cond> (%icc|%xcc), $rs2, $rd
+ def : InstAlias<!strconcat(!strconcat("fmovq", cond), " %icc, $rs2, $rd"),
+ (FMOVQ_ICC QFPRegs:$rd, QFPRegs:$rs2, condVal)>,
+ Requires<[HasV9, HasHardQuad]>;
+ def : InstAlias<!strconcat(!strconcat("fmovq", cond), " %xcc, $rs2, $rd"),
+ (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)>,
+ 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> 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)>;
+
+ // 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)>,
+ 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> rs1 + imm => t<cond> %icc, rs1 + imm
+ def : InstAlias<!strconcat(!strconcat("t", cond), " $rs1 + $imm"),
+ (TICCri 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)>;
+
+}
+
+
+// Instruction aliases for floating point conditional branches and moves.
+multiclass fp_cond_alias<string cond, int condVal> {
+
+ // fb<cond> $imm
+ def : InstAlias<!strconcat(!strconcat("fb", cond), " $imm"),
+ (FBCOND brtarget:$imm, condVal), 0>;
+
+ // fb<cond>,a $imm
+ def : InstAlias<!strconcat(!strconcat("fb", cond), ",a $imm"),
+ (FBCONDA brtarget:$imm, condVal), 0>;
+
+ // fb<cond> %fcc0, $imm
+ def : InstAlias<!strconcat(!strconcat("fb", cond), " $cc, $imm"),
+ (BPFCC brtarget:$imm, condVal, FCCRegs:$cc)>,
+ Requires<[HasV9]>;
+
+ // fb<cond>,pt %fcc0, $imm
+ def : InstAlias<!strconcat(!strconcat("fb", cond), ",pt $cc, $imm"),
+ (BPFCC brtarget:$imm, condVal, FCCRegs:$cc)>,
+ Requires<[HasV9]>;
+
+ // fb<cond>,a %fcc0, $imm
+ def : InstAlias<!strconcat(!strconcat("fb", cond), ",a $cc, $imm"),
+ (BPFCCA brtarget:$imm, condVal, FCCRegs:$cc)>,
+ Requires<[HasV9]>;
+
+ // fb<cond>,a,pt %fcc0, $imm
+ def : InstAlias<!strconcat(!strconcat("fb", cond), ",a,pt $cc, $imm"),
+ (BPFCCA brtarget:$imm, condVal, FCCRegs:$cc)>,
+ Requires<[HasV9]>;
+
+ // fb<cond>,pn %fcc0, $imm
+ def : InstAlias<!strconcat(!strconcat("fb", cond), ",pn $cc, $imm"),
+ (BPFCCNT brtarget:$imm, condVal, FCCRegs:$cc)>,
+ Requires<[HasV9]>;
+
+ // fb<cond>,a,pn %fcc0, $imm
+ def : InstAlias<!strconcat(!strconcat("fb", cond), ",a,pn $cc, $imm"),
+ (BPFCCANT brtarget:$imm, condVal, FCCRegs:$cc)>,
+ Requires<[HasV9]>;
+
+ defm : fpcond_mov_alias<cond, condVal,
+ V9MOVFCCrr, V9MOVFCCri,
+ V9FMOVS_FCC, V9FMOVD_FCC>, Requires<[HasV9]>;
+
+ // fmovq<cond> %fcc0, $rs2, $rd
+ def : InstAlias<!strconcat(!strconcat("fmovq", cond), " $cc, $rs2, $rd"),
+ (V9FMOVQ_FCC QFPRegs:$rd, FCCRegs:$cc, QFPRegs:$rs2,
+ condVal)>,
+ Requires<[HasV9, HasHardQuad]>;
+}
+
+defm : int_cond_alias<"a", 0b1000>;
+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<"z", 0b0001>; // same as e
+defm : int_cond_alias<"g", 0b1010>;
+defm : int_cond_alias<"le", 0b0010>;
+defm : int_cond_alias<"ge", 0b1011>;
+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>;
+
+defm : fp_cond_alias<"a", 0b0000>;
+defm : fp_cond_alias<"n", 0b1000>;
+defm : fp_cond_alias<"u", 0b0111>;
+defm : fp_cond_alias<"g", 0b0110>;
+defm : fp_cond_alias<"ug", 0b0101>;
+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>;
+
+// Instruction aliases for JMPL.
+
+// jmp addr -> jmpl addr, %g0
+def : InstAlias<"jmp $addr", (JMPLrr G0, MEMrr:$addr), 0>;
+def : InstAlias<"jmp $addr", (JMPLri G0, MEMri:$addr), 0>;
+
+// call addr -> jmpl addr, %o7
+def : InstAlias<"call $addr", (JMPLrr O7, MEMrr:$addr), 0>;
+def : InstAlias<"call $addr", (JMPLri O7, MEMri:$addr), 0>;
+
+// retl -> RETL 8
+def : InstAlias<"retl", (RETL 8)>;
+
+// ret -> RET 8
+def : InstAlias<"ret", (RET 8)>;
+
+// mov reg, rd -> or %g0, reg, rd
+def : InstAlias<"mov $rs2, $rd", (ORrr IntRegs:$rd, G0, IntRegs:$rs2)>;
+
+// mov simm13, rd -> or %g0, simm13, rd
+def : InstAlias<"mov $simm13, $rd", (ORri IntRegs:$rd, G0, i32imm:$simm13)>;
+
+// set value, rd
+// (turns into a sequence of sethi+or, depending on the value)
+// def : InstAlias<"set $val, $rd", (ORri IntRegs:$rd, (SETHIi (HI22 imm:$val)), (LO10 imm:$val))>;
+def SET : AsmPseudoInst<(outs IntRegs:$rd), (ins i32imm:$val), "set $val, $rd">;
+
+// restore -> restore %g0, %g0, %g0
+def : InstAlias<"restore", (RESTORErr G0, G0, G0)>;
+
+def : MnemonicAlias<"return", "rett">, Requires<[HasV9]>;
+
+def : MnemonicAlias<"addc", "addx">, Requires<[HasV9]>;
+def : MnemonicAlias<"addccc", "addxcc">, Requires<[HasV9]>;
+
+def : MnemonicAlias<"subc", "subx">, Requires<[HasV9]>;
+def : MnemonicAlias<"subccc", "subxcc">, Requires<[HasV9]>;
+
+
+def : InstAlias<"fcmps $rs1, $rs2", (V9FCMPS FCC0, FPRegs:$rs1, FPRegs:$rs2)>;
+def : InstAlias<"fcmpd $rs1, $rs2", (V9FCMPD FCC0, DFPRegs:$rs1, DFPRegs:$rs2)>;
+def : InstAlias<"fcmpq $rs1, $rs2", (V9FCMPQ FCC0, QFPRegs:$rs1, QFPRegs:$rs2)>,
+ Requires<[HasHardQuad]>;
+
+def : InstAlias<"fcmpes $rs1, $rs2", (V9FCMPES FCC0, FPRegs:$rs1, FPRegs:$rs2)>;
+def : InstAlias<"fcmped $rs1, $rs2", (V9FCMPED FCC0, DFPRegs:$rs1,
+ DFPRegs:$rs2)>;
+def : InstAlias<"fcmpeq $rs1, $rs2", (V9FCMPEQ FCC0, QFPRegs:$rs1,
+ QFPRegs:$rs2)>,
+ Requires<[HasHardQuad]>;
+
diff --git a/contrib/llvm/lib/Target/Sparc/SparcInstrFormats.td b/contrib/llvm/lib/Target/Sparc/SparcInstrFormats.td
new file mode 100644
index 0000000..74ccf55
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/SparcInstrFormats.td
@@ -0,0 +1,341 @@
+//===-- SparcInstrFormats.td - Sparc Instruction Formats ---*- tablegen -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+class InstSP<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : Instruction {
+ field bits<32> Inst;
+
+ let Namespace = "SP";
+ let Size = 4;
+
+ bits<2> op;
+ let Inst{31-30} = op; // Top two bits are the 'op' field
+
+ dag OutOperandList = outs;
+ dag InOperandList = ins;
+ let AsmString = asmstr;
+ let Pattern = pattern;
+
+ let DecoderNamespace = "Sparc";
+ field bits<32> SoftFail = 0;
+}
+
+//===----------------------------------------------------------------------===//
+// Format #2 instruction classes in the Sparc
+//===----------------------------------------------------------------------===//
+
+// Format 2 instructions
+class F2<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSP<outs, ins, asmstr, pattern> {
+ bits<3> op2;
+ bits<22> imm22;
+ let op = 0; // op = 0
+ let Inst{24-22} = op2;
+ let Inst{21-0} = imm22;
+}
+
+// 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> {
+ bits<5> rd;
+
+ let op2 = op2Val;
+
+ let Inst{29-25} = rd;
+}
+
+class F2_2<bits<3> op2Val, bit annul, dag outs, dag ins, string asmstr,
+ list<dag> pattern> : F2<outs, ins, asmstr, pattern> {
+ bits<4> cond;
+ let op2 = op2Val;
+
+ let Inst{29} = annul;
+ let Inst{28-25} = cond;
+}
+
+class F2_3<bits<3> op2Val, bit annul, bit pred,
+ dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSP<outs, ins, asmstr, pattern> {
+ bits<2> cc;
+ bits<4> cond;
+ bits<19> imm19;
+
+ let op = 0; // op = 0
+
+ let Inst{29} = annul;
+ let Inst{28-25} = cond;
+ let Inst{24-22} = op2Val;
+ let Inst{21-20} = cc;
+ let Inst{19} = 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> {
+ bits<16> imm16;
+ bits<5> rs1;
+
+ let op = 0; // op = 0
+
+ let Inst{29} = annul;
+ let Inst{28} = 0;
+ let Inst{27-25} = cond;
+ let Inst{24-22} = 0b011;
+ let Inst{21-20} = imm16{15-14};
+ let Inst{19} = pred;
+ let Inst{18-14} = rs1;
+ let Inst{13-0} = imm16{13-0};
+}
+
+
+//===----------------------------------------------------------------------===//
+// Format #3 instruction classes in the Sparc
+//===----------------------------------------------------------------------===//
+
+class F3<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSP<outs, ins, asmstr, pattern> {
+ bits<5> rd;
+ bits<6> op3;
+ bits<5> rs1;
+ let op{1} = 1; // Op = 2 or 3
+ let Inst{29-25} = rd;
+ let Inst{24-19} = op3;
+ let Inst{18-14} = rs1;
+}
+
+// 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> {
+ bits<8> asi;
+ bits<5> rs2;
+
+ let op = opVal;
+ let op3 = op3val;
+
+ let Inst{13} = 0; // i field = 0
+ let Inst{12-5} = asi; // address space identifier
+ let Inst{4-0} = rs2;
+}
+
+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> {
+ 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> {
+ bits<13> simm13;
+
+ let op = opVal;
+ let op3 = op3val;
+
+ let Inst{13} = 1; // i field = 1
+ let Inst{12-0} = simm13;
+}
+
+// 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> {
+ bits<5> rs2;
+
+ let op = opVal;
+ let op3 = op3val;
+
+ let Inst{13-5} = opfval; // fp opcode
+ let Inst{4-0} = rs2;
+}
+
+// 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> {
+ bits<5> rs2;
+
+ let op = opVal;
+ let op3 = op3val;
+ let rs1 = 0;
+
+ let Inst{13-5} = opfval; // fp opcode
+ let Inst{4-0} = rs2;
+}
+
+// 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> {
+ bits<5> rs2;
+
+ let op = opVal;
+ let op3 = op3val;
+
+ let Inst{13-5} = opfval; // fp opcode
+ let Inst{4-0} = rs2;
+}
+
+// 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> {
+ bit x = xVal; // 1 for 64-bit shifts.
+ bits<5> rs2;
+
+ let op = opVal;
+ let op3 = op3val;
+
+ let Inst{13} = 0; // i field = 0
+ let Inst{12} = x; // extended registers.
+ let Inst{4-0} = rs2;
+}
+
+// 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> {
+ bit x = xVal; // 1 for 64-bit shifts.
+ bits<6> shcnt; // shcnt32 / shcnt64.
+
+ let op = opVal;
+ let op3 = op3val;
+
+ let Inst{13} = 1; // i field = 1
+ let Inst{12} = x; // extended registers.
+ let Inst{5-0} = shcnt;
+}
+
+// Define rr and ri shift instructions with patterns.
+multiclass F3_S<string OpcStr, bits<6> Op3Val, bit XVal, SDNode OpNode,
+ ValueType VT, RegisterClass RC> {
+ 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))]>;
+ 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)))]>;
+}
+
+class F4<bits<6> op3, dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSP<outs, ins, asmstr, pattern> {
+ bits<5> rd;
+
+ let op = 2;
+ let Inst{29-25} = rd;
+ let Inst{24-19} = op3;
+}
+
+
+class F4_1<bits<6> op3, dag outs, dag ins,
+ string asmstr, list<dag> pattern>
+ : F4<op3, outs, ins, asmstr, pattern> {
+
+ bit intcc;
+ bits<2> cc;
+ bits<4> cond;
+ bits<5> rs2;
+
+ let Inst{4-0} = rs2;
+ let Inst{12-11} = cc;
+ 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> {
+ bit intcc;
+ bits<2> cc;
+ bits<4> cond;
+ bits<11> simm11;
+
+ let Inst{10-0} = simm11;
+ let Inst{12-11} = cc;
+ let Inst{13} = 1;
+ let Inst{17-14} = cond;
+ let Inst{18} = intcc;
+}
+
+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> {
+ bits<4> cond;
+ bit intcc;
+ bits<2> opf_cc;
+ bits<5> rs2;
+
+ let Inst{18} = 0;
+ let Inst{17-14} = cond;
+ let Inst{13} = intcc;
+ let Inst{12-11} = opf_cc;
+ let Inst{10-5} = opf_low;
+ let Inst{4-0} = rs2;
+}
+
+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> {
+ bits <5> rs1;
+ bits <5> rs2;
+ let Inst{18-14} = rs1;
+ let Inst{13} = 0; // IsImm
+ let Inst{12-10} = rcond;
+ let Inst{9-5} = opf_low;
+ let Inst{4-0} = rs2;
+}
+
+
+class F4_4i<bits<6> op3, bits<3> rcond, dag outs, dag ins,
+ string asmstr, list<dag> pattern>
+ : F4<op3, outs, ins, asmstr, pattern> {
+ bits<5> rs1;
+ bits<10> simm10;
+ let Inst{18-14} = rs1;
+ let Inst{13} = 1; // IsImm
+ let Inst{12-10} = rcond;
+ let Inst{9-0} = simm10;
+}
+
+
+class TRAPSP<bits<6> op3Val, bit isimm, dag outs, dag ins, string asmstr,
+ list<dag> pattern>: F3<outs, ins, asmstr, pattern> {
+
+ bits<4> cond;
+ bits<2> cc;
+
+ let op = 0b10;
+ let rd{4} = 0;
+ let rd{3-0} = cond;
+ let op3 = op3Val;
+ let Inst{13} = isimm;
+ let Inst{12-11} = cc;
+
+}
+
+class TRAPSPrr<bits<6> op3Val, dag outs, dag ins, string asmstr,
+ list<dag> pattern>: TRAPSP<op3Val, 0, outs, ins, asmstr, pattern> {
+ 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> {
+ bits<8> imm;
+
+ let Inst{10-8} = 0;
+ let Inst{7-0} = imm;
+}
+
+// Pseudo-instructions for alternate assembly syntax (never used by codegen).
+// These are aliases that require C++ handling to convert to the target
+// instruction, while InstAliases can be handled directly by tblgen.
+class AsmPseudoInst<dag outs, dag ins, string asm>
+ : InstSP<outs, ins, asm, []> {
+ let isPseudo = 1;
+}
diff --git a/contrib/llvm/lib/Target/Sparc/SparcInstrInfo.cpp b/contrib/llvm/lib/Target/Sparc/SparcInstrInfo.cpp
new file mode 100644
index 0000000..f87cee4
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/SparcInstrInfo.cpp
@@ -0,0 +1,445 @@
+//===-- SparcInstrInfo.cpp - Sparc Instruction Information ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the Sparc implementation of the TargetInstrInfo class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SparcInstrInfo.h"
+#include "Sparc.h"
+#include "SparcMachineFunctionInfo.h"
+#include "SparcSubtarget.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/CodeGen/MachineMemOperand.h"
+#include "llvm/CodeGen/MachineRegisterInfo.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/TargetRegistry.h"
+
+using namespace llvm;
+
+#define GET_INSTRINFO_CTOR_DTOR
+#include "SparcGenInstrInfo.inc"
+
+// Pin the vtable to this file.
+void SparcInstrInfo::anchor() {}
+
+SparcInstrInfo::SparcInstrInfo(SparcSubtarget &ST)
+ : SparcGenInstrInfo(SP::ADJCALLSTACKDOWN, SP::ADJCALLSTACKUP), RI(),
+ Subtarget(ST) {}
+
+/// isLoadFromStackSlot - If the specified machine instruction is a direct
+/// load from a stack slot, return the virtual or physical register number of
+/// 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,
+ 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();
+ }
+ }
+ return 0;
+}
+
+/// isStoreToStackSlot - If the specified machine instruction is a direct
+/// store to a stack slot, return the virtual or physical register number of
+/// 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,
+ 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();
+ }
+ }
+ return 0;
+}
+
+static bool IsIntegerCC(unsigned CC)
+{
+ return (CC <= SPCC::ICC_VC);
+}
+
+
+static SPCC::CondCodes GetOppositeBranchCondition(SPCC::CondCodes CC)
+{
+ switch(CC) {
+ case SPCC::ICC_A: return SPCC::ICC_N;
+ case SPCC::ICC_N: return SPCC::ICC_A;
+ case SPCC::ICC_NE: return SPCC::ICC_E;
+ case SPCC::ICC_E: return SPCC::ICC_NE;
+ case SPCC::ICC_G: return SPCC::ICC_LE;
+ case SPCC::ICC_LE: return SPCC::ICC_G;
+ case SPCC::ICC_GE: return SPCC::ICC_L;
+ case SPCC::ICC_L: return SPCC::ICC_GE;
+ case SPCC::ICC_GU: return SPCC::ICC_LEU;
+ case SPCC::ICC_LEU: return SPCC::ICC_GU;
+ case SPCC::ICC_CC: return SPCC::ICC_CS;
+ case SPCC::ICC_CS: return SPCC::ICC_CC;
+ case SPCC::ICC_POS: return SPCC::ICC_NEG;
+ case SPCC::ICC_NEG: return SPCC::ICC_POS;
+ case SPCC::ICC_VC: return SPCC::ICC_VS;
+ case SPCC::ICC_VS: return SPCC::ICC_VC;
+
+ case SPCC::FCC_A: return SPCC::FCC_N;
+ case SPCC::FCC_N: return SPCC::FCC_A;
+ case SPCC::FCC_U: return SPCC::FCC_O;
+ case SPCC::FCC_O: return SPCC::FCC_U;
+ case SPCC::FCC_G: return SPCC::FCC_ULE;
+ case SPCC::FCC_LE: return SPCC::FCC_UG;
+ case SPCC::FCC_UG: return SPCC::FCC_LE;
+ case SPCC::FCC_ULE: return SPCC::FCC_G;
+ case SPCC::FCC_L: return SPCC::FCC_UGE;
+ case SPCC::FCC_GE: return SPCC::FCC_UL;
+ case SPCC::FCC_UL: return SPCC::FCC_GE;
+ case SPCC::FCC_UGE: return SPCC::FCC_L;
+ case SPCC::FCC_LG: return SPCC::FCC_UE;
+ case SPCC::FCC_UE: return SPCC::FCC_LG;
+ case SPCC::FCC_NE: return SPCC::FCC_E;
+ case SPCC::FCC_E: return SPCC::FCC_NE;
+ }
+ llvm_unreachable("Invalid cond code");
+}
+
+bool SparcInstrInfo::AnalyzeBranch(MachineBasicBlock &MBB,
+ MachineBasicBlock *&TBB,
+ MachineBasicBlock *&FBB,
+ SmallVectorImpl<MachineOperand> &Cond,
+ bool AllowModify) const
+{
+
+ MachineBasicBlock::iterator I = MBB.end();
+ MachineBasicBlock::iterator UnCondBrIter = MBB.end();
+ while (I != MBB.begin()) {
+ --I;
+
+ if (I->isDebugValue())
+ continue;
+
+ // When we see a non-terminator, we are done.
+ if (!isUnpredicatedTerminator(I))
+ break;
+
+ // Terminator is not a branch.
+ if (!I->isBranch())
+ return true;
+
+ // Handle Unconditional branches.
+ if (I->getOpcode() == SP::BA) {
+ UnCondBrIter = I;
+
+ if (!AllowModify) {
+ TBB = I->getOperand(0).getMBB();
+ continue;
+ }
+
+ while (std::next(I) != MBB.end())
+ std::next(I)->eraseFromParent();
+
+ Cond.clear();
+ FBB = nullptr;
+
+ if (MBB.isLayoutSuccessor(I->getOperand(0).getMBB())) {
+ TBB = nullptr;
+ I->eraseFromParent();
+ I = MBB.end();
+ UnCondBrIter = MBB.end();
+ continue;
+ }
+
+ TBB = I->getOperand(0).getMBB();
+ continue;
+ }
+
+ unsigned Opcode = I->getOpcode();
+ if (Opcode != SP::BCOND && Opcode != SP::FBCOND)
+ return true; // Unknown Opcode.
+
+ SPCC::CondCodes BranchCode = (SPCC::CondCodes)I->getOperand(1).getImm();
+
+ if (Cond.empty()) {
+ MachineBasicBlock *TargetBB = I->getOperand(0).getMBB();
+ if (AllowModify && UnCondBrIter != MBB.end() &&
+ MBB.isLayoutSuccessor(TargetBB)) {
+
+ // Transform the code
+ //
+ // brCC L1
+ // ba L2
+ // L1:
+ // ..
+ // L2:
+ //
+ // into
+ //
+ // brnCC L2
+ // L1:
+ // ...
+ // L2:
+ //
+ BranchCode = GetOppositeBranchCondition(BranchCode);
+ MachineBasicBlock::iterator OldInst = I;
+ BuildMI(MBB, UnCondBrIter, MBB.findDebugLoc(I), get(Opcode))
+ .addMBB(UnCondBrIter->getOperand(0).getMBB()).addImm(BranchCode);
+ BuildMI(MBB, UnCondBrIter, MBB.findDebugLoc(I), get(SP::BA))
+ .addMBB(TargetBB);
+
+ OldInst->eraseFromParent();
+ UnCondBrIter->eraseFromParent();
+
+ UnCondBrIter = MBB.end();
+ I = MBB.end();
+ continue;
+ }
+ FBB = TBB;
+ TBB = I->getOperand(0).getMBB();
+ Cond.push_back(MachineOperand::CreateImm(BranchCode));
+ continue;
+ }
+ // FIXME: Handle subsequent conditional branches.
+ // For now, we can't handle multiple conditional branches.
+ return true;
+ }
+ return false;
+}
+
+unsigned
+SparcInstrInfo::InsertBranch(MachineBasicBlock &MBB,MachineBasicBlock *TBB,
+ MachineBasicBlock *FBB,
+ ArrayRef<MachineOperand> Cond,
+ 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!");
+
+ if (Cond.empty()) {
+ assert(!FBB && "Unconditional branch with multiple successors!");
+ BuildMI(&MBB, DL, get(SP::BA)).addMBB(TBB);
+ return 1;
+ }
+
+ // Conditional branch
+ unsigned CC = Cond[0].getImm();
+
+ if (IsIntegerCC(CC))
+ BuildMI(&MBB, DL, get(SP::BCOND)).addMBB(TBB).addImm(CC);
+ else
+ BuildMI(&MBB, DL, get(SP::FBCOND)).addMBB(TBB).addImm(CC);
+ if (!FBB)
+ return 1;
+
+ BuildMI(&MBB, DL, get(SP::BA)).addMBB(FBB);
+ return 2;
+}
+
+unsigned SparcInstrInfo::RemoveBranch(MachineBasicBlock &MBB) const
+{
+ MachineBasicBlock::iterator I = MBB.end();
+ unsigned Count = 0;
+ while (I != MBB.begin()) {
+ --I;
+
+ if (I->isDebugValue())
+ continue;
+
+ if (I->getOpcode() != SP::BA
+ && I->getOpcode() != SP::BCOND
+ && I->getOpcode() != SP::FBCOND)
+ break; // Not a branch
+
+ I->eraseFromParent();
+ I = MBB.end();
+ ++Count;
+ }
+ return Count;
+}
+
+void SparcInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I, DebugLoc DL,
+ unsigned DestReg, unsigned SrcReg,
+ bool KillSrc) const {
+ unsigned numSubRegs = 0;
+ unsigned movOpc = 0;
+ const unsigned *subRegIdx = nullptr;
+
+ const unsigned DFP_FP_SubRegsIdx[] = { SP::sub_even, SP::sub_odd };
+ const unsigned QFP_DFP_SubRegsIdx[] = { SP::sub_even64, SP::sub_odd64 };
+ const unsigned QFP_FP_SubRegsIdx[] = { SP::sub_even, SP::sub_odd,
+ SP::sub_odd64_then_sub_even,
+ SP::sub_odd64_then_sub_odd };
+
+ if (SP::IntRegsRegClass.contains(DestReg, SrcReg))
+ BuildMI(MBB, I, DL, get(SP::ORrr), DestReg).addReg(SP::G0)
+ .addReg(SrcReg, getKillRegState(KillSrc));
+ else if (SP::FPRegsRegClass.contains(DestReg, SrcReg))
+ BuildMI(MBB, I, DL, get(SP::FMOVS), DestReg)
+ .addReg(SrcReg, getKillRegState(KillSrc));
+ else if (SP::DFPRegsRegClass.contains(DestReg, SrcReg)) {
+ if (Subtarget.isV9()) {
+ BuildMI(MBB, I, DL, get(SP::FMOVD), DestReg)
+ .addReg(SrcReg, getKillRegState(KillSrc));
+ } else {
+ // Use two FMOVS instructions.
+ subRegIdx = DFP_FP_SubRegsIdx;
+ numSubRegs = 2;
+ movOpc = SP::FMOVS;
+ }
+ } else if (SP::QFPRegsRegClass.contains(DestReg, SrcReg)) {
+ if (Subtarget.isV9()) {
+ if (Subtarget.hasHardQuad()) {
+ BuildMI(MBB, I, DL, get(SP::FMOVQ), DestReg)
+ .addReg(SrcReg, getKillRegState(KillSrc));
+ } else {
+ // Use two FMOVD instructions.
+ subRegIdx = QFP_DFP_SubRegsIdx;
+ numSubRegs = 2;
+ movOpc = SP::FMOVD;
+ }
+ } else {
+ // Use four FMOVS instructions.
+ subRegIdx = QFP_FP_SubRegsIdx;
+ numSubRegs = 4;
+ movOpc = SP::FMOVS;
+ }
+ } else
+ llvm_unreachable("Impossible reg-to-reg copy");
+
+ if (numSubRegs == 0 || subRegIdx == nullptr || movOpc == 0)
+ return;
+
+ const TargetRegisterInfo *TRI = &getRegisterInfo();
+ MachineInstr *MovMI = nullptr;
+
+ for (unsigned i = 0; i != numSubRegs; ++i) {
+ unsigned Dst = TRI->getSubReg(DestReg, subRegIdx[i]);
+ unsigned Src = TRI->getSubReg(SrcReg, subRegIdx[i]);
+ assert(Dst && Src && "Bad sub-register");
+
+ MovMI = BuildMI(MBB, I, DL, get(movOpc), Dst).addReg(Src);
+ }
+ // Add implicit super-register defs and kills to the last MovMI.
+ MovMI->addRegisterDefined(DestReg, TRI);
+ if (KillSrc)
+ MovMI->addRegisterKilled(SrcReg, TRI);
+}
+
+void SparcInstrInfo::
+storeRegToStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
+ unsigned SrcReg, bool isKill, int FI,
+ const TargetRegisterClass *RC,
+ const TargetRegisterInfo *TRI) const {
+ DebugLoc DL;
+ if (I != MBB.end()) DL = I->getDebugLoc();
+
+ MachineFunction *MF = MBB.getParent();
+ const MachineFrameInfo &MFI = *MF->getFrameInfo();
+ MachineMemOperand *MMO =
+ MF->getMachineMemOperand(MachinePointerInfo::getFixedStack(FI),
+ MachineMemOperand::MOStore,
+ MFI.getObjectSize(FI),
+ MFI.getObjectAlignment(FI));
+
+ // On the order of operands here: think "[FrameIdx + 0] = SrcReg".
+ if (RC == &SP::I64RegsRegClass)
+ BuildMI(MBB, I, DL, get(SP::STXri)).addFrameIndex(FI).addImm(0)
+ .addReg(SrcReg, getKillRegState(isKill)).addMemOperand(MMO);
+ else if (RC == &SP::IntRegsRegClass)
+ BuildMI(MBB, I, DL, get(SP::STri)).addFrameIndex(FI).addImm(0)
+ .addReg(SrcReg, getKillRegState(isKill)).addMemOperand(MMO);
+ else if (RC == &SP::FPRegsRegClass)
+ BuildMI(MBB, I, DL, get(SP::STFri)).addFrameIndex(FI).addImm(0)
+ .addReg(SrcReg, getKillRegState(isKill)).addMemOperand(MMO);
+ else if (SP::DFPRegsRegClass.hasSubClassEq(RC))
+ BuildMI(MBB, I, DL, get(SP::STDFri)).addFrameIndex(FI).addImm(0)
+ .addReg(SrcReg, getKillRegState(isKill)).addMemOperand(MMO);
+ else if (SP::QFPRegsRegClass.hasSubClassEq(RC))
+ // Use STQFri irrespective of its legality. If STQ is not legal, it will be
+ // lowered into two STDs in eliminateFrameIndex.
+ BuildMI(MBB, I, DL, get(SP::STQFri)).addFrameIndex(FI).addImm(0)
+ .addReg(SrcReg, getKillRegState(isKill)).addMemOperand(MMO);
+ else
+ llvm_unreachable("Can't store this register to stack slot");
+}
+
+void SparcInstrInfo::
+loadRegFromStackSlot(MachineBasicBlock &MBB, MachineBasicBlock::iterator I,
+ unsigned DestReg, int FI,
+ const TargetRegisterClass *RC,
+ const TargetRegisterInfo *TRI) const {
+ DebugLoc DL;
+ if (I != MBB.end()) DL = I->getDebugLoc();
+
+ MachineFunction *MF = MBB.getParent();
+ const MachineFrameInfo &MFI = *MF->getFrameInfo();
+ MachineMemOperand *MMO =
+ MF->getMachineMemOperand(MachinePointerInfo::getFixedStack(FI),
+ MachineMemOperand::MOLoad,
+ MFI.getObjectSize(FI),
+ MFI.getObjectAlignment(FI));
+
+ if (RC == &SP::I64RegsRegClass)
+ BuildMI(MBB, I, DL, get(SP::LDXri), DestReg).addFrameIndex(FI).addImm(0)
+ .addMemOperand(MMO);
+ else if (RC == &SP::IntRegsRegClass)
+ BuildMI(MBB, I, DL, get(SP::LDri), DestReg).addFrameIndex(FI).addImm(0)
+ .addMemOperand(MMO);
+ else if (RC == &SP::FPRegsRegClass)
+ BuildMI(MBB, I, DL, get(SP::LDFri), DestReg).addFrameIndex(FI).addImm(0)
+ .addMemOperand(MMO);
+ else if (SP::DFPRegsRegClass.hasSubClassEq(RC))
+ BuildMI(MBB, I, DL, get(SP::LDDFri), DestReg).addFrameIndex(FI).addImm(0)
+ .addMemOperand(MMO);
+ else if (SP::QFPRegsRegClass.hasSubClassEq(RC))
+ // Use LDQFri irrespective of its legality. If LDQ is not legal, it will be
+ // lowered into two LDDs in eliminateFrameIndex.
+ BuildMI(MBB, I, DL, get(SP::LDQFri), DestReg).addFrameIndex(FI).addImm(0)
+ .addMemOperand(MMO);
+ else
+ llvm_unreachable("Can't load this register from stack slot");
+}
+
+unsigned SparcInstrInfo::getGlobalBaseReg(MachineFunction *MF) const
+{
+ SparcMachineFunctionInfo *SparcFI = MF->getInfo<SparcMachineFunctionInfo>();
+ unsigned GlobalBaseReg = SparcFI->getGlobalBaseReg();
+ if (GlobalBaseReg != 0)
+ return GlobalBaseReg;
+
+ // Insert the set of GlobalBaseReg into the first MBB of the function
+ MachineBasicBlock &FirstMBB = MF->front();
+ MachineBasicBlock::iterator MBBI = FirstMBB.begin();
+ MachineRegisterInfo &RegInfo = MF->getRegInfo();
+
+ const TargetRegisterClass *PtrRC =
+ Subtarget.is64Bit() ? &SP::I64RegsRegClass : &SP::IntRegsRegClass;
+ GlobalBaseReg = RegInfo.createVirtualRegister(PtrRC);
+
+ DebugLoc dl;
+
+ BuildMI(FirstMBB, MBBI, dl, get(SP::GETPCX), GlobalBaseReg);
+ SparcFI->setGlobalBaseReg(GlobalBaseReg);
+ return GlobalBaseReg;
+}
diff --git a/contrib/llvm/lib/Target/Sparc/SparcInstrInfo.h b/contrib/llvm/lib/Target/Sparc/SparcInstrInfo.h
new file mode 100644
index 0000000..b59dd89
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/SparcInstrInfo.h
@@ -0,0 +1,101 @@
+//===-- SparcInstrInfo.h - Sparc Instruction Information --------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the Sparc implementation of the TargetInstrInfo class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_SPARC_SPARCINSTRINFO_H
+#define LLVM_LIB_TARGET_SPARC_SPARCINSTRINFO_H
+
+#include "SparcRegisterInfo.h"
+#include "llvm/Target/TargetInstrInfo.h"
+
+#define GET_INSTRINFO_HEADER
+#include "SparcGenInstrInfo.inc"
+
+namespace llvm {
+
+class SparcSubtarget;
+
+/// SPII - This namespace holds all of the target specific flags that
+/// instruction info tracks.
+///
+namespace SPII {
+ enum {
+ Pseudo = (1<<0),
+ Load = (1<<1),
+ Store = (1<<2),
+ DelaySlot = (1<<3)
+ };
+}
+
+class SparcInstrInfo : public SparcGenInstrInfo {
+ const SparcRegisterInfo RI;
+ const SparcSubtarget& Subtarget;
+ virtual void anchor();
+public:
+ explicit SparcInstrInfo(SparcSubtarget &ST);
+
+ /// getRegisterInfo - TargetInstrInfo is a superset of MRegister info. As
+ /// such, whenever a client has an instance of instruction info, it should
+ /// always be able to get register info as well (through this method).
+ ///
+ const SparcRegisterInfo &getRegisterInfo() const { return RI; }
+
+ /// isLoadFromStackSlot - If the specified machine instruction is a direct
+ /// load from a stack slot, return the virtual or physical register number of
+ /// 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,
+ int &FrameIndex) const override;
+
+ /// isStoreToStackSlot - If the specified machine instruction is a direct
+ /// store to a stack slot, return the virtual or physical register number of
+ /// 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,
+ int &FrameIndex) const override;
+
+ bool AnalyzeBranch(MachineBasicBlock &MBB, MachineBasicBlock *&TBB,
+ MachineBasicBlock *&FBB,
+ SmallVectorImpl<MachineOperand> &Cond,
+ 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;
+
+ void copyPhysReg(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator I, DebugLoc DL,
+ unsigned DestReg, unsigned SrcReg,
+ bool KillSrc) const override;
+
+ void storeRegToStackSlot(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI,
+ unsigned SrcReg, bool isKill, int FrameIndex,
+ const TargetRegisterClass *RC,
+ const TargetRegisterInfo *TRI) const override;
+
+ void loadRegFromStackSlot(MachineBasicBlock &MBB,
+ MachineBasicBlock::iterator MBBI,
+ unsigned DestReg, int FrameIndex,
+ const TargetRegisterClass *RC,
+ const TargetRegisterInfo *TRI) const override;
+
+ unsigned getGlobalBaseReg(MachineFunction *MF) const;
+};
+
+} // namespace llvm
+
+#endif
diff --git a/contrib/llvm/lib/Target/Sparc/SparcInstrInfo.td b/contrib/llvm/lib/Target/Sparc/SparcInstrInfo.td
new file mode 100644
index 0000000..b1f795b
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/SparcInstrInfo.td
@@ -0,0 +1,1306 @@
+//===-- SparcInstrInfo.td - Target Description for Sparc Target -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file describes the Sparc instructions in TableGen format.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Instruction format superclass
+//===----------------------------------------------------------------------===//
+
+include "SparcInstrFormats.td"
+
+//===----------------------------------------------------------------------===//
+// Feature predicates.
+//===----------------------------------------------------------------------===//
+
+// True when generating 32-bit code.
+def Is32Bit : Predicate<"!Subtarget->is64Bit()">;
+
+// True when generating 64-bit code. This also implies HasV9.
+def Is64Bit : Predicate<"Subtarget->is64Bit()">;
+
+// HasV9 - This predicate is true when the target processor supports V9
+// instructions. Note that the machine may be running in 32-bit mode.
+def HasV9 : Predicate<"Subtarget->isV9()">,
+ AssemblerPredicate<"FeatureV9">;
+
+// HasNoV9 - This predicate is true when the target doesn't have V9
+// instructions. Use of this is just a hack for the isel not having proper
+// costs for V8 instructions that are more expensive than their V9 ones.
+def HasNoV9 : Predicate<"!Subtarget->isV9()">;
+
+// HasVIS - This is true when the target processor has VIS extensions.
+def HasVIS : Predicate<"Subtarget->isVIS()">,
+ AssemblerPredicate<"FeatureVIS">;
+def HasVIS2 : Predicate<"Subtarget->isVIS2()">,
+ AssemblerPredicate<"FeatureVIS2">;
+def HasVIS3 : Predicate<"Subtarget->isVIS3()">,
+ AssemblerPredicate<"FeatureVIS3">;
+
+// HasHardQuad - This is true when the target processor supports quad floating
+// point instructions.
+def HasHardQuad : Predicate<"Subtarget->hasHardQuad()">;
+
+// 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
+// will pick deprecated instructions.
+def UseDeprecatedInsts : Predicate<"Subtarget->useDeprecatedV8Instructions()">;
+
+//===----------------------------------------------------------------------===//
+// Instruction Pattern Stuff
+//===----------------------------------------------------------------------===//
+
+def simm11 : PatLeaf<(imm), [{ return isInt<11>(N->getSExtValue()); }]>;
+
+def simm13 : PatLeaf<(imm), [{ return isInt<13>(N->getSExtValue()); }]>;
+
+def LO10 : SDNodeXForm<imm, [{
+ return CurDAG->getTargetConstant((unsigned)N->getZExtValue() & 1023, SDLoc(N),
+ MVT::i32);
+}]>;
+
+def HI22 : SDNodeXForm<imm, [{
+ // Transformation function: shift the immediate value down into the low bits.
+ return CurDAG->getTargetConstant((unsigned)N->getZExtValue() >> 10, SDLoc(N),
+ MVT::i32);
+}]>;
+
+def SETHIimm : PatLeaf<(imm), [{
+ return isShiftedUInt<22, 10>(N->getZExtValue());
+}], HI22>;
+
+// Addressing modes.
+def ADDRrr : ComplexPattern<iPTR, 2, "SelectADDRrr", [], []>;
+def ADDRri : ComplexPattern<iPTR, 2, "SelectADDRri", [frameindex], []>;
+
+// Address operands
+def SparcMEMrrAsmOperand : AsmOperandClass {
+ let Name = "MEMrr";
+ let ParserMethod = "parseMEMOperand";
+}
+
+def SparcMEMriAsmOperand : AsmOperandClass {
+ let Name = "MEMri";
+ let ParserMethod = "parseMEMOperand";
+}
+
+def MEMrr : Operand<iPTR> {
+ let PrintMethod = "printMemOperand";
+ let MIOperandInfo = (ops ptr_rc, ptr_rc);
+ let ParserMatchClass = SparcMEMrrAsmOperand;
+}
+def MEMri : Operand<iPTR> {
+ let PrintMethod = "printMemOperand";
+ let MIOperandInfo = (ops ptr_rc, i32imm);
+ let ParserMatchClass = SparcMEMriAsmOperand;
+}
+
+def TLSSym : Operand<iPTR>;
+
+// Branch targets have OtherVT type.
+def brtarget : Operand<OtherVT> {
+ let EncoderMethod = "getBranchTargetOpValue";
+}
+
+def bprtarget : Operand<OtherVT> {
+ let EncoderMethod = "getBranchPredTargetOpValue";
+}
+
+def bprtarget16 : Operand<OtherVT> {
+ let EncoderMethod = "getBranchOnRegTargetOpValue";
+}
+
+def calltarget : Operand<i32> {
+ let EncoderMethod = "getCallTargetOpValue";
+ let DecoderMethod = "DecodeCall";
+}
+
+def simm13Op : Operand<i32> {
+ let DecoderMethod = "DecodeSIMM13";
+}
+
+// Operand for printing out a condition code.
+let PrintMethod = "printCCOperand" in
+ def CCOp : Operand<i32>;
+
+def SDTSPcmpicc :
+SDTypeProfile<0, 2, [SDTCisInt<0>, SDTCisSameAs<0, 1>]>;
+def SDTSPcmpfcc :
+SDTypeProfile<0, 2, [SDTCisFP<0>, SDTCisSameAs<0, 1>]>;
+def SDTSPbrcc :
+SDTypeProfile<0, 2, [SDTCisVT<0, OtherVT>, SDTCisVT<1, i32>]>;
+def SDTSPselectcc :
+SDTypeProfile<1, 3, [SDTCisSameAs<0, 1>, SDTCisSameAs<1, 2>, SDTCisVT<3, i32>]>;
+def SDTSPFTOI :
+SDTypeProfile<1, 1, [SDTCisVT<0, f32>, SDTCisFP<1>]>;
+def SDTSPITOF :
+SDTypeProfile<1, 1, [SDTCisFP<0>, SDTCisVT<1, f32>]>;
+def SDTSPFTOX :
+SDTypeProfile<1, 1, [SDTCisVT<0, f64>, SDTCisFP<1>]>;
+def SDTSPXTOF :
+SDTypeProfile<1, 1, [SDTCisFP<0>, SDTCisVT<1, f64>]>;
+
+def SDTSPtlsadd :
+SDTypeProfile<1, 3, [SDTCisInt<0>, SDTCisSameAs<0, 1>, SDTCisPtrTy<2>]>;
+def SDTSPtlsld :
+SDTypeProfile<1, 2, [SDTCisPtrTy<0>, SDTCisPtrTy<1>]>;
+
+def SPcmpicc : SDNode<"SPISD::CMPICC", SDTSPcmpicc, [SDNPOutGlue]>;
+def SPcmpfcc : SDNode<"SPISD::CMPFCC", SDTSPcmpfcc, [SDNPOutGlue]>;
+def SPbricc : SDNode<"SPISD::BRICC", SDTSPbrcc, [SDNPHasChain, SDNPInGlue]>;
+def SPbrxcc : SDNode<"SPISD::BRXCC", SDTSPbrcc, [SDNPHasChain, SDNPInGlue]>;
+def SPbrfcc : SDNode<"SPISD::BRFCC", SDTSPbrcc, [SDNPHasChain, SDNPInGlue]>;
+
+def SPhi : SDNode<"SPISD::Hi", SDTIntUnaryOp>;
+def SPlo : SDNode<"SPISD::Lo", SDTIntUnaryOp>;
+
+def SPftoi : SDNode<"SPISD::FTOI", SDTSPFTOI>;
+def SPitof : SDNode<"SPISD::ITOF", SDTSPITOF>;
+def SPftox : SDNode<"SPISD::FTOX", SDTSPFTOX>;
+def SPxtof : SDNode<"SPISD::XTOF", SDTSPXTOF>;
+
+def SPselecticc : SDNode<"SPISD::SELECT_ICC", SDTSPselectcc, [SDNPInGlue]>;
+def SPselectxcc : SDNode<"SPISD::SELECT_XCC", SDTSPselectcc, [SDNPInGlue]>;
+def SPselectfcc : SDNode<"SPISD::SELECT_FCC", SDTSPselectcc, [SDNPInGlue]>;
+
+// These are target-independent nodes, but have target-specific formats.
+def SDT_SPCallSeqStart : SDCallSeqStart<[ SDTCisVT<0, i32> ]>;
+def SDT_SPCallSeqEnd : SDCallSeqEnd<[ SDTCisVT<0, i32>,
+ SDTCisVT<1, i32> ]>;
+
+def callseq_start : SDNode<"ISD::CALLSEQ_START", SDT_SPCallSeqStart,
+ [SDNPHasChain, SDNPOutGlue]>;
+def callseq_end : SDNode<"ISD::CALLSEQ_END", SDT_SPCallSeqEnd,
+ [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue]>;
+
+def SDT_SPCall : SDTypeProfile<0, -1, [SDTCisVT<0, i32>]>;
+def call : SDNode<"SPISD::CALL", SDT_SPCall,
+ [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue,
+ SDNPVariadic]>;
+
+def SDT_SPRet : SDTypeProfile<0, 1, [SDTCisVT<0, i32>]>;
+def retflag : SDNode<"SPISD::RET_FLAG", SDT_SPRet,
+ [SDNPHasChain, SDNPOptInGlue, SDNPVariadic]>;
+
+def flushw : SDNode<"SPISD::FLUSHW", SDTNone,
+ [SDNPHasChain, SDNPSideEffect, SDNPMayStore]>;
+
+def tlsadd : SDNode<"SPISD::TLS_ADD", SDTSPtlsadd>;
+def tlsld : SDNode<"SPISD::TLS_LD", SDTSPtlsld>;
+def tlscall : SDNode<"SPISD::TLS_CALL", SDT_SPCall,
+ [SDNPHasChain, SDNPOptInGlue, SDNPOutGlue,
+ SDNPVariadic]>;
+
+def getPCX : Operand<iPTR> {
+ let PrintMethod = "printGetPCX";
+}
+
+//===----------------------------------------------------------------------===//
+// SPARC Flag Conditions
+//===----------------------------------------------------------------------===//
+
+// Note that these values must be kept in sync with the CCOp::CondCode enum
+// values.
+class ICC_VAL<int N> : PatLeaf<(i32 N)>;
+def ICC_NE : ICC_VAL< 9>; // Not Equal
+def ICC_E : ICC_VAL< 1>; // Equal
+def ICC_G : ICC_VAL<10>; // Greater
+def ICC_LE : ICC_VAL< 2>; // Less or Equal
+def ICC_GE : ICC_VAL<11>; // Greater or Equal
+def ICC_L : ICC_VAL< 3>; // Less
+def ICC_GU : ICC_VAL<12>; // Greater Unsigned
+def ICC_LEU : ICC_VAL< 4>; // Less or Equal Unsigned
+def ICC_CC : ICC_VAL<13>; // Carry Clear/Great or Equal Unsigned
+def ICC_CS : ICC_VAL< 5>; // Carry Set/Less Unsigned
+def ICC_POS : ICC_VAL<14>; // Positive
+def ICC_NEG : ICC_VAL< 6>; // Negative
+def ICC_VC : ICC_VAL<15>; // Overflow Clear
+def ICC_VS : ICC_VAL< 7>; // Overflow Set
+
+class FCC_VAL<int N> : PatLeaf<(i32 N)>;
+def FCC_U : FCC_VAL<23>; // Unordered
+def FCC_G : FCC_VAL<22>; // Greater
+def FCC_UG : FCC_VAL<21>; // Unordered or Greater
+def FCC_L : FCC_VAL<20>; // Less
+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
+
+//===----------------------------------------------------------------------===//
+// Instruction Class Templates
+//===----------------------------------------------------------------------===//
+
+/// 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> {
+ 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))]>;
+ 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)))]>;
+}
+
+/// 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> {
+ def rr : F3_1<2, Op3Val,
+ (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2),
+ !strconcat(OpcStr, " $rs1, $rs2, $rd"), []>;
+ def ri : F3_2<2, Op3Val,
+ (outs IntRegs:$rd), (ins IntRegs:$rs1, simm13Op:$simm13),
+ !strconcat(OpcStr, " $rs1, $simm13, $rd"), []>;
+}
+
+// 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> {
+ def rr : F3_1<3, Op3Val,
+ (outs RC:$dst), (ins MEMrr:$addr),
+ !strconcat(OpcStr, " [$addr], $dst"),
+ [(set Ty:$dst, (OpNode ADDRrr:$addr))]>;
+ def ri : F3_2<3, Op3Val,
+ (outs RC:$dst), (ins MEMri:$addr),
+ !strconcat(OpcStr, " [$addr], $dst"),
+ [(set Ty:$dst, (OpNode ADDRri:$addr))]>;
+}
+
+// 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> {
+ // TODO: The LD*Arr instructions are currently asm only; hooking up
+ // CodeGen's address spaces to use these is a future task.
+ def Arr : F3_1_asi<3, LoadAOp3Val, (outs RC:$dst), (ins MEMrr:$addr, i8imm:$asi),
+ !strconcat(OpcStr, "a [$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> {
+ def rr : F3_1<3, Op3Val,
+ (outs), (ins MEMrr:$addr, RC:$rd),
+ !strconcat(OpcStr, " $rd, [$addr]"),
+ [(OpNode Ty:$rd, ADDRrr:$addr)]>;
+ def ri : F3_2<3, Op3Val,
+ (outs), (ins MEMri:$addr, RC:$rd),
+ !strconcat(OpcStr, " $rd, [$addr]"),
+ [(OpNode Ty:$rd, ADDRri:$addr)]>;
+}
+
+multiclass StoreA<string OpcStr, bits<6> Op3Val, bits<6> StoreAOp3Val,
+ SDPatternOperator OpNode, RegisterClass RC, ValueType Ty> :
+ Store<OpcStr, Op3Val, OpNode, RC, Ty> {
+ // TODO: The ST*Arr instructions are currently asm only; hooking up
+ // CodeGen's address spaces to use these is a future task.
+ def Arr : F3_1_asi<3, StoreAOp3Val, (outs), (ins MEMrr:$addr, RC:$rd, i8imm:$asi),
+ !strconcat(OpcStr, "a $rd, [$addr] $asi"),
+ []>;
+}
+
+//===----------------------------------------------------------------------===//
+// Instructions
+//===----------------------------------------------------------------------===//
+
+// Pseudo instructions.
+class Pseudo<dag outs, dag ins, string asmstr, list<dag> pattern>
+ : InstSP<outs, ins, asmstr, pattern> {
+ let isCodeGenOnly = 1;
+ let isPseudo = 1;
+}
+
+// GETPCX for PIC
+let Defs = [O7] in {
+ def GETPCX : Pseudo<(outs getPCX:$getpcseq), (ins), "$getpcseq", [] >;
+}
+
+let Defs = [O6], Uses = [O6] in {
+def ADJCALLSTACKDOWN : Pseudo<(outs), (ins i32imm:$amt),
+ "!ADJCALLSTACKDOWN $amt",
+ [(callseq_start timm:$amt)]>;
+def ADJCALLSTACKUP : Pseudo<(outs), (ins i32imm:$amt1, i32imm:$amt2),
+ "!ADJCALLSTACKUP $amt1",
+ [(callseq_end timm:$amt1, timm:$amt2)]>;
+}
+
+let hasSideEffects = 1, mayStore = 1 in {
+ let rd = 0, rs1 = 0, rs2 = 0 in
+ def FLUSHW : F3_1<0b10, 0b101011, (outs), (ins),
+ "flushw",
+ [(flushw)]>, Requires<[HasV9]>;
+ let rd = 0, rs1 = 1, simm13 = 3 in
+ def TA3 : F3_2<0b10, 0b111010, (outs), (ins),
+ "ta 3",
+ [(flushw)]>;
+}
+
+let isBarrier = 1, isTerminator = 1, rd = 0b01000, rs1 = 0, simm13 = 5 in
+ def TA5 : F3_2<0b10, 0b111010, (outs), (ins), "ta 5", [(trap)]>;
+
+let rd = 0 in
+ def UNIMP : F2_1<0b000, (outs), (ins i32imm:$imm22),
+ "unimp $imm22", []>;
+
+// SELECT_CC_* - Used to implement the SELECT_CC DAG operation. Expanded after
+// instruction selection into a branch sequence. This has to handle all
+// permutations of selection between i32/f32/f64 on ICC and FCC.
+// Expanded after instruction selection.
+let Uses = [ICC], usesCustomInserter = 1 in {
+ def SELECT_CC_Int_ICC
+ : Pseudo<(outs IntRegs:$dst), (ins IntRegs:$T, IntRegs:$F, i32imm:$Cond),
+ "; SELECT_CC_Int_ICC PSEUDO!",
+ [(set i32:$dst, (SPselecticc i32:$T, i32:$F, imm:$Cond))]>;
+ def SELECT_CC_FP_ICC
+ : Pseudo<(outs FPRegs:$dst), (ins FPRegs:$T, FPRegs:$F, i32imm:$Cond),
+ "; SELECT_CC_FP_ICC PSEUDO!",
+ [(set f32:$dst, (SPselecticc f32:$T, f32:$F, imm:$Cond))]>;
+
+ def SELECT_CC_DFP_ICC
+ : Pseudo<(outs DFPRegs:$dst), (ins DFPRegs:$T, DFPRegs:$F, i32imm:$Cond),
+ "; SELECT_CC_DFP_ICC PSEUDO!",
+ [(set f64:$dst, (SPselecticc f64:$T, f64:$F, imm:$Cond))]>;
+
+ def SELECT_CC_QFP_ICC
+ : Pseudo<(outs QFPRegs:$dst), (ins QFPRegs:$T, QFPRegs:$F, i32imm:$Cond),
+ "; SELECT_CC_QFP_ICC PSEUDO!",
+ [(set f128:$dst, (SPselecticc f128:$T, f128:$F, imm:$Cond))]>;
+}
+
+let usesCustomInserter = 1, Uses = [FCC0] in {
+
+ def SELECT_CC_Int_FCC
+ : Pseudo<(outs IntRegs:$dst), (ins IntRegs:$T, IntRegs:$F, i32imm:$Cond),
+ "; SELECT_CC_Int_FCC PSEUDO!",
+ [(set i32:$dst, (SPselectfcc i32:$T, i32:$F, imm:$Cond))]>;
+
+ def SELECT_CC_FP_FCC
+ : Pseudo<(outs FPRegs:$dst), (ins FPRegs:$T, FPRegs:$F, i32imm:$Cond),
+ "; SELECT_CC_FP_FCC PSEUDO!",
+ [(set f32:$dst, (SPselectfcc f32:$T, f32:$F, imm:$Cond))]>;
+ def SELECT_CC_DFP_FCC
+ : Pseudo<(outs DFPRegs:$dst), (ins DFPRegs:$T, DFPRegs:$F, i32imm:$Cond),
+ "; SELECT_CC_DFP_FCC PSEUDO!",
+ [(set f64:$dst, (SPselectfcc f64:$T, f64:$F, imm:$Cond))]>;
+ def SELECT_CC_QFP_FCC
+ : Pseudo<(outs QFPRegs:$dst), (ins QFPRegs:$T, QFPRegs:$F, i32imm:$Cond),
+ "; SELECT_CC_QFP_FCC PSEUDO!",
+ [(set f128:$dst, (SPselectfcc f128:$T, f128:$F, imm:$Cond))]>;
+}
+
+// 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", []>;
+}
+
+// Section A.3 - Synthetic Instructions, p. 85
+// special cases of JMPL:
+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)]>;
+
+ let rd = 0, rs1 = 31 in
+ def RET: F3_2<2, 0b111000, (outs), (ins i32imm:$val),
+ "jmp %i7+$val", []>;
+}
+
+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", []>;
+}
+
+// Section B.1 - Load Integer Instructions, p. 90
+let DecoderMethod = "DecodeLoadInt" in {
+ defm LDSB : LoadA<"ldsb", 0b001001, 0b011001, sextloadi8, IntRegs, i32>;
+ defm LDSH : LoadA<"ldsh", 0b001010, 0b011010, sextloadi16, IntRegs, i32>;
+ defm LDUB : LoadA<"ldub", 0b000001, 0b010001, zextloadi8, IntRegs, i32>;
+ defm LDUH : LoadA<"lduh", 0b000010, 0b010010, zextloadi16, IntRegs, i32>;
+ defm LD : LoadA<"ld", 0b000000, 0b010000, load, IntRegs, i32>;
+}
+
+// Section B.2 - Load Floating-point Instructions, p. 92
+let DecoderMethod = "DecodeLoadFP" in
+ defm LDF : Load<"ld", 0b100000, load, FPRegs, f32>;
+let DecoderMethod = "DecodeLoadDFP" in
+ defm LDDF : Load<"ldd", 0b100011, load, DFPRegs, f64>;
+let DecoderMethod = "DecodeLoadQFP" in
+ defm LDQF : Load<"ldq", 0b100010, load, QFPRegs, f128>,
+ Requires<[HasV9, HasHardQuad]>;
+
+// Section B.4 - Store Integer Instructions, p. 95
+let DecoderMethod = "DecodeStoreInt" in {
+ defm STB : StoreA<"stb", 0b000101, 0b010101, truncstorei8, IntRegs, i32>;
+ defm STH : StoreA<"sth", 0b000110, 0b010110, truncstorei16, IntRegs, i32>;
+ defm ST : StoreA<"st", 0b000100, 0b010100, store, IntRegs, i32>;
+}
+
+// Section B.5 - Store Floating-point Instructions, p. 97
+let DecoderMethod = "DecodeStoreFP" in
+ defm STF : Store<"st", 0b100100, store, FPRegs, f32>;
+let DecoderMethod = "DecodeStoreDFP" in
+ defm STDF : Store<"std", 0b100111, store, DFPRegs, f64>;
+let DecoderMethod = "DecodeStoreQFP" in
+ defm STQF : Store<"stq", 0b100110, store, QFPRegs, f128>,
+ Requires<[HasV9, HasHardQuad]>;
+
+// Section B.9 - SETHI Instruction, p. 104
+def SETHIi: F2_1<0b100,
+ (outs IntRegs:$rd), (ins i32imm:$imm22),
+ "sethi $imm22, $rd",
+ [(set i32:$rd, SETHIimm:$imm22)]>;
+
+// Section B.10 - NOP Instruction, p. 105
+// (It's a special case of SETHI)
+let rd = 0, imm22 = 0 in
+ def NOP : F2_1<0b100, (outs), (ins), "nop", []>;
+
+// Section B.11 - Logical Instructions, p. 106
+defm AND : F3_12<"and", 0b000001, and, IntRegs, i32, simm13Op>;
+
+def ANDNrr : F3_1<2, 0b000101,
+ (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2),
+ "andn $rs1, $rs2, $rd",
+ [(set i32:$rd, (and i32:$rs1, (not i32:$rs2)))]>;
+def ANDNri : F3_2<2, 0b000101,
+ (outs IntRegs:$rd), (ins IntRegs:$rs1, simm13Op:$simm13),
+ "andn $rs1, $simm13, $rd", []>;
+
+defm OR : F3_12<"or", 0b000010, or, IntRegs, i32, simm13Op>;
+
+def ORNrr : F3_1<2, 0b000110,
+ (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2),
+ "orn $rs1, $rs2, $rd",
+ [(set i32:$rd, (or i32:$rs1, (not i32:$rs2)))]>;
+def ORNri : F3_2<2, 0b000110,
+ (outs IntRegs:$rd), (ins IntRegs:$rs1, simm13Op:$simm13),
+ "orn $rs1, $simm13, $rd", []>;
+defm XOR : F3_12<"xor", 0b000011, xor, IntRegs, i32, simm13Op>;
+
+def XNORrr : F3_1<2, 0b000111,
+ (outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2),
+ "xnor $rs1, $rs2, $rd",
+ [(set i32:$rd, (not (xor i32:$rs1, i32:$rs2)))]>;
+def XNORri : F3_2<2, 0b000111,
+ (outs IntRegs:$rd), (ins IntRegs:$rs1, simm13Op:$simm13),
+ "xnor $rs1, $simm13, $rd", []>;
+
+let Defs = [ICC] in {
+ defm ANDCC : F3_12np<"andcc", 0b010001>;
+ defm ANDNCC : F3_12np<"andncc", 0b010101>;
+ defm ORCC : F3_12np<"orcc", 0b010010>;
+ defm ORNCC : F3_12np<"orncc", 0b010110>;
+ defm XORCC : F3_12np<"xorcc", 0b010011>;
+ defm XNORCC : F3_12np<"xnorcc", 0b010111>;
+}
+
+// Section B.12 - Shift Instructions, p. 107
+defm SLL : F3_12<"sll", 0b100101, shl, IntRegs, i32, simm13Op>;
+defm SRL : F3_12<"srl", 0b100110, srl, IntRegs, i32, simm13Op>;
+defm SRA : F3_12<"sra", 0b100111, sra, IntRegs, i32, simm13Op>;
+
+// Section B.13 - Add Instructions, p. 108
+defm ADD : F3_12<"add", 0b000000, add, IntRegs, i32, simm13Op>;
+
+// "LEA" forms of add (patterns to make tblgen happy)
+let Predicates = [Is32Bit], isCodeGenOnly = 1 in
+ def LEA_ADDri : F3_2<2, 0b000000,
+ (outs IntRegs:$dst), (ins MEMri:$addr),
+ "add ${addr:arith}, $dst",
+ [(set iPTR:$dst, ADDRri:$addr)]>;
+
+let Defs = [ICC] in
+ defm ADDCC : F3_12<"addcc", 0b010000, addc, IntRegs, i32, simm13Op>;
+
+let Uses = [ICC] in
+ defm ADDC : F3_12np<"addx", 0b001000>;
+
+let Uses = [ICC], Defs = [ICC] in
+ defm ADDE : F3_12<"addxcc", 0b011000, adde, IntRegs, i32, simm13Op>;
+
+// Section B.15 - Subtract Instructions, p. 110
+defm SUB : F3_12 <"sub" , 0b000100, sub, IntRegs, i32, simm13Op>;
+let Uses = [ICC], Defs = [ICC] in
+ defm SUBE : F3_12 <"subxcc" , 0b011100, sube, IntRegs, i32, simm13Op>;
+
+let Defs = [ICC] in
+ defm SUBCC : F3_12 <"subcc", 0b010100, subc, IntRegs, i32, simm13Op>;
+
+let Uses = [ICC] in
+ defm SUBC : F3_12np <"subx", 0b001100>;
+
+let Defs = [ICC], rd = 0 in {
+ def CMPrr : F3_1<2, 0b010100,
+ (outs), (ins IntRegs:$rs1, IntRegs:$rs2),
+ "cmp $rs1, $rs2",
+ [(SPcmpicc i32:$rs1, i32:$rs2)]>;
+ def CMPri : F3_2<2, 0b010100,
+ (outs), (ins IntRegs:$rs1, simm13Op:$simm13),
+ "cmp $rs1, $simm13",
+ [(SPcmpicc i32:$rs1, (i32 simm13:$simm13))]>;
+}
+
+// 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>;
+}
+
+let Defs = [Y, ICC] in {
+ defm UMULCC : F3_12np<"umulcc", 0b011010>;
+ defm SMULCC : F3_12np<"smulcc", 0b011011>;
+}
+
+// Section B.19 - Divide Instructions, p. 115
+let Defs = [Y] in {
+ defm UDIV : F3_12np<"udiv", 0b001110>;
+ defm SDIV : F3_12np<"sdiv", 0b001111>;
+}
+
+let Defs = [Y, ICC] in {
+ defm UDIVCC : F3_12np<"udivcc", 0b011110>;
+ defm SDIVCC : F3_12np<"sdivcc", 0b011111>;
+}
+
+// Section B.20 - SAVE and RESTORE, p. 117
+defm SAVE : F3_12np<"save" , 0b111100>;
+defm RESTORE : F3_12np<"restore", 0b111101>;
+
+// Section B.21 - Branch on Integer Condition Codes Instructions, p. 119
+
+// unconditional branch class.
+class BranchAlways<dag ins, string asmstr, list<dag> pattern>
+ : F2_2<0b010, 0, (outs), ins, asmstr, pattern> {
+ let isBranch = 1;
+ let isTerminator = 1;
+ let hasDelaySlot = 1;
+ let isBarrier = 1;
+}
+
+let cond = 8 in
+ def BA : BranchAlways<(ins brtarget:$imm22), "ba $imm22", [(br bb:$imm22)]>;
+
+
+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>;
+
+// conditional branch with annul class:
+class BranchSPA<dag ins, string asmstr, list<dag> pattern>
+ : F2_2<0b010, 1, (outs), ins, asmstr, pattern>;
+
+// 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>;
+ def CCA : F2_3<0b001, 1, 1, (outs), (ins bprtarget:$imm19, CCOp:$cond),
+ !strconcat("b$cond,a ", !strconcat(regstr, ", $imm19")),
+ []>;
+ def CCNT : F2_3<0b001, 0, 0, (outs), (ins bprtarget:$imm19, CCOp:$cond),
+ !strconcat("b$cond,pn ", !strconcat(regstr, ", $imm19")),
+ []>;
+ def CCANT : F2_3<0b001, 1, 0, (outs), (ins bprtarget:$imm19, CCOp:$cond),
+ !strconcat("b$cond,a,pn ", !strconcat(regstr, ", $imm19")),
+ []>;
+}
+
+} // let isBranch = 1, isTerminator = 1, hasDelaySlot = 1
+
+
+// Indirect branch instructions.
+let isTerminator = 1, isBarrier = 1, hasDelaySlot = 1, isBranch =1,
+ isIndirectBranch = 1, rd = 0, isCodeGenOnly = 1 in {
+ def BINDrr : F3_1<2, 0b111000,
+ (outs), (ins MEMrr:$ptr),
+ "jmp $ptr",
+ [(brind ADDRrr:$ptr)]>;
+ def BINDri : F3_2<2, 0b111000,
+ (outs), (ins MEMri:$ptr),
+ "jmp $ptr",
+ [(brind ADDRri:$ptr)]>;
+}
+
+let Uses = [ICC] in {
+ def BCOND : BranchSP<(ins brtarget:$imm22, CCOp:$cond),
+ "b$cond $imm22",
+ [(SPbricc bb:$imm22, imm:$cond)]>;
+ def BCONDA : BranchSPA<(ins brtarget:$imm22, CCOp:$cond),
+ "b$cond,a $imm22", []>;
+
+ let Predicates = [HasV9], cc = 0b00 in
+ defm BPI : IPredBranch<"%icc", []>;
+}
+
+// Section B.22 - Branch on Floating-point Condition Codes Instructions, p. 121
+
+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>;
+
+// floating-point conditional branch with annul class:
+class FPBranchSPA<dag ins, string asmstr, list<dag> pattern>
+ : F2_2<0b110, 1, (outs), ins, asmstr, pattern>;
+
+// 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", []>;
+ def CCA : F2_3<0b101, 1, 1, (outs), (ins bprtarget:$imm19, CCOp:$cond,
+ FCCRegs:$cc),
+ "fb$cond,a $cc, $imm19", []>;
+ def CCNT : F2_3<0b101, 0, 0, (outs), (ins bprtarget:$imm19, CCOp:$cond,
+ FCCRegs:$cc),
+ "fb$cond,pn $cc, $imm19", []>;
+ def CCANT : F2_3<0b101, 1, 0, (outs), (ins bprtarget:$imm19, CCOp:$cond,
+ FCCRegs:$cc),
+ "fb$cond,a,pn $cc, $imm19", []>;
+}
+} // let isBranch = 1, isTerminator = 1, hasDelaySlot = 1
+
+let Uses = [FCC0] in {
+ def FBCOND : FPBranchSP<(ins brtarget:$imm22, CCOp:$cond),
+ "fb$cond $imm22",
+ [(SPbrfcc bb:$imm22, imm:$cond)]>;
+ def FBCONDA : FPBranchSPA<(ins brtarget:$imm22, CCOp:$cond),
+ "fb$cond,a $imm22", []>;
+}
+
+let Predicates = [HasV9] in
+ defm BPF : FPredBranch;
+
+
+// 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", []> {
+ bits<30> disp;
+ let op = 1;
+ let Inst{29-0} = disp;
+ }
+
+ // indirect calls: special cases of JMPL.
+ let isCodeGenOnly = 1, rd = 15 in {
+ def CALLrr : F3_1<2, 0b111000,
+ (outs), (ins MEMrr:$ptr, variable_ops),
+ "call $ptr",
+ [(call ADDRrr:$ptr)]>;
+ def CALLri : F3_2<2, 0b111000,
+ (outs), (ins MEMri:$ptr, variable_ops),
+ "call $ptr",
+ [(call ADDRri:$ptr)]>;
+ }
+}
+
+// Section B.28 - Read State Register Instructions
+let rs2 = 0 in
+ def RDASR : F3_1<2, 0b101000,
+ (outs IntRegs:$rd), (ins ASRRegs:$rs1),
+ "rd $rs1, $rd", []>;
+
+// PSR, WIM, and TBR don't exist on the SparcV9, only the V8.
+let Predicates = [HasNoV9] in {
+ let rs2 = 0, rs1 = 0, Uses=[PSR] in
+ def RDPSR : F3_1<2, 0b101001,
+ (outs IntRegs:$rd), (ins),
+ "rd %psr, $rd", []>;
+
+ let rs2 = 0, rs1 = 0, Uses=[WIM] in
+ def RDWIM : F3_1<2, 0b101010,
+ (outs IntRegs:$rd), (ins),
+ "rd %wim, $rd", []>;
+
+ let rs2 = 0, rs1 = 0, Uses=[TBR] in
+ def RDTBR : F3_1<2, 0b101011,
+ (outs IntRegs:$rd), (ins),
+ "rd %tbr, $rd", []>;
+}
+
+// Section B.29 - Write State Register Instructions
+def WRASRrr : F3_1<2, 0b110000,
+ (outs ASRRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2),
+ "wr $rs1, $rs2, $rd", []>;
+def WRASRri : F3_2<2, 0b110000,
+ (outs ASRRegs:$rd), (ins IntRegs:$rs1, simm13Op:$simm13),
+ "wr $rs1, $simm13, $rd", []>;
+
+// PSR, WIM, and TBR don't exist on the SparcV9, only the V8.
+let Predicates = [HasNoV9] in {
+ let Defs = [PSR], rd=0 in {
+ def WRPSRrr : F3_1<2, 0b110001,
+ (outs), (ins IntRegs:$rs1, IntRegs:$rs2),
+ "wr $rs1, $rs2, %psr", []>;
+ def WRPSRri : F3_2<2, 0b110001,
+ (outs), (ins IntRegs:$rs1, simm13Op:$simm13),
+ "wr $rs1, $simm13, %psr", []>;
+ }
+
+ let Defs = [WIM], rd=0 in {
+ def WRWIMrr : F3_1<2, 0b110010,
+ (outs), (ins IntRegs:$rs1, IntRegs:$rs2),
+ "wr $rs1, $rs2, %wim", []>;
+ def WRWIMri : F3_2<2, 0b110010,
+ (outs), (ins IntRegs:$rs1, simm13Op:$simm13),
+ "wr $rs1, $simm13, %wim", []>;
+ }
+
+ let Defs = [TBR], rd=0 in {
+ def WRTBRrr : F3_1<2, 0b110011,
+ (outs), (ins IntRegs:$rs1, IntRegs:$rs2),
+ "wr $rs1, $rs2, %tbr", []>;
+ def WRTBRri : F3_2<2, 0b110011,
+ (outs), (ins IntRegs:$rs1, simm13Op:$simm13),
+ "wr $rs1, $simm13, %tbr", []>;
+ }
+}
+
+// Convert Integer to Floating-point Instructions, p. 141
+def FITOS : F3_3u<2, 0b110100, 0b011000100,
+ (outs FPRegs:$rd), (ins FPRegs:$rs2),
+ "fitos $rs2, $rd",
+ [(set FPRegs:$rd, (SPitof FPRegs:$rs2))]>;
+def FITOD : F3_3u<2, 0b110100, 0b011001000,
+ (outs DFPRegs:$rd), (ins FPRegs:$rs2),
+ "fitod $rs2, $rd",
+ [(set DFPRegs:$rd, (SPitof FPRegs:$rs2))]>;
+def FITOQ : F3_3u<2, 0b110100, 0b011001100,
+ (outs QFPRegs:$rd), (ins FPRegs:$rs2),
+ "fitoq $rs2, $rd",
+ [(set QFPRegs:$rd, (SPitof FPRegs:$rs2))]>,
+ Requires<[HasHardQuad]>;
+
+// Convert Floating-point to Integer Instructions, p. 142
+def FSTOI : F3_3u<2, 0b110100, 0b011010001,
+ (outs FPRegs:$rd), (ins FPRegs:$rs2),
+ "fstoi $rs2, $rd",
+ [(set FPRegs:$rd, (SPftoi FPRegs:$rs2))]>;
+def FDTOI : F3_3u<2, 0b110100, 0b011010010,
+ (outs FPRegs:$rd), (ins DFPRegs:$rs2),
+ "fdtoi $rs2, $rd",
+ [(set FPRegs:$rd, (SPftoi DFPRegs:$rs2))]>;
+def FQTOI : F3_3u<2, 0b110100, 0b011010011,
+ (outs FPRegs:$rd), (ins QFPRegs:$rs2),
+ "fqtoi $rs2, $rd",
+ [(set FPRegs:$rd, (SPftoi QFPRegs:$rs2))]>,
+ Requires<[HasHardQuad]>;
+
+// Convert between Floating-point Formats Instructions, p. 143
+def FSTOD : F3_3u<2, 0b110100, 0b011001001,
+ (outs DFPRegs:$rd), (ins FPRegs:$rs2),
+ "fstod $rs2, $rd",
+ [(set f64:$rd, (fextend f32:$rs2))]>;
+def FSTOQ : F3_3u<2, 0b110100, 0b011001101,
+ (outs QFPRegs:$rd), (ins FPRegs:$rs2),
+ "fstoq $rs2, $rd",
+ [(set f128:$rd, (fextend f32:$rs2))]>,
+ Requires<[HasHardQuad]>;
+def FDTOS : F3_3u<2, 0b110100, 0b011000110,
+ (outs FPRegs:$rd), (ins DFPRegs:$rs2),
+ "fdtos $rs2, $rd",
+ [(set f32:$rd, (fround f64:$rs2))]>;
+def FDTOQ : F3_3u<2, 0b110100, 0b011001110,
+ (outs QFPRegs:$rd), (ins DFPRegs:$rs2),
+ "fdtoq $rs2, $rd",
+ [(set f128:$rd, (fextend f64:$rs2))]>,
+ Requires<[HasHardQuad]>;
+def FQTOS : F3_3u<2, 0b110100, 0b011000111,
+ (outs FPRegs:$rd), (ins QFPRegs:$rs2),
+ "fqtos $rs2, $rd",
+ [(set f32:$rd, (fround f128:$rs2))]>,
+ Requires<[HasHardQuad]>;
+def FQTOD : F3_3u<2, 0b110100, 0b011001011,
+ (outs DFPRegs:$rd), (ins QFPRegs:$rs2),
+ "fqtod $rs2, $rd",
+ [(set f64:$rd, (fround f128:$rs2))]>,
+ Requires<[HasHardQuad]>;
+
+// Floating-point Move Instructions, p. 144
+def FMOVS : F3_3u<2, 0b110100, 0b000000001,
+ (outs FPRegs:$rd), (ins FPRegs:$rs2),
+ "fmovs $rs2, $rd", []>;
+def FNEGS : F3_3u<2, 0b110100, 0b000000101,
+ (outs FPRegs:$rd), (ins FPRegs:$rs2),
+ "fnegs $rs2, $rd",
+ [(set f32:$rd, (fneg f32:$rs2))]>;
+def FABSS : F3_3u<2, 0b110100, 0b000001001,
+ (outs FPRegs:$rd), (ins FPRegs:$rs2),
+ "fabss $rs2, $rd",
+ [(set f32:$rd, (fabs f32:$rs2))]>;
+
+
+// Floating-point Square Root Instructions, p.145
+def FSQRTS : F3_3u<2, 0b110100, 0b000101001,
+ (outs FPRegs:$rd), (ins FPRegs:$rs2),
+ "fsqrts $rs2, $rd",
+ [(set f32:$rd, (fsqrt f32:$rs2))]>;
+def FSQRTD : F3_3u<2, 0b110100, 0b000101010,
+ (outs DFPRegs:$rd), (ins DFPRegs:$rs2),
+ "fsqrtd $rs2, $rd",
+ [(set f64:$rd, (fsqrt f64:$rs2))]>;
+def FSQRTQ : F3_3u<2, 0b110100, 0b000101011,
+ (outs QFPRegs:$rd), (ins QFPRegs:$rs2),
+ "fsqrtq $rs2, $rd",
+ [(set f128:$rd, (fsqrt f128:$rs2))]>,
+ Requires<[HasHardQuad]>;
+
+
+
+// Floating-point Add and Subtract Instructions, p. 146
+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))]>;
+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))]>;
+def FADDQ : F3_3<2, 0b110100, 0b001000011,
+ (outs QFPRegs:$rd), (ins QFPRegs:$rs1, QFPRegs:$rs2),
+ "faddq $rs1, $rs2, $rd",
+ [(set f128:$rd, (fadd f128:$rs1, f128:$rs2))]>,
+ Requires<[HasHardQuad]>;
+
+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))]>;
+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))]>;
+def FSUBQ : F3_3<2, 0b110100, 0b001000111,
+ (outs QFPRegs:$rd), (ins QFPRegs:$rs1, QFPRegs:$rs2),
+ "fsubq $rs1, $rs2, $rd",
+ [(set f128:$rd, (fsub f128:$rs1, f128:$rs2))]>,
+ Requires<[HasHardQuad]>;
+
+
+// Floating-point Multiply and Divide Instructions, p. 147
+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))]>;
+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))]>;
+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]>;
+
+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)))]>;
+def FDMULQ : F3_3<2, 0b110100, 0b001101110,
+ (outs QFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
+ "fdmulq $rs1, $rs2, $rd",
+ [(set f128:$rd, (fmul (fextend f64:$rs1),
+ (fextend f64:$rs2)))]>,
+ Requires<[HasHardQuad]>;
+
+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))]>;
+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))]>;
+def FDIVQ : F3_3<2, 0b110100, 0b001001111,
+ (outs QFPRegs:$rd), (ins QFPRegs:$rs1, QFPRegs:$rs2),
+ "fdivq $rs1, $rs2, $rd",
+ [(set f128:$rd, (fdiv f128:$rs1, f128:$rs2))]>,
+ Requires<[HasHardQuad]>;
+
+// Floating-point Compare Instructions, p. 148
+// Note: the 2nd template arg is different for these guys.
+// Note 2: the result of a FCMP is not available until the 2nd cycle
+// after the instr is retired, but there is no interlock in Sparc V8.
+// This behavior is modeled with a forced noop after the instruction in
+// DelaySlotFiller.
+
+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)]>;
+ def FCMPD : F3_3c<2, 0b110101, 0b001010010,
+ (outs), (ins DFPRegs:$rs1, DFPRegs:$rs2),
+ "fcmpd $rs1, $rs2",
+ [(SPcmpfcc f64:$rs1, f64:$rs2)]>;
+ def FCMPQ : F3_3c<2, 0b110101, 0b001010011,
+ (outs), (ins QFPRegs:$rs1, QFPRegs:$rs2),
+ "fcmpq $rs1, $rs2",
+ [(SPcmpfcc f128:$rs1, f128:$rs2)]>,
+ Requires<[HasHardQuad]>;
+}
+
+//===----------------------------------------------------------------------===//
+// Instructions for Thread Local Storage(TLS).
+//===----------------------------------------------------------------------===//
+let isCodeGenOnly = 1, isAsmParserOnly = 1 in {
+def TLS_ADDrr : F3_1<2, 0b000000,
+ (outs IntRegs:$rd),
+ (ins IntRegs:$rs1, IntRegs:$rs2, TLSSym:$sym),
+ "add $rs1, $rs2, $rd, $sym",
+ [(set i32:$rd,
+ (tlsadd i32:$rs1, i32:$rs2, tglobaltlsaddr:$sym))]>;
+
+let mayLoad = 1 in
+ def TLS_LDrr : F3_1<3, 0b000000,
+ (outs IntRegs:$dst), (ins MEMrr:$addr, TLSSym:$sym),
+ "ld [$addr], $dst, $sym",
+ [(set i32:$dst,
+ (tlsld ADDRrr:$addr, tglobaltlsaddr:$sym))]>;
+
+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)]> {
+ bits<30> disp;
+ let op = 1;
+ let Inst{29-0} = disp;
+}
+}
+
+//===----------------------------------------------------------------------===//
+// V9 Instructions
+//===----------------------------------------------------------------------===//
+
+// V9 Conditional Moves.
+let Predicates = [HasV9], Constraints = "$f = $rd" in {
+ // Move Integer Register on Condition (MOVcc) p. 194 of the V9 manual.
+ let Uses = [ICC], intcc = 1, cc = 0b00 in {
+ def MOVICCrr
+ : F4_1<0b101100, (outs IntRegs:$rd),
+ (ins IntRegs:$rs2, IntRegs:$f, CCOp:$cond),
+ "mov$cond %icc, $rs2, $rd",
+ [(set i32:$rd, (SPselecticc i32:$rs2, i32:$f, imm:$cond))]>;
+
+ def MOVICCri
+ : F4_2<0b101100, (outs IntRegs:$rd),
+ (ins i32imm:$simm11, IntRegs:$f, CCOp:$cond),
+ "mov$cond %icc, $simm11, $rd",
+ [(set i32:$rd,
+ (SPselecticc simm11:$simm11, i32:$f, imm:$cond))]>;
+ }
+
+ let Uses = [FCC0], intcc = 0, cc = 0b00 in {
+ def MOVFCCrr
+ : F4_1<0b101100, (outs IntRegs:$rd),
+ (ins IntRegs:$rs2, IntRegs:$f, CCOp:$cond),
+ "mov$cond %fcc0, $rs2, $rd",
+ [(set i32:$rd, (SPselectfcc i32:$rs2, i32:$f, imm:$cond))]>;
+ def MOVFCCri
+ : F4_2<0b101100, (outs IntRegs:$rd),
+ (ins i32imm:$simm11, IntRegs:$f, CCOp:$cond),
+ "mov$cond %fcc0, $simm11, $rd",
+ [(set i32:$rd,
+ (SPselectfcc simm11:$simm11, i32:$f, imm:$cond))]>;
+ }
+
+ let Uses = [ICC], intcc = 1, opf_cc = 0b00 in {
+ def FMOVS_ICC
+ : F4_3<0b110101, 0b000001, (outs FPRegs:$rd),
+ (ins FPRegs:$rs2, FPRegs:$f, CCOp:$cond),
+ "fmovs$cond %icc, $rs2, $rd",
+ [(set f32:$rd, (SPselecticc f32:$rs2, f32:$f, imm:$cond))]>;
+ def FMOVD_ICC
+ : F4_3<0b110101, 0b000010, (outs DFPRegs:$rd),
+ (ins DFPRegs:$rs2, DFPRegs:$f, CCOp:$cond),
+ "fmovd$cond %icc, $rs2, $rd",
+ [(set f64:$rd, (SPselecticc f64:$rs2, f64:$f, imm:$cond))]>;
+ def FMOVQ_ICC
+ : F4_3<0b110101, 0b000011, (outs QFPRegs:$rd),
+ (ins QFPRegs:$rs2, QFPRegs:$f, CCOp:$cond),
+ "fmovq$cond %icc, $rs2, $rd",
+ [(set f128:$rd, (SPselecticc f128:$rs2, f128:$f, imm:$cond))]>,
+ Requires<[HasHardQuad]>;
+ }
+
+ let Uses = [FCC0], intcc = 0, opf_cc = 0b00 in {
+ def FMOVS_FCC
+ : F4_3<0b110101, 0b000001, (outs FPRegs:$rd),
+ (ins FPRegs:$rs2, FPRegs:$f, CCOp:$cond),
+ "fmovs$cond %fcc0, $rs2, $rd",
+ [(set f32:$rd, (SPselectfcc f32:$rs2, f32:$f, imm:$cond))]>;
+ def FMOVD_FCC
+ : F4_3<0b110101, 0b000010, (outs DFPRegs:$rd),
+ (ins DFPRegs:$rs2, DFPRegs:$f, CCOp:$cond),
+ "fmovd$cond %fcc0, $rs2, $rd",
+ [(set f64:$rd, (SPselectfcc f64:$rs2, f64:$f, imm:$cond))]>;
+ def FMOVQ_FCC
+ : F4_3<0b110101, 0b000011, (outs QFPRegs:$rd),
+ (ins QFPRegs:$rs2, QFPRegs:$f, CCOp:$cond),
+ "fmovq$cond %fcc0, $rs2, $rd",
+ [(set f128:$rd, (SPselectfcc f128:$rs2, f128:$f, imm:$cond))]>,
+ Requires<[HasHardQuad]>;
+ }
+
+}
+
+// Floating-Point Move Instructions, p. 164 of the V9 manual.
+let Predicates = [HasV9] in {
+ def FMOVD : F3_3u<2, 0b110100, 0b000000010,
+ (outs DFPRegs:$rd), (ins DFPRegs:$rs2),
+ "fmovd $rs2, $rd", []>;
+ def FMOVQ : F3_3u<2, 0b110100, 0b000000011,
+ (outs QFPRegs:$rd), (ins QFPRegs:$rs2),
+ "fmovq $rs2, $rd", []>,
+ Requires<[HasHardQuad]>;
+ def FNEGD : F3_3u<2, 0b110100, 0b000000110,
+ (outs DFPRegs:$rd), (ins DFPRegs:$rs2),
+ "fnegd $rs2, $rd",
+ [(set f64:$rd, (fneg f64:$rs2))]>;
+ def FNEGQ : F3_3u<2, 0b110100, 0b000000111,
+ (outs QFPRegs:$rd), (ins QFPRegs:$rs2),
+ "fnegq $rs2, $rd",
+ [(set f128:$rd, (fneg f128:$rs2))]>,
+ Requires<[HasHardQuad]>;
+ def FABSD : F3_3u<2, 0b110100, 0b000001010,
+ (outs DFPRegs:$rd), (ins DFPRegs:$rs2),
+ "fabsd $rs2, $rd",
+ [(set f64:$rd, (fabs f64:$rs2))]>;
+ def FABSQ : F3_3u<2, 0b110100, 0b000001011,
+ (outs QFPRegs:$rd), (ins QFPRegs:$rs2),
+ "fabsq $rs2, $rd",
+ [(set f128:$rd, (fabs f128:$rs2))]>,
+ Requires<[HasHardQuad]>;
+}
+
+// Floating-point compare instruction with %fcc0-%fcc3.
+def V9FCMPS : F3_3c<2, 0b110101, 0b001010001,
+ (outs FCCRegs:$rd), (ins FPRegs:$rs1, FPRegs:$rs2),
+ "fcmps $rd, $rs1, $rs2", []>;
+def V9FCMPD : F3_3c<2, 0b110101, 0b001010010,
+ (outs FCCRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
+ "fcmpd $rd, $rs1, $rs2", []>;
+def V9FCMPQ : F3_3c<2, 0b110101, 0b001010011,
+ (outs FCCRegs:$rd), (ins QFPRegs:$rs1, QFPRegs:$rs2),
+ "fcmpq $rd, $rs1, $rs2", []>,
+ Requires<[HasHardQuad]>;
+
+let hasSideEffects = 1 in {
+ def V9FCMPES : F3_3c<2, 0b110101, 0b001010101,
+ (outs FCCRegs:$rd), (ins FPRegs:$rs1, FPRegs:$rs2),
+ "fcmpes $rd, $rs1, $rs2", []>;
+ def V9FCMPED : F3_3c<2, 0b110101, 0b001010110,
+ (outs FCCRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
+ "fcmped $rd, $rs1, $rs2", []>;
+ def V9FCMPEQ : F3_3c<2, 0b110101, 0b001010111,
+ (outs FCCRegs:$rd), (ins QFPRegs:$rs1, QFPRegs:$rs2),
+ "fcmpeq $rd, $rs1, $rs2", []>,
+ Requires<[HasHardQuad]>;
+}
+
+// Floating point conditional move instrucitons with %fcc0-%fcc3.
+let Predicates = [HasV9] in {
+ let Constraints = "$f = $rd", intcc = 0 in {
+ def V9MOVFCCrr
+ : F4_1<0b101100, (outs IntRegs:$rd),
+ (ins FCCRegs:$cc, IntRegs:$rs2, IntRegs:$f, CCOp:$cond),
+ "mov$cond $cc, $rs2, $rd", []>;
+ def V9MOVFCCri
+ : F4_2<0b101100, (outs IntRegs:$rd),
+ (ins FCCRegs:$cc, i32imm:$simm11, IntRegs:$f, CCOp:$cond),
+ "mov$cond $cc, $simm11, $rd", []>;
+ def V9FMOVS_FCC
+ : F4_3<0b110101, 0b000001, (outs FPRegs:$rd),
+ (ins FCCRegs:$opf_cc, FPRegs:$rs2, FPRegs:$f, CCOp:$cond),
+ "fmovs$cond $opf_cc, $rs2, $rd", []>;
+ def V9FMOVD_FCC
+ : F4_3<0b110101, 0b000010, (outs DFPRegs:$rd),
+ (ins FCCRegs:$opf_cc, DFPRegs:$rs2, DFPRegs:$f, CCOp:$cond),
+ "fmovd$cond $opf_cc, $rs2, $rd", []>;
+ def V9FMOVQ_FCC
+ : F4_3<0b110101, 0b000011, (outs QFPRegs:$rd),
+ (ins FCCRegs:$opf_cc, QFPRegs:$rs2, QFPRegs:$f, CCOp:$cond),
+ "fmovq$cond $opf_cc, $rs2, $rd", []>,
+ Requires<[HasHardQuad]>;
+ } // Constraints = "$f = $rd", ...
+} // let Predicates = [hasV9]
+
+
+// POPCrr - This does a ctpop of a 64-bit register. As such, we have to clear
+// the top 32-bits before using it. To do this clearing, we use a SRLri X,0.
+let rs1 = 0 in
+ def POPCrr : F3_1<2, 0b101110,
+ (outs IntRegs:$dst), (ins IntRegs:$src),
+ "popc $src, $dst", []>, Requires<[HasV9]>;
+def : Pat<(ctpop i32:$src),
+ (POPCrr (SRLri $src, 0))>;
+
+// Atomic swap.
+let hasSideEffects =1, rd = 0, rs1 = 0b01111, rs2 = 0 in
+ def STBAR : F3_1<2, 0b101000, (outs), (ins), "stbar", []>;
+
+let Predicates = [HasV9], hasSideEffects = 1, rd = 0, rs1 = 0b01111 in
+ def MEMBARi : F3_2<2, 0b101000, (outs), (ins simm13Op:$simm13),
+ "membar $simm13", []>;
+
+let Constraints = "$val = $dst", DecoderMethod = "DecodeSWAP" in {
+ def SWAPrr : F3_1<3, 0b001111,
+ (outs IntRegs:$dst), (ins MEMrr:$addr, IntRegs:$val),
+ "swap [$addr], $dst",
+ [(set i32:$dst, (atomic_swap_32 ADDRrr:$addr, i32:$val))]>;
+ def SWAPri : F3_2<3, 0b001111,
+ (outs IntRegs:$dst), (ins MEMri:$addr, IntRegs:$val),
+ "swap [$addr], $dst",
+ [(set i32:$dst, (atomic_swap_32 ADDRri:$addr, i32:$val))]>;
+ def SWAPArr : F3_1_asi<3, 0b011111,
+ (outs IntRegs:$dst), (ins MEMrr:$addr, i8imm:$asi, IntRegs:$val),
+ "swapa [$addr] $asi, $dst",
+ [/*FIXME: pattern?*/]>;
+}
+
+// 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.)
+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))]>;
+
+let Defs = [ICC] in {
+defm TADDCC : F3_12np<"taddcc", 0b100000>;
+defm TSUBCC : F3_12np<"tsubcc", 0b100001>;
+
+let hasSideEffects = 1 in {
+ defm TADDCCTV : F3_12np<"taddcctv", 0b100010>;
+ defm TSUBCCTV : F3_12np<"tsubcctv", 0b100011>;
+}
+}
+
+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"), []>;
+}
+
+let hasSideEffects = 1, Uses = [ICC], cc = 0b00 in
+ defm TICC : TRAP<"%icc">;
+
+//===----------------------------------------------------------------------===//
+// Non-Instruction Patterns
+//===----------------------------------------------------------------------===//
+
+// Small immediates.
+def : Pat<(i32 simm13:$val),
+ (ORri (i32 G0), imm:$val)>;
+// Arbitrary immediates.
+def : Pat<(i32 imm:$val),
+ (ORri (SETHIi (HI22 imm:$val)), (LO10 imm:$val))>;
+
+
+// Global addresses, constant pool entries
+let Predicates = [Is32Bit] in {
+
+def : Pat<(SPhi tglobaladdr:$in), (SETHIi tglobaladdr:$in)>;
+def : Pat<(SPlo tglobaladdr:$in), (ORri (i32 G0), tglobaladdr:$in)>;
+def : Pat<(SPhi tconstpool:$in), (SETHIi tconstpool:$in)>;
+def : Pat<(SPlo tconstpool:$in), (ORri (i32 G0), tconstpool:$in)>;
+
+// GlobalTLS addresses
+def : Pat<(SPhi tglobaltlsaddr:$in), (SETHIi tglobaltlsaddr:$in)>;
+def : Pat<(SPlo tglobaltlsaddr:$in), (ORri (i32 G0), tglobaltlsaddr:$in)>;
+def : Pat<(add (SPhi tglobaltlsaddr:$in1), (SPlo tglobaltlsaddr:$in2)),
+ (ADDri (SETHIi tglobaltlsaddr:$in1), (tglobaltlsaddr:$in2))>;
+def : Pat<(xor (SPhi tglobaltlsaddr:$in1), (SPlo tglobaltlsaddr:$in2)),
+ (XORri (SETHIi tglobaltlsaddr:$in1), (tglobaltlsaddr:$in2))>;
+
+// Blockaddress
+def : Pat<(SPhi tblockaddress:$in), (SETHIi tblockaddress:$in)>;
+def : Pat<(SPlo tblockaddress:$in), (ORri (i32 G0), tblockaddress:$in)>;
+
+// Add reg, lo. This is used when taking the addr of a global/constpool entry.
+def : Pat<(add iPTR:$r, (SPlo tglobaladdr:$in)), (ADDri $r, tglobaladdr:$in)>;
+def : Pat<(add iPTR:$r, (SPlo tconstpool:$in)), (ADDri $r, tconstpool:$in)>;
+def : Pat<(add iPTR:$r, (SPlo tblockaddress:$in)),
+ (ADDri $r, tblockaddress:$in)>;
+}
+
+// Calls:
+def : Pat<(call tglobaladdr:$dst),
+ (CALL tglobaladdr:$dst)>;
+def : Pat<(call texternalsym:$dst),
+ (CALL texternalsym:$dst)>;
+
+// Map integer extload's to zextloads.
+def : Pat<(i32 (extloadi1 ADDRrr:$src)), (LDUBrr ADDRrr:$src)>;
+def : Pat<(i32 (extloadi1 ADDRri:$src)), (LDUBri ADDRri:$src)>;
+def : Pat<(i32 (extloadi8 ADDRrr:$src)), (LDUBrr ADDRrr:$src)>;
+def : Pat<(i32 (extloadi8 ADDRri:$src)), (LDUBri ADDRri:$src)>;
+def : Pat<(i32 (extloadi16 ADDRrr:$src)), (LDUHrr ADDRrr:$src)>;
+def : Pat<(i32 (extloadi16 ADDRri:$src)), (LDUHri ADDRri:$src)>;
+
+// zextload bool -> zextload byte
+def : Pat<(i32 (zextloadi1 ADDRrr:$src)), (LDUBrr ADDRrr:$src)>;
+def : Pat<(i32 (zextloadi1 ADDRri:$src)), (LDUBri ADDRri:$src)>;
+
+// store 0, addr -> store %g0, addr
+def : Pat<(store (i32 0), ADDRrr:$dst), (STrr ADDRrr:$dst, (i32 G0))>;
+def : Pat<(store (i32 0), ADDRri:$dst), (STri ADDRri:$dst, (i32 G0))>;
+
+// store bar for all atomic_fence in V8.
+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)>;
+
+
+include "SparcInstr64Bit.td"
+include "SparcInstrVIS.td"
+include "SparcInstrAliases.td"
diff --git a/contrib/llvm/lib/Target/Sparc/SparcInstrVIS.td b/contrib/llvm/lib/Target/Sparc/SparcInstrVIS.td
new file mode 100644
index 0000000..d9adf3e
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/SparcInstrVIS.td
@@ -0,0 +1,263 @@
+//===---- SparcInstrVIS.td - Visual Instruction Set extensions (VIS) -----===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains instruction formats, definitions and patterns needed for
+// VIS, VIS II, VIS II instructions on SPARC.
+//===----------------------------------------------------------------------===//
+
+// VIS Instruction Format.
+class VISInstFormat<bits<9> opfval, dag outs, dag ins, string asmstr,
+ list<dag> pattern>
+ : F3_3<0b10, 0b110110, opfval, outs, ins, asmstr, pattern>;
+
+class VISInst<bits<9> opfval, string OpcStr, RegisterClass RC = DFPRegs>
+ : VISInstFormat<opfval,
+ (outs RC:$rd), (ins RC:$rs1, RC:$rs2),
+ !strconcat(OpcStr, " $rs1, $rs2, $rd"), []>;
+
+// VIS Instruction with integer destination register.
+class VISInstID<bits<9> opfval, string OpcStr>
+ : VISInstFormat<opfval,
+ (outs I64Regs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
+ !strconcat(OpcStr, " $rs1, $rs2, $rd"), []>;
+
+// For VIS Instructions with no operand.
+let rd = 0, rs1 = 0, rs2 = 0 in
+class VISInst0<bits<9> opfval, string asmstr>
+ : VISInstFormat<opfval, (outs), (ins), asmstr, []>;
+
+// For VIS Instructions with only rs1, rd operands.
+let rs2 = 0 in
+class VISInst1<bits<9> opfval, string OpcStr, RegisterClass RC = DFPRegs>
+ : VISInstFormat<opfval,
+ (outs RC:$rd), (ins RC:$rs1),
+ !strconcat(OpcStr, " $rs1, $rd"), []>;
+
+// For VIS Instructions with only rs2, rd operands.
+let rs1 = 0 in
+class VISInst2<bits<9> opfval, string OpcStr, RegisterClass RC = DFPRegs>
+ : VISInstFormat<opfval,
+ (outs RC:$rd), (ins RC:$rs2),
+ !strconcat(OpcStr, " $rs2, $rd"), []>;
+
+// For VIS Instructions with only rd operand.
+let Constraints = "$rd = $f", rs1 = 0, rs2 = 0 in
+class VISInstD<bits<9> opfval, string OpcStr, RegisterClass RC = DFPRegs>
+ : VISInstFormat<opfval,
+ (outs RC:$rd), (ins RC:$f),
+ !strconcat(OpcStr, " $rd"), []>;
+
+// VIS 1 Instructions
+let Predicates = [HasVIS] in {
+
+def FPADD16 : VISInst<0b001010000, "fpadd16">;
+def FPADD16S : VISInst<0b001010001, "fpadd16s">;
+def FPADD32 : VISInst<0b001010010, "fpadd32">;
+def FPADD32S : VISInst<0b001010011, "fpadd32s">;
+def FPSUB16 : VISInst<0b001010100, "fpsub16">;
+def FPSUB16S : VISInst<0b001010101, "fpsub16S">;
+def FPSUB32 : VISInst<0b001010110, "fpsub32">;
+def FPSUB32S : VISInst<0b001010111, "fpsub32S">;
+
+def FPACK16 : VISInst2<0b000111011, "fpack16">;
+def FPACK32 : VISInst <0b000111010, "fpack32">;
+def FPACKFIX : VISInst2<0b000111101, "fpackfix">;
+def FEXPAND : VISInst2<0b001001101, "fexpand">;
+def FPMERGE : VISInst <0b001001011, "fpmerge">;
+
+def FMUL8X16 : VISInst<0b000110001, "fmul8x16">;
+def FMUL8X16AU : VISInst<0b000110011, "fmul8x16au">;
+def FMUL8X16AL : VISInst<0b000110101, "fmul8x16al">;
+def FMUL8SUX16 : VISInst<0b000110110, "fmul8sux16">;
+def FMUL8ULX16 : VISInst<0b000110111, "fmul8ulx16">;
+def FMULD8SUX16 : VISInst<0b000111000, "fmuld8sux16">;
+def FMULD8ULX16 : VISInst<0b000111001, "fmuld8ulx16">;
+
+def ALIGNADDR : VISInst<0b000011000, "alignaddr", I64Regs>;
+def ALIGNADDRL : VISInst<0b000011010, "alignaddrl", I64Regs>;
+def FALIGNADATA : VISInst<0b001001000, "faligndata">;
+
+def FZERO : VISInstD<0b001100000, "fzero">;
+def FZEROS : VISInstD<0b001100001, "fzeros", FPRegs>;
+def FONE : VISInstD<0b001111110, "fone">;
+def FONES : VISInstD<0b001111111, "fones", FPRegs>;
+def FSRC1 : VISInst1<0b001110100, "fsrc1">;
+def FSRC1S : VISInst1<0b001110101, "fsrc1s", FPRegs>;
+def FSRC2 : VISInst2<0b001111000, "fsrc2">;
+def FSRC2S : VISInst2<0b001111001, "fsrc2s", FPRegs>;
+def FNOT1 : VISInst1<0b001101010, "fnot1">;
+def FNOT1S : VISInst1<0b001101011, "fnot1s", FPRegs>;
+def FNOT2 : VISInst2<0b001100110, "fnot2">;
+def FNOT2S : VISInst2<0b001100111, "fnot2s", FPRegs>;
+def FOR : VISInst<0b001111100, "for">;
+def FORS : VISInst<0b001111101, "fors", FPRegs>;
+def FNOR : VISInst<0b001100010, "fnor">;
+def FNORS : VISInst<0b001100011, "fnors", FPRegs>;
+def FAND : VISInst<0b001110000, "fand">;
+def FANDS : VISInst<0b001110001, "fands", FPRegs>;
+def FNAND : VISInst<0b001101110, "fnand">;
+def FNANDS : VISInst<0b001101111, "fnands", FPRegs>;
+def FXOR : VISInst<0b001101100, "fxor">;
+def FXORS : VISInst<0b001101101, "fxors", FPRegs>;
+def FXNOR : VISInst<0b001110010, "fxnor">;
+def FXNORS : VISInst<0b001110011, "fxnors", FPRegs>;
+
+def FORNOT1 : VISInst<0b001111010, "fornot1">;
+def FORNOT1S : VISInst<0b001111011, "fornot1s", FPRegs>;
+def FORNOT2 : VISInst<0b001110110, "fornot2">;
+def FORNOT2S : VISInst<0b001110111, "fornot2s", FPRegs>;
+def FANDNOT1 : VISInst<0b001101000, "fandnot1">;
+def FANDNOT1S : VISInst<0b001101001, "fandnot1s", FPRegs>;
+def FANDNOT2 : VISInst<0b001100100, "fandnot2">;
+def FANDNOT2S : VISInst<0b001100101, "fandnot2s", FPRegs>;
+
+def FCMPGT16 : VISInstID<0b000101000, "fcmpgt16">;
+def FCMPGT32 : VISInstID<0b000101100, "fcmpgt32">;
+def FCMPLE16 : VISInstID<0b000100000, "fcmple16">;
+def FCMPLE32 : VISInstID<0b000100100, "fcmple32">;
+def FCMPNE16 : VISInstID<0b000100010, "fcmpne16">;
+def FCMPNE32 : VISInstID<0b000100110, "fcmpne32">;
+def FCMPEQ16 : VISInstID<0b000101010, "fcmpeq16">;
+def FCMPEQ32 : VISInstID<0b000101110, "fcmpeq32">;
+
+
+def EDGE8 : VISInst<0b000000000, "edge8", I64Regs>;
+def EDGE8L : VISInst<0b000000010, "edge8l", I64Regs>;
+def EDGE16 : VISInst<0b000000100, "edge16", I64Regs>;
+def EDGE16L : VISInst<0b000000110, "edge16l", I64Regs>;
+def EDGE32 : VISInst<0b000001000, "edge32", I64Regs>;
+def EDGE32L : VISInst<0b000001010, "edge32l", I64Regs>;
+
+def PDIST : VISInst<0b000111110, "pdist">;
+
+def ARRAY8 : VISInst<0b000010000, "array8", I64Regs>;
+def ARRAY16 : VISInst<0b000010010, "array16", I64Regs>;
+def ARRAY32 : VISInst<0b000010100, "array32", I64Regs>;
+
+def SHUTDOWN : VISInst0<0b010000000, "shutdown">;
+
+} // Predicates = [HasVIS]
+
+
+// VIS 2 Instructions.
+let Predicates = [HasVIS2] in {
+
+def BMASK : VISInst<0b000011001, "bmask", I64Regs>;
+def BSHUFFLE : VISInst<0b000011100, "bshuffle">;
+
+def SIAM : VISInst0<0b010000001, "siam">;
+
+def EDGE8N : VISInst<0b000000001, "edge8n", I64Regs>;
+def EDGE8LN : VISInst<0b000000011, "edge8ln", I64Regs>;
+def EDGE16N : VISInst<0b000000101, "edge16n", I64Regs>;
+def EDGE16LN : VISInst<0b000000111, "edge16ln", I64Regs>;
+def EDGE32N : VISInst<0b000001001, "edge32n", I64Regs>;
+def EDGE32LN : VISInst<0b000001011, "edge32ln", I64Regs>;
+} // Predicates = [HasVIS2]
+
+
+// VIS 3 Instructions.
+let Predicates = [HasVIS3] in {
+
+let Uses = [ICC] in
+def ADDXC : VISInst<0b000010001, "addxc", I64Regs>;
+
+let Defs = [ICC], Uses = [ICC] in
+def ADDXCCC : VISInst<0b000010011, "addxccc", I64Regs>;
+
+let rd = 0, rs1 = 0 in {
+def CMASK8 : VISInstFormat<0b000011011, (outs), (ins I64Regs:$rs2),
+ "cmask8 $rs2", []>;
+def CMASK16 : VISInstFormat<0b000011101, (outs), (ins I64Regs:$rs2),
+ "cmask16 $rs2", []>;
+def CMASK32 : VISInstFormat<0b000011111, (outs), (ins I64Regs:$rs2),
+ "cmask32 $rs2", []>;
+
+}
+
+def FCHKSM16 : VISInst<0b001000100, "fchksm16">;
+
+def FHADDS : F3_3<0b10, 0b110100, 0b001100001,
+ (outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
+ "fhadds $rs1, $rs2, $rd", []>;
+def FHADDD : F3_3<0b10, 0b110100, 0b001100010,
+ (outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
+ "fhaddd $rs1, $rs2, $rd", []>;
+def FHSUBS : F3_3<0b10, 0b110100, 0b001100101,
+ (outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
+ "fhsubs $rs1, $rs2, $rd", []>;
+def FHSUBD : F3_3<0b10, 0b110100, 0b001100110,
+ (outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
+ "fhsubd $rs1, $rs2, $rd", []>;
+def FLCMPS : VISInstFormat<0b101010001, (outs FCCRegs:$rd),
+ (ins DFPRegs:$rs1, DFPRegs:$rs2),
+ "flcmps $rd, $rs1, $rs2", []>;
+def FLCMPD : VISInstFormat<0b101010010, (outs FCCRegs:$rd),
+ (ins DFPRegs:$rs1, DFPRegs:$rs2),
+ "flcmpd $rd, $rs1, $rs2", []>;
+
+def FMEAN16 : VISInst<0b001000000, "fmean16">;
+
+def FNADDS : F3_3<0b10, 0b110100, 0b001010001,
+ (outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
+ "fnadds $rs1, $rs2, $rd", []>;
+def FNADDD : F3_3<0b10, 0b110100, 0b001010010,
+ (outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
+ "fnaddd $rs1, $rs2, $rd", []>;
+def FNHADDS : F3_3<0b10, 0b110100, 0b001110001,
+ (outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
+ "fnhadds $rs1, $rs2, $rd", []>;
+def FNHADDD : F3_3<0b10, 0b110100, 0b001110010,
+ (outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
+ "fnhaddd $rs1, $rs2, $rd", []>;
+
+def FNMULS : F3_3<0b10, 0b110100, 0b001011001,
+ (outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
+ "fnhadds $rs1, $rs2, $rd", []>;
+def FNMULD : F3_3<0b10, 0b110100, 0b001011010,
+ (outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
+ "fnhaddd $rs1, $rs2, $rd", []>;
+def FNSMULD : F3_3<0b10, 0b110100, 0b001111001,
+ (outs DFPRegs:$rd), (ins DFPRegs:$rs1, DFPRegs:$rs2),
+ "fnhadds $rs1, $rs2, $rd", []>;
+
+def FPADD64 : VISInst<0b001000010, "fpadd64">;
+
+def FSLL16 : VISInst<0b000100001, "fsll16">;
+def FSRL16 : VISInst<0b000100011, "fsrl16">;
+def FSLL32 : VISInst<0b000100101, "fsll32">;
+def FSRL32 : VISInst<0b000100111, "fsrl32">;
+def FSLAS16 : VISInst<0b000101001, "fslas16">;
+def FSRA16 : VISInst<0b000101011, "fsra16">;
+def FSLAS32 : VISInst<0b000101101, "fslas32">;
+def FSRA32 : VISInst<0b000101111, "fsra32">;
+
+let rs1 = 0 in
+def LZCNT : VISInstFormat<0b000010111, (outs I64Regs:$rd),
+ (ins I64Regs:$rs2), "lzcnt $rs2, $rd", []>;
+
+let rs1 = 0 in {
+def MOVSTOSW : VISInstFormat<0b100010011, (outs I64Regs:$rd),
+ (ins DFPRegs:$rs2), "movstosw $rs2, $rd", []>;
+def MOVSTOUW : VISInstFormat<0b100010001, (outs I64Regs:$rd),
+ (ins DFPRegs:$rs2), "movstouw $rs2, $rd", []>;
+def MOVDTOX : VISInstFormat<0b100010000, (outs I64Regs:$rd),
+ (ins DFPRegs:$rs2), "movdtox $rs2, $rd", []>;
+def MOVWTOS : VISInstFormat<0b100011001, (outs DFPRegs:$rd),
+ (ins I64Regs:$rs2), "movdtox $rs2, $rd", []>;
+def MOVXTOD : VISInstFormat<0b100011000, (outs DFPRegs:$rd),
+ (ins I64Regs:$rs2), "movdtox $rs2, $rd", []>;
+}
+
+def PDISTN : VISInst<0b000111111, "pdistn">;
+
+def UMULXHI : VISInst<0b000010110, "umulxhi", I64Regs>;
+def XMULX : VISInst<0b100010101, "xmulx", I64Regs>;
+def XMULXHI : VISInst<0b100010111, "xmulxhi", I64Regs>;
+} // Predicates = [IsVIS3]
diff --git a/contrib/llvm/lib/Target/Sparc/SparcMCInstLower.cpp b/contrib/llvm/lib/Target/Sparc/SparcMCInstLower.cpp
new file mode 100644
index 0000000..b084d00
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/SparcMCInstLower.cpp
@@ -0,0 +1,109 @@
+//===-- SparcMCInstLower.cpp - Convert Sparc MachineInstr to MCInst -------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains code to lower Sparc MachineInstrs to their corresponding
+// MCInst records.
+//
+//===----------------------------------------------------------------------===//
+
+#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"
+#include "llvm/CodeGen/MachineOperand.h"
+#include "llvm/IR/Mangler.h"
+#include "llvm/MC/MCAsmInfo.h"
+#include "llvm/MC/MCContext.h"
+#include "llvm/MC/MCExpr.h"
+#include "llvm/MC/MCInst.h"
+
+using namespace llvm;
+
+
+static MCOperand LowerSymbolOperand(const MachineInstr *MI,
+ const MachineOperand &MO,
+ AsmPrinter &AP) {
+
+ SparcMCExpr::VariantKind Kind =
+ (SparcMCExpr::VariantKind)MO.getTargetFlags();
+ const MCSymbol *Symbol = nullptr;
+
+ switch(MO.getType()) {
+ default: llvm_unreachable("Unknown type in LowerSymbolOperand");
+ case MachineOperand::MO_MachineBasicBlock:
+ Symbol = MO.getMBB()->getSymbol();
+ break;
+
+ case MachineOperand::MO_GlobalAddress:
+ Symbol = AP.getSymbol(MO.getGlobal());
+ break;
+
+ case MachineOperand::MO_BlockAddress:
+ Symbol = AP.GetBlockAddressSymbol(MO.getBlockAddress());
+ break;
+
+ case MachineOperand::MO_ExternalSymbol:
+ Symbol = AP.GetExternalSymbolSymbol(MO.getSymbolName());
+ break;
+
+ case MachineOperand::MO_ConstantPoolIndex:
+ Symbol = AP.GetCPISymbol(MO.getIndex());
+ break;
+ }
+
+ const MCSymbolRefExpr *MCSym = MCSymbolRefExpr::create(Symbol,
+ AP.OutContext);
+ const SparcMCExpr *expr = SparcMCExpr::create(Kind, MCSym,
+ AP.OutContext);
+ return MCOperand::createExpr(expr);
+}
+
+static MCOperand LowerOperand(const MachineInstr *MI,
+ const MachineOperand &MO,
+ AsmPrinter &AP) {
+ switch(MO.getType()) {
+ default: llvm_unreachable("unknown operand type"); break;
+ case MachineOperand::MO_Register:
+ if (MO.isImplicit())
+ break;
+ return MCOperand::createReg(MO.getReg());
+
+ case MachineOperand::MO_Immediate:
+ return MCOperand::createImm(MO.getImm());
+
+ case MachineOperand::MO_MachineBasicBlock:
+ case MachineOperand::MO_GlobalAddress:
+ case MachineOperand::MO_BlockAddress:
+ case MachineOperand::MO_ExternalSymbol:
+ case MachineOperand::MO_ConstantPoolIndex:
+ return LowerSymbolOperand(MI, MO, AP);
+
+ case MachineOperand::MO_RegisterMask: break;
+
+ }
+ return MCOperand();
+}
+
+void llvm::LowerSparcMachineInstrToMCInst(const MachineInstr *MI,
+ MCInst &OutMI,
+ AsmPrinter &AP)
+{
+
+ OutMI.setOpcode(MI->getOpcode());
+
+ for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) {
+ const MachineOperand &MO = MI->getOperand(i);
+ MCOperand MCOp = LowerOperand(MI, MO, AP);
+
+ if (MCOp.isValid())
+ OutMI.addOperand(MCOp);
+ }
+}
diff --git a/contrib/llvm/lib/Target/Sparc/SparcMachineFunctionInfo.cpp b/contrib/llvm/lib/Target/Sparc/SparcMachineFunctionInfo.cpp
new file mode 100644
index 0000000..e744282
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/SparcMachineFunctionInfo.cpp
@@ -0,0 +1,14 @@
+//===-- SparcMachineFunctionInfo.cpp - Sparc Machine Function Info --------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SparcMachineFunctionInfo.h"
+
+using namespace llvm;
+
+void SparcMachineFunctionInfo::anchor() { }
diff --git a/contrib/llvm/lib/Target/Sparc/SparcMachineFunctionInfo.h b/contrib/llvm/lib/Target/Sparc/SparcMachineFunctionInfo.h
new file mode 100644
index 0000000..0471443
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/SparcMachineFunctionInfo.h
@@ -0,0 +1,56 @@
+//===- SparcMachineFunctionInfo.h - Sparc Machine Function Info -*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares Sparc specific per-machine-function information.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_LIB_TARGET_SPARC_SPARCMACHINEFUNCTIONINFO_H
+#define LLVM_LIB_TARGET_SPARC_SPARCMACHINEFUNCTIONINFO_H
+
+#include "llvm/CodeGen/MachineFunction.h"
+
+namespace llvm {
+
+ class SparcMachineFunctionInfo : public MachineFunctionInfo {
+ virtual void anchor();
+ private:
+ unsigned GlobalBaseReg;
+
+ /// VarArgsFrameOffset - Frame offset to start of varargs area.
+ int VarArgsFrameOffset;
+
+ /// SRetReturnReg - Holds the virtual register into which the sret
+ /// argument is passed.
+ unsigned SRetReturnReg;
+
+ /// IsLeafProc - True if the function is a leaf procedure.
+ bool IsLeafProc;
+ public:
+ SparcMachineFunctionInfo()
+ : GlobalBaseReg(0), VarArgsFrameOffset(0), SRetReturnReg(0),
+ IsLeafProc(false) {}
+ explicit SparcMachineFunctionInfo(MachineFunction &MF)
+ : GlobalBaseReg(0), VarArgsFrameOffset(0), SRetReturnReg(0),
+ IsLeafProc(false) {}
+
+ unsigned getGlobalBaseReg() const { return GlobalBaseReg; }
+ void setGlobalBaseReg(unsigned Reg) { GlobalBaseReg = Reg; }
+
+ int getVarArgsFrameOffset() const { return VarArgsFrameOffset; }
+ void setVarArgsFrameOffset(int Offset) { VarArgsFrameOffset = Offset; }
+
+ unsigned getSRetReturnReg() const { return SRetReturnReg; }
+ void setSRetReturnReg(unsigned Reg) { SRetReturnReg = Reg; }
+
+ void setLeafProc(bool rhs) { IsLeafProc = rhs; }
+ bool isLeafProc() const { return IsLeafProc; }
+ };
+} // namespace llvm
+
+#endif
diff --git a/contrib/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp b/contrib/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp
new file mode 100644
index 0000000..9667bc0
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp
@@ -0,0 +1,213 @@
+//===-- SparcRegisterInfo.cpp - SPARC Register Information ----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the SPARC implementation of the TargetRegisterInfo class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SparcRegisterInfo.h"
+#include "Sparc.h"
+#include "SparcMachineFunctionInfo.h"
+#include "SparcSubtarget.h"
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/CodeGen/MachineFrameInfo.h"
+#include "llvm/CodeGen/MachineFunction.h"
+#include "llvm/CodeGen/MachineInstrBuilder.h"
+#include "llvm/IR/Type.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Target/TargetInstrInfo.h"
+
+using namespace llvm;
+
+#define GET_REGINFO_TARGET_DESC
+#include "SparcGenRegisterInfo.inc"
+
+static cl::opt<bool>
+ReserveAppRegisters("sparc-reserve-app-registers", cl::Hidden, cl::init(false),
+ cl::desc("Reserve application registers (%g2-%g4)"));
+
+SparcRegisterInfo::SparcRegisterInfo() : SparcGenRegisterInfo(SP::O7) {}
+
+const MCPhysReg*
+SparcRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
+ return CSR_SaveList;
+}
+
+const uint32_t *
+SparcRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
+ CallingConv::ID CC) const {
+ return CSR_RegMask;
+}
+
+const uint32_t*
+SparcRegisterInfo::getRTCallPreservedMask(CallingConv::ID CC) const {
+ return RTCSR_RegMask;
+}
+
+BitVector SparcRegisterInfo::getReservedRegs(const MachineFunction &MF) const {
+ BitVector Reserved(getNumRegs());
+ const SparcSubtarget &Subtarget = MF.getSubtarget<SparcSubtarget>();
+ // FIXME: G1 reserved for now for large imm generation by frame code.
+ Reserved.set(SP::G1);
+
+ // G1-G4 can be used in applications.
+ if (ReserveAppRegisters) {
+ Reserved.set(SP::G2);
+ Reserved.set(SP::G3);
+ Reserved.set(SP::G4);
+ }
+ // G5 is not reserved in 64 bit mode.
+ if (!Subtarget.is64Bit())
+ Reserved.set(SP::G5);
+
+ Reserved.set(SP::O6);
+ Reserved.set(SP::I6);
+ Reserved.set(SP::I7);
+ Reserved.set(SP::G0);
+ Reserved.set(SP::G6);
+ Reserved.set(SP::G7);
+
+ // Unaliased double registers are not available in non-V9 targets.
+ if (!Subtarget.isV9()) {
+ for (unsigned n = 0; n != 16; ++n) {
+ for (MCRegAliasIterator AI(SP::D16 + n, this, true); AI.isValid(); ++AI)
+ Reserved.set(*AI);
+ }
+ }
+
+ return Reserved;
+}
+
+const TargetRegisterClass*
+SparcRegisterInfo::getPointerRegClass(const MachineFunction &MF,
+ unsigned Kind) const {
+ const SparcSubtarget &Subtarget = MF.getSubtarget<SparcSubtarget>();
+ 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)
+{
+ // 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
+ // encode it.
+ MI.getOperand(FIOperandNum).ChangeToRegister(FramePtr, false);
+ MI.getOperand(FIOperandNum + 1).ChangeToImmediate(Offset);
+ return;
+ }
+
+ const TargetInstrInfo &TII = *MF.getSubtarget().getInstrInfo();
+
+ // FIXME: it would be better to scavenge a register here instead of
+ // reserving G1 all of the time.
+ if (Offset >= 0) {
+ // Emit nonnegaive immediates with sethi + or.
+ // sethi %hi(Offset), %g1
+ // add %g1, %fp, %g1
+ // Insert G1+%lo(offset) into the user.
+ BuildMI(*MI.getParent(), II, dl, TII.get(SP::SETHIi), SP::G1)
+ .addImm(HI22(Offset));
+
+
+ // Emit G1 = G1 + I6
+ BuildMI(*MI.getParent(), II, dl, TII.get(SP::ADDrr), SP::G1).addReg(SP::G1)
+ .addReg(FramePtr);
+ // Insert: G1+%lo(offset) into the user.
+ MI.getOperand(FIOperandNum).ChangeToRegister(SP::G1, false);
+ MI.getOperand(FIOperandNum + 1).ChangeToImmediate(LO10(Offset));
+ return;
+ }
+
+ // Emit Negative numbers with sethi + xor
+ // sethi %hix(Offset), %g1
+ // xor %g1, %lox(offset), %g1
+ // add %g1, %fp, %g1
+ // Insert: G1 + 0 into the user.
+ BuildMI(*MI.getParent(), II, dl, TII.get(SP::SETHIi), SP::G1)
+ .addImm(HIX22(Offset));
+ BuildMI(*MI.getParent(), II, dl, TII.get(SP::XORri), SP::G1)
+ .addReg(SP::G1).addImm(LOX10(Offset));
+
+ BuildMI(*MI.getParent(), II, dl, TII.get(SP::ADDrr), SP::G1).addReg(SP::G1)
+ .addReg(FramePtr);
+ // Insert: G1+%lo(offset) into the user.
+ MI.getOperand(FIOperandNum).ChangeToRegister(SP::G1, false);
+ MI.getOperand(FIOperandNum + 1).ChangeToImmediate(0);
+}
+
+
+void
+SparcRegisterInfo::eliminateFrameIndex(MachineBasicBlock::iterator II,
+ int SPAdj, unsigned FIOperandNum,
+ RegScavenger *RS) const {
+ assert(SPAdj == 0 && "Unexpected");
+
+ MachineInstr &MI = *II;
+ DebugLoc dl = MI.getDebugLoc();
+ int FrameIndex = MI.getOperand(FIOperandNum).getIndex();
+
+ // Addressable stack objects are accessed using neg. offsets from %fp
+ MachineFunction &MF = *MI.getParent()->getParent();
+ const SparcSubtarget &Subtarget = MF.getSubtarget<SparcSubtarget>();
+ int64_t Offset = MF.getFrameInfo()->getObjectOffset(FrameIndex) +
+ MI.getOperand(FIOperandNum + 1).getImm() +
+ Subtarget.getStackPointerBias();
+ SparcMachineFunctionInfo *FuncInfo = MF.getInfo<SparcMachineFunctionInfo>();
+ unsigned FramePtr = SP::I6;
+ if (FuncInfo->isLeafProc()) {
+ // Use %sp and adjust offset if needed.
+ FramePtr = SP::O6;
+ int stackSize = MF.getFrameInfo()->getStackSize();
+ Offset += (stackSize) ? Subtarget.getAdjustedFrameSize(stackSize) : 0 ;
+ }
+
+ if (!Subtarget.isV9() || !Subtarget.hasHardQuad()) {
+ if (MI.getOpcode() == SP::STQFri) {
+ const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
+ unsigned SrcReg = MI.getOperand(2).getReg();
+ unsigned SrcEvenReg = getSubReg(SrcReg, SP::sub_even64);
+ unsigned SrcOddReg = getSubReg(SrcReg, SP::sub_odd64);
+ MachineInstr *StMI =
+ BuildMI(*MI.getParent(), II, dl, TII.get(SP::STDFri))
+ .addReg(FramePtr).addImm(0).addReg(SrcEvenReg);
+ replaceFI(MF, II, *StMI, dl, 0, Offset, FramePtr);
+ MI.setDesc(TII.get(SP::STDFri));
+ MI.getOperand(2).setReg(SrcOddReg);
+ Offset += 8;
+ } else if (MI.getOpcode() == SP::LDQFri) {
+ const TargetInstrInfo &TII = *Subtarget.getInstrInfo();
+ unsigned DestReg = MI.getOperand(0).getReg();
+ unsigned DestEvenReg = getSubReg(DestReg, SP::sub_even64);
+ unsigned DestOddReg = getSubReg(DestReg, SP::sub_odd64);
+ MachineInstr *StMI =
+ BuildMI(*MI.getParent(), II, dl, TII.get(SP::LDDFri), DestEvenReg)
+ .addReg(FramePtr).addImm(0);
+ replaceFI(MF, II, *StMI, dl, 1, Offset, FramePtr);
+
+ MI.setDesc(TII.get(SP::LDDFri));
+ MI.getOperand(0).setReg(DestOddReg);
+ Offset += 8;
+ }
+ }
+
+ replaceFI(MF, II, MI, dl, FIOperandNum, Offset, FramePtr);
+
+}
+
+unsigned SparcRegisterInfo::getFrameRegister(const MachineFunction &MF) const {
+ return SP::I6;
+}
+
diff --git a/contrib/llvm/lib/Target/Sparc/SparcRegisterInfo.h b/contrib/llvm/lib/Target/Sparc/SparcRegisterInfo.h
new file mode 100644
index 0000000..764a894
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/SparcRegisterInfo.h
@@ -0,0 +1,51 @@
+//===-- SparcRegisterInfo.h - Sparc Register Information Impl ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file contains the Sparc implementation of the TargetRegisterInfo class.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_SPARC_SPARCREGISTERINFO_H
+#define LLVM_LIB_TARGET_SPARC_SPARCREGISTERINFO_H
+
+#include "llvm/Target/TargetRegisterInfo.h"
+
+#define GET_REGINFO_HEADER
+#include "SparcGenRegisterInfo.inc"
+
+namespace llvm {
+struct SparcRegisterInfo : public SparcGenRegisterInfo {
+ SparcRegisterInfo();
+
+ /// Code Generation virtual methods...
+ const MCPhysReg *getCalleeSavedRegs(const MachineFunction *MF) const override;
+ const uint32_t *getCallPreservedMask(const MachineFunction &MF,
+ CallingConv::ID CC) const override;
+
+ const uint32_t* getRTCallPreservedMask(CallingConv::ID CC) const;
+
+ BitVector getReservedRegs(const MachineFunction &MF) const override;
+
+ const TargetRegisterClass *getPointerRegClass(const MachineFunction &MF,
+ unsigned Kind) const override;
+
+ void eliminateFrameIndex(MachineBasicBlock::iterator II,
+ int SPAdj, unsigned FIOperandNum,
+ RegScavenger *RS = nullptr) const override;
+
+ void processFunctionBeforeFrameFinalized(MachineFunction &MF,
+ RegScavenger *RS = nullptr) const;
+
+ // Debug information queries.
+ unsigned getFrameRegister(const MachineFunction &MF) const override;
+};
+
+} // end namespace llvm
+
+#endif
diff --git a/contrib/llvm/lib/Target/Sparc/SparcRegisterInfo.td b/contrib/llvm/lib/Target/Sparc/SparcRegisterInfo.td
new file mode 100644
index 0000000..e504da4
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/SparcRegisterInfo.td
@@ -0,0 +1,252 @@
+//===-- SparcRegisterInfo.td - Sparc Register defs ---------*- tablegen -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Declarations that describe the Sparc register file
+//===----------------------------------------------------------------------===//
+
+class SparcReg<bits<16> Enc, string n> : Register<n> {
+ let HWEncoding = Enc;
+ let Namespace = "SP";
+}
+
+class SparcCtrlReg<bits<16> Enc, string n>: Register<n> {
+ let HWEncoding = Enc;
+ let Namespace = "SP";
+}
+
+let Namespace = "SP" in {
+def sub_even : SubRegIndex<32>;
+def sub_odd : SubRegIndex<32, 32>;
+def sub_even64 : SubRegIndex<64>;
+def sub_odd64 : SubRegIndex<64, 64>;
+}
+
+// Registers are identified with 5-bit ID numbers.
+// Ri - 32-bit integer registers
+class Ri<bits<16> Enc, string n> : SparcReg<Enc, n>;
+
+// Rf - 32-bit floating-point registers
+class Rf<bits<16> Enc, string n> : SparcReg<Enc, n>;
+
+// Rd - Slots in the FP register file for 64-bit floating-point values.
+class Rd<bits<16> Enc, string n, list<Register> subregs> : SparcReg<Enc, n> {
+ let SubRegs = subregs;
+ let SubRegIndices = [sub_even, sub_odd];
+ let CoveredBySubRegs = 1;
+}
+
+// Rq - Slots in the FP register file for 128-bit floating-point values.
+class Rq<bits<16> Enc, string n, list<Register> subregs> : SparcReg<Enc, n> {
+ let SubRegs = subregs;
+ let SubRegIndices = [sub_even64, sub_odd64];
+ let CoveredBySubRegs = 1;
+}
+
+// Control Registers
+def ICC : SparcCtrlReg<0, "ICC">; // This represents icc and xcc in 64-bit code.
+foreach I = 0-3 in
+ def FCC#I : SparcCtrlReg<I, "FCC"#I>;
+
+// Y register
+def Y : SparcCtrlReg<0, "Y">, DwarfRegNum<[64]>;
+// Ancillary state registers (implementation defined)
+def ASR1 : SparcCtrlReg<1, "ASR1">;
+def ASR2 : SparcCtrlReg<2, "ASR2">;
+def ASR3 : SparcCtrlReg<3, "ASR3">;
+def ASR4 : SparcCtrlReg<4, "ASR4">;
+def ASR5 : SparcCtrlReg<5, "ASR5">;
+def ASR6 : SparcCtrlReg<6, "ASR6">;
+def ASR7 : SparcCtrlReg<7, "ASR7">;
+def ASR8 : SparcCtrlReg<8, "ASR8">;
+def ASR9 : SparcCtrlReg<9, "ASR9">;
+def ASR10 : SparcCtrlReg<10, "ASR10">;
+def ASR11 : SparcCtrlReg<11, "ASR11">;
+def ASR12 : SparcCtrlReg<12, "ASR12">;
+def ASR13 : SparcCtrlReg<13, "ASR13">;
+def ASR14 : SparcCtrlReg<14, "ASR14">;
+def ASR15 : SparcCtrlReg<15, "ASR15">;
+def ASR16 : SparcCtrlReg<16, "ASR16">;
+def ASR17 : SparcCtrlReg<17, "ASR17">;
+def ASR18 : SparcCtrlReg<18, "ASR18">;
+def ASR19 : SparcCtrlReg<19, "ASR19">;
+def ASR20 : SparcCtrlReg<20, "ASR20">;
+def ASR21 : SparcCtrlReg<21, "ASR21">;
+def ASR22 : SparcCtrlReg<22, "ASR22">;
+def ASR23 : SparcCtrlReg<23, "ASR23">;
+def ASR24 : SparcCtrlReg<24, "ASR24">;
+def ASR25 : SparcCtrlReg<25, "ASR25">;
+def ASR26 : SparcCtrlReg<26, "ASR26">;
+def ASR27 : SparcCtrlReg<27, "ASR27">;
+def ASR28 : SparcCtrlReg<28, "ASR28">;
+def ASR29 : SparcCtrlReg<29, "ASR29">;
+def ASR30 : SparcCtrlReg<30, "ASR30">;
+def ASR31 : SparcCtrlReg<31, "ASR31">;
+
+// Note that PSR, WIM, and TBR don't exist on the SparcV9, only the V8.
+def PSR : SparcCtrlReg<0, "PSR">;
+def WIM : SparcCtrlReg<0, "WIM">;
+def TBR : SparcCtrlReg<0, "TBR">;
+
+// Integer registers
+def G0 : Ri< 0, "G0">, DwarfRegNum<[0]>;
+def G1 : Ri< 1, "G1">, DwarfRegNum<[1]>;
+def G2 : Ri< 2, "G2">, DwarfRegNum<[2]>;
+def G3 : Ri< 3, "G3">, DwarfRegNum<[3]>;
+def G4 : Ri< 4, "G4">, DwarfRegNum<[4]>;
+def G5 : Ri< 5, "G5">, DwarfRegNum<[5]>;
+def G6 : Ri< 6, "G6">, DwarfRegNum<[6]>;
+def G7 : Ri< 7, "G7">, DwarfRegNum<[7]>;
+def O0 : Ri< 8, "O0">, DwarfRegNum<[8]>;
+def O1 : Ri< 9, "O1">, DwarfRegNum<[9]>;
+def O2 : Ri<10, "O2">, DwarfRegNum<[10]>;
+def O3 : Ri<11, "O3">, DwarfRegNum<[11]>;
+def O4 : Ri<12, "O4">, DwarfRegNum<[12]>;
+def O5 : Ri<13, "O5">, DwarfRegNum<[13]>;
+def O6 : Ri<14, "SP">, DwarfRegNum<[14]>;
+def O7 : Ri<15, "O7">, DwarfRegNum<[15]>;
+def L0 : Ri<16, "L0">, DwarfRegNum<[16]>;
+def L1 : Ri<17, "L1">, DwarfRegNum<[17]>;
+def L2 : Ri<18, "L2">, DwarfRegNum<[18]>;
+def L3 : Ri<19, "L3">, DwarfRegNum<[19]>;
+def L4 : Ri<20, "L4">, DwarfRegNum<[20]>;
+def L5 : Ri<21, "L5">, DwarfRegNum<[21]>;
+def L6 : Ri<22, "L6">, DwarfRegNum<[22]>;
+def L7 : Ri<23, "L7">, DwarfRegNum<[23]>;
+def I0 : Ri<24, "I0">, DwarfRegNum<[24]>;
+def I1 : Ri<25, "I1">, DwarfRegNum<[25]>;
+def I2 : Ri<26, "I2">, DwarfRegNum<[26]>;
+def I3 : Ri<27, "I3">, DwarfRegNum<[27]>;
+def I4 : Ri<28, "I4">, DwarfRegNum<[28]>;
+def I5 : Ri<29, "I5">, DwarfRegNum<[29]>;
+def I6 : Ri<30, "FP">, DwarfRegNum<[30]>;
+def I7 : Ri<31, "I7">, DwarfRegNum<[31]>;
+
+// Floating-point registers
+def F0 : Rf< 0, "F0">, DwarfRegNum<[32]>;
+def F1 : Rf< 1, "F1">, DwarfRegNum<[33]>;
+def F2 : Rf< 2, "F2">, DwarfRegNum<[34]>;
+def F3 : Rf< 3, "F3">, DwarfRegNum<[35]>;
+def F4 : Rf< 4, "F4">, DwarfRegNum<[36]>;
+def F5 : Rf< 5, "F5">, DwarfRegNum<[37]>;
+def F6 : Rf< 6, "F6">, DwarfRegNum<[38]>;
+def F7 : Rf< 7, "F7">, DwarfRegNum<[39]>;
+def F8 : Rf< 8, "F8">, DwarfRegNum<[40]>;
+def F9 : Rf< 9, "F9">, DwarfRegNum<[41]>;
+def F10 : Rf<10, "F10">, DwarfRegNum<[42]>;
+def F11 : Rf<11, "F11">, DwarfRegNum<[43]>;
+def F12 : Rf<12, "F12">, DwarfRegNum<[44]>;
+def F13 : Rf<13, "F13">, DwarfRegNum<[45]>;
+def F14 : Rf<14, "F14">, DwarfRegNum<[46]>;
+def F15 : Rf<15, "F15">, DwarfRegNum<[47]>;
+def F16 : Rf<16, "F16">, DwarfRegNum<[48]>;
+def F17 : Rf<17, "F17">, DwarfRegNum<[49]>;
+def F18 : Rf<18, "F18">, DwarfRegNum<[50]>;
+def F19 : Rf<19, "F19">, DwarfRegNum<[51]>;
+def F20 : Rf<20, "F20">, DwarfRegNum<[52]>;
+def F21 : Rf<21, "F21">, DwarfRegNum<[53]>;
+def F22 : Rf<22, "F22">, DwarfRegNum<[54]>;
+def F23 : Rf<23, "F23">, DwarfRegNum<[55]>;
+def F24 : Rf<24, "F24">, DwarfRegNum<[56]>;
+def F25 : Rf<25, "F25">, DwarfRegNum<[57]>;
+def F26 : Rf<26, "F26">, DwarfRegNum<[58]>;
+def F27 : Rf<27, "F27">, DwarfRegNum<[59]>;
+def F28 : Rf<28, "F28">, DwarfRegNum<[60]>;
+def F29 : Rf<29, "F29">, DwarfRegNum<[61]>;
+def F30 : Rf<30, "F30">, DwarfRegNum<[62]>;
+def F31 : Rf<31, "F31">, DwarfRegNum<[63]>;
+
+// Aliases of the F* registers used to hold 64-bit fp values (doubles)
+def D0 : Rd< 0, "F0", [F0, F1]>, DwarfRegNum<[72]>;
+def D1 : Rd< 2, "F2", [F2, F3]>, DwarfRegNum<[73]>;
+def D2 : Rd< 4, "F4", [F4, F5]>, DwarfRegNum<[74]>;
+def D3 : Rd< 6, "F6", [F6, F7]>, DwarfRegNum<[75]>;
+def D4 : Rd< 8, "F8", [F8, F9]>, DwarfRegNum<[76]>;
+def D5 : Rd<10, "F10", [F10, F11]>, DwarfRegNum<[77]>;
+def D6 : Rd<12, "F12", [F12, F13]>, DwarfRegNum<[78]>;
+def D7 : Rd<14, "F14", [F14, F15]>, DwarfRegNum<[79]>;
+def D8 : Rd<16, "F16", [F16, F17]>, DwarfRegNum<[80]>;
+def D9 : Rd<18, "F18", [F18, F19]>, DwarfRegNum<[81]>;
+def D10 : Rd<20, "F20", [F20, F21]>, DwarfRegNum<[82]>;
+def D11 : Rd<22, "F22", [F22, F23]>, DwarfRegNum<[83]>;
+def D12 : Rd<24, "F24", [F24, F25]>, DwarfRegNum<[84]>;
+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]>;
+
+// Unaliased double precision floating point registers.
+// FIXME: Define DwarfRegNum for these registers.
+def D16 : SparcReg< 1, "F32">;
+def D17 : SparcReg< 3, "F34">;
+def D18 : SparcReg< 5, "F36">;
+def D19 : SparcReg< 7, "F38">;
+def D20 : SparcReg< 9, "F40">;
+def D21 : SparcReg<11, "F42">;
+def D22 : SparcReg<13, "F44">;
+def D23 : SparcReg<15, "F46">;
+def D24 : SparcReg<17, "F48">;
+def D25 : SparcReg<19, "F50">;
+def D26 : SparcReg<21, "F52">;
+def D27 : SparcReg<23, "F54">;
+def D28 : SparcReg<25, "F56">;
+def D29 : SparcReg<27, "F58">;
+def D30 : SparcReg<29, "F60">;
+def D31 : SparcReg<31, "F62">;
+
+// Aliases of the F* registers used to hold 128-bit for values (long doubles).
+def Q0 : Rq< 0, "F0", [D0, D1]>;
+def Q1 : Rq< 4, "F4", [D2, D3]>;
+def Q2 : Rq< 8, "F8", [D4, D5]>;
+def Q3 : Rq<12, "F12", [D6, D7]>;
+def Q4 : Rq<16, "F16", [D8, D9]>;
+def Q5 : Rq<20, "F20", [D10, D11]>;
+def Q6 : Rq<24, "F24", [D12, D13]>;
+def Q7 : Rq<28, "F28", [D14, D15]>;
+def Q8 : Rq< 1, "F32", [D16, D17]>;
+def Q9 : Rq< 5, "F36", [D18, D19]>;
+def Q10 : Rq< 9, "F40", [D20, D21]>;
+def Q11 : Rq<13, "F44", [D22, D23]>;
+def Q12 : Rq<17, "F48", [D24, D25]>;
+def Q13 : Rq<21, "F52", [D26, D27]>;
+def Q14 : Rq<25, "F56", [D28, D29]>;
+def Q15 : Rq<29, "F60", [D30, D31]>;
+
+// Register classes.
+//
+// FIXME: the register order should be defined in terms of the preferred
+// allocation order...
+//
+// This register class should not be used to hold i64 values, use the I64Regs
+// register class for that. The i64 type is included here to allow i64 patterns
+// using the integer instructions.
+def IntRegs : RegisterClass<"SP", [i32, i64], 32,
+ (add (sequence "I%u", 0, 7),
+ (sequence "G%u", 0, 7),
+ (sequence "L%u", 0, 7),
+ (sequence "O%u", 0, 7))>;
+
+// Register class for 64-bit mode, with a 64-bit spill slot size.
+// These are the same as the 32-bit registers, so TableGen will consider this
+// to be a sub-class of IntRegs. That works out because requiring a 64-bit
+// spill slot is a stricter constraint than only requiring a 32-bit spill slot.
+def I64Regs : RegisterClass<"SP", [i64], 64, (add IntRegs)>;
+
+// Floating point register classes.
+def FPRegs : RegisterClass<"SP", [f32], 32, (sequence "F%u", 0, 31)>;
+
+def DFPRegs : RegisterClass<"SP", [f64], 64, (sequence "D%u", 0, 31)>;
+
+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))>;
diff --git a/contrib/llvm/lib/Target/Sparc/SparcSelectionDAGInfo.cpp b/contrib/llvm/lib/Target/Sparc/SparcSelectionDAGInfo.cpp
new file mode 100644
index 0000000..a308fc5
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/SparcSelectionDAGInfo.cpp
@@ -0,0 +1,24 @@
+//===-- SparcSelectionDAGInfo.cpp - Sparc SelectionDAG Info ---------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the SparcSelectionDAGInfo class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SparcSelectionDAGInfo.h"
+using namespace llvm;
+
+#define DEBUG_TYPE "sparc-selectiondag-info"
+
+SparcSelectionDAGInfo::SparcSelectionDAGInfo(const DataLayout &DL)
+ : TargetSelectionDAGInfo(&DL) {
+}
+
+SparcSelectionDAGInfo::~SparcSelectionDAGInfo() {
+}
diff --git a/contrib/llvm/lib/Target/Sparc/SparcSelectionDAGInfo.h b/contrib/llvm/lib/Target/Sparc/SparcSelectionDAGInfo.h
new file mode 100644
index 0000000..2ceae82
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/SparcSelectionDAGInfo.h
@@ -0,0 +1,31 @@
+//===-- SparcSelectionDAGInfo.h - Sparc SelectionDAG Info -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the Sparc subclass for TargetSelectionDAGInfo.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_SPARC_SPARCSELECTIONDAGINFO_H
+#define LLVM_LIB_TARGET_SPARC_SPARCSELECTIONDAGINFO_H
+
+#include "llvm/Target/TargetSelectionDAGInfo.h"
+
+namespace llvm {
+
+class SparcTargetMachine;
+
+class SparcSelectionDAGInfo : public TargetSelectionDAGInfo {
+public:
+ explicit SparcSelectionDAGInfo(const DataLayout &DL);
+ ~SparcSelectionDAGInfo() override;
+};
+
+} // namespace llvm
+
+#endif
diff --git a/contrib/llvm/lib/Target/Sparc/SparcSubtarget.cpp b/contrib/llvm/lib/Target/Sparc/SparcSubtarget.cpp
new file mode 100644
index 0000000..479b25d
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/SparcSubtarget.cpp
@@ -0,0 +1,83 @@
+//===-- SparcSubtarget.cpp - SPARC Subtarget Information ------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the SPARC specific subclass of TargetSubtargetInfo.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SparcSubtarget.h"
+#include "Sparc.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/TargetRegistry.h"
+
+using namespace llvm;
+
+#define DEBUG_TYPE "sparc-subtarget"
+
+#define GET_SUBTARGETINFO_TARGET_DESC
+#define GET_SUBTARGETINFO_CTOR
+#include "SparcGenSubtargetInfo.inc"
+
+void SparcSubtarget::anchor() { }
+
+SparcSubtarget &SparcSubtarget::initializeSubtargetDependencies(StringRef CPU,
+ StringRef FS) {
+ IsV9 = false;
+ V8DeprecatedInsts = false;
+ IsVIS = false;
+ HasHardQuad = false;
+ UsePopc = false;
+
+ // Determine default and user specified characteristics
+ std::string CPUName = CPU;
+ if (CPUName.empty())
+ CPUName = (Is64Bit) ? "v9" : "v8";
+
+ // Parse features string.
+ ParseSubtargetFeatures(CPUName, FS);
+
+ // Popc is a v9-only instruction.
+ if (!IsV9)
+ UsePopc = false;
+
+ return *this;
+}
+
+SparcSubtarget::SparcSubtarget(const Triple &TT, const std::string &CPU,
+ const std::string &FS, TargetMachine &TM,
+ bool is64Bit)
+ : SparcGenSubtargetInfo(TT, CPU, FS), Is64Bit(is64Bit),
+ InstrInfo(initializeSubtargetDependencies(CPU, FS)), TLInfo(TM, *this),
+ TSInfo(*TM.getDataLayout()), FrameLowering(*this) {}
+
+int SparcSubtarget::getAdjustedFrameSize(int frameSize) const {
+
+ if (is64Bit()) {
+ // All 64-bit stack frames must be 16-byte aligned, and must reserve space
+ // for spilling the 16 window registers at %sp+BIAS..%sp+BIAS+128.
+ 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.
+ assert(frameSize % 16 == 0 && "Stack size not 16-byte aligned");
+ } else {
+ // Emit the correct save instruction based on the number of bytes in
+ // the frame. Minimum stack frame size according to V8 ABI is:
+ // 16 words for register window spill
+ // 1 word for address of returned aggregate-value
+ // + 6 words for passing parameters on the stack
+ // ----------
+ // 23 words * 4 bytes per word = 92 bytes
+ frameSize += 92;
+
+ // Round up to next doubleword boundary -- a double-word boundary
+ // is required by the ABI.
+ frameSize = RoundUpToAlignment(frameSize, 8);
+ }
+ return frameSize;
+}
diff --git a/contrib/llvm/lib/Target/Sparc/SparcSubtarget.h b/contrib/llvm/lib/Target/Sparc/SparcSubtarget.h
new file mode 100644
index 0000000..983b119
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/SparcSubtarget.h
@@ -0,0 +1,93 @@
+//===-- SparcSubtarget.h - Define Subtarget for the SPARC -------*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the SPARC specific subclass of TargetSubtargetInfo.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_SPARC_SPARCSUBTARGET_H
+#define LLVM_LIB_TARGET_SPARC_SPARCSUBTARGET_H
+
+#include "SparcFrameLowering.h"
+#include "SparcInstrInfo.h"
+#include "SparcISelLowering.h"
+#include "SparcSelectionDAGInfo.h"
+#include "llvm/IR/DataLayout.h"
+#include "llvm/Target/TargetFrameLowering.h"
+#include "llvm/Target/TargetSubtargetInfo.h"
+#include <string>
+
+#define GET_SUBTARGETINFO_HEADER
+#include "SparcGenSubtargetInfo.inc"
+
+namespace llvm {
+class StringRef;
+
+class SparcSubtarget : public SparcGenSubtargetInfo {
+ virtual void anchor();
+ bool IsV9;
+ bool V8DeprecatedInsts;
+ bool IsVIS, IsVIS2, IsVIS3;
+ bool Is64Bit;
+ bool HasHardQuad;
+ bool UsePopc;
+ SparcInstrInfo InstrInfo;
+ SparcTargetLowering TLInfo;
+ SparcSelectionDAGInfo TSInfo;
+ SparcFrameLowering FrameLowering;
+
+public:
+ SparcSubtarget(const Triple &TT, const std::string &CPU,
+ const std::string &FS, TargetMachine &TM, bool is64bit);
+
+ const SparcInstrInfo *getInstrInfo() const override { return &InstrInfo; }
+ const TargetFrameLowering *getFrameLowering() const override {
+ return &FrameLowering;
+ }
+ const SparcRegisterInfo *getRegisterInfo() const override {
+ return &InstrInfo.getRegisterInfo();
+ }
+ const SparcTargetLowering *getTargetLowering() const override {
+ return &TLInfo;
+ }
+ const SparcSelectionDAGInfo *getSelectionDAGInfo() const override {
+ return &TSInfo;
+ }
+
+ bool isV9() const { return IsV9; }
+ 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; }
+
+ /// ParseSubtargetFeatures - Parses features string setting specified
+ /// subtarget options. Definition of function is auto generated by tblgen.
+ void ParseSubtargetFeatures(StringRef CPU, StringRef FS);
+ SparcSubtarget &initializeSubtargetDependencies(StringRef CPU, StringRef FS);
+
+ bool is64Bit() const { return Is64Bit; }
+
+ /// The 64-bit ABI uses biased stack and frame pointers, so the stack frame
+ /// of the current function is the area from [%sp+BIAS] to [%fp+BIAS].
+ int64_t getStackPointerBias() const {
+ return is64Bit() ? 2047 : 0;
+ }
+
+ /// Given a actual stack size as determined by FrameInfo, this function
+ /// returns adjusted framesize which includes space for register window
+ /// spills and arguments.
+ int getAdjustedFrameSize(int stackSize) const;
+
+};
+
+} // end namespace llvm
+
+#endif
diff --git a/contrib/llvm/lib/Target/Sparc/SparcTargetMachine.cpp b/contrib/llvm/lib/Target/Sparc/SparcTargetMachine.cpp
new file mode 100644
index 0000000..725d7f0
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/SparcTargetMachine.cpp
@@ -0,0 +1,132 @@
+//===-- SparcTargetMachine.cpp - Define TargetMachine for Sparc -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+//
+//===----------------------------------------------------------------------===//
+
+#include "SparcTargetMachine.h"
+#include "SparcTargetObjectFile.h"
+#include "Sparc.h"
+#include "llvm/CodeGen/Passes.h"
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/Support/TargetRegistry.h"
+using namespace llvm;
+
+extern "C" void LLVMInitializeSparcTarget() {
+ // Register the target.
+ RegisterTargetMachine<SparcV8TargetMachine> X(TheSparcTarget);
+ RegisterTargetMachine<SparcV9TargetMachine> Y(TheSparcV9Target);
+ RegisterTargetMachine<SparcelTargetMachine> Z(TheSparcelTarget);
+}
+
+static std::string computeDataLayout(const Triple &T, bool is64Bit) {
+ // Sparc is typically big endian, but some are little.
+ std::string Ret = T.getArch() == Triple::sparcel ? "e" : "E";
+ Ret += "-m:e";
+
+ // Some ABIs have 32bit pointers.
+ if (!is64Bit)
+ Ret += "-p:32:32";
+
+ // Alignments for 64 bit integers.
+ Ret += "-i64:64";
+
+ // On SparcV9 128 floats are aligned to 128 bits, on others only to 64.
+ // On SparcV9 registers can hold 64 or 32 bits, on others only 32.
+ if (is64Bit)
+ Ret += "-n32:64";
+ else
+ Ret += "-f128:64-n32";
+
+ if (is64Bit)
+ Ret += "-S128";
+ else
+ Ret += "-S64";
+
+ return Ret;
+}
+
+/// SparcTargetMachine ctor - 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,
+ CodeGenOpt::Level OL, bool is64bit)
+ : LLVMTargetMachine(T, computeDataLayout(TT, is64bit), TT, CPU, FS, Options,
+ RM, CM, OL),
+ TLOF(make_unique<SparcELFTargetObjectFile>()),
+ Subtarget(TT, CPU, FS, *this, is64bit) {
+ initAsmInfo();
+}
+
+SparcTargetMachine::~SparcTargetMachine() {}
+
+namespace {
+/// Sparc Code Generator Pass Configuration Options.
+class SparcPassConfig : public TargetPassConfig {
+public:
+ SparcPassConfig(SparcTargetMachine *TM, PassManagerBase &PM)
+ : TargetPassConfig(TM, PM) {}
+
+ SparcTargetMachine &getSparcTargetMachine() const {
+ return getTM<SparcTargetMachine>();
+ }
+
+ void addIRPasses() override;
+ bool addInstSelector() override;
+ void addPreEmitPass() override;
+};
+} // namespace
+
+TargetPassConfig *SparcTargetMachine::createPassConfig(PassManagerBase &PM) {
+ return new SparcPassConfig(this, PM);
+}
+
+void SparcPassConfig::addIRPasses() {
+ addPass(createAtomicExpandPass(&getSparcTargetMachine()));
+
+ TargetPassConfig::addIRPasses();
+}
+
+bool SparcPassConfig::addInstSelector() {
+ addPass(createSparcISelDag(getSparcTargetMachine()));
+ return false;
+}
+
+void SparcPassConfig::addPreEmitPass(){
+ addPass(createSparcDelaySlotFillerPass(getSparcTargetMachine()));
+}
+
+void SparcV8TargetMachine::anchor() { }
+
+SparcV8TargetMachine::SparcV8TargetMachine(const Target &T, const Triple &TT,
+ StringRef CPU, StringRef FS,
+ const TargetOptions &Options,
+ Reloc::Model RM, CodeModel::Model CM,
+ CodeGenOpt::Level OL)
+ : SparcTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, false) {}
+
+void SparcV9TargetMachine::anchor() { }
+
+SparcV9TargetMachine::SparcV9TargetMachine(const Target &T, const Triple &TT,
+ StringRef CPU, StringRef FS,
+ const TargetOptions &Options,
+ Reloc::Model RM, CodeModel::Model CM,
+ CodeGenOpt::Level OL)
+ : SparcTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, true) {}
+
+void SparcelTargetMachine::anchor() {}
+
+SparcelTargetMachine::SparcelTargetMachine(const Target &T, const Triple &TT,
+ StringRef CPU, StringRef FS,
+ const TargetOptions &Options,
+ Reloc::Model RM, CodeModel::Model CM,
+ CodeGenOpt::Level OL)
+ : SparcTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, false) {}
diff --git a/contrib/llvm/lib/Target/Sparc/SparcTargetMachine.h b/contrib/llvm/lib/Target/Sparc/SparcTargetMachine.h
new file mode 100644
index 0000000..903c2d1
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/SparcTargetMachine.h
@@ -0,0 +1,78 @@
+//===-- SparcTargetMachine.h - Define TargetMachine for Sparc ---*- C++ -*-===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the Sparc specific subclass of TargetMachine.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_SPARC_SPARCTARGETMACHINE_H
+#define LLVM_LIB_TARGET_SPARC_SPARCTARGETMACHINE_H
+
+#include "SparcInstrInfo.h"
+#include "SparcSubtarget.h"
+#include "llvm/Target/TargetMachine.h"
+
+namespace llvm {
+
+class SparcTargetMachine : public LLVMTargetMachine {
+ std::unique_ptr<TargetLoweringObjectFile> TLOF;
+ SparcSubtarget Subtarget;
+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);
+ ~SparcTargetMachine() override;
+
+ const SparcSubtarget *getSubtargetImpl(const Function &) const override {
+ return &Subtarget;
+ }
+
+ // Pass Pipeline Configuration
+ TargetPassConfig *createPassConfig(PassManagerBase &PM) override;
+ TargetLoweringObjectFile *getObjFileLowering() const override {
+ return TLOF.get();
+ }
+};
+
+/// SparcV8TargetMachine - 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,
+ CodeGenOpt::Level OL);
+};
+
+/// SparcV9TargetMachine - 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,
+ CodeGenOpt::Level OL);
+};
+
+class SparcelTargetMachine : public SparcTargetMachine {
+ virtual void anchor();
+
+public:
+ SparcelTargetMachine(const Target &T, const Triple &TT, StringRef CPU,
+ StringRef FS, const TargetOptions &Options,
+ Reloc::Model RM, CodeModel::Model CM,
+ CodeGenOpt::Level OL);
+};
+
+} // end namespace llvm
+
+#endif
diff --git a/contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.cpp b/contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.cpp
new file mode 100644
index 0000000..412e124
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.cpp
@@ -0,0 +1,43 @@
+//===------- SparcTargetObjectFile.cpp - Sparc Object Info Impl -----------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SparcTargetObjectFile.h"
+#include "MCTargetDesc/SparcMCExpr.h"
+#include "llvm/CodeGen/MachineModuleInfoImpls.h"
+#include "llvm/Support/Dwarf.h"
+#include "llvm/Target/TargetLowering.h"
+
+using namespace llvm;
+
+const MCExpr *SparcELFTargetObjectFile::getTTypeGlobalReference(
+ const GlobalValue *GV, unsigned Encoding, Mangler &Mang,
+ const TargetMachine &TM, MachineModuleInfo *MMI,
+ MCStreamer &Streamer) const {
+
+ if (Encoding & dwarf::DW_EH_PE_pcrel) {
+ MachineModuleInfoELF &ELFMMI = MMI->getObjFileInfo<MachineModuleInfoELF>();
+
+ MCSymbol *SSym = getSymbolWithGlobalValueBase(GV, ".DW.stub", Mang, TM);
+
+ // Add information about the stub reference to ELFMMI so that the stub
+ // gets emitted by the asmprinter.
+ MachineModuleInfoImpl::StubValueTy &StubSym = ELFMMI.getGVStubEntry(SSym);
+ if (!StubSym.getPointer()) {
+ MCSymbol *Sym = TM.getSymbol(GV, Mang);
+ StubSym = MachineModuleInfoImpl::StubValueTy(Sym, !GV->hasLocalLinkage());
+ }
+
+ MCContext &Ctx = getContext();
+ return SparcMCExpr::create(SparcMCExpr::VK_Sparc_R_DISP32,
+ MCSymbolRefExpr::create(SSym, Ctx), Ctx);
+ }
+
+ return TargetLoweringObjectFileELF::getTTypeGlobalReference(
+ GV, Encoding, Mang, TM, MMI, Streamer);
+}
diff --git a/contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.h b/contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.h
new file mode 100644
index 0000000..76c8cca
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.h
@@ -0,0 +1,35 @@
+//===-- SparcTargetObjectFile.h - Sparc Object Info -------------*- C++ -*-===//
+//
+// 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_SPARCTARGETOBJECTFILE_H
+#define LLVM_LIB_TARGET_SPARC_SPARCTARGETOBJECTFILE_H
+
+#include "llvm/CodeGen/TargetLoweringObjectFileImpl.h"
+
+namespace llvm {
+
+class MCContext;
+class TargetMachine;
+
+class SparcELFTargetObjectFile : public TargetLoweringObjectFileELF {
+public:
+ SparcELFTargetObjectFile() :
+ TargetLoweringObjectFileELF()
+ {}
+
+ const MCExpr *
+ getTTypeGlobalReference(const GlobalValue *GV, unsigned Encoding,
+ Mangler &Mang, const TargetMachine &TM,
+ MachineModuleInfo *MMI,
+ MCStreamer &Streamer) const override;
+};
+
+} // end namespace llvm
+
+#endif
diff --git a/contrib/llvm/lib/Target/Sparc/SparcTargetStreamer.h b/contrib/llvm/lib/Target/Sparc/SparcTargetStreamer.h
new file mode 100644
index 0000000..3b50350
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/SparcTargetStreamer.h
@@ -0,0 +1,49 @@
+//===-- SparcTargetStreamer.h - Sparc Target Streamer ----------*- C++ -*--===//
+//
+// 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_SPARCTARGETSTREAMER_H
+#define LLVM_LIB_TARGET_SPARC_SPARCTARGETSTREAMER_H
+
+#include "llvm/MC/MCELFStreamer.h"
+#include "llvm/MC/MCStreamer.h"
+
+namespace llvm {
+class SparcTargetStreamer : public MCTargetStreamer {
+ virtual void anchor();
+
+public:
+ SparcTargetStreamer(MCStreamer &S);
+ /// Emit ".register <reg>, #ignore".
+ virtual void emitSparcRegisterIgnore(unsigned reg) = 0;
+ /// Emit ".register <reg>, #scratch".
+ virtual void emitSparcRegisterScratch(unsigned reg) = 0;
+};
+
+// This part is for ascii assembly output
+class SparcTargetAsmStreamer : public SparcTargetStreamer {
+ formatted_raw_ostream &OS;
+
+public:
+ SparcTargetAsmStreamer(MCStreamer &S, formatted_raw_ostream &OS);
+ void emitSparcRegisterIgnore(unsigned reg) override;
+ void emitSparcRegisterScratch(unsigned reg) override;
+
+};
+
+// This part is for ELF object output
+class SparcTargetELFStreamer : public SparcTargetStreamer {
+public:
+ SparcTargetELFStreamer(MCStreamer &S);
+ MCELFStreamer &getStreamer();
+ void emitSparcRegisterIgnore(unsigned reg) override {}
+ void emitSparcRegisterScratch(unsigned reg) override {}
+};
+} // end namespace llvm
+
+#endif
diff --git a/contrib/llvm/lib/Target/Sparc/TargetInfo/SparcTargetInfo.cpp b/contrib/llvm/lib/Target/Sparc/TargetInfo/SparcTargetInfo.cpp
new file mode 100644
index 0000000..ab1c6be
--- /dev/null
+++ b/contrib/llvm/lib/Target/Sparc/TargetInfo/SparcTargetInfo.cpp
@@ -0,0 +1,26 @@
+//===-- SparcTargetInfo.cpp - Sparc Target Implementation -----------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Sparc.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/TargetRegistry.h"
+using namespace llvm;
+
+Target llvm::TheSparcTarget;
+Target llvm::TheSparcV9Target;
+Target llvm::TheSparcelTarget;
+
+extern "C" void LLVMInitializeSparcTargetInfo() {
+ RegisterTarget<Triple::sparc, /*HasJIT=*/true> X(TheSparcTarget, "sparc",
+ "Sparc");
+ RegisterTarget<Triple::sparcv9, /*HasJIT=*/true> Y(TheSparcV9Target,
+ "sparcv9", "Sparc V9");
+ RegisterTarget<Triple::sparcel, /*HasJIT=*/true> Z(TheSparcelTarget,
+ "sparcel", "Sparc LE");
+}
OpenPOWER on IntegriCloud