Import a whole bunch of llvm trunk commits to enable self-hosting clang
3.4 on Sparc64 (commit descriptions left out for brevity): r196755 r198028 r198029 r198030 r198145 r198149 r198157 r198565 r199186 r199187 r198280 r198281 r198286 r198480 r198484 r198533 r198567 r198580 r198591 r198592 r198658 r198681 r198738 r198739 r198740 r198893 r198909 r198910 r199014 r199024 r199028 r199031 r199033 r199061 r199775 r199781 r199786 r199940 r199974 r199975 r199977 r200103 r200104 r200112 r200130 r200131 r200141 r200282 r200368 r200373 r200376 r200509 r200617 r200960 r200961 r200962 r200963 r200965 Submitted by: rdivacky
This commit is contained in:
parent
93c4e6d498
commit
48173d357a
Notes:
svn2git
2020-12-20 02:59:44 +00:00
svn path=/projects/clang-sparc64/; revision=262261
@ -371,7 +371,7 @@ namespace llvm {
|
||||
unsigned Encoding,
|
||||
MCStreamer &Streamer) const;
|
||||
|
||||
const MCExpr *
|
||||
virtual const MCExpr *
|
||||
getExprForFDESymbol(const MCSymbol *Sym,
|
||||
unsigned Encoding,
|
||||
MCStreamer &Streamer) const;
|
||||
|
@ -922,6 +922,9 @@ StringRef ELFObjectFile<ELFT>::getFileFormatName() const {
|
||||
return "ELF32-mips";
|
||||
case ELF::EM_PPC:
|
||||
return "ELF32-ppc";
|
||||
case ELF::EM_SPARC:
|
||||
case ELF::EM_SPARC32PLUS:
|
||||
return "ELF32-sparc";
|
||||
default:
|
||||
return "ELF32-unknown";
|
||||
}
|
||||
@ -937,6 +940,8 @@ StringRef ELFObjectFile<ELFT>::getFileFormatName() const {
|
||||
return "ELF64-ppc64";
|
||||
case ELF::EM_S390:
|
||||
return "ELF64-s390";
|
||||
case ELF::EM_SPARCV9:
|
||||
return "ELF64-sparc";
|
||||
default:
|
||||
return "ELF64-unknown";
|
||||
}
|
||||
@ -967,6 +972,13 @@ unsigned ELFObjectFile<ELFT>::getArch() const {
|
||||
: Triple::ppc64;
|
||||
case ELF::EM_S390:
|
||||
return Triple::systemz;
|
||||
|
||||
case ELF::EM_SPARC:
|
||||
case ELF::EM_SPARC32PLUS:
|
||||
return Triple::sparc;
|
||||
case ELF::EM_SPARCV9:
|
||||
return Triple::sparcv9;
|
||||
|
||||
default:
|
||||
return Triple::UnknownArch;
|
||||
}
|
||||
|
@ -1087,6 +1087,94 @@ enum {
|
||||
R_390_IRELATIVE = 61
|
||||
};
|
||||
|
||||
// ELF Relocation type for Sparc.
|
||||
enum {
|
||||
R_SPARC_NONE = 0,
|
||||
R_SPARC_8 = 1,
|
||||
R_SPARC_16 = 2,
|
||||
R_SPARC_32 = 3,
|
||||
R_SPARC_DISP8 = 4,
|
||||
R_SPARC_DISP16 = 5,
|
||||
R_SPARC_DISP32 = 6,
|
||||
R_SPARC_WDISP30 = 7,
|
||||
R_SPARC_WDISP22 = 8,
|
||||
R_SPARC_HI22 = 9,
|
||||
R_SPARC_22 = 10,
|
||||
R_SPARC_13 = 11,
|
||||
R_SPARC_LO10 = 12,
|
||||
R_SPARC_GOT10 = 13,
|
||||
R_SPARC_GOT13 = 14,
|
||||
R_SPARC_GOT22 = 15,
|
||||
R_SPARC_PC10 = 16,
|
||||
R_SPARC_PC22 = 17,
|
||||
R_SPARC_WPLT30 = 18,
|
||||
R_SPARC_COPY = 19,
|
||||
R_SPARC_GLOB_DAT = 20,
|
||||
R_SPARC_JMP_SLOT = 21,
|
||||
R_SPARC_RELATIVE = 22,
|
||||
R_SPARC_UA32 = 23,
|
||||
R_SPARC_PLT32 = 24,
|
||||
R_SPARC_HIPLT22 = 25,
|
||||
R_SPARC_LOPLT10 = 26,
|
||||
R_SPARC_PCPLT32 = 27,
|
||||
R_SPARC_PCPLT22 = 28,
|
||||
R_SPARC_PCPLT10 = 29,
|
||||
R_SPARC_10 = 30,
|
||||
R_SPARC_11 = 31,
|
||||
R_SPARC_64 = 32,
|
||||
R_SPARC_OLO10 = 33,
|
||||
R_SPARC_HH22 = 34,
|
||||
R_SPARC_HM10 = 35,
|
||||
R_SPARC_LM22 = 36,
|
||||
R_SPARC_PC_HH22 = 37,
|
||||
R_SPARC_PC_HM10 = 38,
|
||||
R_SPARC_PC_LM22 = 39,
|
||||
R_SPARC_WDISP16 = 40,
|
||||
R_SPARC_WDISP19 = 41,
|
||||
R_SPARC_7 = 43,
|
||||
R_SPARC_5 = 44,
|
||||
R_SPARC_6 = 45,
|
||||
R_SPARC_DISP64 = 46,
|
||||
R_SPARC_PLT64 = 47,
|
||||
R_SPARC_HIX22 = 48,
|
||||
R_SPARC_LOX10 = 49,
|
||||
R_SPARC_H44 = 50,
|
||||
R_SPARC_M44 = 51,
|
||||
R_SPARC_L44 = 52,
|
||||
R_SPARC_REGISTER = 53,
|
||||
R_SPARC_UA64 = 54,
|
||||
R_SPARC_UA16 = 55,
|
||||
R_SPARC_TLS_GD_HI22 = 56,
|
||||
R_SPARC_TLS_GD_LO10 = 57,
|
||||
R_SPARC_TLS_GD_ADD = 58,
|
||||
R_SPARC_TLS_GD_CALL = 59,
|
||||
R_SPARC_TLS_LDM_HI22 = 60,
|
||||
R_SPARC_TLS_LDM_LO10 = 61,
|
||||
R_SPARC_TLS_LDM_ADD = 62,
|
||||
R_SPARC_TLS_LDM_CALL = 63,
|
||||
R_SPARC_TLS_LDO_HIX22 = 64,
|
||||
R_SPARC_TLS_LDO_LOX10 = 65,
|
||||
R_SPARC_TLS_LDO_ADD = 66,
|
||||
R_SPARC_TLS_IE_HI22 = 67,
|
||||
R_SPARC_TLS_IE_LO10 = 68,
|
||||
R_SPARC_TLS_IE_LD = 69,
|
||||
R_SPARC_TLS_IE_LDX = 70,
|
||||
R_SPARC_TLS_IE_ADD = 71,
|
||||
R_SPARC_TLS_LE_HIX22 = 72,
|
||||
R_SPARC_TLS_LE_LOX10 = 73,
|
||||
R_SPARC_TLS_DTPMOD32 = 74,
|
||||
R_SPARC_TLS_DTPMOD64 = 75,
|
||||
R_SPARC_TLS_DTPOFF32 = 76,
|
||||
R_SPARC_TLS_DTPOFF64 = 77,
|
||||
R_SPARC_TLS_TPOFF32 = 78,
|
||||
R_SPARC_TLS_TPOFF64 = 79,
|
||||
R_SPARC_GOTDATA_HIX22 = 80,
|
||||
R_SPARC_GOTDATA_LOX22 = 81,
|
||||
R_SPARC_GOTDATA_OP_HIX22 = 82,
|
||||
R_SPARC_GOTDATA_OP_LOX22 = 83,
|
||||
R_SPARC_GOTDATA_OP = 84
|
||||
};
|
||||
|
||||
// Section header.
|
||||
struct Elf32_Shdr {
|
||||
Elf32_Word sh_name; // Section name (index into string table)
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "llvm/CodeGen/MachineConstantPool.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineInstrBundle.h"
|
||||
#include "llvm/CodeGen/MachineJumpTableInfo.h"
|
||||
#include "llvm/CodeGen/MachineLoopInfo.h"
|
||||
#include "llvm/CodeGen/MachineModuleInfo.h"
|
||||
@ -2221,14 +2222,13 @@ isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) const {
|
||||
if (!MI.isBranch() || MI.isIndirectBranch())
|
||||
return false;
|
||||
|
||||
// If we are the operands of one of the branches, this is not
|
||||
// a fall through.
|
||||
for (MachineInstr::mop_iterator OI = MI.operands_begin(),
|
||||
OE = MI.operands_end(); OI != OE; ++OI) {
|
||||
const MachineOperand& OP = *OI;
|
||||
if (OP.isJTI())
|
||||
// If we are the operands of one of the branches, this is not a fall
|
||||
// through. Note that targets with delay slots will usually bundle
|
||||
// terminators with the delay slot instruction.
|
||||
for (ConstMIBundleOperands OP(&MI); OP.isValid(); ++OP) {
|
||||
if (OP->isJTI())
|
||||
return false;
|
||||
if (OP.isMBB() && OP.getMBB() == MBB)
|
||||
if (OP->isMBB() && OP->getMBB() == MBB)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
@ -220,10 +220,19 @@ void InstrEmitter::CreateVirtualRegisters(SDNode *Node,
|
||||
unsigned VRBase = 0;
|
||||
const TargetRegisterClass *RC =
|
||||
TRI->getAllocatableClass(TII->getRegClass(II, i, TRI, *MF));
|
||||
// If the register class is unknown for the given definition, then try to
|
||||
// infer one from the value type.
|
||||
if (!RC && i < NumResults)
|
||||
RC = TLI->getRegClassFor(Node->getSimpleValueType(i));
|
||||
// Always let the value type influence the used register class. The
|
||||
// constraints on the instruction may be too lax to represent the value
|
||||
// type correctly. For example, a 64-bit float (X86::FR64) can't live in
|
||||
// the 32-bit float super-class (X86::FR32).
|
||||
if (i < NumResults && TLI->isTypeLegal(Node->getSimpleValueType(i))) {
|
||||
const TargetRegisterClass *VTRC =
|
||||
TLI->getRegClassFor(Node->getSimpleValueType(i));
|
||||
if (RC)
|
||||
VTRC = TRI->getCommonSubClass(RC, VTRC);
|
||||
if (VTRC)
|
||||
RC = VTRC;
|
||||
}
|
||||
|
||||
if (II.OpInfo[i].isOptionalDef()) {
|
||||
// Optional def must be a physical register.
|
||||
unsigned NumResults = CountResults(Node);
|
||||
|
@ -310,6 +310,33 @@ void MCObjectFileInfo::InitELFMCObjectFileInfo(Triple T) {
|
||||
FDEEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_udata8;
|
||||
TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
|
||||
dwarf::DW_EH_PE_udata8;
|
||||
} else if (T.getArch() == Triple::sparc) {
|
||||
if (RelocM == Reloc::PIC_) {
|
||||
LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4;
|
||||
PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
|
||||
dwarf::DW_EH_PE_sdata4;
|
||||
FDEEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4;
|
||||
TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
|
||||
dwarf::DW_EH_PE_sdata4;
|
||||
} else {
|
||||
LSDAEncoding = dwarf::DW_EH_PE_absptr;
|
||||
PersonalityEncoding = dwarf::DW_EH_PE_absptr;
|
||||
FDEEncoding = dwarf::DW_EH_PE_udata4;
|
||||
TTypeEncoding = dwarf::DW_EH_PE_absptr;
|
||||
}
|
||||
} else if (T.getArch() == Triple::sparcv9) {
|
||||
LSDAEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4;
|
||||
if (RelocM == Reloc::PIC_) {
|
||||
PersonalityEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
|
||||
dwarf::DW_EH_PE_sdata4;
|
||||
FDEEncoding = dwarf::DW_EH_PE_pcrel | dwarf::DW_EH_PE_sdata4;
|
||||
TTypeEncoding = dwarf::DW_EH_PE_indirect | dwarf::DW_EH_PE_pcrel |
|
||||
dwarf::DW_EH_PE_sdata4;
|
||||
} else {
|
||||
PersonalityEncoding = dwarf::DW_EH_PE_absptr;
|
||||
FDEEncoding = dwarf::DW_EH_PE_udata4;
|
||||
TTypeEncoding = dwarf::DW_EH_PE_absptr;
|
||||
}
|
||||
} else if (T.getArch() == Triple::systemz) {
|
||||
// All currently-defined code models guarantee that 4-byte PC-relative
|
||||
// values will be in range.
|
||||
|
@ -702,6 +702,98 @@ StringRef getELFRelocationTypeName(uint32_t Machine, uint32_t Type) {
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case ELF::EM_SPARC:
|
||||
case ELF::EM_SPARC32PLUS:
|
||||
case ELF::EM_SPARCV9:
|
||||
switch (Type) {
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_NONE);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_8);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_16);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_32);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_DISP8);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_DISP16);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_DISP32);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_WDISP30);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_WDISP22);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_HI22);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_22);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_13);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_LO10);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOT10);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOT13);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOT22);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PC10);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PC22);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_WPLT30);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_COPY);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GLOB_DAT);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_JMP_SLOT);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_RELATIVE);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_UA32);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PLT32);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_HIPLT22);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_LOPLT10);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PCPLT32);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PCPLT22);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PCPLT10);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_10);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_11);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_64);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_OLO10);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_HH22);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_HM10);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_LM22);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PC_HH22);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PC_HM10);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PC_LM22);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_WDISP16);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_WDISP19);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_7);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_5);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_6);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_DISP64);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_PLT64);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_HIX22);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_LOX10);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_H44);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_M44);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_L44);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_REGISTER);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_UA64);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_UA16);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_GD_HI22);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_GD_LO10);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_GD_ADD);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_GD_CALL);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LDM_HI22);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LDM_LO10);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LDM_ADD);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LDM_CALL);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LDO_HIX22);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LDO_LOX10);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LDO_ADD);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_IE_HI22);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_IE_LO10);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_IE_LD);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_IE_LDX);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_IE_ADD);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LE_HIX22);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_LE_LOX10);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_DTPMOD32);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_DTPMOD64);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_DTPOFF32);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_DTPOFF64);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_TPOFF32);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_TLS_TPOFF64);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOTDATA_HIX22);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOTDATA_LOX22);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOTDATA_OP_HIX22);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOTDATA_OP_LOX22);
|
||||
LLVM_ELF_SWITCH_RELOC_TYPE_NAME(R_SPARC_GOTDATA_OP);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
@ -156,7 +156,7 @@ void ARMTargetLowering::addDRTypeForNEON(MVT VT) {
|
||||
}
|
||||
|
||||
void ARMTargetLowering::addQRTypeForNEON(MVT VT) {
|
||||
addRegisterClass(VT, &ARM::QPRRegClass);
|
||||
addRegisterClass(VT, &ARM::DPairRegClass);
|
||||
addTypeForNEON(VT, MVT::v2f64, MVT::v4i32);
|
||||
}
|
||||
|
||||
|
828
contrib/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
Normal file
828
contrib/llvm/lib/Target/Sparc/AsmParser/SparcAsmParser.cpp
Normal file
@ -0,0 +1,828 @@
|
||||
//===-- 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/MCParser/MCParsedAsmOperand.h"
|
||||
#include "llvm/MC/MCStreamer.h"
|
||||
#include "llvm/MC/MCSubtargetInfo.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,
|
||||
SmallVectorImpl<MCParsedAsmOperand*> &Operands,
|
||||
MCStreamer &Out, unsigned &ErrorInfo,
|
||||
bool MatchingInlineAsm);
|
||||
bool ParseRegister(unsigned &RegNo, SMLoc &StartLoc, SMLoc &EndLoc);
|
||||
bool ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
|
||||
SMLoc NameLoc,
|
||||
SmallVectorImpl<MCParsedAsmOperand*> &Operands);
|
||||
bool ParseDirective(AsmToken DirectiveID);
|
||||
|
||||
virtual unsigned validateTargetOperandClass(MCParsedAsmOperand *Op,
|
||||
unsigned Kind);
|
||||
|
||||
// Custom parse functions for Sparc specific operands.
|
||||
OperandMatchResultTy
|
||||
parseMEMOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands);
|
||||
|
||||
OperandMatchResultTy
|
||||
parseOperand(SmallVectorImpl<MCParsedAsmOperand*> &Operands,
|
||||
StringRef Name);
|
||||
|
||||
OperandMatchResultTy
|
||||
parseSparcAsmOperand(SparcOperand *&Operand);
|
||||
|
||||
// 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);
|
||||
|
||||
public:
|
||||
SparcAsmParser(MCSubtargetInfo &sti, MCAsmParser &parser,
|
||||
const MCInstrInfo &MII)
|
||||
: 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 };
|
||||
|
||||
|
||||
/// 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_CCReg,
|
||||
rk_Y
|
||||
};
|
||||
private:
|
||||
enum KindTy {
|
||||
k_Token,
|
||||
k_Register,
|
||||
k_Immediate,
|
||||
k_MemoryReg,
|
||||
k_MemoryImm
|
||||
} Kind;
|
||||
|
||||
SMLoc StartLoc, EndLoc;
|
||||
|
||||
SparcOperand(KindTy K) : MCParsedAsmOperand(), Kind(K) {}
|
||||
|
||||
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:
|
||||
bool isToken() const { return Kind == k_Token; }
|
||||
bool isReg() const { return Kind == k_Register; }
|
||||
bool isImm() const { return Kind == k_Immediate; }
|
||||
bool isMem() const { 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 {
|
||||
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 {
|
||||
return StartLoc;
|
||||
}
|
||||
/// getEndLoc - Get the location of the last token of this operand.
|
||||
SMLoc getEndLoc() const {
|
||||
return EndLoc;
|
||||
}
|
||||
|
||||
virtual void print(raw_ostream &OS) const {
|
||||
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() != 0);
|
||||
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 == 0)
|
||||
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 SparcOperand *CreateToken(StringRef Str, SMLoc S) {
|
||||
SparcOperand *Op = new SparcOperand(k_Token);
|
||||
Op->Tok.Data = Str.data();
|
||||
Op->Tok.Length = Str.size();
|
||||
Op->StartLoc = S;
|
||||
Op->EndLoc = S;
|
||||
return Op;
|
||||
}
|
||||
|
||||
static SparcOperand *CreateReg(unsigned RegNum,
|
||||
unsigned Kind,
|
||||
SMLoc S, SMLoc E) {
|
||||
SparcOperand *Op = new SparcOperand(k_Register);
|
||||
Op->Reg.RegNum = RegNum;
|
||||
Op->Reg.Kind = (SparcOperand::RegisterKind)Kind;
|
||||
Op->StartLoc = S;
|
||||
Op->EndLoc = E;
|
||||
return Op;
|
||||
}
|
||||
|
||||
static SparcOperand *CreateImm(const MCExpr *Val, SMLoc S, SMLoc E) {
|
||||
SparcOperand *Op = new SparcOperand(k_Immediate);
|
||||
Op->Imm.Val = Val;
|
||||
Op->StartLoc = S;
|
||||
Op->EndLoc = E;
|
||||
return Op;
|
||||
}
|
||||
|
||||
static SparcOperand *MorphToDoubleReg(SparcOperand *Op) {
|
||||
unsigned Reg = Op->getReg();
|
||||
assert(Op->Reg.Kind == rk_FloatReg);
|
||||
unsigned regIdx = Reg - Sparc::F0;
|
||||
if (regIdx % 2 || regIdx > 31)
|
||||
return 0;
|
||||
Op->Reg.RegNum = DoubleRegs[regIdx / 2];
|
||||
Op->Reg.Kind = rk_DoubleReg;
|
||||
return Op;
|
||||
}
|
||||
|
||||
static SparcOperand *MorphToQuadReg(SparcOperand *Op) {
|
||||
unsigned Reg = Op->getReg();
|
||||
unsigned regIdx = 0;
|
||||
switch (Op->Reg.Kind) {
|
||||
default: assert(0 && "Unexpected register kind!");
|
||||
case rk_FloatReg:
|
||||
regIdx = Reg - Sparc::F0;
|
||||
if (regIdx % 4 || regIdx > 31)
|
||||
return 0;
|
||||
Reg = QuadFPRegs[regIdx / 4];
|
||||
break;
|
||||
case rk_DoubleReg:
|
||||
regIdx = Reg - Sparc::D0;
|
||||
if (regIdx % 2 || regIdx > 31)
|
||||
return 0;
|
||||
Reg = QuadFPRegs[regIdx / 2];
|
||||
break;
|
||||
}
|
||||
Op->Reg.RegNum = Reg;
|
||||
Op->Reg.Kind = rk_QuadReg;
|
||||
return Op;
|
||||
}
|
||||
|
||||
static SparcOperand *MorphToMEMrr(unsigned Base, SparcOperand *Op) {
|
||||
unsigned offsetReg = Op->getReg();
|
||||
Op->Kind = k_MemoryReg;
|
||||
Op->Mem.Base = Base;
|
||||
Op->Mem.OffsetReg = offsetReg;
|
||||
Op->Mem.Off = 0;
|
||||
return Op;
|
||||
}
|
||||
|
||||
static SparcOperand *CreateMEMri(unsigned Base,
|
||||
const MCExpr *Off,
|
||||
SMLoc S, SMLoc E) {
|
||||
SparcOperand *Op = new SparcOperand(k_MemoryImm);
|
||||
Op->Mem.Base = Base;
|
||||
Op->Mem.OffsetReg = 0;
|
||||
Op->Mem.Off = Off;
|
||||
Op->StartLoc = S;
|
||||
Op->EndLoc = E;
|
||||
return Op;
|
||||
}
|
||||
|
||||
static SparcOperand *MorphToMEMri(unsigned Base, 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
|
||||
|
||||
bool SparcAsmParser::
|
||||
MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
|
||||
SmallVectorImpl<MCParsedAsmOperand*> &Operands,
|
||||
MCStreamer &Out, unsigned &ErrorInfo,
|
||||
bool MatchingInlineAsm) {
|
||||
MCInst Inst;
|
||||
SmallVector<MCInst, 8> Instructions;
|
||||
unsigned MatchResult = MatchInstructionImpl(Operands, Inst, ErrorInfo,
|
||||
MatchingInlineAsm);
|
||||
switch (MatchResult) {
|
||||
default:
|
||||
break;
|
||||
|
||||
case Match_Success: {
|
||||
Inst.setLoc(IDLoc);
|
||||
Out.EmitInstruction(Inst);
|
||||
return false;
|
||||
}
|
||||
|
||||
case Match_MissingFeature:
|
||||
return Error(IDLoc,
|
||||
"instruction requires a CPU feature not currently enabled");
|
||||
|
||||
case Match_InvalidOperand: {
|
||||
SMLoc ErrorLoc = IDLoc;
|
||||
if (ErrorInfo != ~0U) {
|
||||
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");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
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");
|
||||
}
|
||||
|
||||
bool SparcAsmParser::
|
||||
ParseInstruction(ParseInstructionInfo &Info, StringRef Name,
|
||||
SMLoc NameLoc,
|
||||
SmallVectorImpl<MCParsedAsmOperand*> &Operands)
|
||||
{
|
||||
// Check if we have valid mnemonic.
|
||||
if (!mnemonicIsValid(Name, 0)) {
|
||||
Parser.eatToEndOfStatement();
|
||||
return Error(NameLoc, "Unknown instruction");
|
||||
}
|
||||
// First operand in MCInst is instruction mnemonic.
|
||||
Operands.push_back(SparcOperand::CreateToken(Name, NameLoc));
|
||||
|
||||
if (getLexer().isNot(AsmToken::EndOfStatement)) {
|
||||
// Read the first operand.
|
||||
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)
|
||||
{
|
||||
// Ignore all directives for now.
|
||||
Parser.eatToEndOfStatement();
|
||||
return false;
|
||||
}
|
||||
|
||||
SparcAsmParser::OperandMatchResultTy SparcAsmParser::
|
||||
parseMEMOperand(SmallVectorImpl<MCParsedAsmOperand*> &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::CreateMEMri(BaseReg, 0, S, E));
|
||||
return MatchOperand_Success;
|
||||
|
||||
case AsmToken:: Plus:
|
||||
Parser.Lex(); // Eat the '+'
|
||||
break;
|
||||
case AsmToken::Minus:
|
||||
break;
|
||||
}
|
||||
|
||||
SparcOperand *Offset = 0;
|
||||
OperandMatchResultTy ResTy = parseSparcAsmOperand(Offset);
|
||||
if (ResTy != MatchOperand_Success || !Offset)
|
||||
return MatchOperand_NoMatch;
|
||||
|
||||
Offset = (Offset->isImm()
|
||||
? SparcOperand::MorphToMEMri(BaseReg, Offset)
|
||||
: SparcOperand::MorphToMEMrr(BaseReg, Offset));
|
||||
|
||||
Operands.push_back(Offset);
|
||||
return MatchOperand_Success;
|
||||
}
|
||||
|
||||
SparcAsmParser::OperandMatchResultTy SparcAsmParser::
|
||||
parseOperand(SmallVectorImpl<MCParsedAsmOperand*> &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 ]
|
||||
return MatchOperand_Success;
|
||||
}
|
||||
|
||||
SparcOperand *Op = 0;
|
||||
ResTy = parseSparcAsmOperand(Op);
|
||||
if (ResTy != MatchOperand_Success || !Op)
|
||||
return MatchOperand_ParseFail;
|
||||
|
||||
// Push the parsed operand into the list of operands
|
||||
Operands.push_back(Op);
|
||||
|
||||
return MatchOperand_Success;
|
||||
}
|
||||
|
||||
SparcAsmParser::OperandMatchResultTy
|
||||
SparcAsmParser::parseSparcAsmOperand(SparcOperand *&Op)
|
||||
{
|
||||
|
||||
SMLoc S = Parser.getTok().getLoc();
|
||||
SMLoc E = SMLoc::getFromPointer(Parser.getTok().getLoc().getPointer() - 1);
|
||||
const MCExpr *EVal;
|
||||
|
||||
Op = 0;
|
||||
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::Y:
|
||||
Op = SparcOperand::CreateToken("%y", S);
|
||||
break;
|
||||
|
||||
case Sparc::ICC:
|
||||
if (name == "xcc")
|
||||
Op = SparcOperand::CreateToken("%xcc", S);
|
||||
else
|
||||
Op = SparcOperand::CreateToken("%icc", S);
|
||||
break;
|
||||
|
||||
case Sparc::FCC:
|
||||
assert(name == "fcc0" && "Cannot handle %fcc other than %fcc0 yet");
|
||||
Op = SparcOperand::CreateToken("%fcc0", 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:
|
||||
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());
|
||||
Op = SparcOperand::CreateImm(Res, S, E);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
return (Op) ? MatchOperand_Success : MatchOperand_ParseFail;
|
||||
}
|
||||
|
||||
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_Y;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (name.equals("icc")) {
|
||||
RegNo = Sparc::ICC;
|
||||
RegKind = SparcOperand::rk_CCReg;
|
||||
return true;
|
||||
}
|
||||
|
||||
if (name.equals("xcc")) {
|
||||
// FIXME:: check 64bit.
|
||||
RegNo = Sparc::ICC;
|
||||
RegKind = SparcOperand::rk_CCReg;
|
||||
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::FCC;
|
||||
RegKind = SparcOperand::rk_CCReg;
|
||||
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;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
EVal = SparcMCExpr::Create(VK, subExpr, getContext());
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
extern "C" void LLVMInitializeSparcAsmParser() {
|
||||
RegisterMCAsmParser<SparcAsmParser> A(TheSparcTarget);
|
||||
RegisterMCAsmParser<SparcAsmParser> B(TheSparcV9Target);
|
||||
}
|
||||
|
||||
#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;
|
||||
}
|
@ -19,6 +19,7 @@
|
||||
#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"
|
||||
@ -55,15 +56,17 @@ namespace {
|
||||
bool runOnMachineBasicBlock(MachineBasicBlock &MBB);
|
||||
bool runOnMachineFunction(MachineFunction &F) {
|
||||
bool Changed = false;
|
||||
|
||||
// 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;
|
||||
}
|
||||
|
||||
bool isDelayFiller(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator candidate);
|
||||
|
||||
void insertCallDefsUses(MachineBasicBlock::iterator MI,
|
||||
SmallSet<unsigned, 32>& RegDefs,
|
||||
SmallSet<unsigned, 32>& RegUses);
|
||||
@ -152,6 +155,10 @@ bool Filler::runOnMachineBasicBlock(MachineBasicBlock &MBB) {
|
||||
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;
|
||||
@ -209,7 +216,7 @@ Filler::findDelayInstr(MachineBasicBlock &MBB,
|
||||
|| I->isInlineAsm()
|
||||
|| I->isLabel()
|
||||
|| I->hasDelaySlot()
|
||||
|| isDelayFiller(MBB, I))
|
||||
|| I->isBundledWithSucc())
|
||||
break;
|
||||
|
||||
if (delayHasHazard(I, sawLoad, sawStore, RegDefs, RegUses)) {
|
||||
@ -278,19 +285,19 @@ void Filler::insertCallDefsUses(MachineBasicBlock::iterator MI,
|
||||
switch(MI->getOpcode()) {
|
||||
default: llvm_unreachable("Unknown opcode.");
|
||||
case SP::CALL: break;
|
||||
case SP::JMPLrr:
|
||||
case SP::JMPLri:
|
||||
case SP::CALLrr:
|
||||
case SP::CALLri:
|
||||
assert(MI->getNumOperands() >= 2);
|
||||
const MachineOperand &Reg = MI->getOperand(0);
|
||||
assert(Reg.isReg() && "JMPL first operand is not a register.");
|
||||
assert(Reg.isUse() && "JMPL first operand is not a use.");
|
||||
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() && "JMPLrr second operand is not a register.");
|
||||
assert(RegOrImm.isUse() && "JMPLrr second operand is not a use.");
|
||||
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;
|
||||
}
|
||||
@ -332,18 +339,6 @@ bool Filler::IsRegInSet(SmallSet<unsigned, 32>& RegSet, unsigned Reg)
|
||||
return false;
|
||||
}
|
||||
|
||||
// return true if the candidate is a delay filler.
|
||||
bool Filler::isDelayFiller(MachineBasicBlock &MBB,
|
||||
MachineBasicBlock::iterator candidate)
|
||||
{
|
||||
if (candidate == MBB.begin())
|
||||
return false;
|
||||
if (candidate->getOpcode() == SP::UNIMP)
|
||||
return true;
|
||||
--candidate;
|
||||
return candidate->hasDelaySlot();
|
||||
}
|
||||
|
||||
bool Filler::needsUnimp(MachineBasicBlock::iterator I, unsigned &StructSize)
|
||||
{
|
||||
if (!I->isCall())
|
||||
@ -353,8 +348,8 @@ bool Filler::needsUnimp(MachineBasicBlock::iterator I, unsigned &StructSize)
|
||||
switch (I->getOpcode()) {
|
||||
default: llvm_unreachable("Unknown call opcode.");
|
||||
case SP::CALL: structSizeOpNum = 1; break;
|
||||
case SP::JMPLrr:
|
||||
case SP::JMPLri: structSizeOpNum = 2; break;
|
||||
case SP::CALLrr:
|
||||
case SP::CALLri: structSizeOpNum = 2; break;
|
||||
case SP::TLS_CALL: return false;
|
||||
}
|
||||
|
||||
@ -484,10 +479,10 @@ bool Filler::tryCombineRestoreWithPrevInst(MachineBasicBlock &MBB,
|
||||
&& MBBI->getOperand(1).getReg() == SP::G0
|
||||
&& MBBI->getOperand(2).getReg() == SP::G0);
|
||||
|
||||
MachineBasicBlock::iterator PrevInst = MBBI; --PrevInst;
|
||||
MachineBasicBlock::iterator PrevInst = llvm::prior(MBBI);
|
||||
|
||||
// It cannot combine with a delay filler.
|
||||
if (isDelayFiller(MBB, PrevInst))
|
||||
// It cannot be combined with a bundled instruction.
|
||||
if (PrevInst->isBundledWithSucc())
|
||||
return false;
|
||||
|
||||
const TargetInstrInfo *TII = TM.getInstrInfo();
|
||||
|
228
contrib/llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp
Normal file
228
contrib/llvm/lib/Target/Sparc/Disassembler/SparcDisassembler.cpp
Normal file
@ -0,0 +1,228 @@
|
||||
//===- 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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define DEBUG_TYPE "sparc-disassembler"
|
||||
|
||||
#include "Sparc.h"
|
||||
#include "SparcRegisterInfo.h"
|
||||
#include "SparcSubtarget.h"
|
||||
#include "llvm/MC/MCDisassembler.h"
|
||||
#include "llvm/MC/MCFixedLenDisassembler.h"
|
||||
#include "llvm/Support/MemoryObject.h"
|
||||
#include "llvm/Support/TargetRegistry.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
typedef MCDisassembler::DecodeStatus DecodeStatus;
|
||||
|
||||
namespace {
|
||||
|
||||
/// SparcDisassembler - a disassembler class for Sparc.
|
||||
class SparcDisassembler : public MCDisassembler {
|
||||
public:
|
||||
/// Constructor - Initializes the disassembler.
|
||||
///
|
||||
SparcDisassembler(const MCSubtargetInfo &STI, const MCRegisterInfo *Info) :
|
||||
MCDisassembler(STI), RegInfo(Info)
|
||||
{}
|
||||
virtual ~SparcDisassembler() {}
|
||||
|
||||
const MCRegisterInfo *getRegInfo() const { return RegInfo.get(); }
|
||||
|
||||
/// getInstruction - See MCDisassembler.
|
||||
virtual DecodeStatus getInstruction(MCInst &instr,
|
||||
uint64_t &size,
|
||||
const MemoryObject ®ion,
|
||||
uint64_t address,
|
||||
raw_ostream &vStream,
|
||||
raw_ostream &cStream) const;
|
||||
private:
|
||||
OwningPtr<const MCRegisterInfo> RegInfo;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
namespace llvm {
|
||||
extern Target TheSparcTarget, TheSparcV9Target;
|
||||
}
|
||||
|
||||
static MCDisassembler *createSparcDisassembler(
|
||||
const Target &T,
|
||||
const MCSubtargetInfo &STI) {
|
||||
return new SparcDisassembler(STI, T.createMCRegInfo(""));
|
||||
}
|
||||
|
||||
|
||||
extern "C" void LLVMInitializeSparcDisassembler() {
|
||||
// Register the disassembler.
|
||||
TargetRegistry::RegisterMCDisassembler(TheSparcTarget,
|
||||
createSparcDisassembler);
|
||||
TargetRegistry::RegisterMCDisassembler(TheSparcV9Target,
|
||||
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 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;
|
||||
}
|
||||
|
||||
|
||||
#include "SparcGenDisassemblerTables.inc"
|
||||
|
||||
/// readInstruction - read four bytes from the MemoryObject
|
||||
/// and return 32 bit word.
|
||||
static DecodeStatus readInstruction32(const MemoryObject ®ion,
|
||||
uint64_t address,
|
||||
uint64_t &size,
|
||||
uint32_t &insn) {
|
||||
uint8_t Bytes[4];
|
||||
|
||||
// We want to read exactly 4 Bytes of data.
|
||||
if (region.readBytes(address, 4, Bytes) == -1) {
|
||||
size = 0;
|
||||
return MCDisassembler::Fail;
|
||||
}
|
||||
|
||||
// Encoded as a big-endian 32-bit word in the stream.
|
||||
insn = (Bytes[3] << 0) |
|
||||
(Bytes[2] << 8) |
|
||||
(Bytes[1] << 16) |
|
||||
(Bytes[0] << 24);
|
||||
|
||||
return MCDisassembler::Success;
|
||||
}
|
||||
|
||||
|
||||
DecodeStatus
|
||||
SparcDisassembler::getInstruction(MCInst &instr,
|
||||
uint64_t &Size,
|
||||
const MemoryObject &Region,
|
||||
uint64_t Address,
|
||||
raw_ostream &vStream,
|
||||
raw_ostream &cStream) const {
|
||||
uint32_t Insn;
|
||||
|
||||
DecodeStatus Result = readInstruction32(Region, Address, Size, Insn);
|
||||
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;
|
||||
}
|
130
contrib/llvm/lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp
Normal file
130
contrib/llvm/lib/Target/Sparc/InstPrinter/SparcInstPrinter.cpp
Normal file
@ -0,0 +1,130 @@
|
||||
//===-- 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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define DEBUG_TYPE "asm-printer"
|
||||
#include "SparcInstPrinter.h"
|
||||
|
||||
#include "Sparc.h"
|
||||
#include "MCTargetDesc/SparcBaseInfo.h"
|
||||
#include "llvm/MC/MCExpr.h"
|
||||
#include "llvm/MC/MCInst.h"
|
||||
#include "llvm/MC/MCSymbol.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
using namespace llvm;
|
||||
|
||||
#define GET_INSTRUCTION_NAME
|
||||
#define PRINT_ALIAS_INSTR
|
||||
#include "SparcGenAsmWriter.inc"
|
||||
|
||||
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)
|
||||
{
|
||||
if (!printAliasInstr(MI, O) && !printSparcAliasInstr(MI, O))
|
||||
printInstruction(MI, O);
|
||||
printAnnotation(O, Annot);
|
||||
}
|
||||
|
||||
bool SparcInstPrinter::printSparcAliasInstr(const MCInst *MI, 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
|
||||
O << "\tjmp "; printMemOperand(MI, 1, O);
|
||||
return true;
|
||||
case SP::O7: // call $addr
|
||||
O << "\tcall "; printMemOperand(MI, 1, O);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SparcInstPrinter::printOperand(const MCInst *MI, int opNum,
|
||||
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);
|
||||
}
|
||||
|
||||
void SparcInstPrinter::printMemOperand(const MCInst *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;
|
||||
}
|
||||
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, O);
|
||||
}
|
||||
|
||||
void SparcInstPrinter::printCCOperand(const MCInst *MI, int opNum,
|
||||
raw_ostream &O)
|
||||
{
|
||||
int CC = (int)MI->getOperand(opNum).getImm();
|
||||
switch (MI->getOpcode()) {
|
||||
default: break;
|
||||
case SP::FBCOND:
|
||||
case SP::MOVFCCrr:
|
||||
case SP::MOVFCCri:
|
||||
case SP::FMOVS_FCC:
|
||||
case SP::FMOVD_FCC:
|
||||
case SP::FMOVQ_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,
|
||||
raw_ostream &O)
|
||||
{
|
||||
assert(0 && "FIXME: Implement SparcInstPrinter::printGetPCX.");
|
||||
return true;
|
||||
}
|
48
contrib/llvm/lib/Target/Sparc/InstPrinter/SparcInstPrinter.h
Normal file
48
contrib/llvm/lib/Target/Sparc/InstPrinter/SparcInstPrinter.h
Normal file
@ -0,0 +1,48 @@
|
||||
//===-- 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 SparcINSTPRINTER_H
|
||||
#define SparcINSTPRINTER_H
|
||||
|
||||
#include "llvm/MC/MCInstPrinter.h"
|
||||
|
||||
namespace llvm {
|
||||
|
||||
class MCOperand;
|
||||
|
||||
class SparcInstPrinter : public MCInstPrinter {
|
||||
public:
|
||||
SparcInstPrinter(const MCAsmInfo &MAI,
|
||||
const MCInstrInfo &MII,
|
||||
const MCRegisterInfo &MRI)
|
||||
: MCInstPrinter(MAI, MII, MRI) {}
|
||||
|
||||
virtual void printRegName(raw_ostream &OS, unsigned RegNo) const;
|
||||
virtual void printInst(const MCInst *MI, raw_ostream &O, StringRef Annot);
|
||||
bool printSparcAliasInstr(const MCInst *MI, raw_ostream &OS);
|
||||
|
||||
// Autogenerated by tblgen.
|
||||
void printInstruction(const MCInst *MI, raw_ostream &O);
|
||||
bool printAliasInstr(const MCInst *MI, raw_ostream &O);
|
||||
static const char *getRegisterName(unsigned RegNo);
|
||||
|
||||
void printOperand(const MCInst *MI, int opNum, raw_ostream &OS);
|
||||
void printMemOperand(const MCInst *MI, int opNum, raw_ostream &OS,
|
||||
const char *Modifier = 0);
|
||||
void printCCOperand(const MCInst *MI, int opNum, raw_ostream &OS);
|
||||
bool printGetPCX(const MCInst *MI, unsigned OpNo, raw_ostream &OS);
|
||||
|
||||
};
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
251
contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
Normal file
251
contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcAsmBackend.cpp
Normal file
@ -0,0 +1,251 @@
|
||||
//===-- 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/SparcMCTargetDesc.h"
|
||||
#include "MCTargetDesc/SparcFixupKinds.h"
|
||||
#include "llvm/MC/MCELFObjectWriter.h"
|
||||
#include "llvm/MC/MCFixupKindInfo.h"
|
||||
#include "llvm/MC/MCObjectWriter.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_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 {
|
||||
const Target &TheTarget;
|
||||
public:
|
||||
SparcAsmBackend(const Target &T) : MCAsmBackend(), TheTarget(T) {}
|
||||
|
||||
unsigned getNumFixupKinds() const {
|
||||
return Sparc::NumTargetFixupKinds;
|
||||
}
|
||||
|
||||
const MCFixupKindInfo &getFixupKindInfo(MCFixupKind Kind) const {
|
||||
const static MCFixupKindInfo Infos[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_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 }
|
||||
};
|
||||
|
||||
if (Kind < FirstTargetFixupKind)
|
||||
return MCAsmBackend::getFixupKindInfo(Kind);
|
||||
|
||||
assert(unsigned(Kind - FirstTargetFixupKind) < getNumFixupKinds() &&
|
||||
"Invalid kind!");
|
||||
return Infos[Kind - FirstTargetFixupKind];
|
||||
}
|
||||
|
||||
void processFixupValue(const MCAssembler &Asm,
|
||||
const MCAsmLayout &Layout,
|
||||
const MCFixup &Fixup,
|
||||
const MCFragment *DF,
|
||||
MCValue & Target,
|
||||
uint64_t &Value,
|
||||
bool &IsResolved) {
|
||||
switch ((Sparc::Fixups)Fixup.getKind()) {
|
||||
default: break;
|
||||
case Sparc::fixup_sparc_wplt30:
|
||||
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 {
|
||||
// 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 {
|
||||
// FIXME.
|
||||
assert(0 && "fixupNeedsRelaxation() unimplemented");
|
||||
return false;
|
||||
}
|
||||
void relaxInstruction(const MCInst &Inst, MCInst &Res) const {
|
||||
// FIXME.
|
||||
assert(0 && "relaxInstruction() unimplemented");
|
||||
}
|
||||
|
||||
bool writeNopData(uint64_t Count, MCObjectWriter *OW) const {
|
||||
// FIXME: Zero fill for now.
|
||||
for (uint64_t i = 0; i != Count; ++i)
|
||||
OW->Write8(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool is64Bit() const {
|
||||
StringRef name = TheTarget.getName();
|
||||
return name == "sparcv9";
|
||||
}
|
||||
};
|
||||
|
||||
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) const {
|
||||
|
||||
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)
|
||||
Data[Offset + i] |= uint8_t((Value >> ((4 - i - 1)*8)) & 0xff);
|
||||
|
||||
}
|
||||
|
||||
MCObjectWriter *createObjectWriter(raw_ostream &OS) const {
|
||||
uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(OSType);
|
||||
return createSparcELFObjectWriter(OS, is64Bit(), OSABI);
|
||||
}
|
||||
|
||||
virtual bool doesSectionRequireSymbols(const MCSection &Section) const {
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
} // end anonymous namespace
|
||||
|
||||
|
||||
MCAsmBackend *llvm::createSparcAsmBackend(const Target &T,
|
||||
const MCRegisterInfo &MRI,
|
||||
StringRef TT,
|
||||
StringRef CPU) {
|
||||
return new ELFSparcAsmBackend(T, Triple(TT).getOS());
|
||||
}
|
@ -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) {}
|
||||
|
||||
virtual ~SparcELFObjectWriter() {}
|
||||
protected:
|
||||
virtual unsigned GetRelocType(const MCValue &Target, const MCFixup &Fixup,
|
||||
bool IsPCRel, bool IsRelocWithSymbol,
|
||||
int64_t Addend) const;
|
||||
|
||||
virtual const MCSymbol *ExplicitRelSym(const MCAssembler &Asm,
|
||||
const MCValue &Target,
|
||||
const MCFragment &F,
|
||||
const MCFixup &Fixup,
|
||||
bool IsPCRel) const;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
unsigned SparcELFObjectWriter::GetRelocType(const MCValue &Target,
|
||||
const MCFixup &Fixup,
|
||||
bool IsPCRel,
|
||||
bool IsRelocWithSymbol,
|
||||
int64_t Addend) 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;
|
||||
}
|
||||
|
||||
const MCSymbol *SparcELFObjectWriter::ExplicitRelSym(const MCAssembler &Asm,
|
||||
const MCValue &Target,
|
||||
const MCFragment &F,
|
||||
const MCFixup &Fixup,
|
||||
bool IsPCRel) const {
|
||||
|
||||
if (!Target.getSymA())
|
||||
return NULL;
|
||||
switch((unsigned)Fixup.getKind()) {
|
||||
default: break;
|
||||
case Sparc::fixup_sparc_got22:
|
||||
case Sparc::fixup_sparc_got10:
|
||||
return &Target.getSymA()->getSymbol().AliasedSymbol();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
MCObjectWriter *llvm::createSparcELFObjectWriter(raw_ostream &OS,
|
||||
bool Is64Bit,
|
||||
uint8_t OSABI) {
|
||||
MCELFObjectTargetWriter *MOTW = new SparcELFObjectWriter(Is64Bit, OSABI);
|
||||
return createELFObjectWriter(MOTW, OS, /*IsLittleEndian=*/false);
|
||||
}
|
93
contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h
Normal file
93
contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcFixupKinds.h
Normal file
@ -0,0 +1,93 @@
|
||||
//===-- 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_SPARC_FIXUPKINDS_H
|
||||
#define LLVM_SPARC_FIXUPKINDS_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_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
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
@ -12,7 +12,9 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "SparcMCAsmInfo.h"
|
||||
#include "SparcMCExpr.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/MC/MCStreamer.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
@ -44,4 +46,27 @@ SparcELFMCAsmInfo::SparcELFMCAsmInfo(StringRef TT) {
|
||||
PrivateGlobalPrefix = ".L";
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
|
@ -17,13 +17,20 @@
|
||||
#include "llvm/MC/MCAsmInfoELF.h"
|
||||
|
||||
namespace llvm {
|
||||
class StringRef;
|
||||
class StringRef;
|
||||
|
||||
class SparcELFMCAsmInfo : public MCAsmInfoELF {
|
||||
virtual void anchor();
|
||||
public:
|
||||
explicit SparcELFMCAsmInfo(StringRef TT);
|
||||
};
|
||||
class SparcELFMCAsmInfo : public MCAsmInfoELF {
|
||||
virtual void anchor();
|
||||
public:
|
||||
explicit SparcELFMCAsmInfo(StringRef TT);
|
||||
virtual const MCExpr* getExprForPersonalitySymbol(const MCSymbol *Sym,
|
||||
unsigned Encoding,
|
||||
MCStreamer &Streamer) const;
|
||||
virtual const MCExpr* getExprForFDESymbol(const MCSymbol *Sym,
|
||||
unsigned Encoding,
|
||||
MCStreamer &Streamer) const;
|
||||
|
||||
};
|
||||
|
||||
} // namespace llvm
|
||||
|
||||
|
@ -0,0 +1,176 @@
|
||||
//===-- 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.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define DEBUG_TYPE "mccodeemitter"
|
||||
#include "SparcMCExpr.h"
|
||||
#include "SparcMCTargetDesc.h"
|
||||
#include "MCTargetDesc/SparcFixupKinds.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/ADT/Statistic.h"
|
||||
#include "llvm/MC/MCSymbol.h"
|
||||
#include "llvm/Support/raw_ostream.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
STATISTIC(MCNumEmitted, "Number of MC instructions emitted");
|
||||
|
||||
namespace {
|
||||
class SparcMCCodeEmitter : public MCCodeEmitter {
|
||||
SparcMCCodeEmitter(const SparcMCCodeEmitter &) LLVM_DELETED_FUNCTION;
|
||||
void operator=(const SparcMCCodeEmitter &) LLVM_DELETED_FUNCTION;
|
||||
MCContext &Ctx;
|
||||
|
||||
public:
|
||||
SparcMCCodeEmitter(MCContext &ctx): Ctx(ctx) {}
|
||||
|
||||
~SparcMCCodeEmitter() {}
|
||||
|
||||
void EncodeInstruction(const MCInst &MI, raw_ostream &OS,
|
||||
SmallVectorImpl<MCFixup> &Fixups) const;
|
||||
|
||||
// getBinaryCodeForInstr - TableGen'erated function for getting the
|
||||
// binary encoding for an instruction.
|
||||
uint64_t getBinaryCodeForInstr(const MCInst &MI,
|
||||
SmallVectorImpl<MCFixup> &Fixups) 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;
|
||||
|
||||
unsigned getCallTargetOpValue(const MCInst &MI, unsigned OpNo,
|
||||
SmallVectorImpl<MCFixup> &Fixups) const;
|
||||
unsigned getBranchTargetOpValue(const MCInst &MI, unsigned OpNo,
|
||||
SmallVectorImpl<MCFixup> &Fixups) const;
|
||||
|
||||
};
|
||||
} // end anonymous namespace
|
||||
|
||||
MCCodeEmitter *llvm::createSparcMCCodeEmitter(const MCInstrInfo &MCII,
|
||||
const MCRegisterInfo &MRI,
|
||||
const MCSubtargetInfo &STI,
|
||||
MCContext &Ctx) {
|
||||
return new SparcMCCodeEmitter(Ctx);
|
||||
}
|
||||
|
||||
void SparcMCCodeEmitter::
|
||||
EncodeInstruction(const MCInst &MI, raw_ostream &OS,
|
||||
SmallVectorImpl<MCFixup> &Fixups) const {
|
||||
unsigned Bits = getBinaryCodeForInstr(MI, Fixups);
|
||||
|
||||
// Output the constant in big endian byte order.
|
||||
for (unsigned i = 0; i != 4; ++i) {
|
||||
OS << (char)(Bits >> 24);
|
||||
Bits <<= 8;
|
||||
}
|
||||
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);
|
||||
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 {
|
||||
|
||||
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;
|
||||
|
||||
assert(0 && "Unhandled expression!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
unsigned SparcMCCodeEmitter::
|
||||
getCallTargetOpValue(const MCInst &MI, unsigned OpNo,
|
||||
SmallVectorImpl<MCFixup> &Fixups) const {
|
||||
const MCOperand &MO = MI.getOperand(OpNo);
|
||||
if (MO.isReg() || MO.isImm())
|
||||
return getMachineOpValue(MI, MO, Fixups);
|
||||
|
||||
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 {
|
||||
const MCOperand &MO = MI.getOperand(OpNo);
|
||||
if (MO.isReg() || MO.isImm())
|
||||
return getMachineOpValue(MI, MO, Fixups);
|
||||
|
||||
Sparc::Fixups fixup = Sparc::fixup_sparc_br22;
|
||||
if (MI.getOpcode() == SP::BPXCC)
|
||||
fixup = Sparc::fixup_sparc_br19;
|
||||
|
||||
Fixups.push_back(MCFixup::Create(0, MO.getExpr(),
|
||||
(MCFixupKind)fixup));
|
||||
return 0;
|
||||
}
|
||||
|
||||
#include "SparcGenMCCodeEmitter.inc"
|
254
contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
Normal file
254
contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.cpp
Normal file
@ -0,0 +1,254 @@
|
||||
//===-- 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", ...).
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#define DEBUG_TYPE "sparcmcexpr"
|
||||
#include "SparcMCExpr.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
#include "llvm/MC/MCAssembler.h"
|
||||
#include "llvm/MC/MCELF.h"
|
||||
#include "llvm/MC/MCSymbol.h"
|
||||
#include "llvm/Object/ELF.h"
|
||||
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
const SparcMCExpr*
|
||||
SparcMCExpr::Create(VariantKind Kind, const MCExpr *Expr,
|
||||
MCContext &Ctx) {
|
||||
return new (Ctx) SparcMCExpr(Kind, Expr);
|
||||
}
|
||||
|
||||
|
||||
|
||||
void SparcMCExpr::PrintImpl(raw_ostream &OS) const
|
||||
{
|
||||
|
||||
bool closeParen = printVariantKind(OS, Kind);
|
||||
|
||||
const MCExpr *Expr = getSubExpr();
|
||||
Expr->print(OS);
|
||||
|
||||
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: assert(0 && "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 {
|
||||
if (!Layout)
|
||||
return false;
|
||||
return getSubExpr()->EvaluateAsRelocatable(Res, *Layout);
|
||||
}
|
||||
|
||||
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);
|
||||
MCSymbolData &SD = Asm.getOrCreateSymbolData(SymRef.getSymbol());
|
||||
MCELF::SetType(SD, 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);
|
||||
}
|
||||
|
||||
// FIXME: This basically copies MCObjectStreamer::AddValueSymbols. Perhaps
|
||||
// that method should be made public?
|
||||
// FIXME: really do above: now that at least three other backends are using it.
|
||||
static void AddValueSymbolsImpl(const MCExpr *Value, MCAssembler *Asm) {
|
||||
switch (Value->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>(Value);
|
||||
AddValueSymbolsImpl(BE->getLHS(), Asm);
|
||||
AddValueSymbolsImpl(BE->getRHS(), Asm);
|
||||
break;
|
||||
}
|
||||
|
||||
case MCExpr::SymbolRef:
|
||||
Asm->getOrCreateSymbolData(cast<MCSymbolRefExpr>(Value)->getSymbol());
|
||||
break;
|
||||
|
||||
case MCExpr::Unary:
|
||||
AddValueSymbolsImpl(cast<MCUnaryExpr>(Value)->getSubExpr(), Asm);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
void SparcMCExpr::AddValueSymbols(MCAssembler *Asm) const {
|
||||
AddValueSymbolsImpl(getSubExpr(), Asm);
|
||||
}
|
111
contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h
Normal file
111
contrib/llvm/lib/Target/Sparc/MCTargetDesc/SparcMCExpr.h
Normal file
@ -0,0 +1,111 @@
|
||||
//====- 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_SPARCMCEXPR_H
|
||||
#define LLVM_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;
|
||||
bool EvaluateAsRelocatableImpl(MCValue &Res,
|
||||
const MCAsmLayout *Layout) const;
|
||||
void AddValueSymbols(MCAssembler *) const;
|
||||
const MCSection *FindAssociatedSection() const {
|
||||
return getSubExpr()->FindAssociatedSection();
|
||||
}
|
||||
|
||||
void fixELFSymbolsInTLSFixups(MCAssembler &Asm) const;
|
||||
|
||||
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
|
@ -13,6 +13,8 @@
|
||||
|
||||
#include "SparcMCTargetDesc.h"
|
||||
#include "SparcMCAsmInfo.h"
|
||||
#include "SparcTargetStreamer.h"
|
||||
#include "InstPrinter/SparcInstPrinter.h"
|
||||
#include "llvm/MC/MCCodeGenInfo.h"
|
||||
#include "llvm/MC/MCInstrInfo.h"
|
||||
#include "llvm/MC/MCRegisterInfo.h"
|
||||
@ -31,6 +33,25 @@
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
|
||||
static MCAsmInfo *createSparcMCAsmInfo(const MCRegisterInfo &MRI,
|
||||
StringRef TT) {
|
||||
MCAsmInfo *MAI = new SparcELFMCAsmInfo(TT);
|
||||
unsigned Reg = MRI.getDwarfRegNum(SP::O6, true);
|
||||
MCCFIInstruction Inst = MCCFIInstruction::createDefCfa(0, Reg, 0);
|
||||
MAI->addInitialFrameState(Inst);
|
||||
return MAI;
|
||||
}
|
||||
|
||||
static MCAsmInfo *createSparcV9MCAsmInfo(const MCRegisterInfo &MRI,
|
||||
StringRef TT) {
|
||||
MCAsmInfo *MAI = new SparcELFMCAsmInfo(TT);
|
||||
unsigned Reg = MRI.getDwarfRegNum(SP::O6, true);
|
||||
MCCFIInstruction Inst = MCCFIInstruction::createDefCfa(0, Reg, 2047);
|
||||
MAI->addInitialFrameState(Inst);
|
||||
return MAI;
|
||||
}
|
||||
|
||||
static MCInstrInfo *createSparcMCInstrInfo() {
|
||||
MCInstrInfo *X = new MCInstrInfo();
|
||||
InitSparcMCInstrInfo(X);
|
||||
@ -39,7 +60,7 @@ static MCInstrInfo *createSparcMCInstrInfo() {
|
||||
|
||||
static MCRegisterInfo *createSparcMCRegisterInfo(StringRef TT) {
|
||||
MCRegisterInfo *X = new MCRegisterInfo();
|
||||
InitSparcMCRegisterInfo(X, SP::I7);
|
||||
InitSparcMCRegisterInfo(X, SP::O7);
|
||||
return X;
|
||||
}
|
||||
|
||||
@ -66,9 +87,13 @@ static MCCodeGenInfo *createSparcMCCodeGenInfo(StringRef TT, Reloc::Model RM,
|
||||
CodeGenOpt::Level OL) {
|
||||
MCCodeGenInfo *X = new MCCodeGenInfo();
|
||||
|
||||
// The default 32-bit code model is abs32/pic32.
|
||||
if (CM == CodeModel::Default)
|
||||
CM = RM == Reloc::PIC_ ? CodeModel::Medium : CodeModel::Small;
|
||||
// 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;
|
||||
@ -79,17 +104,55 @@ static MCCodeGenInfo *createSparcV9MCCodeGenInfo(StringRef TT, Reloc::Model RM,
|
||||
CodeGenOpt::Level OL) {
|
||||
MCCodeGenInfo *X = new MCCodeGenInfo();
|
||||
|
||||
// The default 64-bit code model is abs44/pic32.
|
||||
if (CM == CodeModel::Default)
|
||||
CM = CodeModel::Medium;
|
||||
// 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 MCStreamer *createMCStreamer(const Target &T, StringRef TT,
|
||||
MCContext &Context, MCAsmBackend &MAB,
|
||||
raw_ostream &OS, MCCodeEmitter *Emitter,
|
||||
bool RelaxAll, bool NoExecStack) {
|
||||
SparcTargetELFStreamer *S = new SparcTargetELFStreamer();
|
||||
return createELFStreamer(Context, S, MAB, OS, Emitter, RelaxAll, NoExecStack);
|
||||
}
|
||||
|
||||
static MCStreamer *
|
||||
createMCAsmStreamer(MCContext &Ctx, formatted_raw_ostream &OS,
|
||||
bool isVerboseAsm, bool useLoc, bool useCFI,
|
||||
bool useDwarfDirectory, MCInstPrinter *InstPrint,
|
||||
MCCodeEmitter *CE, MCAsmBackend *TAB, bool ShowInst) {
|
||||
SparcTargetAsmStreamer *S = new SparcTargetAsmStreamer(OS);
|
||||
|
||||
return llvm::createAsmStreamer(Ctx, S, OS, isVerboseAsm, useLoc, useCFI,
|
||||
useDwarfDirectory, InstPrint, CE, TAB,
|
||||
ShowInst);
|
||||
}
|
||||
|
||||
static MCInstPrinter *createSparcMCInstPrinter(const Target &T,
|
||||
unsigned SyntaxVariant,
|
||||
const MCAsmInfo &MAI,
|
||||
const MCInstrInfo &MII,
|
||||
const MCRegisterInfo &MRI,
|
||||
const MCSubtargetInfo &STI) {
|
||||
return new SparcInstPrinter(MAI, MII, MRI);
|
||||
}
|
||||
|
||||
extern "C" void LLVMInitializeSparcTargetMC() {
|
||||
// Register the MC asm info.
|
||||
RegisterMCAsmInfo<SparcELFMCAsmInfo> X(TheSparcTarget);
|
||||
RegisterMCAsmInfo<SparcELFMCAsmInfo> Y(TheSparcV9Target);
|
||||
RegisterMCAsmInfoFn X(TheSparcTarget, createSparcMCAsmInfo);
|
||||
RegisterMCAsmInfoFn Y(TheSparcV9Target, createSparcV9MCAsmInfo);
|
||||
|
||||
// Register the MC codegen info.
|
||||
TargetRegistry::RegisterMCCodeGenInfo(TheSparcTarget,
|
||||
@ -99,11 +162,46 @@ extern "C" void LLVMInitializeSparcTargetMC() {
|
||||
|
||||
// Register the MC instruction info.
|
||||
TargetRegistry::RegisterMCInstrInfo(TheSparcTarget, createSparcMCInstrInfo);
|
||||
TargetRegistry::RegisterMCInstrInfo(TheSparcV9Target, createSparcMCInstrInfo);
|
||||
|
||||
// Register the MC register info.
|
||||
TargetRegistry::RegisterMCRegInfo(TheSparcTarget, createSparcMCRegisterInfo);
|
||||
TargetRegistry::RegisterMCRegInfo(TheSparcV9Target,
|
||||
createSparcMCRegisterInfo);
|
||||
|
||||
// Register the MC subtarget info.
|
||||
TargetRegistry::RegisterMCSubtargetInfo(TheSparcTarget,
|
||||
createSparcMCSubtargetInfo);
|
||||
TargetRegistry::RegisterMCSubtargetInfo(TheSparcV9Target,
|
||||
createSparcMCSubtargetInfo);
|
||||
|
||||
// Register the MC Code Emitter.
|
||||
TargetRegistry::RegisterMCCodeEmitter(TheSparcTarget,
|
||||
createSparcMCCodeEmitter);
|
||||
TargetRegistry::RegisterMCCodeEmitter(TheSparcV9Target,
|
||||
createSparcMCCodeEmitter);
|
||||
|
||||
//Register the asm backend.
|
||||
TargetRegistry::RegisterMCAsmBackend(TheSparcTarget,
|
||||
createSparcAsmBackend);
|
||||
TargetRegistry::RegisterMCAsmBackend(TheSparcV9Target,
|
||||
createSparcAsmBackend);
|
||||
|
||||
// Register the object streamer.
|
||||
TargetRegistry::RegisterMCObjectStreamer(TheSparcTarget,
|
||||
createMCStreamer);
|
||||
TargetRegistry::RegisterMCObjectStreamer(TheSparcV9Target,
|
||||
createMCStreamer);
|
||||
|
||||
// Register the asm streamer.
|
||||
TargetRegistry::RegisterAsmStreamer(TheSparcTarget,
|
||||
createMCAsmStreamer);
|
||||
TargetRegistry::RegisterAsmStreamer(TheSparcV9Target,
|
||||
createMCAsmStreamer);
|
||||
|
||||
// Register the MCInstPrinter
|
||||
TargetRegistry::RegisterMCInstPrinter(TheSparcTarget,
|
||||
createSparcMCInstPrinter);
|
||||
TargetRegistry::RegisterMCInstPrinter(TheSparcV9Target,
|
||||
createSparcMCInstPrinter);
|
||||
}
|
||||
|
@ -14,12 +14,34 @@
|
||||
#ifndef SPARCMCTARGETDESC_H
|
||||
#define 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 StringRef;
|
||||
class raw_ostream;
|
||||
|
||||
extern Target TheSparcTarget;
|
||||
extern Target TheSparcV9Target;
|
||||
|
||||
MCCodeEmitter *createSparcMCCodeEmitter(const MCInstrInfo &MCII,
|
||||
const MCRegisterInfo &MRI,
|
||||
const MCSubtargetInfo &STI,
|
||||
MCContext &Ctx);
|
||||
MCAsmBackend *createSparcAsmBackend(const Target &T,
|
||||
const MCRegisterInfo &MRI,
|
||||
StringRef TT,
|
||||
StringRef CPU);
|
||||
MCObjectWriter *createSparcELFObjectWriter(raw_ostream &OS,
|
||||
bool Is64Bit,
|
||||
uint8_t OSABI);
|
||||
} // End llvm namespace
|
||||
|
||||
// Defines symbolic names for Sparc registers. This defines a mapping from
|
||||
|
@ -0,0 +1,40 @@
|
||||
//===-- 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
|
||||
void SparcTargetStreamer::anchor() {}
|
||||
|
||||
SparcTargetAsmStreamer::SparcTargetAsmStreamer(formatted_raw_ostream &OS)
|
||||
: 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";
|
||||
}
|
||||
|
||||
MCELFStreamer &SparcTargetELFStreamer::getStreamer() {
|
||||
return static_cast<MCELFStreamer &>(*Streamer);
|
||||
}
|
@ -23,12 +23,18 @@ namespace llvm {
|
||||
class FunctionPass;
|
||||
class SparcTargetMachine;
|
||||
class formatted_raw_ostream;
|
||||
class AsmPrinter;
|
||||
class MCInst;
|
||||
class MachineInstr;
|
||||
|
||||
FunctionPass *createSparcISelDag(SparcTargetMachine &TM);
|
||||
FunctionPass *createSparcDelaySlotFillerPass(TargetMachine &TM);
|
||||
FunctionPass *createSparcJITCodeEmitterPass(SparcTargetMachine &TM,
|
||||
JITCodeEmitter &JCE);
|
||||
|
||||
void LowerSparcMachineInstrToMCInst(const MachineInstr *MI,
|
||||
MCInst &OutMI,
|
||||
AsmPrinter &AP);
|
||||
} // end namespace llvm;
|
||||
|
||||
namespace llvm {
|
||||
|
@ -34,6 +34,9 @@ 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
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -44,6 +47,10 @@ include "SparcInstrInfo.td"
|
||||
|
||||
def SparcInstrInfo : InstrInfo;
|
||||
|
||||
def SparcAsmParser : AsmParser {
|
||||
bit ShouldEmitMatchRegisterName = 0;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// SPARC processors supported.
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -52,6 +59,7 @@ 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", []>;
|
||||
@ -63,8 +71,15 @@ def : Proc<"tsc701", []>;
|
||||
def : Proc<"v9", [FeatureV9]>;
|
||||
def : Proc<"ultrasparc", [FeatureV9, FeatureV8Deprecated]>;
|
||||
def : Proc<"ultrasparc3", [FeatureV9, FeatureV8Deprecated]>;
|
||||
def : Proc<"ultrasparc3-vis", [FeatureV9, FeatureV8Deprecated, FeatureVIS]>;
|
||||
def : Proc<"niagara", [FeatureV9, FeatureV8Deprecated]>;
|
||||
def : Proc<"niagara2", [FeatureV9, FeatureV8Deprecated, UsePopc]>;
|
||||
def : Proc<"niagara3", [FeatureV9, FeatureV8Deprecated, UsePopc]>;
|
||||
def : Proc<"niagara4", [FeatureV9, FeatureV8Deprecated, UsePopc]>;
|
||||
|
||||
def SparcAsmWriter : AsmWriter {
|
||||
string AsmWriterClassName = "InstPrinter";
|
||||
bit isMCAsmWriter = 1;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Declare the target which we are implementing
|
||||
@ -73,4 +88,7 @@ def : Proc<"ultrasparc3-vis", [FeatureV9, FeatureV8Deprecated, FeatureVIS]>;
|
||||
def Sparc : Target {
|
||||
// Pull in Instruction Info:
|
||||
let InstructionSet = SparcInstrInfo;
|
||||
let AssemblyParsers = [SparcAsmParser];
|
||||
|
||||
let AssemblyWriters = [SparcAsmWriter];
|
||||
}
|
||||
|
@ -16,12 +16,18 @@
|
||||
#include "Sparc.h"
|
||||
#include "SparcInstrInfo.h"
|
||||
#include "SparcTargetMachine.h"
|
||||
#include "MCTargetDesc/SparcBaseInfo.h"
|
||||
#include "SparcTargetStreamer.h"
|
||||
#include "InstPrinter/SparcInstPrinter.h"
|
||||
#include "MCTargetDesc/SparcMCExpr.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/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"
|
||||
@ -31,6 +37,9 @@ using namespace llvm;
|
||||
|
||||
namespace {
|
||||
class SparcAsmPrinter : public AsmPrinter {
|
||||
SparcTargetStreamer &getTargetStreamer() {
|
||||
return static_cast<SparcTargetStreamer&>(OutStreamer.getTargetStreamer());
|
||||
}
|
||||
public:
|
||||
explicit SparcAsmPrinter(TargetMachine &TM, MCStreamer &Streamer)
|
||||
: AsmPrinter(TM, Streamer) {}
|
||||
@ -45,14 +54,12 @@ namespace {
|
||||
void printCCOperand(const MachineInstr *MI, int opNum, raw_ostream &OS);
|
||||
|
||||
virtual void EmitFunctionBodyStart();
|
||||
virtual void EmitInstruction(const MachineInstr *MI) {
|
||||
SmallString<128> Str;
|
||||
raw_svector_ostream OS(Str);
|
||||
printInstruction(MI, OS);
|
||||
OutStreamer.EmitRawText(OS.str());
|
||||
virtual void EmitInstruction(const MachineInstr *MI);
|
||||
virtual void EmitEndOfAsmFile(Module &M);
|
||||
|
||||
static const char *getRegisterName(unsigned RegNo) {
|
||||
return SparcInstPrinter::getRegisterName(RegNo);
|
||||
}
|
||||
void printInstruction(const MachineInstr *MI, raw_ostream &OS);// autogen'd.
|
||||
static const char *getRegisterName(unsigned RegNo);
|
||||
|
||||
bool PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
|
||||
unsigned AsmVariant, const char *ExtraCode,
|
||||
@ -61,24 +68,202 @@ namespace {
|
||||
unsigned AsmVariant, const char *ExtraCode,
|
||||
raw_ostream &O);
|
||||
|
||||
bool printGetPCX(const MachineInstr *MI, unsigned OpNo, raw_ostream &OS);
|
||||
|
||||
virtual bool isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB)
|
||||
const;
|
||||
void EmitGlobalRegisterDecl(unsigned reg) {
|
||||
SmallString<128> Str;
|
||||
raw_svector_ostream OS(Str);
|
||||
OS << "\t.register "
|
||||
<< "%" << StringRef(getRegisterName(reg)).lower()
|
||||
<< ", "
|
||||
<< ((reg == SP::G6 || reg == SP::G7)? "#ignore" : "#scratch");
|
||||
OutStreamer.EmitRawText(OS.str());
|
||||
}
|
||||
void LowerGETPCXAndEmitMCInsts(const MachineInstr *MI);
|
||||
|
||||
};
|
||||
} // end of anonymous namespace
|
||||
|
||||
#include "SparcGenAsmWriter.inc"
|
||||
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)
|
||||
{
|
||||
MCInst CallInst;
|
||||
CallInst.setOpcode(SP::CALL);
|
||||
CallInst.addOperand(Callee);
|
||||
OutStreamer.EmitInstruction(CallInst);
|
||||
}
|
||||
|
||||
static void EmitSETHI(MCStreamer &OutStreamer,
|
||||
MCOperand &Imm, MCOperand &RD)
|
||||
{
|
||||
MCInst SETHIInst;
|
||||
SETHIInst.setOpcode(SP::SETHIi);
|
||||
SETHIInst.addOperand(RD);
|
||||
SETHIInst.addOperand(Imm);
|
||||
OutStreamer.EmitInstruction(SETHIInst);
|
||||
}
|
||||
|
||||
static void EmitBinary(MCStreamer &OutStreamer, unsigned Opcode,
|
||||
MCOperand &RS1, MCOperand &Src2, MCOperand &RD)
|
||||
{
|
||||
MCInst Inst;
|
||||
Inst.setOpcode(Opcode);
|
||||
Inst.addOperand(RD);
|
||||
Inst.addOperand(RS1);
|
||||
Inst.addOperand(Src2);
|
||||
OutStreamer.EmitInstruction(Inst);
|
||||
}
|
||||
|
||||
static void EmitOR(MCStreamer &OutStreamer,
|
||||
MCOperand &RS1, MCOperand &Imm, MCOperand &RD) {
|
||||
EmitBinary(OutStreamer, SP::ORri, RS1, Imm, RD);
|
||||
}
|
||||
|
||||
static void EmitADD(MCStreamer &OutStreamer,
|
||||
MCOperand &RS1, MCOperand &RS2, MCOperand &RD) {
|
||||
EmitBinary(OutStreamer, SP::ADDrr, RS1, RS2, RD);
|
||||
}
|
||||
|
||||
static void EmitSHL(MCStreamer &OutStreamer,
|
||||
MCOperand &RS1, MCOperand &Imm, MCOperand &RD) {
|
||||
EmitBinary(OutStreamer, SP::SLLri, RS1, Imm, RD);
|
||||
}
|
||||
|
||||
|
||||
static void EmitHiLo(MCStreamer &OutStreamer, MCSymbol *GOTSym,
|
||||
SparcMCExpr::VariantKind HiKind,
|
||||
SparcMCExpr::VariantKind LoKind,
|
||||
MCOperand &RD,
|
||||
MCContext &OutContext) {
|
||||
|
||||
MCOperand hi = createSparcMCOperand(HiKind, GOTSym, OutContext);
|
||||
MCOperand lo = createSparcMCOperand(LoKind, GOTSym, OutContext);
|
||||
EmitSETHI(OutStreamer, hi, RD);
|
||||
EmitOR(OutStreamer, RD, lo, RD);
|
||||
}
|
||||
|
||||
void SparcAsmPrinter::LowerGETPCXAndEmitMCInsts(const MachineInstr *MI)
|
||||
{
|
||||
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);
|
||||
break;
|
||||
case CodeModel::Medium: {
|
||||
EmitHiLo(OutStreamer, GOTLabel,
|
||||
SparcMCExpr::VK_Sparc_H44, SparcMCExpr::VK_Sparc_M44,
|
||||
MCRegOP, OutContext);
|
||||
MCOperand imm = MCOperand::CreateExpr(MCConstantExpr::Create(12,
|
||||
OutContext));
|
||||
EmitSHL(OutStreamer, MCRegOP, imm, MCRegOP);
|
||||
MCOperand lo = createSparcMCOperand(SparcMCExpr::VK_Sparc_L44,
|
||||
GOTLabel, OutContext);
|
||||
EmitOR(OutStreamer, MCRegOP, lo, MCRegOP);
|
||||
break;
|
||||
}
|
||||
case CodeModel::Large: {
|
||||
EmitHiLo(OutStreamer, GOTLabel,
|
||||
SparcMCExpr::VK_Sparc_HH, SparcMCExpr::VK_Sparc_HM,
|
||||
MCRegOP, OutContext);
|
||||
MCOperand imm = MCOperand::CreateExpr(MCConstantExpr::Create(32,
|
||||
OutContext));
|
||||
EmitSHL(OutStreamer, MCRegOP, imm, MCRegOP);
|
||||
// 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);
|
||||
EmitADD(OutStreamer, MCRegOP, RegO7, MCRegOP);
|
||||
}
|
||||
}
|
||||
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);
|
||||
OutStreamer.EmitLabel(SethiLabel);
|
||||
MCOperand hiImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_PC22,
|
||||
GOTLabel, StartLabel, SethiLabel,
|
||||
OutContext);
|
||||
EmitSETHI(OutStreamer, hiImm, MCRegOP);
|
||||
OutStreamer.EmitLabel(EndLabel);
|
||||
MCOperand loImm = createPCXRelExprOp(SparcMCExpr::VK_Sparc_PC10,
|
||||
GOTLabel, StartLabel, EndLabel,
|
||||
OutContext);
|
||||
EmitOR(OutStreamer, MCRegOP, loImm, MCRegOP);
|
||||
EmitADD(OutStreamer, MCRegOP, RegO7, MCRegOP);
|
||||
}
|
||||
|
||||
void SparcAsmPrinter::EmitInstruction(const MachineInstr *MI)
|
||||
{
|
||||
|
||||
switch (MI->getOpcode()) {
|
||||
default: break;
|
||||
case TargetOpcode::DBG_VALUE:
|
||||
// FIXME: Debug Value.
|
||||
return;
|
||||
case SP::GETPCX:
|
||||
LowerGETPCXAndEmitMCInsts(MI);
|
||||
return;
|
||||
}
|
||||
MachineBasicBlock::const_instr_iterator I = MI;
|
||||
MachineBasicBlock::const_instr_iterator E = MI->getParent()->instr_end();
|
||||
do {
|
||||
MCInst TmpInst;
|
||||
LowerSparcMachineInstrToMCInst(I, TmpInst, *this);
|
||||
OutStreamer.EmitInstruction(TmpInst);
|
||||
} while ((++I != E) && I->isInsideBundle()); // Delay slot check.
|
||||
}
|
||||
|
||||
void SparcAsmPrinter::EmitFunctionBodyStart() {
|
||||
if (!TM.getSubtarget<SparcSubtarget>().is64Bit())
|
||||
@ -90,89 +275,70 @@ void SparcAsmPrinter::EmitFunctionBodyStart() {
|
||||
unsigned reg = globalRegs[i];
|
||||
if (MRI.use_empty(reg))
|
||||
continue;
|
||||
EmitGlobalRegisterDecl(reg);
|
||||
|
||||
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 MachineOperand &MO = MI->getOperand (opNum);
|
||||
unsigned TF = MO.getTargetFlags();
|
||||
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 == SPII::MO_NO_FLAG &&
|
||||
assert(TF == SparcMCExpr::VK_Sparc_None &&
|
||||
"Cannot handle target flags on call address");
|
||||
else if (MI->getOpcode() == SP::SETHIi)
|
||||
assert((TF == SPII::MO_HI || TF == SPII::MO_H44 || TF == SPII::MO_HH
|
||||
|| TF == SPII::MO_TLS_GD_HI22
|
||||
|| TF == SPII::MO_TLS_LDM_HI22
|
||||
|| TF == SPII::MO_TLS_LDO_HIX22
|
||||
|| TF == SPII::MO_TLS_IE_HI22
|
||||
|| TF == SPII::MO_TLS_LE_HIX22) &&
|
||||
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 == SPII::MO_NO_FLAG
|
||||
|| TF == SPII::MO_TLS_GD_CALL
|
||||
|| TF == SPII::MO_TLS_LDM_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 == SPII::MO_TLS_GD_ADD || TF == SPII::MO_TLS_LDM_ADD
|
||||
|| TF == SPII::MO_TLS_LDO_ADD || TF == SPII::MO_TLS_IE_ADD) &&
|
||||
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 == SPII::MO_TLS_IE_LD &&
|
||||
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 == SPII::MO_TLS_IE_LDX &&
|
||||
assert(TF == SparcMCExpr::VK_Sparc_TLS_IE_LDX &&
|
||||
"Cannot handle target flags on ldx for TLS");
|
||||
else if (MI->getOpcode() == SP::XORri)
|
||||
assert((TF == SPII::MO_TLS_LDO_LOX10 || TF == SPII::MO_TLS_LE_LOX10) &&
|
||||
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 == SPII::MO_LO || TF == SPII::MO_M44 || TF == SPII::MO_L44
|
||||
|| TF == SPII::MO_HM
|
||||
|| TF == SPII::MO_TLS_GD_LO10
|
||||
|| TF == SPII::MO_TLS_LDM_LO10
|
||||
|| TF == SPII::MO_TLS_IE_LO10 ) &&
|
||||
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 = true;
|
||||
switch (TF) {
|
||||
default:
|
||||
llvm_unreachable("Unknown target flags on operand");
|
||||
case SPII::MO_NO_FLAG:
|
||||
CloseParen = false;
|
||||
break;
|
||||
case SPII::MO_LO: O << "%lo("; break;
|
||||
case SPII::MO_HI: O << "%hi("; break;
|
||||
case SPII::MO_H44: O << "%h44("; break;
|
||||
case SPII::MO_M44: O << "%m44("; break;
|
||||
case SPII::MO_L44: O << "%l44("; break;
|
||||
case SPII::MO_HH: O << "%hh("; break;
|
||||
case SPII::MO_HM: O << "%hm("; break;
|
||||
case SPII::MO_TLS_GD_HI22: O << "%tgd_hi22("; break;
|
||||
case SPII::MO_TLS_GD_LO10: O << "%tgd_lo10("; break;
|
||||
case SPII::MO_TLS_GD_ADD: O << "%tgd_add("; break;
|
||||
case SPII::MO_TLS_GD_CALL: O << "%tgd_call("; break;
|
||||
case SPII::MO_TLS_LDM_HI22: O << "%tldm_hi22("; break;
|
||||
case SPII::MO_TLS_LDM_LO10: O << "%tldm_lo10("; break;
|
||||
case SPII::MO_TLS_LDM_ADD: O << "%tldm_add("; break;
|
||||
case SPII::MO_TLS_LDM_CALL: O << "%tldm_call("; break;
|
||||
case SPII::MO_TLS_LDO_HIX22: O << "%tldo_hix22("; break;
|
||||
case SPII::MO_TLS_LDO_LOX10: O << "%tldo_lox10("; break;
|
||||
case SPII::MO_TLS_LDO_ADD: O << "%tldo_add("; break;
|
||||
case SPII::MO_TLS_IE_HI22: O << "%tie_hi22("; break;
|
||||
case SPII::MO_TLS_IE_LO10: O << "%tie_lo10("; break;
|
||||
case SPII::MO_TLS_IE_LD: O << "%tie_ld("; break;
|
||||
case SPII::MO_TLS_IE_LDX: O << "%tie_ldx("; break;
|
||||
case SPII::MO_TLS_IE_ADD: O << "%tie_add("; break;
|
||||
case SPII::MO_TLS_LE_HIX22: O << "%tle_hix22("; break;
|
||||
case SPII::MO_TLS_LE_LOX10: O << "%tle_lox10("; break;
|
||||
}
|
||||
|
||||
bool CloseParen = SparcMCExpr::printVariantKind(O, TF);
|
||||
|
||||
switch (MO.getType()) {
|
||||
case MachineOperand::MO_Register:
|
||||
@ -226,46 +392,6 @@ void SparcAsmPrinter::printMemOperand(const MachineInstr *MI, int opNum,
|
||||
printOperand(MI, opNum+1, O);
|
||||
}
|
||||
|
||||
bool SparcAsmPrinter::printGetPCX(const MachineInstr *MI, unsigned opNum,
|
||||
raw_ostream &O) {
|
||||
std::string operand = "";
|
||||
const MachineOperand &MO = MI->getOperand(opNum);
|
||||
switch (MO.getType()) {
|
||||
default: llvm_unreachable("Operand is not a register");
|
||||
case MachineOperand::MO_Register:
|
||||
assert(TargetRegisterInfo::isPhysicalRegister(MO.getReg()) &&
|
||||
"Operand is not a physical register ");
|
||||
assert(MO.getReg() != SP::O7 &&
|
||||
"%o7 is assigned as destination for getpcx!");
|
||||
operand = "%" + StringRef(getRegisterName(MO.getReg())).lower();
|
||||
break;
|
||||
}
|
||||
|
||||
unsigned mfNum = MI->getParent()->getParent()->getFunctionNumber();
|
||||
unsigned bbNum = MI->getParent()->getNumber();
|
||||
|
||||
O << '\n' << ".LLGETPCH" << mfNum << '_' << bbNum << ":\n";
|
||||
O << "\tcall\t.LLGETPC" << mfNum << '_' << bbNum << '\n' ;
|
||||
|
||||
O << "\t sethi\t"
|
||||
<< "%hi(_GLOBAL_OFFSET_TABLE_+(.-.LLGETPCH" << mfNum << '_' << bbNum
|
||||
<< ")), " << operand << '\n' ;
|
||||
|
||||
O << ".LLGETPC" << mfNum << '_' << bbNum << ":\n" ;
|
||||
O << "\tor\t" << operand
|
||||
<< ", %lo(_GLOBAL_OFFSET_TABLE_+(.-.LLGETPCH" << mfNum << '_' << bbNum
|
||||
<< ")), " << operand << '\n';
|
||||
O << "\tadd\t" << operand << ", %o7, " << operand << '\n';
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void SparcAsmPrinter::printCCOperand(const MachineInstr *MI, int opNum,
|
||||
raw_ostream &O) {
|
||||
int CC = (int)MI->getOperand(opNum).getImm();
|
||||
O << SPARCCondCodeToString((SPCC::CondCodes)CC);
|
||||
}
|
||||
|
||||
/// PrintAsmOperand - Print out an operand for an inline asm expression.
|
||||
///
|
||||
bool SparcAsmPrinter::PrintAsmOperand(const MachineInstr *MI, unsigned OpNo,
|
||||
@ -303,35 +429,21 @@ bool SparcAsmPrinter::PrintAsmMemoryOperand(const MachineInstr *MI,
|
||||
return false;
|
||||
}
|
||||
|
||||
/// isBlockOnlyReachableByFallthough - Return true if the basic block has
|
||||
/// exactly one predecessor and the control transfer mechanism between
|
||||
/// the predecessor and this block is a fall-through.
|
||||
///
|
||||
/// This overrides AsmPrinter's implementation to handle delay slots.
|
||||
bool SparcAsmPrinter::
|
||||
isBlockOnlyReachableByFallthrough(const MachineBasicBlock *MBB) const {
|
||||
// If this is a landing pad, it isn't a fall through. If it has no preds,
|
||||
// then nothing falls through to it.
|
||||
if (MBB->isLandingPad() || MBB->pred_empty())
|
||||
return false;
|
||||
void SparcAsmPrinter::EmitEndOfAsmFile(Module &M) {
|
||||
const TargetLoweringObjectFileELF &TLOFELF =
|
||||
static_cast<const TargetLoweringObjectFileELF &>(getObjFileLowering());
|
||||
MachineModuleInfoELF &MMIELF = MMI->getObjFileInfo<MachineModuleInfoELF>();
|
||||
|
||||
// If there isn't exactly one predecessor, it can't be a fall through.
|
||||
MachineBasicBlock::const_pred_iterator PI = MBB->pred_begin(), PI2 = PI;
|
||||
++PI2;
|
||||
if (PI2 != MBB->pred_end())
|
||||
return false;
|
||||
|
||||
// The predecessor has to be immediately before this block.
|
||||
const MachineBasicBlock *Pred = *PI;
|
||||
|
||||
if (!Pred->isLayoutSuccessor(MBB))
|
||||
return false;
|
||||
|
||||
// Check if the last terminator is an unconditional branch.
|
||||
MachineBasicBlock::const_iterator I = Pred->end();
|
||||
while (I != Pred->begin() && !(--I)->isTerminator())
|
||||
; // Noop
|
||||
return I == Pred->end() || !I->isBarrier();
|
||||
// Generate stubs for global variables.
|
||||
MachineModuleInfoELF::SymbolListTy Stubs = MMIELF.GetGVStubList();
|
||||
if (!Stubs.empty()) {
|
||||
OutStreamer.SwitchSection(TLOFELF.getDataSection());
|
||||
unsigned PtrSize = TM.getDataLayout()->getPointerSize(0);
|
||||
for (unsigned i = 0, e = Stubs.size(); i != e; ++i) {
|
||||
OutStreamer.EmitLabel(Stubs[i].first);
|
||||
OutStreamer.EmitSymbolValue(Stubs[i].second.getPointer(), PtrSize);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Force static initialization.
|
||||
|
@ -103,7 +103,7 @@ def RetCC_Sparc32 : CallingConv<[
|
||||
// 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 return values.
|
||||
// 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
|
||||
@ -118,6 +118,15 @@ def CC_Sparc64 : CallingConv<[
|
||||
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),
|
||||
|
@ -14,7 +14,7 @@
|
||||
|
||||
#define DEBUG_TYPE "jit"
|
||||
#include "Sparc.h"
|
||||
#include "MCTargetDesc/SparcBaseInfo.h"
|
||||
#include "MCTargetDesc/SparcMCExpr.h"
|
||||
#include "SparcRelocations.h"
|
||||
#include "SparcTargetMachine.h"
|
||||
#include "llvm/ADT/Statistic.h"
|
||||
@ -72,6 +72,11 @@ class SparcCodeEmitter : public MachineFunctionPass {
|
||||
unsigned getMachineOpValue(const MachineInstr &MI,
|
||||
const MachineOperand &MO) const;
|
||||
|
||||
unsigned getCallTargetOpValue(const MachineInstr &MI,
|
||||
unsigned) const;
|
||||
unsigned getBranchTargetOpValue(const MachineInstr &MI,
|
||||
unsigned) const;
|
||||
|
||||
void emitWord(unsigned Word);
|
||||
|
||||
unsigned getRelocation(const MachineInstr &MI,
|
||||
@ -181,20 +186,32 @@ unsigned SparcCodeEmitter::getMachineOpValue(const MachineInstr &MI,
|
||||
llvm_unreachable("Unable to encode MachineOperand!");
|
||||
return 0;
|
||||
}
|
||||
unsigned SparcCodeEmitter::getCallTargetOpValue(const MachineInstr &MI,
|
||||
unsigned opIdx) const {
|
||||
const MachineOperand MO = MI.getOperand(opIdx);
|
||||
return getMachineOpValue(MI, MO);
|
||||
}
|
||||
|
||||
unsigned SparcCodeEmitter::getBranchTargetOpValue(const MachineInstr &MI,
|
||||
unsigned opIdx) const {
|
||||
const MachineOperand MO = MI.getOperand(opIdx);
|
||||
return getMachineOpValue(MI, MO);
|
||||
}
|
||||
|
||||
unsigned SparcCodeEmitter::getRelocation(const MachineInstr &MI,
|
||||
const MachineOperand &MO) const {
|
||||
|
||||
unsigned TF = MO.getTargetFlags();
|
||||
switch (TF) {
|
||||
default:
|
||||
case SPII::MO_NO_FLAG: break;
|
||||
case SPII::MO_LO: return SP::reloc_sparc_lo;
|
||||
case SPII::MO_HI: return SP::reloc_sparc_hi;
|
||||
case SPII::MO_H44:
|
||||
case SPII::MO_M44:
|
||||
case SPII::MO_L44:
|
||||
case SPII::MO_HH:
|
||||
case SPII::MO_HM: assert(0 && "FIXME: Implement Medium/Large code model.");
|
||||
case SparcMCExpr::VK_Sparc_None: break;
|
||||
case SparcMCExpr::VK_Sparc_LO: return SP::reloc_sparc_lo;
|
||||
case SparcMCExpr::VK_Sparc_HI: return SP::reloc_sparc_hi;
|
||||
case SparcMCExpr::VK_Sparc_H44: return SP::reloc_sparc_h44;
|
||||
case SparcMCExpr::VK_Sparc_M44: return SP::reloc_sparc_m44;
|
||||
case SparcMCExpr::VK_Sparc_L44: return SP::reloc_sparc_l44;
|
||||
case SparcMCExpr::VK_Sparc_HH: return SP::reloc_sparc_hh;
|
||||
case SparcMCExpr::VK_Sparc_HM: return SP::reloc_sparc_hm;
|
||||
}
|
||||
|
||||
unsigned Opc = MI.getOpcode();
|
||||
|
@ -13,10 +13,12 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "SparcISelLowering.h"
|
||||
#include "MCTargetDesc/SparcMCExpr.h"
|
||||
#include "SparcMachineFunctionInfo.h"
|
||||
#include "SparcRegisterInfo.h"
|
||||
#include "SparcTargetMachine.h"
|
||||
#include "MCTargetDesc/SparcBaseInfo.h"
|
||||
#include "SparcTargetObjectFile.h"
|
||||
#include "llvm/CodeGen/CallingConvLower.h"
|
||||
#include "llvm/CodeGen/MachineFrameInfo.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
@ -80,11 +82,14 @@ static bool CC_Sparc_Assign_f64(unsigned &ValNo, MVT &ValVT,
|
||||
static bool CC_Sparc64_Full(unsigned &ValNo, MVT &ValVT,
|
||||
MVT &LocVT, CCValAssign::LocInfo &LocInfo,
|
||||
ISD::ArgFlagsTy &ArgFlags, CCState &State) {
|
||||
assert((LocVT == MVT::f32 || LocVT.getSizeInBits() == 64) &&
|
||||
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 Offset = State.AllocateStack(8, 8);
|
||||
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)
|
||||
@ -96,6 +101,9 @@ static bool CC_Sparc64_Full(unsigned &ValNo, MVT &ValVT,
|
||||
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) {
|
||||
@ -248,7 +256,7 @@ SparcTargetLowering::LowerReturn_64(SDValue Chain,
|
||||
DAG.getTarget(), RVLocs, *DAG.getContext());
|
||||
|
||||
// Analyze return values.
|
||||
CCInfo.AnalyzeReturn(Outs, CC_Sparc64);
|
||||
CCInfo.AnalyzeReturn(Outs, RetCC_Sparc64);
|
||||
|
||||
SDValue Flag;
|
||||
SmallVector<SDValue, 4> RetOps(1, Chain);
|
||||
@ -888,10 +896,12 @@ SparcTargetLowering::LowerCall_32(TargetLowering::CallLoweringInfo &CLI,
|
||||
// If the callee is a GlobalAddress node (quite common, every direct call is)
|
||||
// turn it into a TargetGlobalAddress node so that legalize doesn't hack it.
|
||||
// Likewise ExternalSymbol -> TargetExternalSymbol.
|
||||
unsigned TF = ((getTargetMachine().getRelocationModel() == Reloc::PIC_)
|
||||
? SparcMCExpr::VK_Sparc_WPLT30 : 0);
|
||||
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee))
|
||||
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), dl, MVT::i32);
|
||||
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);
|
||||
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);
|
||||
@ -998,9 +1008,10 @@ 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() || VA.getLocVT() != MVT::f64)
|
||||
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)
|
||||
@ -1010,15 +1021,25 @@ static void fixupVariableFloatArgs(SmallVectorImpl<CCValAssign> &ArgLocs,
|
||||
CCValAssign NewVA;
|
||||
|
||||
// Determine the offset into the argument array.
|
||||
unsigned Offset = 8 * (VA.getLocReg() - SP::D0);
|
||||
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;
|
||||
// Full register, just bitconvert into i64.
|
||||
NewVA = CCValAssign::getReg(VA.getValNo(), VA.getValVT(),
|
||||
IReg, MVT::i64, CCValAssign::BCvt);
|
||||
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(),
|
||||
@ -1094,11 +1115,46 @@ SparcTargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI,
|
||||
Arg = DAG.getNode(ISD::ANY_EXTEND, DL, VA.getLocVT(), Arg);
|
||||
break;
|
||||
case CCValAssign::BCvt:
|
||||
Arg = DAG.getNode(ISD::BITCAST, DL, VA.getLocVT(), Arg);
|
||||
// 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);
|
||||
HiPtrOff = DAG.getNode(ISD::ADD, DL, getPointerTy(), StackPtr,
|
||||
HiPtrOff);
|
||||
SDValue LoPtrOff = DAG.getIntPtrConstant(StackOffset + 8);
|
||||
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()) {
|
||||
@ -1156,10 +1212,13 @@ SparcTargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI,
|
||||
// Likewise ExternalSymbol -> TargetExternalSymbol.
|
||||
SDValue Callee = CLI.Callee;
|
||||
bool hasReturnsTwice = hasReturnsTwiceAttr(DAG, Callee, CLI.CS);
|
||||
unsigned TF = ((getTargetMachine().getRelocationModel() == Reloc::PIC_)
|
||||
? SparcMCExpr::VK_Sparc_WPLT30 : 0);
|
||||
if (GlobalAddressSDNode *G = dyn_cast<GlobalAddressSDNode>(Callee))
|
||||
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), DL, getPointerTy());
|
||||
Callee = DAG.getTargetGlobalAddress(G->getGlobal(), DL, getPointerTy(), 0,
|
||||
TF);
|
||||
else if (ExternalSymbolSDNode *E = dyn_cast<ExternalSymbolSDNode>(Callee))
|
||||
Callee = DAG.getTargetExternalSymbol(E->getSymbol(), getPointerTy());
|
||||
Callee = DAG.getTargetExternalSymbol(E->getSymbol(), getPointerTy(), TF);
|
||||
|
||||
// Build the operands for the call instruction itself.
|
||||
SmallVector<SDValue, 8> Ops;
|
||||
@ -1200,7 +1259,13 @@ SparcTargetLowering::LowerCall_64(TargetLowering::CallLoweringInfo &CLI,
|
||||
SmallVector<CCValAssign, 16> RVLocs;
|
||||
CCState RVInfo(CLI.CallConv, CLI.IsVarArg, DAG.getMachineFunction(),
|
||||
DAG.getTarget(), RVLocs, *DAG.getContext());
|
||||
RVInfo.AnalyzeCallResult(CLI.Ins, CC_Sparc64);
|
||||
|
||||
// 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 == 0)
|
||||
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) {
|
||||
@ -1303,7 +1368,7 @@ static SPCC::CondCodes FPCondCCodeToFCC(ISD::CondCode CC) {
|
||||
}
|
||||
|
||||
SparcTargetLowering::SparcTargetLowering(TargetMachine &TM)
|
||||
: TargetLowering(TM, new TargetLoweringObjectFileELF()) {
|
||||
: TargetLowering(TM, new SparcELFTargetObjectFile()) {
|
||||
Subtarget = &TM.getSubtarget<SparcSubtarget>();
|
||||
|
||||
// Set up the register classes.
|
||||
@ -1403,7 +1468,8 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM)
|
||||
setOperationAction(ISD::BR_CC, MVT::i64, Custom);
|
||||
setOperationAction(ISD::SELECT_CC, MVT::i64, Custom);
|
||||
|
||||
setOperationAction(ISD::CTPOP, MVT::i64, Legal);
|
||||
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);
|
||||
@ -1414,9 +1480,29 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM)
|
||||
setOperationAction(ISD::DYNAMIC_STACKALLOC, MVT::i64, Custom);
|
||||
}
|
||||
|
||||
// FIXME: There are instructions available for ATOMIC_FENCE
|
||||
// on SparcV8 and later.
|
||||
setOperationAction(ISD::ATOMIC_FENCE, MVT::Other, Expand);
|
||||
// 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, Expand);
|
||||
setOperationAction(ISD::ATOMIC_LOAD, MVT::i64, Custom);
|
||||
setOperationAction(ISD::ATOMIC_STORE, MVT::i64, Custom);
|
||||
}
|
||||
|
||||
if (!Subtarget->isV9()) {
|
||||
// SparcV8 does not have FNEGD and FABSD.
|
||||
@ -1439,7 +1525,6 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM)
|
||||
setOperationAction(ISD::FSINCOS, MVT::f32, Expand);
|
||||
setOperationAction(ISD::FREM , MVT::f32, Expand);
|
||||
setOperationAction(ISD::FMA , MVT::f32, Expand);
|
||||
setOperationAction(ISD::CTPOP, MVT::i32, Expand);
|
||||
setOperationAction(ISD::CTTZ , MVT::i32, Expand);
|
||||
setOperationAction(ISD::CTTZ_ZERO_UNDEF, MVT::i32, Expand);
|
||||
setOperationAction(ISD::CTLZ , MVT::i32, Expand);
|
||||
@ -1467,6 +1552,9 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM)
|
||||
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);
|
||||
}
|
||||
|
||||
// VASTART needs to be custom lowered to use the VarArgsFrameIndex.
|
||||
@ -1486,8 +1574,8 @@ SparcTargetLowering::SparcTargetLowering(TargetMachine &TM)
|
||||
|
||||
setStackPointerRegisterToSaveRestore(SP::O6);
|
||||
|
||||
if (Subtarget->isV9())
|
||||
setOperationAction(ISD::CTPOP, MVT::i32, Legal);
|
||||
setOperationAction(ISD::CTPOP, MVT::i32,
|
||||
Subtarget->usePopc() ? Legal : Expand);
|
||||
|
||||
if (Subtarget->isV9() && Subtarget->hasHardQuad()) {
|
||||
setOperationAction(ISD::LOAD, MVT::f128, Legal);
|
||||
@ -1714,7 +1802,8 @@ SDValue SparcTargetLowering::makeAddress(SDValue Op, SelectionDAG &DAG) const {
|
||||
// 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, SPII::MO_HI, SPII::MO_LO, DAG);
|
||||
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
|
||||
@ -1729,23 +1818,26 @@ SDValue SparcTargetLowering::makeAddress(SDValue Op, SelectionDAG &DAG) const {
|
||||
switch(getTargetMachine().getCodeModel()) {
|
||||
default:
|
||||
llvm_unreachable("Unsupported absolute code model");
|
||||
case CodeModel::JITDefault:
|
||||
case CodeModel::Small:
|
||||
// abs32.
|
||||
return makeHiLoPair(Op, SPII::MO_HI, SPII::MO_LO, DAG);
|
||||
return makeHiLoPair(Op, SparcMCExpr::VK_Sparc_HI,
|
||||
SparcMCExpr::VK_Sparc_LO, DAG);
|
||||
case CodeModel::Medium: {
|
||||
// abs44.
|
||||
SDValue H44 = makeHiLoPair(Op, SPII::MO_H44, SPII::MO_M44, DAG);
|
||||
SDValue H44 = makeHiLoPair(Op, SparcMCExpr::VK_Sparc_H44,
|
||||
SparcMCExpr::VK_Sparc_M44, DAG);
|
||||
H44 = DAG.getNode(ISD::SHL, DL, VT, H44, DAG.getConstant(12, MVT::i32));
|
||||
SDValue L44 = withTargetFlags(Op, SPII::MO_L44, DAG);
|
||||
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, SPII::MO_HH, SPII::MO_HM, DAG);
|
||||
SDValue Hi = makeHiLoPair(Op, SparcMCExpr::VK_Sparc_HH,
|
||||
SparcMCExpr::VK_Sparc_HM, DAG);
|
||||
Hi = DAG.getNode(ISD::SHL, DL, VT, Hi, DAG.getConstant(32, MVT::i32));
|
||||
SDValue Lo = makeHiLoPair(Op, SPII::MO_HI, SPII::MO_LO, DAG);
|
||||
SDValue Lo = makeHiLoPair(Op, SparcMCExpr::VK_Sparc_HI,
|
||||
SparcMCExpr::VK_Sparc_LO, DAG);
|
||||
return DAG.getNode(ISD::ADD, DL, VT, Hi, Lo);
|
||||
}
|
||||
}
|
||||
@ -1777,14 +1869,18 @@ SDValue SparcTargetLowering::LowerGlobalTLSAddress(SDValue Op,
|
||||
TLSModel::Model model = getTargetMachine().getTLSModel(GV);
|
||||
|
||||
if (model == TLSModel::GeneralDynamic || model == TLSModel::LocalDynamic) {
|
||||
unsigned HiTF = ((model == TLSModel::GeneralDynamic)? SPII::MO_TLS_GD_HI22
|
||||
: SPII::MO_TLS_LDM_HI22);
|
||||
unsigned LoTF = ((model == TLSModel::GeneralDynamic)? SPII::MO_TLS_GD_LO10
|
||||
: SPII::MO_TLS_LDM_LO10);
|
||||
unsigned addTF = ((model == TLSModel::GeneralDynamic)? SPII::MO_TLS_GD_ADD
|
||||
: SPII::MO_TLS_LDM_ADD);
|
||||
unsigned callTF = ((model == TLSModel::GeneralDynamic)? SPII::MO_TLS_GD_CALL
|
||||
: SPII::MO_TLS_LDM_CALL);
|
||||
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);
|
||||
@ -1822,17 +1918,17 @@ SDValue SparcTargetLowering::LowerGlobalTLSAddress(SDValue Op,
|
||||
return Ret;
|
||||
|
||||
SDValue Hi = DAG.getNode(SPISD::Hi, DL, PtrVT,
|
||||
withTargetFlags(Op, SPII::MO_TLS_LDO_HIX22, DAG));
|
||||
withTargetFlags(Op, SparcMCExpr::VK_Sparc_TLS_LDO_HIX22, DAG));
|
||||
SDValue Lo = DAG.getNode(SPISD::Lo, DL, PtrVT,
|
||||
withTargetFlags(Op, SPII::MO_TLS_LDO_LOX10, DAG));
|
||||
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, SPII::MO_TLS_LDO_ADD, DAG));
|
||||
withTargetFlags(Op, SparcMCExpr::VK_Sparc_TLS_LDO_ADD, DAG));
|
||||
}
|
||||
|
||||
if (model == TLSModel::InitialExec) {
|
||||
unsigned ldTF = ((PtrVT == MVT::i64)? SPII::MO_TLS_IE_LDX
|
||||
: SPII::MO_TLS_IE_LD);
|
||||
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);
|
||||
|
||||
@ -1842,21 +1938,23 @@ SDValue SparcTargetLowering::LowerGlobalTLSAddress(SDValue Op,
|
||||
MFI->setHasCalls(true);
|
||||
|
||||
SDValue TGA = makeHiLoPair(Op,
|
||||
SPII::MO_TLS_IE_HI22, SPII::MO_TLS_IE_LO10, DAG);
|
||||
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, SPII::MO_TLS_IE_ADD, DAG));
|
||||
withTargetFlags(Op,
|
||||
SparcMCExpr::VK_Sparc_TLS_IE_ADD, DAG));
|
||||
}
|
||||
|
||||
assert(model == TLSModel::LocalExec);
|
||||
SDValue Hi = DAG.getNode(SPISD::Hi, DL, PtrVT,
|
||||
withTargetFlags(Op, SPII::MO_TLS_LE_HIX22, DAG));
|
||||
withTargetFlags(Op, SparcMCExpr::VK_Sparc_TLS_LE_HIX22, DAG));
|
||||
SDValue Lo = DAG.getNode(SPISD::Lo, DL, PtrVT,
|
||||
withTargetFlags(Op, SPII::MO_TLS_LE_LOX10, DAG));
|
||||
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,
|
||||
@ -2334,39 +2432,57 @@ static SDValue getFLUSHW(SDValue Op, SelectionDAG &DAG) {
|
||||
return Chain;
|
||||
}
|
||||
|
||||
static SDValue LowerFRAMEADDR(SDValue Op, SelectionDAG &DAG) {
|
||||
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;
|
||||
|
||||
uint64_t depth = Op.getConstantOperandVal(0);
|
||||
unsigned stackBias = Subtarget->getStackPointerBias();
|
||||
|
||||
SDValue FrameAddr;
|
||||
if (depth == 0)
|
||||
FrameAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl, FrameReg, VT);
|
||||
else {
|
||||
// flush first to make sure the windowed registers' values are in stack
|
||||
SDValue Chain = getFLUSHW(Op, DAG);
|
||||
FrameAddr = DAG.getCopyFromReg(Chain, dl, FrameReg, VT);
|
||||
|
||||
for (uint64_t i = 0; i != depth; ++i) {
|
||||
SDValue Ptr = DAG.getNode(ISD::ADD,
|
||||
dl, MVT::i32,
|
||||
FrameAddr, DAG.getIntPtrConstant(56));
|
||||
FrameAddr = DAG.getLoad(MVT::i32, dl,
|
||||
Chain,
|
||||
Ptr,
|
||||
MachinePointerInfo(), false, false, false, 0);
|
||||
}
|
||||
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));
|
||||
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));
|
||||
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));
|
||||
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 SparcTargetLowering &TLI,
|
||||
const SparcSubtarget *Subtarget) {
|
||||
MachineFunction &MF = DAG.getMachineFunction();
|
||||
MachineFrameInfo *MFI = MF.getFrameInfo();
|
||||
MFI->setReturnAddressIsTaken(true);
|
||||
@ -2380,25 +2496,20 @@ static SDValue LowerRETURNADDR(SDValue Op, SelectionDAG &DAG,
|
||||
unsigned RetReg = MF.addLiveIn(SP::I7,
|
||||
TLI.getRegClassFor(TLI.getPointerTy()));
|
||||
RetAddr = DAG.getCopyFromReg(DAG.getEntryNode(), dl, RetReg, VT);
|
||||
} else {
|
||||
// Need frame address to find return address of the caller.
|
||||
MFI->setFrameAddressIsTaken(true);
|
||||
|
||||
// flush first to make sure the windowed registers' values are in stack
|
||||
SDValue Chain = getFLUSHW(Op, DAG);
|
||||
RetAddr = DAG.getCopyFromReg(Chain, dl, SP::I6, VT);
|
||||
|
||||
for (uint64_t i = 0; i != depth; ++i) {
|
||||
SDValue Ptr = DAG.getNode(ISD::ADD,
|
||||
dl, MVT::i32,
|
||||
RetAddr,
|
||||
DAG.getIntPtrConstant((i == depth-1)?60:56));
|
||||
RetAddr = DAG.getLoad(MVT::i32, dl,
|
||||
Chain,
|
||||
Ptr,
|
||||
MachinePointerInfo(), false, false, false, 0);
|
||||
}
|
||||
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));
|
||||
RetAddr = DAG.getLoad(VT, dl, DAG.getEntryNode(), Ptr,
|
||||
MachinePointerInfo(), false, false, false, 0);
|
||||
|
||||
return RetAddr;
|
||||
}
|
||||
|
||||
@ -2615,6 +2726,63 @@ static SDValue LowerADDC_ADDE_SUBC_SUBE(SDValue Op, SelectionDAG &DAG) {
|
||||
return DAG.getMergeValues(Ops, 2, 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, 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));
|
||||
SDValue TopHalf = DAG.getNode(ISD::EXTRACT_ELEMENT, dl, VT,
|
||||
MulResult, DAG.getIntPtrConstant(1));
|
||||
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, VT),
|
||||
ISD::SETNE);
|
||||
}
|
||||
// MulResult is a node with an illegal type. Because such things are not
|
||||
// generally permitted during this phase of legalization, delete the
|
||||
// node. The above EXTRACT_ELEMENT nodes should have been folded.
|
||||
DAG.DeleteNode(MulResult.getNode());
|
||||
|
||||
SDValue Ops[2] = { BottomHalf, TopHalf } ;
|
||||
return DAG.getMergeValues(Ops, 2, 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 {
|
||||
|
||||
@ -2625,8 +2793,10 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const {
|
||||
switch (Op.getOpcode()) {
|
||||
default: llvm_unreachable("Should not custom lower this!");
|
||||
|
||||
case ISD::RETURNADDR: return LowerRETURNADDR(Op, DAG, *this);
|
||||
case ISD::FRAMEADDR: return LowerFRAMEADDR(Op, DAG);
|
||||
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);
|
||||
@ -2668,34 +2838,80 @@ LowerOperation(SDValue Op, SelectionDAG &DAG) const {
|
||||
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 {
|
||||
const TargetInstrInfo &TII = *getTargetMachine().getInstrInfo();
|
||||
unsigned BROpcode;
|
||||
unsigned CC;
|
||||
DebugLoc dl = MI->getDebugLoc();
|
||||
// Figure out the conditional branch opcode to use for this select_cc.
|
||||
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:
|
||||
BROpcode = SP::BCOND;
|
||||
break;
|
||||
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:
|
||||
BROpcode = SP::FBCOND;
|
||||
break;
|
||||
}
|
||||
return expandSelectCC(MI, BB, SP::FBCOND);
|
||||
|
||||
CC = (SPCC::CondCodes)MI->getOperand(3).getImm();
|
||||
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_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 = *getTargetMachine().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
|
||||
@ -2749,6 +2965,100 @@ SparcTargetLowering::EmitInstrWithCustomInserter(MachineInstr *MI,
|
||||
return BB;
|
||||
}
|
||||
|
||||
MachineBasicBlock*
|
||||
SparcTargetLowering::expandAtomicRMW(MachineInstr *MI,
|
||||
MachineBasicBlock *MBB,
|
||||
unsigned Opcode,
|
||||
unsigned CondCode) const {
|
||||
const TargetInstrInfo &TII = *getTargetMachine().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);
|
||||
unsigned UpdReg = MRI.createVirtualRegister(ValueRC);
|
||||
|
||||
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 {
|
||||
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
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -2761,12 +3071,72 @@ SparcTargetLowering::getConstraintType(const std::string &Constraint) const {
|
||||
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 == NULL)
|
||||
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(0, 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(), 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 std::string &Constraint,
|
||||
MVT VT) const {
|
||||
@ -2775,6 +3145,26 @@ SparcTargetLowering::getRegForInlineAsmConstraint(const std::string &Constraint,
|
||||
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(newConstraint, VT);
|
||||
}
|
||||
}
|
||||
|
||||
return TargetLowering::getRegForInlineAsmConstraint(Constraint, VT);
|
||||
|
@ -73,6 +73,13 @@ namespace llvm {
|
||||
virtual const char *getTargetNodeName(unsigned Opcode) const;
|
||||
|
||||
ConstraintType getConstraintType(const std::string &Constraint) const;
|
||||
ConstraintWeight
|
||||
getSingleConstraintMatchWeight(AsmOperandInfo &info,
|
||||
const char *constraint) const;
|
||||
void LowerAsmOperandForConstraint(SDValue Op,
|
||||
std::string &Constraint,
|
||||
std::vector<SDValue> &Ops,
|
||||
SelectionDAG &DAG) const;
|
||||
std::pair<unsigned, const TargetRegisterClass*>
|
||||
getRegForInlineAsmConstraint(const std::string &Constraint, MVT VT) const;
|
||||
|
||||
@ -158,6 +165,13 @@ namespace llvm {
|
||||
virtual void ReplaceNodeResults(SDNode *N,
|
||||
SmallVectorImpl<SDValue>& Results,
|
||||
SelectionDAG &DAG) const;
|
||||
|
||||
MachineBasicBlock *expandSelectCC(MachineInstr *MI, MachineBasicBlock *BB,
|
||||
unsigned BROpcode) const;
|
||||
MachineBasicBlock *expandAtomicRMW(MachineInstr *MI,
|
||||
MachineBasicBlock *BB,
|
||||
unsigned Opcode,
|
||||
unsigned CondCode = 0) const;
|
||||
};
|
||||
} // end namespace llvm
|
||||
|
||||
|
@ -141,41 +141,43 @@ def : Pat<(i64 imm:$val),
|
||||
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 : Pat<(and i64:$a, i64:$b), (ANDrr $a, $b)>;
|
||||
def : Pat<(or i64:$a, i64:$b), (ORrr $a, $b)>;
|
||||
def : Pat<(xor i64:$a, i64:$b), (XORrr $a, $b)>;
|
||||
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)))]>;
|
||||
|
||||
def : Pat<(and i64:$a, (not i64:$b)), (ANDNrr $a, $b)>;
|
||||
def : Pat<(or i64:$a, (not i64:$b)), (ORNrr $a, $b)>;
|
||||
def : Pat<(xor i64:$a, (not i64:$b)), (XNORrr $a, $b)>;
|
||||
defm ADDX : F3_12<"add", 0b000000, add, I64Regs, i64, i64imm>;
|
||||
defm SUBX : F3_12<"sub", 0b000100, sub, I64Regs, i64, i64imm>;
|
||||
|
||||
def : Pat<(add i64:$a, i64:$b), (ADDrr $a, $b)>;
|
||||
def : Pat<(sub i64:$a, i64:$b), (SUBrr $a, $b)>;
|
||||
|
||||
def : Pat<(SPcmpicc i64:$a, i64:$b), (CMPrr $a, $b)>;
|
||||
|
||||
def : Pat<(tlsadd i64:$a, i64:$b, tglobaltlsaddr:$sym),
|
||||
(TLS_ADDrr $a, $b, $sym)>;
|
||||
|
||||
// Register-immediate instructions.
|
||||
|
||||
def : Pat<(and i64:$a, (i64 simm13:$b)), (ANDri $a, (as_i32imm $b))>;
|
||||
def : Pat<(or i64:$a, (i64 simm13:$b)), (ORri $a, (as_i32imm $b))>;
|
||||
def : Pat<(xor i64:$a, (i64 simm13:$b)), (XORri $a, (as_i32imm $b))>;
|
||||
|
||||
def : Pat<(add i64:$a, (i64 simm13:$b)), (ADDri $a, (as_i32imm $b))>;
|
||||
def : Pat<(sub i64:$a, (i64 simm13:$b)), (SUBri $a, (as_i32imm $b))>;
|
||||
|
||||
def : Pat<(SPcmpicc i64:$a, (i64 simm13:$b)), (CMPri $a, (as_i32imm $b))>;
|
||||
|
||||
def : Pat<(ctpop i64:$src), (POPCrr $src)>;
|
||||
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]
|
||||
|
||||
@ -191,9 +193,9 @@ def MULXrr : F3_1<2, 0b001001,
|
||||
"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:$i),
|
||||
"mulx $rs1, $i, $rd",
|
||||
[(set i64:$rd, (mul i64:$rs1, (i64 simm13:$i)))]>;
|
||||
(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 {
|
||||
@ -202,18 +204,18 @@ def SDIVXrr : F3_1<2, 0b101101,
|
||||
"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:$i),
|
||||
"sdivx $rs1, $i, $rd",
|
||||
[(set i64:$rd, (sdiv i64:$rs1, (i64 simm13:$i)))]>;
|
||||
(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:$i),
|
||||
"udivx $rs1, $i, $rd",
|
||||
[(set i64:$rd, (udiv i64:$rs1, (i64 simm13:$i)))]>;
|
||||
(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]
|
||||
@ -233,15 +235,9 @@ def UDIVXri : F3_2<2, 0b001101,
|
||||
let Predicates = [Is64Bit] in {
|
||||
|
||||
// 64-bit loads.
|
||||
def LDXrr : F3_1<3, 0b001011,
|
||||
(outs I64Regs:$dst), (ins MEMrr:$addr),
|
||||
"ldx [$addr], $dst",
|
||||
[(set i64:$dst, (load ADDRrr:$addr))]>;
|
||||
def LDXri : F3_2<3, 0b001011,
|
||||
(outs I64Regs:$dst), (ins MEMri:$addr),
|
||||
"ldx [$addr], $dst",
|
||||
[(set i64:$dst, (load ADDRri:$addr))]>;
|
||||
let mayLoad = 1 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",
|
||||
@ -274,24 +270,10 @@ 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.
|
||||
def LDSWrr : F3_1<3, 0b001011,
|
||||
(outs I64Regs:$dst), (ins MEMrr:$addr),
|
||||
"ldsw [$addr], $dst",
|
||||
[(set i64:$dst, (sextloadi32 ADDRrr:$addr))]>;
|
||||
def LDSWri : F3_2<3, 0b001011,
|
||||
(outs I64Regs:$dst), (ins MEMri:$addr),
|
||||
"ldsw [$addr], $dst",
|
||||
[(set i64:$dst, (sextloadi32 ADDRri:$addr))]>;
|
||||
defm LDSW : Load<"ldsw", 0b001000, sextloadi32, I64Regs, i64>;
|
||||
|
||||
// 64-bit stores.
|
||||
def STXrr : F3_1<3, 0b001110,
|
||||
(outs), (ins MEMrr:$addr, I64Regs:$src),
|
||||
"stx $src, [$addr]",
|
||||
[(store i64:$src, ADDRrr:$addr)]>;
|
||||
def STXri : F3_2<3, 0b001110,
|
||||
(outs), (ins MEMri:$addr, I64Regs:$src),
|
||||
"stx $src, [$addr]",
|
||||
[(store i64:$src, ADDRri:$addr)]>;
|
||||
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)>;
|
||||
@ -311,6 +293,15 @@ def : Pat<(store (i64 0), ADDRri:$dst), (STXri ADDRri:$dst, (i64 G0))>;
|
||||
//===----------------------------------------------------------------------===//
|
||||
// 64-bit Conditionals.
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
// Conditional branch class on %xcc:
|
||||
class XBranchSP<dag ins, string asmstr, list<dag> pattern>
|
||||
: F2_3<0b001, 0b10, (outs), ins, asmstr, pattern> {
|
||||
let isBranch = 1;
|
||||
let isTerminator = 1;
|
||||
let hasDelaySlot = 1;
|
||||
}
|
||||
|
||||
//
|
||||
// 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
|
||||
@ -322,32 +313,42 @@ def : Pat<(store (i64 0), ADDRri:$dst), (STXri ADDRri:$dst, (i64 G0))>;
|
||||
let Predicates = [Is64Bit] in {
|
||||
|
||||
let Uses = [ICC] in
|
||||
def BPXCC : BranchSP<(ins brtarget:$imm22, CCOp:$cond),
|
||||
"b$cond %xcc, $imm22",
|
||||
[(SPbrxcc bb:$imm22, imm:$cond)]>;
|
||||
def BPXCC : XBranchSP<(ins brtarget:$imm19, CCOp:$cond),
|
||||
"b$cond %xcc, $imm19",
|
||||
[(SPbrxcc bb:$imm19, imm:$cond)]>;
|
||||
|
||||
// Conditional moves on %xcc.
|
||||
let Uses = [ICC], Constraints = "$f = $rd" in {
|
||||
def MOVXCCrr : Pseudo<(outs IntRegs:$rd),
|
||||
let cc = 0b110 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 : Pseudo<(outs IntRegs:$rd),
|
||||
(ins i32imm:$i, IntRegs:$f, CCOp:$cond),
|
||||
"mov$cond %xcc, $i, $rd",
|
||||
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:$i, i32:$f, imm:$cond))]>;
|
||||
def FMOVS_XCC : Pseudo<(outs FPRegs:$rd),
|
||||
(SPselectxcc simm11:$simm11, i32:$f, imm:$cond))]>;
|
||||
} // cc
|
||||
|
||||
let opf_cc = 0b110 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 : Pseudo<(outs DFPRegs:$rd),
|
||||
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
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -357,31 +358,31 @@ def FMOVD_XCC : Pseudo<(outs DFPRegs:$rd),
|
||||
let Predicates = [Is64Bit] in {
|
||||
|
||||
def FXTOS : F3_3u<2, 0b110100, 0b010000100,
|
||||
(outs FPRegs:$dst), (ins DFPRegs:$src),
|
||||
"fxtos $src, $dst",
|
||||
[(set FPRegs:$dst, (SPxtof DFPRegs:$src))]>;
|
||||
(outs FPRegs:$rd), (ins DFPRegs:$rs2),
|
||||
"fxtos $rs2, $rd",
|
||||
[(set FPRegs:$rd, (SPxtof DFPRegs:$rs2))]>;
|
||||
def FXTOD : F3_3u<2, 0b110100, 0b010001000,
|
||||
(outs DFPRegs:$dst), (ins DFPRegs:$src),
|
||||
"fxtod $src, $dst",
|
||||
[(set DFPRegs:$dst, (SPxtof DFPRegs:$src))]>;
|
||||
(outs DFPRegs:$rd), (ins DFPRegs:$rs2),
|
||||
"fxtod $rs2, $rd",
|
||||
[(set DFPRegs:$rd, (SPxtof DFPRegs:$rs2))]>;
|
||||
def FXTOQ : F3_3u<2, 0b110100, 0b010001100,
|
||||
(outs QFPRegs:$dst), (ins DFPRegs:$src),
|
||||
"fxtoq $src, $dst",
|
||||
[(set QFPRegs:$dst, (SPxtof DFPRegs:$src))]>,
|
||||
(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:$dst), (ins FPRegs:$src),
|
||||
"fstox $src, $dst",
|
||||
[(set DFPRegs:$dst, (SPftox FPRegs:$src))]>;
|
||||
(outs DFPRegs:$rd), (ins FPRegs:$rs2),
|
||||
"fstox $rs2, $rd",
|
||||
[(set DFPRegs:$rd, (SPftox FPRegs:$rs2))]>;
|
||||
def FDTOX : F3_3u<2, 0b110100, 0b010000010,
|
||||
(outs DFPRegs:$dst), (ins DFPRegs:$src),
|
||||
"fdtox $src, $dst",
|
||||
[(set DFPRegs:$dst, (SPftox DFPRegs:$src))]>;
|
||||
(outs DFPRegs:$rd), (ins DFPRegs:$rs2),
|
||||
"fdtox $rs2, $rd",
|
||||
[(set DFPRegs:$rd, (SPftox DFPRegs:$rs2))]>;
|
||||
def FQTOX : F3_3u<2, 0b110100, 0b010000011,
|
||||
(outs DFPRegs:$dst), (ins QFPRegs:$src),
|
||||
"fqtox $src, $dst",
|
||||
[(set DFPRegs:$dst, (SPftox QFPRegs:$src))]>,
|
||||
(outs DFPRegs:$rd), (ins QFPRegs:$rs2),
|
||||
"fqtox $rs2, $rd",
|
||||
[(set DFPRegs:$rd, (SPftox QFPRegs:$rs2))]>,
|
||||
Requires<[HasHardQuad]>;
|
||||
|
||||
} // Predicates = [Is64Bit]
|
||||
@ -402,3 +403,89 @@ 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" in {
|
||||
def CASXrr: F3_1_asi<3, 0b111110, 0b10000000,
|
||||
(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>;
|
||||
|
||||
// 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)>;
|
||||
}
|
||||
|
142
contrib/llvm/lib/Target/Sparc/SparcInstrAliases.td
Normal file
142
contrib/llvm/lib/Target/Sparc/SparcInstrAliases.td
Normal file
@ -0,0 +1,142 @@
|
||||
//===-- 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 cond_mov_alias<string cond, int condVal, string ccreg,
|
||||
Instruction movrr, Instruction movri,
|
||||
Instruction fmovs, Instruction fmovd> {
|
||||
|
||||
// mov<cond> (%icc|%xcc|%fcc0), rs2, rd
|
||||
def : InstAlias<!strconcat(!strconcat(!strconcat("mov", cond), ccreg),
|
||||
", $rs2, $rd"),
|
||||
(movrr IntRegs:$rd, IntRegs:$rs2, condVal)>;
|
||||
|
||||
// mov<cond> (%icc|%xcc|%fcc0), simm11, rd
|
||||
def : InstAlias<!strconcat(!strconcat(!strconcat("mov", cond), ccreg),
|
||||
", $simm11, $rd"),
|
||||
(movri IntRegs:$rd, i32imm:$simm11, condVal)>;
|
||||
|
||||
// fmovs<cond> (%icc|%xcc|%fcc0), $rs2, $rd
|
||||
def : InstAlias<!strconcat(!strconcat(!strconcat("fmovs", cond), ccreg),
|
||||
", $rs2, $rd"),
|
||||
(fmovs FPRegs:$rd, FPRegs:$rs2, condVal)>;
|
||||
|
||||
// fmovd<cond> (%icc|%xcc|%fcc0), $rs2, $rd
|
||||
def : InstAlias<!strconcat(!strconcat(!strconcat("fmovd", cond), ccreg),
|
||||
", $rs2, $rd"),
|
||||
(fmovd DFPRegs:$rd, 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> %xcc, $imm
|
||||
def : InstAlias<!strconcat(!strconcat("b", cond), " %xcc, $imm"),
|
||||
(BPXCC brtarget:$imm, condVal)>, Requires<[Is64Bit]>;
|
||||
|
||||
defm : cond_mov_alias<cond, condVal, " %icc",
|
||||
MOVICCrr, MOVICCri,
|
||||
FMOVS_ICC, FMOVD_ICC>, Requires<[HasV9]>;
|
||||
|
||||
defm : cond_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]>;
|
||||
|
||||
}
|
||||
|
||||
|
||||
// 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>;
|
||||
|
||||
defm : cond_mov_alias<cond, condVal, " %fcc0",
|
||||
MOVFCCrr, MOVFCCri,
|
||||
FMOVS_FCC, FMOVD_FCC>, Requires<[HasV9]>;
|
||||
|
||||
// fmovq<cond> %fcc0, $rs2, $rd
|
||||
def : InstAlias<!strconcat(!strconcat("fmovq", cond), " %fcc0, $rs2, $rd"),
|
||||
(FMOVQ_ICC QFPRegs:$rd, 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<"e", 0b0001>;
|
||||
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<"cs", 0b0101>;
|
||||
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<"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<"e", 0b1001>;
|
||||
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)>;
|
||||
def : InstAlias<"jmp $addr", (JMPLri G0, MEMri:$addr)>;
|
||||
|
||||
// call addr -> jmpl addr, %o7
|
||||
def : InstAlias<"call $addr", (JMPLrr O7, MEMrr:$addr)>;
|
||||
def : InstAlias<"call $addr", (JMPLri O7, MEMri:$addr)>;
|
||||
|
||||
// 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)>;
|
@ -12,6 +12,7 @@ class InstSP<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
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
|
||||
@ -20,6 +21,9 @@ class InstSP<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
dag InOperandList = ins;
|
||||
let AsmString = asmstr;
|
||||
let Pattern = pattern;
|
||||
|
||||
let DecoderNamespace = "Sparc";
|
||||
field bits<32> SoftFail = 0;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -58,6 +62,27 @@ class F2_2<bits<3> op2Val, dag outs, dag ins, string asmstr,
|
||||
let Inst{28-25} = cond;
|
||||
}
|
||||
|
||||
class F2_3<bits<3> op2Val, bits<2> ccVal, dag outs, dag ins, string asmstr,
|
||||
list<dag> pattern>
|
||||
: InstSP<outs, ins, asmstr, pattern> {
|
||||
bit annul;
|
||||
bits<4> cond;
|
||||
bit pred;
|
||||
bits<19> imm19;
|
||||
|
||||
let op = 0; // op = 0
|
||||
|
||||
bit annul = 0; // currently unused
|
||||
let pred = 1; // default is predict taken
|
||||
|
||||
let Inst{29} = annul;
|
||||
let Inst{28-25} = cond;
|
||||
let Inst{24-22} = op2Val;
|
||||
let Inst{21-20} = ccVal;
|
||||
let Inst{19} = pred;
|
||||
let Inst{18-0} = imm19;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Format #3 instruction classes in the Sparc
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -75,9 +100,8 @@ class F3<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
|
||||
// Specific F3 classes: SparcV8 manual, page 44
|
||||
//
|
||||
class F3_1<bits<2> opVal, bits<6> op3val, dag outs, dag ins,
|
||||
class F3_1_asi<bits<2> opVal, bits<6> op3val, bits<8> asi, dag outs, dag ins,
|
||||
string asmstr, list<dag> pattern> : F3<outs, ins, asmstr, pattern> {
|
||||
bits<8> asi = 0; // asi not currently used
|
||||
bits<5> rs2;
|
||||
|
||||
let op = opVal;
|
||||
@ -88,6 +112,10 @@ class F3_1<bits<2> opVal, bits<6> op3val, dag outs, dag ins,
|
||||
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, 0, outs, ins,
|
||||
asmstr, pattern>;
|
||||
|
||||
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;
|
||||
@ -168,12 +196,12 @@ class F3_Si<bits<2> opVal, bits<6> op3val, bit xVal, dag outs, dag ins,
|
||||
// Define rr and ri shift instructions with patterns.
|
||||
multiclass F3_S<string OpcStr, bits<6> Op3Val, bit XVal, SDNode OpNode,
|
||||
ValueType VT, RegisterClass RC> {
|
||||
def rr : F3_Sr<2, Op3Val, XVal, (outs RC:$rd), (ins RC:$rs, IntRegs:$rs2),
|
||||
!strconcat(OpcStr, " $rs, $rs2, $rd"),
|
||||
[(set VT:$rd, (OpNode VT:$rs, i32:$rs2))]>;
|
||||
def ri : F3_Si<2, Op3Val, XVal, (outs RC:$rd), (ins RC:$rs, i32imm:$shcnt),
|
||||
!strconcat(OpcStr, " $rs, $shcnt, $rd"),
|
||||
[(set VT:$rd, (OpNode VT:$rs, (i32 imm:$shcnt)))]>;
|
||||
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>
|
||||
|
@ -431,8 +431,9 @@ unsigned SparcInstrInfo::getGlobalBaseReg(MachineFunction *MF) const
|
||||
MachineBasicBlock::iterator MBBI = FirstMBB.begin();
|
||||
MachineRegisterInfo &RegInfo = MF->getRegInfo();
|
||||
|
||||
GlobalBaseReg = RegInfo.createVirtualRegister(&SP::IntRegsRegClass);
|
||||
|
||||
const TargetRegisterClass *PtrRC =
|
||||
Subtarget.is64Bit() ? &SP::I64RegsRegClass : &SP::IntRegsRegClass;
|
||||
GlobalBaseReg = RegInfo.createVirtualRegister(PtrRC);
|
||||
|
||||
DebugLoc dl;
|
||||
|
||||
|
@ -76,20 +76,37 @@ 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>;
|
||||
def calltarget : Operand<i32>;
|
||||
def brtarget : Operand<OtherVT> {
|
||||
let EncoderMethod = "getBranchTargetOpValue";
|
||||
}
|
||||
|
||||
def calltarget : Operand<i32> {
|
||||
let EncoderMethod = "getCallTargetOpValue";
|
||||
}
|
||||
|
||||
// Operand for printing out a condition code.
|
||||
let PrintMethod = "printCCOperand" in
|
||||
@ -163,7 +180,7 @@ def tlscall : SDNode<"SPISD::TLS_CALL", SDT_SPCall,
|
||||
[SDNPHasChain, SDNPOptInGlue, SDNPOutGlue,
|
||||
SDNPVariadic]>;
|
||||
|
||||
def getPCX : Operand<i32> {
|
||||
def getPCX : Operand<iPTR> {
|
||||
let PrintMethod = "printGetPCX";
|
||||
}
|
||||
|
||||
@ -210,26 +227,53 @@ def FCC_O : FCC_VAL<29>; // Ordered
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
/// F3_12 multiclass - Define a normal F3_1/F3_2 pattern in one shot.
|
||||
multiclass F3_12<string OpcStr, bits<6> Op3Val, SDNode OpNode> {
|
||||
multiclass F3_12<string OpcStr, bits<6> Op3Val, SDNode OpNode,
|
||||
RegisterClass RC, ValueType Ty, Operand immOp> {
|
||||
def rr : F3_1<2, Op3Val,
|
||||
(outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c),
|
||||
!strconcat(OpcStr, " $b, $c, $dst"),
|
||||
[(set i32:$dst, (OpNode i32:$b, i32:$c))]>;
|
||||
(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 IntRegs:$dst), (ins IntRegs:$b, i32imm:$c),
|
||||
!strconcat(OpcStr, " $b, $c, $dst"),
|
||||
[(set i32:$dst, (OpNode i32:$b, (i32 simm13:$c)))]>;
|
||||
(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:$dst), (ins IntRegs:$b, IntRegs:$c),
|
||||
!strconcat(OpcStr, " $b, $c, $dst"), []>;
|
||||
(outs IntRegs:$rd), (ins IntRegs:$rs1, IntRegs:$rs2),
|
||||
!strconcat(OpcStr, " $rs1, $rs2, $rd"), []>;
|
||||
def ri : F3_2<2, Op3Val,
|
||||
(outs IntRegs:$dst), (ins IntRegs:$b, i32imm:$c),
|
||||
!strconcat(OpcStr, " $b, $c, $dst"), []>;
|
||||
(outs IntRegs:$rd), (ins IntRegs:$rs1, i32imm:$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))]>;
|
||||
}
|
||||
|
||||
// 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)]>;
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
@ -238,7 +282,10 @@ multiclass F3_12np<string OpcStr, bits<6> Op3Val> {
|
||||
|
||||
// Pseudo instructions.
|
||||
class Pseudo<dag outs, dag ins, string asmstr, list<dag> pattern>
|
||||
: InstSP<outs, ins, asmstr, pattern>;
|
||||
: InstSP<outs, ins, asmstr, pattern> {
|
||||
let isCodeGenOnly = 1;
|
||||
let isPseudo = 1;
|
||||
}
|
||||
|
||||
// GETPCX for PIC
|
||||
let Defs = [O7] in {
|
||||
@ -315,10 +362,18 @@ let usesCustomInserter = 1, Uses = [FCC] in {
|
||||
[(set f128:$dst, (SPselectfcc f128:$T, f128:$F, imm:$Cond))]>;
|
||||
}
|
||||
|
||||
// JMPL Instruction.
|
||||
let isTerminator = 1, hasDelaySlot = 1, isBarrier = 1 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 in {
|
||||
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)]>;
|
||||
@ -329,128 +384,28 @@ let isReturn = 1, isTerminator = 1, hasDelaySlot = 1, isBarrier = 1 in {
|
||||
}
|
||||
|
||||
// Section B.1 - Load Integer Instructions, p. 90
|
||||
def LDSBrr : F3_1<3, 0b001001,
|
||||
(outs IntRegs:$dst), (ins MEMrr:$addr),
|
||||
"ldsb [$addr], $dst",
|
||||
[(set i32:$dst, (sextloadi8 ADDRrr:$addr))]>;
|
||||
def LDSBri : F3_2<3, 0b001001,
|
||||
(outs IntRegs:$dst), (ins MEMri:$addr),
|
||||
"ldsb [$addr], $dst",
|
||||
[(set i32:$dst, (sextloadi8 ADDRri:$addr))]>;
|
||||
def LDSHrr : F3_1<3, 0b001010,
|
||||
(outs IntRegs:$dst), (ins MEMrr:$addr),
|
||||
"ldsh [$addr], $dst",
|
||||
[(set i32:$dst, (sextloadi16 ADDRrr:$addr))]>;
|
||||
def LDSHri : F3_2<3, 0b001010,
|
||||
(outs IntRegs:$dst), (ins MEMri:$addr),
|
||||
"ldsh [$addr], $dst",
|
||||
[(set i32:$dst, (sextloadi16 ADDRri:$addr))]>;
|
||||
def LDUBrr : F3_1<3, 0b000001,
|
||||
(outs IntRegs:$dst), (ins MEMrr:$addr),
|
||||
"ldub [$addr], $dst",
|
||||
[(set i32:$dst, (zextloadi8 ADDRrr:$addr))]>;
|
||||
def LDUBri : F3_2<3, 0b000001,
|
||||
(outs IntRegs:$dst), (ins MEMri:$addr),
|
||||
"ldub [$addr], $dst",
|
||||
[(set i32:$dst, (zextloadi8 ADDRri:$addr))]>;
|
||||
def LDUHrr : F3_1<3, 0b000010,
|
||||
(outs IntRegs:$dst), (ins MEMrr:$addr),
|
||||
"lduh [$addr], $dst",
|
||||
[(set i32:$dst, (zextloadi16 ADDRrr:$addr))]>;
|
||||
def LDUHri : F3_2<3, 0b000010,
|
||||
(outs IntRegs:$dst), (ins MEMri:$addr),
|
||||
"lduh [$addr], $dst",
|
||||
[(set i32:$dst, (zextloadi16 ADDRri:$addr))]>;
|
||||
def LDrr : F3_1<3, 0b000000,
|
||||
(outs IntRegs:$dst), (ins MEMrr:$addr),
|
||||
"ld [$addr], $dst",
|
||||
[(set i32:$dst, (load ADDRrr:$addr))]>;
|
||||
def LDri : F3_2<3, 0b000000,
|
||||
(outs IntRegs:$dst), (ins MEMri:$addr),
|
||||
"ld [$addr], $dst",
|
||||
[(set i32:$dst, (load ADDRri:$addr))]>;
|
||||
defm LDSB : Load<"ldsb", 0b001001, sextloadi8, IntRegs, i32>;
|
||||
defm LDSH : Load<"ldsh", 0b001010, sextloadi16, IntRegs, i32>;
|
||||
defm LDUB : Load<"ldub", 0b000001, zextloadi8, IntRegs, i32>;
|
||||
defm LDUH : Load<"lduh", 0b000010, zextloadi16, IntRegs, i32>;
|
||||
defm LD : Load<"ld", 0b000000, load, IntRegs, i32>;
|
||||
|
||||
// Section B.2 - Load Floating-point Instructions, p. 92
|
||||
def LDFrr : F3_1<3, 0b100000,
|
||||
(outs FPRegs:$dst), (ins MEMrr:$addr),
|
||||
"ld [$addr], $dst",
|
||||
[(set f32:$dst, (load ADDRrr:$addr))]>;
|
||||
def LDFri : F3_2<3, 0b100000,
|
||||
(outs FPRegs:$dst), (ins MEMri:$addr),
|
||||
"ld [$addr], $dst",
|
||||
[(set f32:$dst, (load ADDRri:$addr))]>;
|
||||
def LDDFrr : F3_1<3, 0b100011,
|
||||
(outs DFPRegs:$dst), (ins MEMrr:$addr),
|
||||
"ldd [$addr], $dst",
|
||||
[(set f64:$dst, (load ADDRrr:$addr))]>;
|
||||
def LDDFri : F3_2<3, 0b100011,
|
||||
(outs DFPRegs:$dst), (ins MEMri:$addr),
|
||||
"ldd [$addr], $dst",
|
||||
[(set f64:$dst, (load ADDRri:$addr))]>;
|
||||
def LDQFrr : F3_1<3, 0b100010,
|
||||
(outs QFPRegs:$dst), (ins MEMrr:$addr),
|
||||
"ldq [$addr], $dst",
|
||||
[(set f128:$dst, (load ADDRrr:$addr))]>,
|
||||
Requires<[HasV9, HasHardQuad]>;
|
||||
def LDQFri : F3_2<3, 0b100010,
|
||||
(outs QFPRegs:$dst), (ins MEMri:$addr),
|
||||
"ldq [$addr], $dst",
|
||||
[(set f128:$dst, (load ADDRri:$addr))]>,
|
||||
Requires<[HasV9, HasHardQuad]>;
|
||||
defm LDF : Load<"ld", 0b100000, load, FPRegs, f32>;
|
||||
defm LDDF : Load<"ldd", 0b100011, load, DFPRegs, f64>;
|
||||
defm LDQF : Load<"ldq", 0b100010, load, QFPRegs, f128>,
|
||||
Requires<[HasV9, HasHardQuad]>;
|
||||
|
||||
// Section B.4 - Store Integer Instructions, p. 95
|
||||
def STBrr : F3_1<3, 0b000101,
|
||||
(outs), (ins MEMrr:$addr, IntRegs:$rd),
|
||||
"stb $rd, [$addr]",
|
||||
[(truncstorei8 i32:$rd, ADDRrr:$addr)]>;
|
||||
def STBri : F3_2<3, 0b000101,
|
||||
(outs), (ins MEMri:$addr, IntRegs:$rd),
|
||||
"stb $rd, [$addr]",
|
||||
[(truncstorei8 i32:$rd, ADDRri:$addr)]>;
|
||||
def STHrr : F3_1<3, 0b000110,
|
||||
(outs), (ins MEMrr:$addr, IntRegs:$rd),
|
||||
"sth $rd, [$addr]",
|
||||
[(truncstorei16 i32:$rd, ADDRrr:$addr)]>;
|
||||
def STHri : F3_2<3, 0b000110,
|
||||
(outs), (ins MEMri:$addr, IntRegs:$rd),
|
||||
"sth $rd, [$addr]",
|
||||
[(truncstorei16 i32:$rd, ADDRri:$addr)]>;
|
||||
def STrr : F3_1<3, 0b000100,
|
||||
(outs), (ins MEMrr:$addr, IntRegs:$rd),
|
||||
"st $rd, [$addr]",
|
||||
[(store i32:$rd, ADDRrr:$addr)]>;
|
||||
def STri : F3_2<3, 0b000100,
|
||||
(outs), (ins MEMri:$addr, IntRegs:$rd),
|
||||
"st $rd, [$addr]",
|
||||
[(store i32:$rd, ADDRri:$addr)]>;
|
||||
defm STB : Store<"stb", 0b000101, truncstorei8, IntRegs, i32>;
|
||||
defm STH : Store<"sth", 0b000110, truncstorei16, IntRegs, i32>;
|
||||
defm ST : Store<"st", 0b000100, store, IntRegs, i32>;
|
||||
|
||||
// Section B.5 - Store Floating-point Instructions, p. 97
|
||||
def STFrr : F3_1<3, 0b100100,
|
||||
(outs), (ins MEMrr:$addr, FPRegs:$rd),
|
||||
"st $rd, [$addr]",
|
||||
[(store f32:$rd, ADDRrr:$addr)]>;
|
||||
def STFri : F3_2<3, 0b100100,
|
||||
(outs), (ins MEMri:$addr, FPRegs:$rd),
|
||||
"st $rd, [$addr]",
|
||||
[(store f32:$rd, ADDRri:$addr)]>;
|
||||
def STDFrr : F3_1<3, 0b100111,
|
||||
(outs), (ins MEMrr:$addr, DFPRegs:$rd),
|
||||
"std $rd, [$addr]",
|
||||
[(store f64:$rd, ADDRrr:$addr)]>;
|
||||
def STDFri : F3_2<3, 0b100111,
|
||||
(outs), (ins MEMri:$addr, DFPRegs:$rd),
|
||||
"std $rd, [$addr]",
|
||||
[(store f64:$rd, ADDRri:$addr)]>;
|
||||
def STQFrr : F3_1<3, 0b100110,
|
||||
(outs), (ins MEMrr:$addr, QFPRegs:$rd),
|
||||
"stq $rd, [$addr]",
|
||||
[(store f128:$rd, ADDRrr:$addr)]>,
|
||||
Requires<[HasV9, HasHardQuad]>;
|
||||
def STQFri : F3_2<3, 0b100110,
|
||||
(outs), (ins MEMri:$addr, QFPRegs:$rd),
|
||||
"stq $rd, [$addr]",
|
||||
[(store f128:$rd, ADDRri:$addr)]>,
|
||||
Requires<[HasV9, HasHardQuad]>;
|
||||
defm STF : Store<"st", 0b100100, store, FPRegs, f32>;
|
||||
defm STDF : Store<"std", 0b100111, store, DFPRegs, f64>;
|
||||
defm STQF : Store<"stq", 0b100110, store, QFPRegs, f128>,
|
||||
Requires<[HasV9, HasHardQuad]>;
|
||||
|
||||
// Section B.9 - SETHI Instruction, p. 104
|
||||
def SETHIi: F2_1<0b100,
|
||||
@ -464,85 +419,79 @@ 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>;
|
||||
defm AND : F3_12<"and", 0b000001, and, IntRegs, i32, i32imm>;
|
||||
|
||||
def ANDNrr : F3_1<2, 0b000101,
|
||||
(outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c),
|
||||
"andn $b, $c, $dst",
|
||||
[(set i32:$dst, (and i32:$b, (not i32:$c)))]>;
|
||||
(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:$dst), (ins IntRegs:$b, i32imm:$c),
|
||||
"andn $b, $c, $dst", []>;
|
||||
(outs IntRegs:$rd), (ins IntRegs:$rs1, i32imm:$simm13),
|
||||
"andn $rs1, $simm13, $rd", []>;
|
||||
|
||||
defm OR : F3_12<"or", 0b000010, or>;
|
||||
defm OR : F3_12<"or", 0b000010, or, IntRegs, i32, i32imm>;
|
||||
|
||||
def ORNrr : F3_1<2, 0b000110,
|
||||
(outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c),
|
||||
"orn $b, $c, $dst",
|
||||
[(set i32:$dst, (or i32:$b, (not i32:$c)))]>;
|
||||
(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:$dst), (ins IntRegs:$b, i32imm:$c),
|
||||
"orn $b, $c, $dst", []>;
|
||||
defm XOR : F3_12<"xor", 0b000011, xor>;
|
||||
(outs IntRegs:$rd), (ins IntRegs:$rs1, i32imm:$simm13),
|
||||
"orn $rs1, $simm13, $rd", []>;
|
||||
defm XOR : F3_12<"xor", 0b000011, xor, IntRegs, i32, i32imm>;
|
||||
|
||||
def XNORrr : F3_1<2, 0b000111,
|
||||
(outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c),
|
||||
"xnor $b, $c, $dst",
|
||||
[(set i32:$dst, (not (xor i32:$b, i32:$c)))]>;
|
||||
(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:$dst), (ins IntRegs:$b, i32imm:$c),
|
||||
"xnor $b, $c, $dst", []>;
|
||||
(outs IntRegs:$rd), (ins IntRegs:$rs1, i32imm:$simm13),
|
||||
"xnor $rs1, $simm13, $rd", []>;
|
||||
|
||||
// Section B.12 - Shift Instructions, p. 107
|
||||
defm SLL : F3_12<"sll", 0b100101, shl>;
|
||||
defm SRL : F3_12<"srl", 0b100110, srl>;
|
||||
defm SRA : F3_12<"sra", 0b100111, sra>;
|
||||
defm SLL : F3_12<"sll", 0b100101, shl, IntRegs, i32, i32imm>;
|
||||
defm SRL : F3_12<"srl", 0b100110, srl, IntRegs, i32, i32imm>;
|
||||
defm SRA : F3_12<"sra", 0b100111, sra, IntRegs, i32, i32imm>;
|
||||
|
||||
// Section B.13 - Add Instructions, p. 108
|
||||
defm ADD : F3_12<"add", 0b000000, add>;
|
||||
defm ADD : F3_12<"add", 0b000000, add, IntRegs, i32, i32imm>;
|
||||
|
||||
// "LEA" forms of add (patterns to make tblgen happy)
|
||||
let Predicates = [Is32Bit] in
|
||||
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>;
|
||||
defm ADDCC : F3_12<"addcc", 0b010000, addc, IntRegs, i32, i32imm>;
|
||||
|
||||
let Uses = [ICC], Defs = [ICC] in
|
||||
defm ADDX : F3_12<"addxcc", 0b011000, adde>;
|
||||
defm ADDE : F3_12<"addxcc", 0b011000, adde, IntRegs, i32, i32imm>;
|
||||
|
||||
// Section B.15 - Subtract Instructions, p. 110
|
||||
defm SUB : F3_12 <"sub" , 0b000100, sub>;
|
||||
defm SUB : F3_12 <"sub" , 0b000100, sub, IntRegs, i32, i32imm>;
|
||||
let Uses = [ICC], Defs = [ICC] in
|
||||
defm SUBX : F3_12 <"subxcc" , 0b011100, sube>;
|
||||
defm SUBE : F3_12 <"subxcc" , 0b011100, sube, IntRegs, i32, i32imm>;
|
||||
|
||||
let Defs = [ICC] in
|
||||
defm SUBCC : F3_12 <"subcc", 0b010100, subc>;
|
||||
defm SUBCC : F3_12 <"subcc", 0b010100, subc, IntRegs, i32, i32imm>;
|
||||
|
||||
let Defs = [ICC], rd = 0 in {
|
||||
def CMPrr : F3_1<2, 0b010100,
|
||||
(outs), (ins IntRegs:$b, IntRegs:$c),
|
||||
"cmp $b, $c",
|
||||
[(SPcmpicc i32:$b, i32:$c)]>;
|
||||
(outs), (ins IntRegs:$rs1, IntRegs:$rs2),
|
||||
"cmp $rs1, $rs2",
|
||||
[(SPcmpicc i32:$rs1, i32:$rs2)]>;
|
||||
def CMPri : F3_2<2, 0b010100,
|
||||
(outs), (ins IntRegs:$b, i32imm:$c),
|
||||
"cmp $b, $c",
|
||||
[(SPcmpicc i32:$b, (i32 simm13:$c))]>;
|
||||
(outs), (ins IntRegs:$rs1, i32imm:$simm13),
|
||||
"cmp $rs1, $simm13",
|
||||
[(SPcmpicc i32:$rs1, (i32 simm13:$simm13))]>;
|
||||
}
|
||||
|
||||
let Uses = [ICC], Defs = [ICC] in
|
||||
def SUBXCCrr: F3_1<2, 0b011100,
|
||||
(outs IntRegs:$dst), (ins IntRegs:$b, IntRegs:$c),
|
||||
"subxcc $b, $c, $dst", []>;
|
||||
|
||||
|
||||
// Section B.18 - Multiply Instructions, p. 113
|
||||
let Defs = [Y] in {
|
||||
defm UMUL : F3_12np<"umul", 0b001010>;
|
||||
defm SMUL : F3_12 <"smul", 0b001011, mul>;
|
||||
defm SMUL : F3_12 <"smul", 0b001011, mul, IntRegs, i32, i32imm>;
|
||||
}
|
||||
|
||||
// Section B.19 - Divide Instructions, p. 115
|
||||
@ -578,9 +527,8 @@ class BranchSP<dag ins, string asmstr, list<dag> pattern>
|
||||
}
|
||||
|
||||
// Indirect branch instructions.
|
||||
let isTerminator = 1, isBarrier = 1,
|
||||
hasDelaySlot = 1, isBranch =1,
|
||||
isIndirectBranch = 1, rd = 0 in {
|
||||
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",
|
||||
@ -623,15 +571,17 @@ let Uses = [O6],
|
||||
let Inst{29-0} = disp;
|
||||
}
|
||||
|
||||
// indirect calls
|
||||
def JMPLrr : F3_1<2, 0b111000,
|
||||
(outs), (ins MEMrr:$ptr, variable_ops),
|
||||
"call $ptr",
|
||||
[(call ADDRrr:$ptr)]> { let rd = 15; }
|
||||
def JMPLri : F3_2<2, 0b111000,
|
||||
(outs), (ins MEMri:$ptr, variable_ops),
|
||||
"call $ptr",
|
||||
[(call ADDRri:$ptr)]> { let rd = 15; }
|
||||
// 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
|
||||
@ -651,164 +601,164 @@ let Defs = [Y], rd = 0 in {
|
||||
}
|
||||
// Convert Integer to Floating-point Instructions, p. 141
|
||||
def FITOS : F3_3u<2, 0b110100, 0b011000100,
|
||||
(outs FPRegs:$dst), (ins FPRegs:$src),
|
||||
"fitos $src, $dst",
|
||||
[(set FPRegs:$dst, (SPitof FPRegs:$src))]>;
|
||||
(outs FPRegs:$rd), (ins FPRegs:$rs2),
|
||||
"fitos $rs2, $rd",
|
||||
[(set FPRegs:$rd, (SPitof FPRegs:$rs2))]>;
|
||||
def FITOD : F3_3u<2, 0b110100, 0b011001000,
|
||||
(outs DFPRegs:$dst), (ins FPRegs:$src),
|
||||
"fitod $src, $dst",
|
||||
[(set DFPRegs:$dst, (SPitof FPRegs:$src))]>;
|
||||
(outs DFPRegs:$rd), (ins FPRegs:$rs2),
|
||||
"fitod $rs2, $rd",
|
||||
[(set DFPRegs:$rd, (SPitof FPRegs:$rs2))]>;
|
||||
def FITOQ : F3_3u<2, 0b110100, 0b011001100,
|
||||
(outs QFPRegs:$dst), (ins FPRegs:$src),
|
||||
"fitoq $src, $dst",
|
||||
[(set QFPRegs:$dst, (SPitof FPRegs:$src))]>,
|
||||
(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:$dst), (ins FPRegs:$src),
|
||||
"fstoi $src, $dst",
|
||||
[(set FPRegs:$dst, (SPftoi FPRegs:$src))]>;
|
||||
(outs FPRegs:$rd), (ins FPRegs:$rs2),
|
||||
"fstoi $rs2, $rd",
|
||||
[(set FPRegs:$rd, (SPftoi FPRegs:$rs2))]>;
|
||||
def FDTOI : F3_3u<2, 0b110100, 0b011010010,
|
||||
(outs FPRegs:$dst), (ins DFPRegs:$src),
|
||||
"fdtoi $src, $dst",
|
||||
[(set FPRegs:$dst, (SPftoi DFPRegs:$src))]>;
|
||||
(outs FPRegs:$rd), (ins DFPRegs:$rs2),
|
||||
"fdtoi $rs2, $rd",
|
||||
[(set FPRegs:$rd, (SPftoi DFPRegs:$rs2))]>;
|
||||
def FQTOI : F3_3u<2, 0b110100, 0b011010011,
|
||||
(outs FPRegs:$dst), (ins QFPRegs:$src),
|
||||
"fqtoi $src, $dst",
|
||||
[(set FPRegs:$dst, (SPftoi QFPRegs:$src))]>,
|
||||
(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:$dst), (ins FPRegs:$src),
|
||||
"fstod $src, $dst",
|
||||
[(set f64:$dst, (fextend f32:$src))]>;
|
||||
(outs DFPRegs:$rd), (ins FPRegs:$rs2),
|
||||
"fstod $rs2, $rd",
|
||||
[(set f64:$rd, (fextend f32:$rs2))]>;
|
||||
def FSTOQ : F3_3u<2, 0b110100, 0b011001101,
|
||||
(outs QFPRegs:$dst), (ins FPRegs:$src),
|
||||
"fstoq $src, $dst",
|
||||
[(set f128:$dst, (fextend f32:$src))]>,
|
||||
(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:$dst), (ins DFPRegs:$src),
|
||||
"fdtos $src, $dst",
|
||||
[(set f32:$dst, (fround f64:$src))]>;
|
||||
def FDTOQ : F3_3u<2, 0b110100, 0b01101110,
|
||||
(outs QFPRegs:$dst), (ins DFPRegs:$src),
|
||||
"fdtoq $src, $dst",
|
||||
[(set f128:$dst, (fextend f64:$src))]>,
|
||||
(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:$dst), (ins QFPRegs:$src),
|
||||
"fqtos $src, $dst",
|
||||
[(set f32:$dst, (fround f128:$src))]>,
|
||||
(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:$dst), (ins QFPRegs:$src),
|
||||
"fqtod $src, $dst",
|
||||
[(set f64:$dst, (fround f128:$src))]>,
|
||||
(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:$dst), (ins FPRegs:$src),
|
||||
"fmovs $src, $dst", []>;
|
||||
(outs FPRegs:$rd), (ins FPRegs:$rs2),
|
||||
"fmovs $rs2, $rd", []>;
|
||||
def FNEGS : F3_3u<2, 0b110100, 0b000000101,
|
||||
(outs FPRegs:$dst), (ins FPRegs:$src),
|
||||
"fnegs $src, $dst",
|
||||
[(set f32:$dst, (fneg f32:$src))]>;
|
||||
(outs FPRegs:$rd), (ins FPRegs:$rs2),
|
||||
"fnegs $rs2, $rd",
|
||||
[(set f32:$rd, (fneg f32:$rs2))]>;
|
||||
def FABSS : F3_3u<2, 0b110100, 0b000001001,
|
||||
(outs FPRegs:$dst), (ins FPRegs:$src),
|
||||
"fabss $src, $dst",
|
||||
[(set f32:$dst, (fabs f32:$src))]>;
|
||||
(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:$dst), (ins FPRegs:$src),
|
||||
"fsqrts $src, $dst",
|
||||
[(set f32:$dst, (fsqrt f32:$src))]>;
|
||||
(outs FPRegs:$rd), (ins FPRegs:$rs2),
|
||||
"fsqrts $rs2, $rd",
|
||||
[(set f32:$rd, (fsqrt f32:$rs2))]>;
|
||||
def FSQRTD : F3_3u<2, 0b110100, 0b000101010,
|
||||
(outs DFPRegs:$dst), (ins DFPRegs:$src),
|
||||
"fsqrtd $src, $dst",
|
||||
[(set f64:$dst, (fsqrt f64:$src))]>;
|
||||
(outs DFPRegs:$rd), (ins DFPRegs:$rs2),
|
||||
"fsqrtd $rs2, $rd",
|
||||
[(set f64:$rd, (fsqrt f64:$rs2))]>;
|
||||
def FSQRTQ : F3_3u<2, 0b110100, 0b000101011,
|
||||
(outs QFPRegs:$dst), (ins QFPRegs:$src),
|
||||
"fsqrtq $src, $dst",
|
||||
[(set f128:$dst, (fsqrt f128:$src))]>,
|
||||
(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:$dst), (ins FPRegs:$src1, FPRegs:$src2),
|
||||
"fadds $src1, $src2, $dst",
|
||||
[(set f32:$dst, (fadd f32:$src1, f32:$src2))]>;
|
||||
(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:$dst), (ins DFPRegs:$src1, DFPRegs:$src2),
|
||||
"faddd $src1, $src2, $dst",
|
||||
[(set f64:$dst, (fadd f64:$src1, f64:$src2))]>;
|
||||
(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:$dst), (ins QFPRegs:$src1, QFPRegs:$src2),
|
||||
"faddq $src1, $src2, $dst",
|
||||
[(set f128:$dst, (fadd f128:$src1, f128:$src2))]>,
|
||||
(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:$dst), (ins FPRegs:$src1, FPRegs:$src2),
|
||||
"fsubs $src1, $src2, $dst",
|
||||
[(set f32:$dst, (fsub f32:$src1, f32:$src2))]>;
|
||||
(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:$dst), (ins DFPRegs:$src1, DFPRegs:$src2),
|
||||
"fsubd $src1, $src2, $dst",
|
||||
[(set f64:$dst, (fsub f64:$src1, f64:$src2))]>;
|
||||
(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:$dst), (ins QFPRegs:$src1, QFPRegs:$src2),
|
||||
"fsubq $src1, $src2, $dst",
|
||||
[(set f128:$dst, (fsub f128:$src1, f128:$src2))]>,
|
||||
(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:$dst), (ins FPRegs:$src1, FPRegs:$src2),
|
||||
"fmuls $src1, $src2, $dst",
|
||||
[(set f32:$dst, (fmul f32:$src1, f32:$src2))]>;
|
||||
(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:$dst), (ins DFPRegs:$src1, DFPRegs:$src2),
|
||||
"fmuld $src1, $src2, $dst",
|
||||
[(set f64:$dst, (fmul f64:$src1, f64:$src2))]>;
|
||||
(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:$dst), (ins QFPRegs:$src1, QFPRegs:$src2),
|
||||
"fmulq $src1, $src2, $dst",
|
||||
[(set f128:$dst, (fmul f128:$src1, f128:$src2))]>,
|
||||
(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:$dst), (ins FPRegs:$src1, FPRegs:$src2),
|
||||
"fsmuld $src1, $src2, $dst",
|
||||
[(set f64:$dst, (fmul (fextend f32:$src1),
|
||||
(fextend f32:$src2)))]>;
|
||||
(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:$dst), (ins DFPRegs:$src1, DFPRegs:$src2),
|
||||
"fdmulq $src1, $src2, $dst",
|
||||
[(set f128:$dst, (fmul (fextend f64:$src1),
|
||||
(fextend f64:$src2)))]>,
|
||||
(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:$dst), (ins FPRegs:$src1, FPRegs:$src2),
|
||||
"fdivs $src1, $src2, $dst",
|
||||
[(set f32:$dst, (fdiv f32:$src1, f32:$src2))]>;
|
||||
(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:$dst), (ins DFPRegs:$src1, DFPRegs:$src2),
|
||||
"fdivd $src1, $src2, $dst",
|
||||
[(set f64:$dst, (fdiv f64:$src1, f64:$src2))]>;
|
||||
(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:$dst), (ins QFPRegs:$src1, QFPRegs:$src2),
|
||||
"fdivq $src1, $src2, $dst",
|
||||
[(set f128:$dst, (fdiv f128:$src1, f128:$src2))]>,
|
||||
(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
|
||||
@ -820,24 +770,24 @@ def FDIVQ : F3_3<2, 0b110100, 0b001001111,
|
||||
|
||||
let Defs = [FCC] in {
|
||||
def FCMPS : F3_3c<2, 0b110101, 0b001010001,
|
||||
(outs), (ins FPRegs:$src1, FPRegs:$src2),
|
||||
"fcmps $src1, $src2",
|
||||
[(SPcmpfcc f32:$src1, f32:$src2)]>;
|
||||
(outs), (ins FPRegs:$rs1, FPRegs:$rs2),
|
||||
"fcmps $rs1, $rs2",
|
||||
[(SPcmpfcc f32:$rs1, f32:$rs2)]>;
|
||||
def FCMPD : F3_3c<2, 0b110101, 0b001010010,
|
||||
(outs), (ins DFPRegs:$src1, DFPRegs:$src2),
|
||||
"fcmpd $src1, $src2",
|
||||
[(SPcmpfcc f64:$src1, f64:$src2)]>;
|
||||
(outs), (ins DFPRegs:$rs1, DFPRegs:$rs2),
|
||||
"fcmpd $rs1, $rs2",
|
||||
[(SPcmpfcc f64:$rs1, f64:$rs2)]>;
|
||||
def FCMPQ : F3_3c<2, 0b110101, 0b001010011,
|
||||
(outs), (ins QFPRegs:$src1, QFPRegs:$src2),
|
||||
"fcmpq $src1, $src2",
|
||||
[(SPcmpfcc f128:$src1, f128:$src2)]>,
|
||||
(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),
|
||||
@ -861,6 +811,7 @@ let Uses = [O6], isCall = 1, hasDelaySlot = 1 in
|
||||
let op = 1;
|
||||
let Inst{29-0} = disp;
|
||||
}
|
||||
}
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// V9 Instructions
|
||||
@ -912,8 +863,9 @@ let Predicates = [HasV9], Constraints = "$f = $rd" in {
|
||||
def FMOVQ_ICC
|
||||
: F4_3<0b110101, 0b000011, (outs QFPRegs:$rd),
|
||||
(ins QFPRegs:$rs2, QFPRegs:$f, CCOp:$cond),
|
||||
"fmovd$cond %icc, $rs2, $rd",
|
||||
[(set f128:$rd, (SPselecticc f128:$rs2, f128:$f, imm:$cond))]>;
|
||||
"fmovq$cond %icc, $rs2, $rd",
|
||||
[(set f128:$rd, (SPselecticc f128:$rs2, f128:$f, imm:$cond))]>,
|
||||
Requires<[HasHardQuad]>;
|
||||
}
|
||||
|
||||
let Uses = [FCC], opf_cc = 0b000 in {
|
||||
@ -930,8 +882,9 @@ let Predicates = [HasV9], Constraints = "$f = $rd" in {
|
||||
def FMOVQ_FCC
|
||||
: F4_3<0b110101, 0b000011, (outs QFPRegs:$rd),
|
||||
(ins QFPRegs:$rs2, QFPRegs:$f, CCOp:$cond),
|
||||
"fmovd$cond %fcc0, $rs2, $rd",
|
||||
[(set f128:$rd, (SPselectfcc f128:$rs2, f128:$f, imm:$cond))]>;
|
||||
"fmovq$cond %fcc0, $rs2, $rd",
|
||||
[(set f128:$rd, (SPselectfcc f128:$rs2, f128:$f, imm:$cond))]>,
|
||||
Requires<[HasHardQuad]>;
|
||||
}
|
||||
|
||||
}
|
||||
@ -939,40 +892,67 @@ let Predicates = [HasV9], Constraints = "$f = $rd" in {
|
||||
// Floating-Point Move Instructions, p. 164 of the V9 manual.
|
||||
let Predicates = [HasV9] in {
|
||||
def FMOVD : F3_3u<2, 0b110100, 0b000000010,
|
||||
(outs DFPRegs:$dst), (ins DFPRegs:$src),
|
||||
"fmovd $src, $dst", []>;
|
||||
(outs DFPRegs:$rd), (ins DFPRegs:$rs2),
|
||||
"fmovd $rs2, $rd", []>;
|
||||
def FMOVQ : F3_3u<2, 0b110100, 0b000000011,
|
||||
(outs QFPRegs:$dst), (ins QFPRegs:$src),
|
||||
"fmovq $src, $dst", []>,
|
||||
(outs QFPRegs:$rd), (ins QFPRegs:$rs2),
|
||||
"fmovq $rs2, $rd", []>,
|
||||
Requires<[HasHardQuad]>;
|
||||
def FNEGD : F3_3u<2, 0b110100, 0b000000110,
|
||||
(outs DFPRegs:$dst), (ins DFPRegs:$src),
|
||||
"fnegd $src, $dst",
|
||||
[(set f64:$dst, (fneg f64:$src))]>;
|
||||
(outs DFPRegs:$rd), (ins DFPRegs:$rs2),
|
||||
"fnegd $rs2, $rd",
|
||||
[(set f64:$rd, (fneg f64:$rs2))]>;
|
||||
def FNEGQ : F3_3u<2, 0b110100, 0b000000111,
|
||||
(outs QFPRegs:$dst), (ins QFPRegs:$src),
|
||||
"fnegq $src, $dst",
|
||||
[(set f128:$dst, (fneg f128:$src))]>,
|
||||
(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:$dst), (ins DFPRegs:$src),
|
||||
"fabsd $src, $dst",
|
||||
[(set f64:$dst, (fabs f64:$src))]>;
|
||||
(outs DFPRegs:$rd), (ins DFPRegs:$rs2),
|
||||
"fabsd $rs2, $rd",
|
||||
[(set f64:$rd, (fabs f64:$rs2))]>;
|
||||
def FABSQ : F3_3u<2, 0b110100, 0b000001011,
|
||||
(outs QFPRegs:$dst), (ins QFPRegs:$src),
|
||||
"fabsq $src, $dst",
|
||||
[(set f128:$dst, (fabs f128:$src))]>,
|
||||
(outs QFPRegs:$rd), (ins QFPRegs:$rs2),
|
||||
"fabsq $rs2, $rd",
|
||||
[(set f128:$rd, (fabs f128:$rs2))]>,
|
||||
Requires<[HasHardQuad]>;
|
||||
}
|
||||
|
||||
// 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 SLLri X,0.
|
||||
// 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 (SLLri $src, 0))>;
|
||||
(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 i32imm:$simm13),
|
||||
"membar $simm13", []>;
|
||||
|
||||
let Constraints = "$val = $dst" 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))]>;
|
||||
}
|
||||
|
||||
let Predicates = [HasV9], Constraints = "$swap = $rd" in
|
||||
def CASrr: F3_1_asi<3, 0b111100, 0b10000000,
|
||||
(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))]>;
|
||||
|
||||
//===----------------------------------------------------------------------===//
|
||||
// Non-Instruction Patterns
|
||||
@ -987,6 +967,8 @@ def : Pat<(i32 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)>;
|
||||
@ -1009,6 +991,7 @@ 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),
|
||||
@ -1032,4 +1015,18 @@ def : Pat<(i32 (zextloadi1 ADDRri:$src)), (LDUBri ADDRri:$src)>;
|
||||
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 "SparcInstrAliases.td"
|
||||
|
@ -12,8 +12,9 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
#define DEBUG_TYPE "jit"
|
||||
#include "SparcJITInfo.h"
|
||||
#include "Sparc.h"
|
||||
#include "SparcRelocations.h"
|
||||
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/CodeGen/JITCodeEmitter.h"
|
||||
#include "llvm/Support/Memory.h"
|
||||
|
||||
@ -27,26 +28,67 @@ extern "C" void SparcCompilationCallback();
|
||||
|
||||
extern "C" {
|
||||
#if defined (__sparc__)
|
||||
|
||||
#if defined(__arch64__)
|
||||
#define FRAME_PTR(X) #X "+2047"
|
||||
#else
|
||||
#define FRAME_PTR(X) #X
|
||||
#endif
|
||||
|
||||
asm(
|
||||
".text\n"
|
||||
"\t.align 4\n"
|
||||
"\t.global SparcCompilationCallback\n"
|
||||
"\t.type SparcCompilationCallback, #function\n"
|
||||
"SparcCompilationCallback:\n"
|
||||
// Save current register window.
|
||||
"\tsave %sp, -192, %sp\n"
|
||||
// stubaddr+4 is in %g1.
|
||||
// Save current register window and create stack.
|
||||
// 128 (save area) + 6*8 (for arguments) + 16*8 (for float regfile) = 304
|
||||
"\tsave %sp, -304, %sp\n"
|
||||
// save float regfile to the stack.
|
||||
"\tstd %f0, [" FRAME_PTR(%fp) "-0]\n"
|
||||
"\tstd %f2, [" FRAME_PTR(%fp) "-8]\n"
|
||||
"\tstd %f4, [" FRAME_PTR(%fp) "-16]\n"
|
||||
"\tstd %f6, [" FRAME_PTR(%fp) "-24]\n"
|
||||
"\tstd %f8, [" FRAME_PTR(%fp) "-32]\n"
|
||||
"\tstd %f10, [" FRAME_PTR(%fp) "-40]\n"
|
||||
"\tstd %f12, [" FRAME_PTR(%fp) "-48]\n"
|
||||
"\tstd %f14, [" FRAME_PTR(%fp) "-56]\n"
|
||||
"\tstd %f16, [" FRAME_PTR(%fp) "-64]\n"
|
||||
"\tstd %f18, [" FRAME_PTR(%fp) "-72]\n"
|
||||
"\tstd %f20, [" FRAME_PTR(%fp) "-80]\n"
|
||||
"\tstd %f22, [" FRAME_PTR(%fp) "-88]\n"
|
||||
"\tstd %f24, [" FRAME_PTR(%fp) "-96]\n"
|
||||
"\tstd %f26, [" FRAME_PTR(%fp) "-104]\n"
|
||||
"\tstd %f28, [" FRAME_PTR(%fp) "-112]\n"
|
||||
"\tstd %f30, [" FRAME_PTR(%fp) "-120]\n"
|
||||
// stubaddr is in %g1.
|
||||
"\tcall SparcCompilationCallbackC\n"
|
||||
"\t sub %g1, 4, %o0\n"
|
||||
"\t mov %g1, %o0\n"
|
||||
// restore float regfile from the stack.
|
||||
"\tldd [" FRAME_PTR(%fp) "-0], %f0\n"
|
||||
"\tldd [" FRAME_PTR(%fp) "-8], %f2\n"
|
||||
"\tldd [" FRAME_PTR(%fp) "-16], %f4\n"
|
||||
"\tldd [" FRAME_PTR(%fp) "-24], %f6\n"
|
||||
"\tldd [" FRAME_PTR(%fp) "-32], %f8\n"
|
||||
"\tldd [" FRAME_PTR(%fp) "-40], %f10\n"
|
||||
"\tldd [" FRAME_PTR(%fp) "-48], %f12\n"
|
||||
"\tldd [" FRAME_PTR(%fp) "-56], %f14\n"
|
||||
"\tldd [" FRAME_PTR(%fp) "-64], %f16\n"
|
||||
"\tldd [" FRAME_PTR(%fp) "-72], %f18\n"
|
||||
"\tldd [" FRAME_PTR(%fp) "-80], %f20\n"
|
||||
"\tldd [" FRAME_PTR(%fp) "-88], %f22\n"
|
||||
"\tldd [" FRAME_PTR(%fp) "-96], %f24\n"
|
||||
"\tldd [" FRAME_PTR(%fp) "-104], %f26\n"
|
||||
"\tldd [" FRAME_PTR(%fp) "-112], %f28\n"
|
||||
"\tldd [" FRAME_PTR(%fp) "-120], %f30\n"
|
||||
// restore original register window and
|
||||
// copy %o0 to %g1
|
||||
"\t restore %o0, 0, %g1\n"
|
||||
"\trestore %o0, 0, %g1\n"
|
||||
// call the new stub
|
||||
"\tjmp %g1\n"
|
||||
"\t nop\n"
|
||||
"\t.size SparcCompilationCallback, .-SparcCompilationCallback"
|
||||
);
|
||||
|
||||
#else
|
||||
void SparcCompilationCallback() {
|
||||
llvm_unreachable(
|
||||
@ -55,75 +97,171 @@ extern "C" {
|
||||
#endif
|
||||
}
|
||||
|
||||
#define HI(Val) (((unsigned)(Val)) >> 10)
|
||||
#define LO(Val) (((unsigned)(Val)) & 0x3FF)
|
||||
|
||||
#define SETHI_INST(imm, rd) (0x01000000 | ((rd) << 25) | ((imm) & 0x3FFFFF))
|
||||
#define JMP_INST(rs1, imm, rd) (0x80000000 | ((rd) << 25) | (0x38 << 19) \
|
||||
| ((rs1) << 14) | (1 << 13) | ((imm) & 0x1FFF))
|
||||
#define NOP_INST SETHI_INST(0, 0)
|
||||
#define OR_INST_I(rs1, imm, rd) (0x80000000 | ((rd) << 25) | (0x02 << 19) \
|
||||
| ((rs1) << 14) | (1 << 13) | ((imm) & 0x1FFF))
|
||||
#define OR_INST_R(rs1, rs2, rd) (0x80000000 | ((rd) << 25) | (0x02 << 19) \
|
||||
| ((rs1) << 14) | (0 << 13) | ((rs2) & 0x1F))
|
||||
#define RDPC_INST(rd) (0x80000000 | ((rd) << 25) | (0x28 << 19) \
|
||||
| (5 << 14))
|
||||
#define LDX_INST(rs1, imm, rd) (0xC0000000 | ((rd) << 25) | (0x0B << 19) \
|
||||
| ((rs1) << 14) | (1 << 13) | ((imm) & 0x1FFF))
|
||||
#define SLLX_INST(rs1, imm, rd) (0x80000000 | ((rd) << 25) | (0x25 << 19) \
|
||||
| ((rs1) << 14) | (3 << 12) | ((imm) & 0x3F))
|
||||
#define SUB_INST(rs1, imm, rd) (0x80000000 | ((rd) << 25) | (0x04 << 19) \
|
||||
| ((rs1) << 14) | (1 << 13) | ((imm) & 0x1FFF))
|
||||
#define XOR_INST(rs1, imm, rd) (0x80000000 | ((rd) << 25) | (0x03 << 19) \
|
||||
| ((rs1) << 14) | (1 << 13) | ((imm) & 0x1FFF))
|
||||
#define BA_INST(tgt) (0x10800000 | ((tgt) & 0x3FFFFF))
|
||||
|
||||
// Emit instructions to jump to Addr and store the starting address of
|
||||
// the instructions emitted in the scratch register.
|
||||
static void emitInstrForIndirectJump(intptr_t Addr,
|
||||
unsigned scratch,
|
||||
SmallVectorImpl<uint32_t> &Insts) {
|
||||
|
||||
if (isInt<13>(Addr)) {
|
||||
// Emit: jmpl %g0+Addr, <scratch>
|
||||
// nop
|
||||
Insts.push_back(JMP_INST(0, LO10(Addr), scratch));
|
||||
Insts.push_back(NOP_INST);
|
||||
return;
|
||||
}
|
||||
|
||||
if (isUInt<32>(Addr)) {
|
||||
// Emit: sethi %hi(Addr), scratch
|
||||
// jmpl scratch+%lo(Addr), scratch
|
||||
// sub scratch, 4, scratch
|
||||
Insts.push_back(SETHI_INST(HI22(Addr), scratch));
|
||||
Insts.push_back(JMP_INST(scratch, LO10(Addr), scratch));
|
||||
Insts.push_back(SUB_INST(scratch, 4, scratch));
|
||||
return;
|
||||
}
|
||||
|
||||
if (Addr < 0 && isInt<33>(Addr)) {
|
||||
// Emit: sethi %hix(Addr), scratch)
|
||||
// xor scratch, %lox(Addr), scratch
|
||||
// jmpl scratch+0, scratch
|
||||
// sub scratch, 8, scratch
|
||||
Insts.push_back(SETHI_INST(HIX22(Addr), scratch));
|
||||
Insts.push_back(XOR_INST(scratch, LOX10(Addr), scratch));
|
||||
Insts.push_back(JMP_INST(scratch, 0, scratch));
|
||||
Insts.push_back(SUB_INST(scratch, 8, scratch));
|
||||
return;
|
||||
}
|
||||
|
||||
// Emit: rd %pc, scratch
|
||||
// ldx [scratch+16], scratch
|
||||
// jmpl scratch+0, scratch
|
||||
// sub scratch, 8, scratch
|
||||
// <Addr: 8 byte>
|
||||
Insts.push_back(RDPC_INST(scratch));
|
||||
Insts.push_back(LDX_INST(scratch, 16, scratch));
|
||||
Insts.push_back(JMP_INST(scratch, 0, scratch));
|
||||
Insts.push_back(SUB_INST(scratch, 8, scratch));
|
||||
Insts.push_back((uint32_t)(((int64_t)Addr) >> 32) & 0xffffffff);
|
||||
Insts.push_back((uint32_t)(Addr & 0xffffffff));
|
||||
|
||||
// Instruction sequence without rdpc instruction
|
||||
// 7 instruction and 2 scratch register
|
||||
// Emit: sethi %hh(Addr), scratch
|
||||
// or scratch, %hm(Addr), scratch
|
||||
// sllx scratch, 32, scratch
|
||||
// sethi %hi(Addr), scratch2
|
||||
// or scratch, scratch2, scratch
|
||||
// jmpl scratch+%lo(Addr), scratch
|
||||
// sub scratch, 20, scratch
|
||||
// Insts.push_back(SETHI_INST(HH22(Addr), scratch));
|
||||
// Insts.push_back(OR_INST_I(scratch, HM10(Addr), scratch));
|
||||
// Insts.push_back(SLLX_INST(scratch, 32, scratch));
|
||||
// Insts.push_back(SETHI_INST(HI22(Addr), scratch2));
|
||||
// Insts.push_back(OR_INST_R(scratch, scratch2, scratch));
|
||||
// Insts.push_back(JMP_INST(scratch, LO10(Addr), scratch));
|
||||
// Insts.push_back(SUB_INST(scratch, 20, scratch));
|
||||
}
|
||||
|
||||
extern "C" void *SparcCompilationCallbackC(intptr_t StubAddr) {
|
||||
// Get the address of the compiled code for this function.
|
||||
intptr_t NewVal = (intptr_t) JITCompilerFunction((void*) StubAddr);
|
||||
|
||||
// Rewrite the function stub so that we don't end up here every time we
|
||||
// execute the call. We're replacing the first three instructions of the
|
||||
// stub with code that jumps to the compiled function:
|
||||
// sethi %hi(NewVal), %g1
|
||||
// jmp %g1+%lo(NewVal)
|
||||
// nop
|
||||
// execute the call. We're replacing the stub instructions with code
|
||||
// that jumps to the compiled function:
|
||||
|
||||
*(intptr_t *)(StubAddr) = SETHI_INST(HI(NewVal), 1);
|
||||
*(intptr_t *)(StubAddr + 4) = JMP_INST(1, LO(NewVal), 0);
|
||||
*(intptr_t *)(StubAddr + 8) = NOP_INST;
|
||||
SmallVector<uint32_t, 8> Insts;
|
||||
intptr_t diff = (NewVal - StubAddr) >> 2;
|
||||
if (isInt<22>(diff)) {
|
||||
// Use branch instruction to jump
|
||||
Insts.push_back(BA_INST(diff));
|
||||
Insts.push_back(NOP_INST);
|
||||
} else {
|
||||
// Otherwise, use indirect jump to the compiled function
|
||||
emitInstrForIndirectJump(NewVal, 1, Insts);
|
||||
}
|
||||
|
||||
sys::Memory::InvalidateInstructionCache((void*) StubAddr, 12);
|
||||
for (unsigned i = 0, e = Insts.size(); i != e; ++i)
|
||||
*(uint32_t *)(StubAddr + i*4) = Insts[i];
|
||||
|
||||
sys::Memory::InvalidateInstructionCache((void*) StubAddr, Insts.size() * 4);
|
||||
return (void*)StubAddr;
|
||||
}
|
||||
|
||||
|
||||
void SparcJITInfo::replaceMachineCodeForFunction(void *Old, void *New) {
|
||||
assert(0 && "FIXME: Implement SparcJITInfo::replaceMachineCodeForFunction");
|
||||
}
|
||||
|
||||
|
||||
TargetJITInfo::StubLayout SparcJITInfo::getStubLayout() {
|
||||
// The stub contains 3 4-byte instructions, aligned at 4 bytes. See
|
||||
// emitFunctionStub for details.
|
||||
|
||||
StubLayout Result = { 3*4, 4 };
|
||||
// The stub contains maximum of 4 4-byte instructions and 8 bytes for address,
|
||||
// aligned at 32 bytes.
|
||||
// See emitFunctionStub and emitInstrForIndirectJump for details.
|
||||
StubLayout Result = { 4*4 + 8, 32 };
|
||||
return Result;
|
||||
}
|
||||
|
||||
void *SparcJITInfo::emitFunctionStub(const Function *F, void *Fn,
|
||||
JITCodeEmitter &JCE)
|
||||
{
|
||||
JCE.emitAlignment(4);
|
||||
JCE.emitAlignment(32);
|
||||
void *Addr = (void*) (JCE.getCurrentPCValue());
|
||||
if (!sys::Memory::setRangeWritable(Addr, 12))
|
||||
|
||||
intptr_t CurrentAddr = (intptr_t)Addr;
|
||||
intptr_t EmittedAddr;
|
||||
SmallVector<uint32_t, 8> Insts;
|
||||
if (Fn != (void*)(intptr_t)SparcCompilationCallback) {
|
||||
EmittedAddr = (intptr_t)Fn;
|
||||
intptr_t diff = (EmittedAddr - CurrentAddr) >> 2;
|
||||
if (isInt<22>(diff)) {
|
||||
Insts.push_back(BA_INST(diff));
|
||||
Insts.push_back(NOP_INST);
|
||||
}
|
||||
} else {
|
||||
EmittedAddr = (intptr_t)SparcCompilationCallback;
|
||||
}
|
||||
|
||||
if (Insts.size() == 0)
|
||||
emitInstrForIndirectJump(EmittedAddr, 1, Insts);
|
||||
|
||||
|
||||
if (!sys::Memory::setRangeWritable(Addr, 4 * Insts.size()))
|
||||
llvm_unreachable("ERROR: Unable to mark stub writable.");
|
||||
|
||||
intptr_t EmittedAddr;
|
||||
if (Fn != (void*)(intptr_t)SparcCompilationCallback)
|
||||
EmittedAddr = (intptr_t)Fn;
|
||||
else
|
||||
EmittedAddr = (intptr_t)SparcCompilationCallback;
|
||||
for (unsigned i = 0, e = Insts.size(); i != e; ++i)
|
||||
JCE.emitWordBE(Insts[i]);
|
||||
|
||||
// sethi %hi(EmittedAddr), %g1
|
||||
// jmp %g1+%lo(EmittedAddr), %g1
|
||||
// nop
|
||||
|
||||
JCE.emitWordBE(SETHI_INST(HI(EmittedAddr), 1));
|
||||
JCE.emitWordBE(JMP_INST(1, LO(EmittedAddr), 1));
|
||||
JCE.emitWordBE(NOP_INST);
|
||||
|
||||
sys::Memory::InvalidateInstructionCache(Addr, 12);
|
||||
if (!sys::Memory::setRangeExecutable(Addr, 12))
|
||||
sys::Memory::InvalidateInstructionCache(Addr, 4 * Insts.size());
|
||||
if (!sys::Memory::setRangeExecutable(Addr, 4 * Insts.size()))
|
||||
llvm_unreachable("ERROR: Unable to mark stub executable.");
|
||||
|
||||
return Addr;
|
||||
}
|
||||
|
||||
|
||||
TargetJITInfo::LazyResolverFn
|
||||
SparcJITInfo::getLazyResolverFunction(JITCompilerFn F) {
|
||||
JITCompilerFunction = F;
|
||||
@ -159,6 +297,27 @@ void SparcJITInfo::relocate(void *Function, MachineRelocation *MR,
|
||||
case SP::reloc_sparc_pc19:
|
||||
ResultPtr = ((ResultPtr - (intptr_t)RelocPos) >> 2) & 0x7ffff;
|
||||
break;
|
||||
|
||||
case SP::reloc_sparc_h44:
|
||||
ResultPtr = (ResultPtr >> 22) & 0x3fffff;
|
||||
break;
|
||||
|
||||
case SP::reloc_sparc_m44:
|
||||
ResultPtr = (ResultPtr >> 12) & 0x3ff;
|
||||
break;
|
||||
|
||||
case SP::reloc_sparc_l44:
|
||||
ResultPtr = (ResultPtr & 0xfff);
|
||||
break;
|
||||
|
||||
case SP::reloc_sparc_hh:
|
||||
ResultPtr = (((int64_t)ResultPtr) >> 42) & 0x3fffff;
|
||||
break;
|
||||
|
||||
case SP::reloc_sparc_hm:
|
||||
ResultPtr = (((int64_t)ResultPtr) >> 32) & 0x3ff;
|
||||
break;
|
||||
|
||||
}
|
||||
*((unsigned*) RelocPos) |= (unsigned) ResultPtr;
|
||||
}
|
||||
|
109
contrib/llvm/lib/Target/Sparc/SparcMCInstLower.cpp
Normal file
109
contrib/llvm/lib/Target/Sparc/SparcMCInstLower.cpp
Normal file
@ -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/CodeGen/AsmPrinter.h"
|
||||
#include "llvm/CodeGen/MachineFunction.h"
|
||||
#include "llvm/CodeGen/MachineInstr.h"
|
||||
#include "llvm/CodeGen/MachineOperand.h"
|
||||
#include "llvm/MC/MCContext.h"
|
||||
#include "llvm/MC/MCAsmInfo.h"
|
||||
#include "llvm/MC/MCExpr.h"
|
||||
#include "llvm/MC/MCInst.h"
|
||||
#include "llvm/Target/Mangler.h"
|
||||
#include "llvm/ADT/SmallString.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 = 0;
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
@ -35,7 +35,7 @@ ReserveAppRegisters("sparc-reserve-app-registers", cl::Hidden, cl::init(false),
|
||||
cl::desc("Reserve application registers (%g2-%g4)"));
|
||||
|
||||
SparcRegisterInfo::SparcRegisterInfo(SparcSubtarget &st)
|
||||
: SparcGenRegisterInfo(SP::I7), Subtarget(st) {
|
||||
: SparcGenRegisterInfo(SP::O7), Subtarget(st) {
|
||||
}
|
||||
|
||||
const uint16_t* SparcRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF)
|
||||
|
@ -33,7 +33,22 @@ namespace llvm {
|
||||
reloc_sparc_pc22 = 4,
|
||||
|
||||
// reloc_sparc_pc22 - pc rel. 19 bits for branch with icc/xcc
|
||||
reloc_sparc_pc19 = 5
|
||||
reloc_sparc_pc19 = 5,
|
||||
|
||||
// reloc_sparc_h44 - 43-22 bits
|
||||
reloc_sparc_h44 = 6,
|
||||
|
||||
// reloc_sparc_m44 - 21-12 bits
|
||||
reloc_sparc_m44 = 7,
|
||||
|
||||
// reloc_sparc_l44 - lower 12 bits
|
||||
reloc_sparc_l44 = 8,
|
||||
|
||||
// reloc_sparc_hh - 63-42 bits
|
||||
reloc_sparc_hh = 9,
|
||||
|
||||
// reloc_sparc_hm - 41-32 bits
|
||||
reloc_sparc_hm = 10
|
||||
};
|
||||
}
|
||||
}
|
||||
|
@ -31,20 +31,20 @@ SparcSubtarget::SparcSubtarget(const std::string &TT, const std::string &CPU,
|
||||
V8DeprecatedInsts(false),
|
||||
IsVIS(false),
|
||||
Is64Bit(is64Bit),
|
||||
HasHardQuad(false) {
|
||||
HasHardQuad(false),
|
||||
UsePopc(false) {
|
||||
|
||||
// Determine default and user specified characteristics
|
||||
std::string CPUName = CPU;
|
||||
if (CPUName.empty()) {
|
||||
if (is64Bit)
|
||||
CPUName = "v9";
|
||||
else
|
||||
CPUName = "v8";
|
||||
}
|
||||
IsV9 = CPUName == "v9";
|
||||
if (CPUName.empty())
|
||||
CPUName = (is64Bit) ? "v9" : "v8";
|
||||
|
||||
// Parse features string.
|
||||
ParseSubtargetFeatures(CPUName, FS);
|
||||
|
||||
// Popc is a v9-only instruction.
|
||||
if (!IsV9)
|
||||
UsePopc = false;
|
||||
}
|
||||
|
||||
|
||||
|
@ -30,6 +30,7 @@ class SparcSubtarget : public SparcGenSubtargetInfo {
|
||||
bool IsVIS;
|
||||
bool Is64Bit;
|
||||
bool HasHardQuad;
|
||||
bool UsePopc;
|
||||
|
||||
public:
|
||||
SparcSubtarget(const std::string &TT, const std::string &CPU,
|
||||
@ -39,6 +40,7 @@ class SparcSubtarget : public SparcGenSubtargetInfo {
|
||||
bool isVIS() const { return IsVIS; }
|
||||
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.
|
||||
|
48
contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.cpp
Normal file
48
contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.cpp
Normal file
@ -0,0 +1,48 @@
|
||||
//===------- 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/Mangler.h"
|
||||
|
||||
using namespace llvm;
|
||||
|
||||
|
||||
const MCExpr *SparcELFTargetObjectFile::
|
||||
getTTypeGlobalReference(const GlobalValue *GV, Mangler *Mang,
|
||||
MachineModuleInfo *MMI, unsigned Encoding,
|
||||
MCStreamer &Streamer) const {
|
||||
|
||||
if (Encoding & dwarf::DW_EH_PE_pcrel) {
|
||||
MachineModuleInfoELF &ELFMMI = MMI->getObjFileInfo<MachineModuleInfoELF>();
|
||||
|
||||
//MCSymbol *SSym = getSymbolWithGlobalValueBase(*Mang, GV, ".DW.stub");
|
||||
SmallString<60> NameStr;
|
||||
Mang->getNameWithPrefix(NameStr, GV, true);
|
||||
NameStr.append(".DW.stub");
|
||||
MCSymbol *SSym = getContext().GetOrCreateSymbol(NameStr.str());
|
||||
|
||||
// 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() == 0) {
|
||||
MCSymbol *Sym = getSymbol(*Mang, GV);
|
||||
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, Mang, MMI, Encoding, Streamer);
|
||||
}
|
34
contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.h
Normal file
34
contrib/llvm/lib/Target/Sparc/SparcTargetObjectFile.h
Normal file
@ -0,0 +1,34 @@
|
||||
//===-- 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_TARGET_SPARC_TARGETOBJECTFILE_H
|
||||
#define LLVM_TARGET_SPARC_TARGETOBJECTFILE_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, Mangler *Mang,
|
||||
MachineModuleInfo *MMI, unsigned Encoding,
|
||||
MCStreamer &Streamer) const;
|
||||
};
|
||||
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
47
contrib/llvm/lib/Target/Sparc/SparcTargetStreamer.h
Normal file
47
contrib/llvm/lib/Target/Sparc/SparcTargetStreamer.h
Normal file
@ -0,0 +1,47 @@
|
||||
//===-- 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 SPARCTARGETSTREAMER_H
|
||||
#define SPARCTARGETSTREAMER_H
|
||||
|
||||
#include "llvm/MC/MCELFStreamer.h"
|
||||
#include "llvm/MC/MCStreamer.h"
|
||||
|
||||
namespace llvm {
|
||||
class SparcTargetStreamer : public MCTargetStreamer {
|
||||
virtual void anchor();
|
||||
|
||||
public:
|
||||
/// 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(formatted_raw_ostream &OS);
|
||||
virtual void emitSparcRegisterIgnore(unsigned reg);
|
||||
virtual void emitSparcRegisterScratch(unsigned reg);
|
||||
|
||||
};
|
||||
|
||||
// This part is for ELF object output
|
||||
class SparcTargetELFStreamer : public SparcTargetStreamer {
|
||||
public:
|
||||
MCELFStreamer &getStreamer();
|
||||
virtual void emitSparcRegisterIgnore(unsigned reg) {}
|
||||
virtual void emitSparcRegisterScratch(unsigned reg) {}
|
||||
};
|
||||
} // end namespace llvm
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user