Index: llvm/include/llvm/BinaryFormat/ELF.h =================================================================== --- llvm/include/llvm/BinaryFormat/ELF.h +++ llvm/include/llvm/BinaryFormat/ELF.h @@ -736,6 +736,11 @@ #include "ELFRelocs/BPF.def" }; +// ELF Relocation types for M680x0 +enum { +#include "ELFRelocs/m680x0.def" +}; + // MSP430 specific e_flags enum : unsigned { EF_MSP430_MACH_MSP430x11 = 11, Index: llvm/include/llvm/BinaryFormat/ELFRelocs/m680x0.def =================================================================== --- /dev/null +++ llvm/include/llvm/BinaryFormat/ELFRelocs/m680x0.def @@ -0,0 +1,49 @@ +#ifndef ELF_RELOC +#error "ELF_RELOC must be defined" +#endif + +ELF_RELOC (R_M680x0_NONE, 0) /* No reloc */ +ELF_RELOC (R_M680x0_32, 1) /* Direct 32 bit */ +ELF_RELOC (R_M680x0_16, 2) /* Direct 16 bit */ +ELF_RELOC (R_M680x0_8, 3) /* Direct 8 bit */ +ELF_RELOC (R_M680x0_PC32, 4) /* PC relative 32 bit */ +ELF_RELOC (R_M680x0_PC16, 5) /* PC relative 16 bit */ +ELF_RELOC (R_M680x0_PC8, 6) /* PC relative 8 bit */ +ELF_RELOC (R_M680x0_GOTPCREL32, 7) /* 32 bit PC relative GOT entry */ +ELF_RELOC (R_M680x0_GOTPCREL16, 8) /* 16 bit PC relative GOT entry */ +ELF_RELOC (R_M680x0_GOTPCREL8, 9) /* 8 bit PC relative GOT entry */ +ELF_RELOC (R_M680x0_GOTOFF32, 10) /* 32 bit GOT offset */ +ELF_RELOC (R_M680x0_GOTOFF16, 11) /* 16 bit GOT offset */ +ELF_RELOC (R_M680x0_GOTOFF8, 12) /* 8 bit GOT offset */ +ELF_RELOC (R_M680x0_PLT32, 13) /* 32 bit PC relative PLT address */ +ELF_RELOC (R_M680x0_PLT16, 14) /* 16 bit PC relative PLT address */ +ELF_RELOC (R_M680x0_PLT8, 15) /* 8 bit PC relative PLT address */ +ELF_RELOC (R_M680x0_PLTOFF32, 16) /* 32 bit PLT offset */ +ELF_RELOC (R_M680x0_PLTOFF16, 17) /* 16 bit PLT offset */ +ELF_RELOC (R_M680x0_PLTOFF8, 18) /* 8 bit PLT offset */ +ELF_RELOC (R_M680x0_COPY, 19) /* Copy symbol at runtime */ +ELF_RELOC (R_M680x0_GLOB_DAT, 20) /* Create GOT entry */ +ELF_RELOC (R_M680x0_JMP_SLOT, 21) /* Create PLT entry */ +ELF_RELOC (R_M680x0_RELATIVE, 22) /* Adjust by program base */ +/* These are GNU extensions to enable C++ vtable garbage collection. */ +ELF_RELOC (R_M680x0_GNU_VTINHERIT, 23) +ELF_RELOC (R_M680x0_GNU_VTENTRY, 24) +/* TLS static relocations. */ +ELF_RELOC (R_M680x0_TLS_GD32, 25) +ELF_RELOC (R_M680x0_TLS_GD16, 26) +ELF_RELOC (R_M680x0_TLS_GD8, 27) +ELF_RELOC (R_M680x0_TLS_LDM32, 28) +ELF_RELOC (R_M680x0_TLS_LDM16, 29) +ELF_RELOC (R_M680x0_TLS_LDM8, 30) +ELF_RELOC (R_M680x0_TLS_LDO32, 31) +ELF_RELOC (R_M680x0_TLS_LDO16, 32) +ELF_RELOC (R_M680x0_TLS_LDO8, 33) +ELF_RELOC (R_M680x0_TLS_IE32, 34) +ELF_RELOC (R_M680x0_TLS_IE16, 35) +ELF_RELOC (R_M680x0_TLS_IE8, 36) +ELF_RELOC (R_M680x0_TLS_LE32, 37) +ELF_RELOC (R_M680x0_TLS_LE16, 38) +ELF_RELOC (R_M680x0_TLS_LE8, 39) +ELF_RELOC (R_M680x0_TLS_DTPMOD32, 40) +ELF_RELOC (R_M680x0_TLS_DTPREL32, 41) +ELF_RELOC (R_M680x0_TLS_TPREL32, 42) Index: llvm/include/llvm/IR/CallingConv.h =================================================================== --- llvm/include/llvm/IR/CallingConv.h +++ llvm/include/llvm/IR/CallingConv.h @@ -241,6 +241,9 @@ /// The remainder matches the regular calling convention. WASM_EmscriptenInvoke = 99, + /// M680x0_INTR - Calling convention used for M680x0 interrupt routines. + M680x0_INTR = 1000, + /// The highest possible calling convention ID. Must be some 2^k - 1. MaxID = 1023 }; Index: llvm/include/llvm/MC/MCExpr.h =================================================================== --- llvm/include/llvm/MC/MCExpr.h +++ llvm/include/llvm/MC/MCExpr.h @@ -199,6 +199,7 @@ VK_GOTOFF, VK_GOTREL, VK_PCREL, + VK_GOTPC, VK_GOTPCREL, VK_GOTTPOFF, VK_INDNTPOFF, Index: llvm/include/llvm/Object/ELFObjectFile.h =================================================================== --- llvm/include/llvm/Object/ELFObjectFile.h +++ llvm/include/llvm/Object/ELFObjectFile.h @@ -1090,6 +1090,8 @@ switch (EF.getHeader()->e_ident[ELF::EI_CLASS]) { case ELF::ELFCLASS32: switch (EF.getHeader()->e_machine) { + case ELF::EM_68K: + return "ELF32-M680x0"; case ELF::EM_386: return "elf32-i386"; case ELF::EM_IAMCU: @@ -1158,6 +1160,8 @@ template Triple::ArchType ELFObjectFile::getArch() const { bool IsLittleEndian = ELFT::TargetEndianness == support::little; switch (EF.getHeader()->e_machine) { + case ELF::EM_68K: + return Triple::m680x0; case ELF::EM_386: case ELF::EM_IAMCU: return Triple::x86; Index: llvm/include/llvm/module.modulemap =================================================================== --- llvm/include/llvm/module.modulemap +++ llvm/include/llvm/module.modulemap @@ -80,6 +80,7 @@ textual header "BinaryFormat/ELFRelocs/x86_64.def" textual header "BinaryFormat/WasmRelocs.def" textual header "BinaryFormat/MsgPack.def" + textual header "BinaryFormat/ELFRelocs/m680x0.def" } module LLVM_Config { Index: llvm/lib/MC/MCExpr.cpp =================================================================== --- llvm/lib/MC/MCExpr.cpp +++ llvm/lib/MC/MCExpr.cpp @@ -225,6 +225,8 @@ case VK_GOTOFF: return "GOTOFF"; case VK_GOTREL: return "GOTREL"; case VK_PCREL: return "PCREL"; + case VK_GOTPC: + return "GOTPC"; case VK_GOTPCREL: return "GOTPCREL"; case VK_GOTTPOFF: return "GOTTPOFF"; case VK_INDNTPOFF: return "INDNTPOFF"; @@ -373,138 +375,139 @@ MCSymbolRefExpr::VariantKind MCSymbolRefExpr::getVariantKindForName(StringRef Name) { return StringSwitch(Name.lower()) - .Case("dtprel", VK_DTPREL) - .Case("dtpoff", VK_DTPOFF) - .Case("got", VK_GOT) - .Case("gotoff", VK_GOTOFF) - .Case("gotrel", VK_GOTREL) - .Case("pcrel", VK_PCREL) - .Case("gotpcrel", VK_GOTPCREL) - .Case("gottpoff", VK_GOTTPOFF) - .Case("indntpoff", VK_INDNTPOFF) - .Case("ntpoff", VK_NTPOFF) - .Case("gotntpoff", VK_GOTNTPOFF) - .Case("plt", VK_PLT) - .Case("tlscall", VK_TLSCALL) - .Case("tlsdesc", VK_TLSDESC) - .Case("tlsgd", VK_TLSGD) - .Case("tlsld", VK_TLSLD) - .Case("tlsldm", VK_TLSLDM) - .Case("tpoff", VK_TPOFF) - .Case("tprel", VK_TPREL) - .Case("tlvp", VK_TLVP) - .Case("tlvppage", VK_TLVPPAGE) - .Case("tlvppageoff", VK_TLVPPAGEOFF) - .Case("page", VK_PAGE) - .Case("pageoff", VK_PAGEOFF) - .Case("gotpage", VK_GOTPAGE) - .Case("gotpageoff", VK_GOTPAGEOFF) - .Case("imgrel", VK_COFF_IMGREL32) - .Case("secrel32", VK_SECREL) - .Case("size", VK_SIZE) - .Case("abs8", VK_X86_ABS8) - .Case("l", VK_PPC_LO) - .Case("h", VK_PPC_HI) - .Case("ha", VK_PPC_HA) - .Case("high", VK_PPC_HIGH) - .Case("higha", VK_PPC_HIGHA) - .Case("higher", VK_PPC_HIGHER) - .Case("highera", VK_PPC_HIGHERA) - .Case("highest", VK_PPC_HIGHEST) - .Case("highesta", VK_PPC_HIGHESTA) - .Case("got@l", VK_PPC_GOT_LO) - .Case("got@h", VK_PPC_GOT_HI) - .Case("got@ha", VK_PPC_GOT_HA) - .Case("local", VK_PPC_LOCAL) - .Case("tocbase", VK_PPC_TOCBASE) - .Case("toc", VK_PPC_TOC) - .Case("toc@l", VK_PPC_TOC_LO) - .Case("toc@h", VK_PPC_TOC_HI) - .Case("toc@ha", VK_PPC_TOC_HA) - .Case("u", VK_PPC_U) - .Case("l", VK_PPC_L) - .Case("tls", VK_PPC_TLS) - .Case("dtpmod", VK_PPC_DTPMOD) - .Case("tprel@l", VK_PPC_TPREL_LO) - .Case("tprel@h", VK_PPC_TPREL_HI) - .Case("tprel@ha", VK_PPC_TPREL_HA) - .Case("tprel@high", VK_PPC_TPREL_HIGH) - .Case("tprel@higha", VK_PPC_TPREL_HIGHA) - .Case("tprel@higher", VK_PPC_TPREL_HIGHER) - .Case("tprel@highera", VK_PPC_TPREL_HIGHERA) - .Case("tprel@highest", VK_PPC_TPREL_HIGHEST) - .Case("tprel@highesta", VK_PPC_TPREL_HIGHESTA) - .Case("dtprel@l", VK_PPC_DTPREL_LO) - .Case("dtprel@h", VK_PPC_DTPREL_HI) - .Case("dtprel@ha", VK_PPC_DTPREL_HA) - .Case("dtprel@high", VK_PPC_DTPREL_HIGH) - .Case("dtprel@higha", VK_PPC_DTPREL_HIGHA) - .Case("dtprel@higher", VK_PPC_DTPREL_HIGHER) - .Case("dtprel@highera", VK_PPC_DTPREL_HIGHERA) - .Case("dtprel@highest", VK_PPC_DTPREL_HIGHEST) - .Case("dtprel@highesta", VK_PPC_DTPREL_HIGHESTA) - .Case("got@tprel", VK_PPC_GOT_TPREL) - .Case("got@tprel@l", VK_PPC_GOT_TPREL_LO) - .Case("got@tprel@h", VK_PPC_GOT_TPREL_HI) - .Case("got@tprel@ha", VK_PPC_GOT_TPREL_HA) - .Case("got@dtprel", VK_PPC_GOT_DTPREL) - .Case("got@dtprel@l", VK_PPC_GOT_DTPREL_LO) - .Case("got@dtprel@h", VK_PPC_GOT_DTPREL_HI) - .Case("got@dtprel@ha", VK_PPC_GOT_DTPREL_HA) - .Case("got@tlsgd", VK_PPC_GOT_TLSGD) - .Case("got@tlsgd@l", VK_PPC_GOT_TLSGD_LO) - .Case("got@tlsgd@h", VK_PPC_GOT_TLSGD_HI) - .Case("got@tlsgd@ha", VK_PPC_GOT_TLSGD_HA) - .Case("got@tlsld", VK_PPC_GOT_TLSLD) - .Case("got@tlsld@l", VK_PPC_GOT_TLSLD_LO) - .Case("got@tlsld@h", VK_PPC_GOT_TLSLD_HI) - .Case("got@tlsld@ha", VK_PPC_GOT_TLSLD_HA) - .Case("got@pcrel", VK_PPC_GOT_PCREL) - .Case("got@tlsgd@pcrel", VK_PPC_GOT_TLSGD_PCREL) - .Case("got@tprel@pcrel", VK_PPC_GOT_TPREL_PCREL) - .Case("tls@pcrel", VK_PPC_TLS_PCREL) - .Case("notoc", VK_PPC_NOTOC) - .Case("gdgot", VK_Hexagon_GD_GOT) - .Case("gdplt", VK_Hexagon_GD_PLT) - .Case("iegot", VK_Hexagon_IE_GOT) - .Case("ie", VK_Hexagon_IE) - .Case("ldgot", VK_Hexagon_LD_GOT) - .Case("ldplt", VK_Hexagon_LD_PLT) - .Case("none", VK_ARM_NONE) - .Case("got_prel", VK_ARM_GOT_PREL) - .Case("target1", VK_ARM_TARGET1) - .Case("target2", VK_ARM_TARGET2) - .Case("prel31", VK_ARM_PREL31) - .Case("sbrel", VK_ARM_SBREL) - .Case("tlsldo", VK_ARM_TLSLDO) - .Case("lo8", VK_AVR_LO8) - .Case("hi8", VK_AVR_HI8) - .Case("hlo8", VK_AVR_HLO8) - .Case("typeindex", VK_WASM_TYPEINDEX) - .Case("tbrel", VK_WASM_TBREL) - .Case("mbrel", VK_WASM_MBREL) - .Case("gotpcrel32@lo", VK_AMDGPU_GOTPCREL32_LO) - .Case("gotpcrel32@hi", VK_AMDGPU_GOTPCREL32_HI) - .Case("rel32@lo", VK_AMDGPU_REL32_LO) - .Case("rel32@hi", VK_AMDGPU_REL32_HI) - .Case("rel64", VK_AMDGPU_REL64) - .Case("abs32@lo", VK_AMDGPU_ABS32_LO) - .Case("abs32@hi", VK_AMDGPU_ABS32_HI) - .Case("hi", VK_VE_HI32) - .Case("lo", VK_VE_LO32) - .Case("pc_hi", VK_VE_PC_HI32) - .Case("pc_lo", VK_VE_PC_LO32) - .Case("got_hi", VK_VE_GOT_HI32) - .Case("got_lo", VK_VE_GOT_LO32) - .Case("gotoff_hi", VK_VE_GOTOFF_HI32) - .Case("gotoff_lo", VK_VE_GOTOFF_LO32) - .Case("plt_hi", VK_VE_PLT_HI32) - .Case("plt_lo", VK_VE_PLT_LO32) - .Case("tls_gd_hi", VK_VE_TLS_GD_HI32) - .Case("tls_gd_lo", VK_VE_TLS_GD_LO32) - .Case("tpoff_hi", VK_VE_TPOFF_HI32) - .Case("tpoff_lo", VK_VE_TPOFF_LO32) - .Default(VK_Invalid); + .Case("dtprel", VK_DTPREL) + .Case("dtpoff", VK_DTPOFF) + .Case("got", VK_GOT) + .Case("gotoff", VK_GOTOFF) + .Case("gotrel", VK_GOTREL) + .Case("pcrel", VK_PCREL) + .Case("gotpc", VK_GOTPC) + .Case("gotpcrel", VK_GOTPCREL) + .Case("gottpoff", VK_GOTTPOFF) + .Case("indntpoff", VK_INDNTPOFF) + .Case("ntpoff", VK_NTPOFF) + .Case("gotntpoff", VK_GOTNTPOFF) + .Case("plt", VK_PLT) + .Case("tlscall", VK_TLSCALL) + .Case("tlsdesc", VK_TLSDESC) + .Case("tlsgd", VK_TLSGD) + .Case("tlsld", VK_TLSLD) + .Case("tlsldm", VK_TLSLDM) + .Case("tpoff", VK_TPOFF) + .Case("tprel", VK_TPREL) + .Case("tlvp", VK_TLVP) + .Case("tlvppage", VK_TLVPPAGE) + .Case("tlvppageoff", VK_TLVPPAGEOFF) + .Case("page", VK_PAGE) + .Case("pageoff", VK_PAGEOFF) + .Case("gotpage", VK_GOTPAGE) + .Case("gotpageoff", VK_GOTPAGEOFF) + .Case("imgrel", VK_COFF_IMGREL32) + .Case("secrel32", VK_SECREL) + .Case("size", VK_SIZE) + .Case("abs8", VK_X86_ABS8) + .Case("l", VK_PPC_LO) + .Case("h", VK_PPC_HI) + .Case("ha", VK_PPC_HA) + .Case("high", VK_PPC_HIGH) + .Case("higha", VK_PPC_HIGHA) + .Case("higher", VK_PPC_HIGHER) + .Case("highera", VK_PPC_HIGHERA) + .Case("highest", VK_PPC_HIGHEST) + .Case("highesta", VK_PPC_HIGHESTA) + .Case("got@l", VK_PPC_GOT_LO) + .Case("got@h", VK_PPC_GOT_HI) + .Case("got@ha", VK_PPC_GOT_HA) + .Case("local", VK_PPC_LOCAL) + .Case("tocbase", VK_PPC_TOCBASE) + .Case("toc", VK_PPC_TOC) + .Case("toc@l", VK_PPC_TOC_LO) + .Case("toc@h", VK_PPC_TOC_HI) + .Case("toc@ha", VK_PPC_TOC_HA) + .Case("u", VK_PPC_U) + .Case("l", VK_PPC_L) + .Case("tls", VK_PPC_TLS) + .Case("dtpmod", VK_PPC_DTPMOD) + .Case("tprel@l", VK_PPC_TPREL_LO) + .Case("tprel@h", VK_PPC_TPREL_HI) + .Case("tprel@ha", VK_PPC_TPREL_HA) + .Case("tprel@high", VK_PPC_TPREL_HIGH) + .Case("tprel@higha", VK_PPC_TPREL_HIGHA) + .Case("tprel@higher", VK_PPC_TPREL_HIGHER) + .Case("tprel@highera", VK_PPC_TPREL_HIGHERA) + .Case("tprel@highest", VK_PPC_TPREL_HIGHEST) + .Case("tprel@highesta", VK_PPC_TPREL_HIGHESTA) + .Case("dtprel@l", VK_PPC_DTPREL_LO) + .Case("dtprel@h", VK_PPC_DTPREL_HI) + .Case("dtprel@ha", VK_PPC_DTPREL_HA) + .Case("dtprel@high", VK_PPC_DTPREL_HIGH) + .Case("dtprel@higha", VK_PPC_DTPREL_HIGHA) + .Case("dtprel@higher", VK_PPC_DTPREL_HIGHER) + .Case("dtprel@highera", VK_PPC_DTPREL_HIGHERA) + .Case("dtprel@highest", VK_PPC_DTPREL_HIGHEST) + .Case("dtprel@highesta", VK_PPC_DTPREL_HIGHESTA) + .Case("got@tprel", VK_PPC_GOT_TPREL) + .Case("got@tprel@l", VK_PPC_GOT_TPREL_LO) + .Case("got@tprel@h", VK_PPC_GOT_TPREL_HI) + .Case("got@tprel@ha", VK_PPC_GOT_TPREL_HA) + .Case("got@dtprel", VK_PPC_GOT_DTPREL) + .Case("got@dtprel@l", VK_PPC_GOT_DTPREL_LO) + .Case("got@dtprel@h", VK_PPC_GOT_DTPREL_HI) + .Case("got@dtprel@ha", VK_PPC_GOT_DTPREL_HA) + .Case("got@tlsgd", VK_PPC_GOT_TLSGD) + .Case("got@tlsgd@l", VK_PPC_GOT_TLSGD_LO) + .Case("got@tlsgd@h", VK_PPC_GOT_TLSGD_HI) + .Case("got@tlsgd@ha", VK_PPC_GOT_TLSGD_HA) + .Case("got@tlsld", VK_PPC_GOT_TLSLD) + .Case("got@tlsld@l", VK_PPC_GOT_TLSLD_LO) + .Case("got@tlsld@h", VK_PPC_GOT_TLSLD_HI) + .Case("got@tlsld@ha", VK_PPC_GOT_TLSLD_HA) + .Case("got@pcrel", VK_PPC_GOT_PCREL) + .Case("got@tlsgd@pcrel", VK_PPC_GOT_TLSGD_PCREL) + .Case("got@tprel@pcrel", VK_PPC_GOT_TPREL_PCREL) + .Case("tls@pcrel", VK_PPC_TLS_PCREL) + .Case("notoc", VK_PPC_NOTOC) + .Case("gdgot", VK_Hexagon_GD_GOT) + .Case("gdplt", VK_Hexagon_GD_PLT) + .Case("iegot", VK_Hexagon_IE_GOT) + .Case("ie", VK_Hexagon_IE) + .Case("ldgot", VK_Hexagon_LD_GOT) + .Case("ldplt", VK_Hexagon_LD_PLT) + .Case("none", VK_ARM_NONE) + .Case("got_prel", VK_ARM_GOT_PREL) + .Case("target1", VK_ARM_TARGET1) + .Case("target2", VK_ARM_TARGET2) + .Case("prel31", VK_ARM_PREL31) + .Case("sbrel", VK_ARM_SBREL) + .Case("tlsldo", VK_ARM_TLSLDO) + .Case("lo8", VK_AVR_LO8) + .Case("hi8", VK_AVR_HI8) + .Case("hlo8", VK_AVR_HLO8) + .Case("typeindex", VK_WASM_TYPEINDEX) + .Case("tbrel", VK_WASM_TBREL) + .Case("mbrel", VK_WASM_MBREL) + .Case("gotpcrel32@lo", VK_AMDGPU_GOTPCREL32_LO) + .Case("gotpcrel32@hi", VK_AMDGPU_GOTPCREL32_HI) + .Case("rel32@lo", VK_AMDGPU_REL32_LO) + .Case("rel32@hi", VK_AMDGPU_REL32_HI) + .Case("rel64", VK_AMDGPU_REL64) + .Case("abs32@lo", VK_AMDGPU_ABS32_LO) + .Case("abs32@hi", VK_AMDGPU_ABS32_HI) + .Case("hi", VK_VE_HI32) + .Case("lo", VK_VE_LO32) + .Case("pc_hi", VK_VE_PC_HI32) + .Case("pc_lo", VK_VE_PC_LO32) + .Case("got_hi", VK_VE_GOT_HI32) + .Case("got_lo", VK_VE_GOT_LO32) + .Case("gotoff_hi", VK_VE_GOTOFF_HI32) + .Case("gotoff_lo", VK_VE_GOTOFF_LO32) + .Case("plt_hi", VK_VE_PLT_HI32) + .Case("plt_lo", VK_VE_PLT_LO32) + .Case("tls_gd_hi", VK_VE_TLS_GD_HI32) + .Case("tls_gd_lo", VK_VE_TLS_GD_LO32) + .Case("tpoff_hi", VK_VE_TPOFF_HI32) + .Case("tpoff_lo", VK_VE_TPOFF_LO32) + .Default(VK_Invalid); } void MCSymbolRefExpr::printVariantKind(raw_ostream &OS) const { Index: llvm/lib/Object/ELF.cpp =================================================================== --- llvm/lib/Object/ELF.cpp +++ llvm/lib/Object/ELF.cpp @@ -22,6 +22,13 @@ StringRef llvm::object::getELFRelocationTypeName(uint32_t Machine, uint32_t Type) { switch (Machine) { + case ELF::EM_68K: + switch (Type) { +#include "llvm/BinaryFormat/ELFRelocs/m680x0.def" + default: + break; + } + break; case ELF::EM_X86_64: switch (Type) { #include "llvm/BinaryFormat/ELFRelocs/x86_64.def" Index: llvm/lib/ObjectYAML/ELFYAML.cpp =================================================================== --- llvm/lib/ObjectYAML/ELFYAML.cpp +++ llvm/lib/ObjectYAML/ELFYAML.cpp @@ -681,6 +681,9 @@ case ELF::EM_PPC64: #include "llvm/BinaryFormat/ELFRelocs/PowerPC64.def" break; + case ELF::EM_68K: +#include "llvm/BinaryFormat/ELFRelocs/m680x0.def" + break; default: // Nothing to do. break; Index: llvm/lib/Target/M680x0/MCTargetDesc/CMakeLists.txt =================================================================== --- llvm/lib/Target/M680x0/MCTargetDesc/CMakeLists.txt +++ llvm/lib/Target/M680x0/MCTargetDesc/CMakeLists.txt @@ -1,3 +1,8 @@ add_llvm_component_library(LLVMM680x0Desc - M680x0DummyDesc.cpp + M680x0AsmBackend.cpp + M680x0MCTargetDesc.cpp + M680x0MCAsmInfo.cpp + M680x0MCCodeEmitter.cpp + M680x0ELFObjectWriter.cpp + M680x0InstPrinter.cpp ) Index: llvm/lib/Target/M680x0/MCTargetDesc/M680x0AsmBackend.cpp =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/MCTargetDesc/M680x0AsmBackend.cpp @@ -0,0 +1,245 @@ +//===-- M680x0AsmBackend.cpp - M680x0 Assembler Backend ---------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains definitions for M680x0 assembler backend. +/// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/M680x0BaseInfo.h" +#include "MCTargetDesc/M680x0FixupKinds.h" + +#include "llvm/ADT/StringSwitch.h" +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/BinaryFormat/MachO.h" +#include "llvm/MC/MCAsmBackend.h" +#include "llvm/MC/MCELFObjectWriter.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCFixupKindInfo.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCMachObjectWriter.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSectionCOFF.h" +#include "llvm/MC/MCSectionELF.h" +#include "llvm/MC/MCSectionMachO.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/TargetRegistry.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +namespace { + +class M680x0AsmBackend : public MCAsmBackend { + +public: + M680x0AsmBackend(const Target &T) : MCAsmBackend(support::big) {} + + unsigned getNumFixupKinds() const override { + return llvm::M680x0::NumTargetFixupKinds; + } + + void applyFixup(const MCAssembler &Asm, const MCFixup &Fixup, + const MCValue &Target, MutableArrayRef Data, + uint64_t Value, bool IsResolved, + const MCSubtargetInfo *STI) const override { + unsigned Size = 1 << getFixupKindLog2Size(Fixup.getKind()); + + assert(Fixup.getOffset() + Size <= Data.size() && "Invalid fixup offset!"); + + // Check that uppper bits are either all zeros or all ones. + // Specifically ignore overflow/underflow as long as the leakage is + // limited to the lower bits. This is to remain compatible with + // other assemblers. + assert(isIntN(Size * 8 + 1, Value) && + "Value does not fit in the Fixup field"); + + // Write in Big Endian + for (unsigned i = 0; i != Size; ++i) + Data[Fixup.getOffset() + i] = uint8_t(Value >> ((Size - i - 1) * 8)); + } + + bool mayNeedRelaxation(const MCInst &Inst, + const MCSubtargetInfo &STI) const override; + + bool fixupNeedsRelaxation(const MCFixup &Fixup, uint64_t Value, + const MCRelaxableFragment *DF, + const MCAsmLayout &Layout) const override; + + void relaxInstruction(MCInst &Inst, + const MCSubtargetInfo &STI) const override; + + /// Returns the minimum size of a nop in bytes on this target. The assembler + /// will use this to emit excess padding in situations where the padding + /// required for simple alignment would be less than the minimum nop size. + unsigned getMinimumNopSize() const override { return 2; } + + /// Write a sequence of optimal nops to the output, covering \p Count bytes. + /// \return - true on success, false on failure + bool writeNopData(raw_ostream &OS, uint64_t Count) const override; +}; +} // end anonymous namespace + +/// cc—Carry clear GE—Greater than or equal +/// LS—Lower or same PL—Plus +/// CS—Carry set GT—Greater than +/// LT—Less than +/// EQ—Equal HI—Higher +/// MI—Minus VC—Overflow clear +/// LE—Less than or equal +/// NE—Not equal VS—Overflow set +static unsigned getRelaxedOpcodeBranch(const MCInst &Inst) { + unsigned Op = Inst.getOpcode(); + switch (Op) { + default: + return Op; + case M680x0::BRA8: + return M680x0::BRA16; + case M680x0::Bcc8: + return M680x0::Bcc16; + case M680x0::Bls8: + return M680x0::Bls16; + case M680x0::Blt8: + return M680x0::Blt16; + case M680x0::Beq8: + return M680x0::Beq16; + case M680x0::Bmi8: + return M680x0::Bmi16; + case M680x0::Bne8: + return M680x0::Bne16; + case M680x0::Bge8: + return M680x0::Bge16; + case M680x0::Bcs8: + return M680x0::Bcs16; + case M680x0::Bpl8: + return M680x0::Bpl16; + case M680x0::Bgt8: + return M680x0::Bgt16; + case M680x0::Bhi8: + return M680x0::Bhi16; + case M680x0::Bvc8: + return M680x0::Bvc16; + case M680x0::Ble8: + return M680x0::Ble16; + case M680x0::Bvs8: + return M680x0::Bvs16; + } +} + +static unsigned getRelaxedOpcodeArith(const MCInst &Inst) { + unsigned Op = Inst.getOpcode(); + switch (Op) { + default: + return Op; + // NOTE there will be some relaxations for PCD and ARD mem for x20 + } +} + +static unsigned getRelaxedOpcode(const MCInst &Inst) { + unsigned R = getRelaxedOpcodeArith(Inst); + if (R != Inst.getOpcode()) + return R; + return getRelaxedOpcodeBranch(Inst); +} + +bool M680x0AsmBackend::mayNeedRelaxation(const MCInst &Inst, + const MCSubtargetInfo &STI) const { + // Branches can always be relaxed in either mode. + if (getRelaxedOpcodeBranch(Inst) != Inst.getOpcode()) + return true; + + // Check if this instruction is ever relaxable. + if (getRelaxedOpcodeArith(Inst) == Inst.getOpcode()) + return false; + + // Check if the relaxable operand has an expression. For the current set of + // relaxable instructions, the relaxable operand is always the last operand. + // NOTE will change for x20 mem + unsigned RelaxableOp = Inst.getNumOperands() - 1; + if (Inst.getOperand(RelaxableOp).isExpr()) + return true; + + return false; +} + +bool M680x0AsmBackend::fixupNeedsRelaxation(const MCFixup &Fixup, + uint64_t Value, + const MCRelaxableFragment *DF, + const MCAsmLayout &Layout) const { + // TODO Newer CPU can use 32 bit offsets, so check for this when ready + if (int64_t(Value) != int64_t(int16_t(Value))) { + llvm_unreachable("Cannot relax the instruction, value does not fit"); + } + // Relax if the value is too big for a (signed) i8. This means that byte-wide + // instructions have to matched by default + // + // NOTE + // A branch to the immediately following instruction automatically + // uses the 16-bit displacement format because the 8-bit + // displacement field contains $00 (zero offset). + return Value == 0 || int64_t(Value) != int64_t(int8_t(Value)); +} + +// NOTE Can tblgen help at all here to verify there aren't other instructions +// we can relax? +void M680x0AsmBackend::relaxInstruction(MCInst &Inst, + const MCSubtargetInfo &STI) const { + // The only relaxations M680x0 does is from a 1byte pcrel to a 2byte PCRel. + unsigned RelaxedOp = getRelaxedOpcode(Inst); + + if (RelaxedOp == Inst.getOpcode()) { + SmallString<256> Tmp; + raw_svector_ostream OS(Tmp); + Inst.dump_pretty(OS); + OS << "\n"; + report_fatal_error("unexpected instruction to relax: " + OS.str()); + } + + Inst.setOpcode(RelaxedOp); +} + +bool M680x0AsmBackend::writeNopData(raw_ostream &OS, uint64_t Count) const { + // Cannot emit NOP with size being not multiple of 16 bits. + if (Count % 2 != 0) + return false; + + uint64_t NumNops = Count / 2; + for (uint64_t i = 0; i != NumNops; ++i) { + OS << "\x4E\x71"; + } + + return true; +} + +namespace { + +class M680x0ELFAsmBackend : public M680x0AsmBackend { +public: + uint8_t OSABI; + M680x0ELFAsmBackend(const Target &T, uint8_t OSABI) + : M680x0AsmBackend(T), OSABI(OSABI) {} + + std::unique_ptr + createObjectTargetWriter() const override { + return createM680x0ELFObjectWriter(OSABI); + } +}; + +} // end anonymous namespace + +MCAsmBackend *llvm::createM680x0AsmBackend(const Target &T, + const MCSubtargetInfo &STI, + const MCRegisterInfo &MRI, + const MCTargetOptions &Options) { + // assert (TheTriple.getEnvironment() == Triple::GNU); + const Triple &TheTriple = STI.getTargetTriple(); + uint8_t OSABI = MCELFObjectTargetWriter::getOSABI(TheTriple.getOS()); + return new M680x0ELFAsmBackend(T, OSABI); +} Index: llvm/lib/Target/M680x0/MCTargetDesc/M680x0BaseInfo.h =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/MCTargetDesc/M680x0BaseInfo.h @@ -0,0 +1,347 @@ +//===-- M680x0BaseInfo.h - Top level definitions for M680X0 MC --*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains small standalone helper functions and enum definitions +/// for the M680x0 target useful for the compiler back-end and the MC +/// libraries. As such, it deliberately does not include references to LLVM +/// core code gen types, passes, etc.. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_M680X0_MCTARGETDESC_M680X0BASEINFO_H +#define LLVM_LIB_TARGET_M680X0_MCTARGETDESC_M680X0BASEINFO_H + +#include "M680x0MCTargetDesc.h" + +#include "llvm/MC/MCExpr.h" +#include "llvm/Support/DataTypes.h" +#include "llvm/Support/ErrorHandling.h" + +#define GET_INSTRINFO_MI_OPS_INFO +#define GET_INSTRINFO_OPERAND_TYPES_ENUM +#define GET_INSTRINFO_LOGICAL_OPERAND_SIZE_MAP +#include "M680x0GenInstrInfo.inc" + +namespace llvm { + +namespace M680x0 { + +/// Enums for memory operand decoding. Supports these forms: +/// (d,An) +/// (d,An,Xn) +/// ([bd,An],Xn,od) +/// ([bd,An,Xn],od) +enum { + MemDisp = 0, + MemBase = 1, + MemIndex = 2, // FIXME #3 assumes Scale 1 for now + + MemOuter = 3 +}; + +/// Enums for pc-relative memory operand decoding. Supports these forms: +/// (d,PC) +/// (d,PC,Xn) +/// ([bd,PC],Xn,od) +/// ([bd,PC,Xn],od) +enum { PCRelDisp = 0, PCRelIndex = 1, PCRelOuter = 2 }; +} // namespace M680x0 + +namespace M680x0Beads { +enum { + Ctrl = 0x0, + Bits1 = 0x1, + Bits2 = 0x2, + Bits3 = 0x3, + Bits4 = 0x4, + DAReg = 0x5, + DA = 0x6, + Reg = 0x7, + Disp8 = 0x8, + Imm8 = 0x9, + Imm16 = 0xA, + Imm32 = 0xB, + Imm3 = 0xC, +}; + +// Ctrl payload +enum { + Term = 0x0, + Ignore = 0x1, +}; +} // namespace M680x0Beads + +/// This namespace holds all of the target specific flags that instruction info +/// tracks. +namespace M680x0II { +/// Target Operand Flag enum. +enum TOF { + + MO_NO_FLAG, + + /// On a symbol operand this indicates that the immediate is the absolute + /// address of the symbol. + MO_ABSOLUTE_ADDRESS, + + /// On a symbol operand this indicates that the immediate is the pc-relative + /// address of the symbol. + MO_PC_RELATIVE_ADDRESS, + + /// On a symbol operand this indicates that the immediate is the offset to + /// the GOT entry for the symbol name from the base of the GOT. + /// + /// name@GOT + MO_GOT, + + /// On a symbol operand this indicates that the immediate is the offset to + /// the location of the symbol name from the base of the GOT. + /// + /// name@GOTOFF + MO_GOTOFF, + + /// On a symbol operand this indicates that the immediate is offset to the + /// GOT entry for the symbol name from the current code location. + /// + /// name@GOTPCREL + MO_GOTPCREL, + + /// On a symbol operand this indicates that the immediate is offset to the + /// PLT entry of symbol name from the current code location. + /// + /// name@PLT + MO_PLT, +}; // enum TOF + +// enum { +// //===------------------------------------------------------------------===// +// // Instruction encodings. These are the standard/most common forms for +// // M680x0 instructions. +// // +// +// // Pseudo - This represents an instruction that is a pseudo instruction +// // or one that has not been implemented yet. It is illegal to code +// generate +// // it, but tolerated for intermediate implementation stages. +// Pseudo = 0, +// FormMask = 15 +// }; + +/// Return true if the specified TargetFlag operand is a reference to a stub +/// for a global, not the global itself. +inline static bool isGlobalStubReference(unsigned char TargetFlag) { + switch (TargetFlag) { + default: + return false; + case M680x0II::MO_GOTPCREL: // pc-relative GOT reference. + case M680x0II::MO_GOT: // normal GOT reference. + return true; + } +} + +/// Return True if the specified GlobalValue is a direct reference for a +/// symbol. +inline static bool isDirectGlobalReference(unsigned char Flag) { + switch (Flag) { + default: + return false; + case M680x0II::MO_NO_FLAG: + case M680x0II::MO_ABSOLUTE_ADDRESS: + case M680x0II::MO_PC_RELATIVE_ADDRESS: + return true; + } +} + +/// Return true if the specified global value reference is relative to a 32-bit +/// PIC base (M680x0ISD::GlobalBaseReg). If this is true, the addressing mode +/// has the PIC base register added in. +inline static bool isGlobalRelativeToPICBase(unsigned char TargetFlag) { + switch (TargetFlag) { + default: + return false; + case M680x0II::MO_GOTOFF: // isPICStyleGOT: local global. + case M680x0II::MO_GOT: // isPICStyleGOT: other global. + return true; + } +} + +/// Return True if the specified GlobalValue requires PC addressing mode. +inline static bool isPCRelGlobalReference(unsigned char Flag) { + switch (Flag) { + default: + return false; + case M680x0II::MO_GOTPCREL: + case M680x0II::MO_PC_RELATIVE_ADDRESS: + return true; + } +} + +/// Return True if the Block is referenced using PC +inline static bool isPCRelBlockReference(unsigned char Flag) { + switch (Flag) { + default: + return false; + case M680x0II::MO_PC_RELATIVE_ADDRESS: + return true; + } +} + +static inline bool isAddressRegister(unsigned RegNo) { + switch (RegNo) { + case M680x0::CCR: + case M680x0::PC: + case M680x0::SR: + default: + llvm_unreachable("Not an Address nor Data register"); + case M680x0::WA0: + case M680x0::WA1: + case M680x0::WA2: + case M680x0::WA3: + case M680x0::WA4: + case M680x0::WA5: + case M680x0::WA6: + case M680x0::WA7: + case M680x0::A0: + case M680x0::A1: + case M680x0::A2: + case M680x0::A3: + case M680x0::A4: + case M680x0::A5: + case M680x0::A6: + // case M680x0::A7: + case M680x0::SP: + return true; + case M680x0::BD0: + case M680x0::BD1: + case M680x0::BD2: + case M680x0::BD3: + case M680x0::BD4: + case M680x0::BD5: + case M680x0::BD6: + case M680x0::BD7: + case M680x0::WD0: + case M680x0::WD1: + case M680x0::WD2: + case M680x0::WD3: + case M680x0::WD4: + case M680x0::WD5: + case M680x0::WD6: + case M680x0::WD7: + case M680x0::D0: + case M680x0::D1: + case M680x0::D2: + case M680x0::D3: + case M680x0::D4: + case M680x0::D5: + case M680x0::D6: + case M680x0::D7: + return false; + } +} + +static inline bool hasMultiMIOperands(unsigned Op, unsigned LogicalOpIdx) { + return M680x0::getLogicalOperandSize(Op, LogicalOpIdx) > 1; +} + +#if 0 +static inline bool isPCRelOpd(unsigned Opd) { + switch (Opd) { + default: + return false; + case M680x0::MIOpTypes::MxPCD32: + case M680x0::MIOpTypes::MxPCD16: + case M680x0::MIOpTypes::MxPCD8: + case M680x0::MIOpTypes::MxPCI32: + case M680x0::MIOpTypes::MxPCI16: + case M680x0::MIOpTypes::MxPCI8: + case MCOI::OPERAND_PCREL: + return true; + } + return false; +} + +static inline unsigned getDispSize(unsigned Opd) { + switch (Opd) { + default: + return 0; + case M680x0::MIOpTypes::MxAL16: + case M680x0::MIOpTypes::MxAL32: + case M680x0::MIOpTypes::MxAL8: + return 32; + case M680x0::MIOpTypes::MxARID16: + case M680x0::MIOpTypes::MxARID16_TC: + case M680x0::MIOpTypes::MxARID32: + case M680x0::MIOpTypes::MxARID32_TC: + case M680x0::MIOpTypes::MxARID8: + case M680x0::MIOpTypes::MxARID8_TC: + case M680x0::MIOpTypes::MxPCD16: + case M680x0::MIOpTypes::MxPCD32: + case M680x0::MIOpTypes::MxPCD8: + case M680x0::MIOpTypes::MxAS16: + case M680x0::MIOpTypes::MxAS32: + case M680x0::MIOpTypes::MxAS8: + return 16; + case M680x0::MIOpTypes::MxARII16: + case M680x0::MIOpTypes::MxARII16_TC: + case M680x0::MIOpTypes::MxARII32: + case M680x0::MIOpTypes::MxARII32_TC: + case M680x0::MIOpTypes::MxARII8: + case M680x0::MIOpTypes::MxARII8_TC: + case M680x0::MIOpTypes::MxPCI16: + case M680x0::MIOpTypes::MxPCI32: + case M680x0::MIOpTypes::MxPCI8: + return 8; + } + return 8; +} +#endif + +static inline unsigned getMaskedSpillRegister(unsigned order) { + switch (order) { + default: + return 0; + case 0: + return M680x0::D0; + case 1: + return M680x0::D1; + case 2: + return M680x0::D2; + case 3: + return M680x0::D3; + case 4: + return M680x0::D4; + case 5: + return M680x0::D5; + case 6: + return M680x0::D6; + case 7: + return M680x0::D7; + case 8: + return M680x0::A0; + case 9: + return M680x0::A1; + case 10: + return M680x0::A2; + case 11: + return M680x0::A3; + case 12: + return M680x0::A4; + case 13: + return M680x0::A5; + case 14: + return M680x0::A6; + case 15: + return M680x0::A7; + } +} + +} // namespace M680x0II + +} // namespace llvm + +#endif Index: llvm/lib/Target/M680x0/MCTargetDesc/M680x0DummyDesc.cpp =================================================================== --- llvm/lib/Target/M680x0/MCTargetDesc/M680x0DummyDesc.cpp +++ /dev/null @@ -1,6 +0,0 @@ -// WARNING: This file is created only for patch review -// In order to build this patch w/o errors, some libraris like -// LLVMCodeGen need to be present and some APIs -// like `LLVMInitializeM680x0Target` need to be there - -extern "C" void LLVMInitializeM680x0TargetMC() {} Index: llvm/lib/Target/M680x0/MCTargetDesc/M680x0ELFObjectWriter.cpp =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/MCTargetDesc/M680x0ELFObjectWriter.cpp @@ -0,0 +1,127 @@ +//===---------- M680x0ELFObjectWriter.cpp - M680x0 ELF Writer ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains definitions for M680x0 ELF Writers +/// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/M680x0FixupKinds.h" +#include "MCTargetDesc/M680x0MCTargetDesc.h" + +#include "llvm/BinaryFormat/ELF.h" +#include "llvm/MC/MCAsmInfo.h" +#include "llvm/MC/MCContext.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 M680x0ELFObjectWriter : public MCELFObjectTargetWriter { +public: + M680x0ELFObjectWriter(uint8_t OSABI); + + ~M680x0ELFObjectWriter() override; + +protected: + unsigned getRelocType(MCContext &Ctx, const MCValue &Target, + const MCFixup &Fixup, bool IsPCRel) const override; +}; +} // namespace + +M680x0ELFObjectWriter::M680x0ELFObjectWriter(uint8_t OSABI) + : MCELFObjectTargetWriter(false, OSABI, ELF::EM_68K, /* RELA */ true) {} + +M680x0ELFObjectWriter::~M680x0ELFObjectWriter() {} + +enum M680x0RelType { RT_32, RT_16, RT_8 }; + +static M680x0RelType +getType(unsigned Kind, MCSymbolRefExpr::VariantKind &Modifier, bool &IsPCRel) { + switch (Kind) { + default: + llvm_unreachable("Unimplemented"); + case FK_Data_4: + case FK_PCRel_4: + return RT_32; + case FK_PCRel_2: + case FK_Data_2: + return RT_16; + case FK_PCRel_1: + case FK_Data_1: + return RT_8; + } +} + +// FIXME #4 Should i split reloc types between pre x20 and the rest? +unsigned M680x0ELFObjectWriter::getRelocType(MCContext &Ctx, + const MCValue &Target, + const MCFixup &Fixup, + bool IsPCRel) const { + MCSymbolRefExpr::VariantKind Modifier = Target.getAccessVariant(); + unsigned Kind = Fixup.getKind(); + M680x0RelType Type = getType(Kind, Modifier, IsPCRel); + switch (Modifier) { + default: + llvm_unreachable("Unimplemented"); + case MCSymbolRefExpr::VK_None: + switch (Type) { + case RT_32: + return IsPCRel ? ELF::R_M680x0_PC32 : ELF::R_M680x0_32; + case RT_16: + return IsPCRel ? ELF::R_M680x0_PC16 : ELF::R_M680x0_16; + case RT_8: + return IsPCRel ? ELF::R_M680x0_PC8 : ELF::R_M680x0_8; + } + // case MCSymbolRefExpr::VK_GOT: + // switch (Type) { + // case RT_32: + // return IsPCRel ? ELF::R_M680x0_GOTPC32 : ELF::R_M680x0_GOT32; + // case RT_16: + // return IsPCRel ? ELF::R_M680x0_GOTPC16 : ELF::R_M680x0_GOT16; + // case RT_8: + // llvm_unreachable("Unimplemented"); + // } + case MCSymbolRefExpr::VK_GOTPCREL: + switch (Type) { + case RT_32: + return ELF::R_M680x0_GOTPCREL32; + case RT_16: + return ELF::R_M680x0_GOTPCREL16; + case RT_8: + return ELF::R_M680x0_GOTPCREL8; + } + case MCSymbolRefExpr::VK_GOTOFF: + assert(!IsPCRel); + switch (Type) { + case RT_32: + return ELF::R_M680x0_GOTOFF32; + case RT_16: + return ELF::R_M680x0_GOTOFF16; + case RT_8: + return ELF::R_M680x0_GOTOFF8; + } + case MCSymbolRefExpr::VK_PLT: + switch (Type) { + case RT_32: + return ELF::R_M680x0_PLT32; + case RT_16: + return ELF::R_M680x0_PLT16; + case RT_8: + return ELF::R_M680x0_PLT8; + } + } +} + +std::unique_ptr +llvm::createM680x0ELFObjectWriter(uint8_t OSABI) { + return std::make_unique(OSABI); +} Index: llvm/lib/Target/M680x0/MCTargetDesc/M680x0FixupKinds.h =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/MCTargetDesc/M680x0FixupKinds.h @@ -0,0 +1,64 @@ +//===-- M680x0FixupKinds.h - M680x0 Specific Fixup Entries ------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains M680x0 specific fixup entries. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_M680x0_MCTARGETDESC_M680x0FIXUPKINDS_H +#define LLVM_LIB_TARGET_M680x0_MCTARGETDESC_M680x0FIXUPKINDS_H + +#include "llvm/MC/MCFixup.h" + +namespace llvm { +namespace M680x0 { +enum Fixups { + // Marker + LastTargetFixupKind, + NumTargetFixupKinds = LastTargetFixupKind - FirstTargetFixupKind +}; +} + +static inline unsigned getFixupKindLog2Size(unsigned Kind) { + switch (Kind) { + default: + llvm_unreachable("invalid fixup kind!"); + case FK_PCRel_1: + case FK_SecRel_1: + case FK_Data_1: + return 0; + case FK_PCRel_2: + case FK_SecRel_2: + case FK_Data_2: + return 1; + case FK_PCRel_4: + case FK_SecRel_4: + case FK_Data_4: + return 2; + } +} + +static inline MCFixupKind getFixupForSize(unsigned Size, bool isPCRel) { + switch (Size) { + default: + llvm_unreachable("Invalid generic fixup size!"); + case 8: + return isPCRel ? FK_PCRel_1 : FK_Data_1; + case 16: + return isPCRel ? FK_PCRel_2 : FK_Data_2; + case 32: + return isPCRel ? FK_PCRel_4 : FK_Data_4; + case 64: + return isPCRel ? FK_PCRel_8 : FK_Data_8; + } +} + +} // namespace llvm + +#endif Index: llvm/lib/Target/M680x0/MCTargetDesc/M680x0InstPrinter.h =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/MCTargetDesc/M680x0InstPrinter.h @@ -0,0 +1,167 @@ +//===-- M680x0InstPrinter.h - Convert M680x0 MCInst to asm ------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains declarations for an M680x0 MCInst printer. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_M680X0_INSTPRINTER_M680X0INSTPRINTER_H +#define LLVM_LIB_TARGET_M680X0_INSTPRINTER_M680X0INSTPRINTER_H + +#include "llvm/MC/MCInstPrinter.h" + +namespace llvm { + +class TargetMachine; + +class M680x0InstPrinter : public MCInstPrinter { +public: + M680x0InstPrinter(const MCAsmInfo &MAI, const MCInstrInfo &MII, + const MCRegisterInfo &MRI) + : MCInstPrinter(MAI, MII, MRI) {} + + // Autogenerated by tblgen. + void printInstruction(const MCInst *MI, uint64_t Address, raw_ostream &O); + static const char *getRegisterName(unsigned RegNo); + + void printRegName(raw_ostream &OS, unsigned RegNo) const override; + void printInst(const MCInst *MI, uint64_t Address, StringRef Annot, + const MCSubtargetInfo &STI, raw_ostream &O) override; + + bool printAliasInstr(const MCInst *MI, uint64_t Address, raw_ostream &OS); + void printCustomAliasOperand(const MCInst *MI, unsigned OpIdx, + unsigned PrintMethodIdx, raw_ostream &O); + +private: + void printOperand(const MCInst *MI, unsigned opNum, raw_ostream &O); + void printImmediate(const MCInst *MI, int opNum, raw_ostream &O); + /// Print register mask for MOVEM instruction in order D0-D7,A0-A7 + void printMoveMask(const MCInst *MI, int opNum, raw_ostream &O); + /// Print register mask for MOVEM instruction in order A7-A0,D7-D0 + void printMoveMaskR(const MCInst *MI, int opNum, raw_ostream &O); + void printDisp(const MCInst *MI, int opNum, raw_ostream &O); + void printARIMem(const MCInst *MI, int opNum, raw_ostream &O); + void printARIPIMem(const MCInst *MI, int opNum, raw_ostream &O); + void printARIPDMem(const MCInst *MI, int opNum, raw_ostream &O); + void printARIDMem(const MCInst *MI, int opNum, raw_ostream &O); + void printARIIMem(const MCInst *MI, int opNum, raw_ostream &O); + void printAbsMem(const MCInst *MI, int opNum, raw_ostream &O); + void printPCDMem(const MCInst *MI, uint64_t Address, int opNum, + raw_ostream &O); + void printPCIMem(const MCInst *MI, uint64_t Address, int opNum, + raw_ostream &O); + + //===----------------------------------------------------------------------===// + // Specializations + //===----------------------------------------------------------------------===// + // + void printPCRelImm(const MCInst *MI, uint64_t Address, int opNum, + raw_ostream &O) { + printOperand(MI, opNum, O); + } + + void printARI8Mem(const MCInst *MI, int opNum, raw_ostream &O) { + printARIMem(MI, opNum, O); + } + void printARI16Mem(const MCInst *MI, int opNum, raw_ostream &O) { + printARIMem(MI, opNum, O); + } + void printARI32Mem(const MCInst *MI, int opNum, raw_ostream &O) { + printARIMem(MI, opNum, O); + } + + void printARIPI8Mem(const MCInst *MI, int opNum, raw_ostream &O) { + printARIPIMem(MI, opNum, O); + } + void printARIPI16Mem(const MCInst *MI, int opNum, raw_ostream &O) { + printARIPIMem(MI, opNum, O); + } + void printARIPI32Mem(const MCInst *MI, int opNum, raw_ostream &O) { + printARIPIMem(MI, opNum, O); + } + + void printARIPD8Mem(const MCInst *MI, int opNum, raw_ostream &O) { + printARIPDMem(MI, opNum, O); + } + void printARIPD16Mem(const MCInst *MI, int opNum, raw_ostream &O) { + printARIPDMem(MI, opNum, O); + } + void printARIPD32Mem(const MCInst *MI, int opNum, raw_ostream &O) { + printARIPDMem(MI, opNum, O); + } + + void printARID8Mem(const MCInst *MI, int opNum, raw_ostream &O) { + printARIDMem(MI, opNum, O); + } + void printARID16Mem(const MCInst *MI, int opNum, raw_ostream &O) { + printARIDMem(MI, opNum, O); + } + void printARID32Mem(const MCInst *MI, int opNum, raw_ostream &O) { + printARIDMem(MI, opNum, O); + } + + void printARII8Mem(const MCInst *MI, int opNum, raw_ostream &O) { + printARIIMem(MI, opNum, O); + } + void printARII16Mem(const MCInst *MI, int opNum, raw_ostream &O) { + printARIIMem(MI, opNum, O); + } + void printARII32Mem(const MCInst *MI, int opNum, raw_ostream &O) { + printARIIMem(MI, opNum, O); + } + + void printAS8Mem(const MCInst *MI, int opNum, raw_ostream &O) { + printAbsMem(MI, opNum, O); + } + void printAS16Mem(const MCInst *MI, int opNum, raw_ostream &O) { + printAbsMem(MI, opNum, O); + } + void printAS32Mem(const MCInst *MI, int opNum, raw_ostream &O) { + printAbsMem(MI, opNum, O); + } + + void printAL8Mem(const MCInst *MI, int opNum, raw_ostream &O) { + printAbsMem(MI, opNum, O); + } + void printAL16Mem(const MCInst *MI, int opNum, raw_ostream &O) { + printAbsMem(MI, opNum, O); + } + void printAL32Mem(const MCInst *MI, int opNum, raw_ostream &O) { + printAbsMem(MI, opNum, O); + } + + void printPCD8Mem(const MCInst *MI, uint64_t Address, int opNum, + raw_ostream &O) { + printPCDMem(MI, Address, opNum, O); + } + void printPCD16Mem(const MCInst *MI, uint64_t Address, int opNum, + raw_ostream &O) { + printPCDMem(MI, Address, opNum, O); + } + void printPCD32Mem(const MCInst *MI, uint64_t Address, int opNum, + raw_ostream &O) { + printPCDMem(MI, Address, opNum, O); + } + + void printPCI8Mem(const MCInst *MI, uint64_t Address, int opNum, + raw_ostream &O) { + printPCIMem(MI, Address, opNum, O); + } + void printPCI16Mem(const MCInst *MI, uint64_t Address, int opNum, + raw_ostream &O) { + printPCIMem(MI, Address, opNum, O); + } + void printPCI32Mem(const MCInst *MI, uint64_t Address, int opNum, + raw_ostream &O) { + printPCIMem(MI, Address, opNum, O); + } +}; +} // end namespace llvm + +#endif Index: llvm/lib/Target/M680x0/MCTargetDesc/M680x0InstPrinter.cpp =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/MCTargetDesc/M680x0InstPrinter.cpp @@ -0,0 +1,195 @@ +//===-- M680x0InstPrinter.cpp - Convert M680x0 MCInst to asm ----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains definitions for an M680x0 MCInst printer. +/// +//===----------------------------------------------------------------------===// + +// TODO #33 finish printer, it does not conform to Motorola asm at all + +#include "M680x0InstPrinter.h" +#include "M680x0BaseInfo.h" + +#include "llvm/ADT/StringExtras.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/raw_ostream.h" + +using namespace llvm; + +#define DEBUG_TYPE "asm-printer" + +#define PRINT_ALIAS_INSTR +#include "M680x0GenAsmWriter.inc" + +void M680x0InstPrinter::printRegName(raw_ostream &OS, unsigned RegNo) const { + OS << "%" << StringRef(getRegisterName(RegNo)); +} + +void M680x0InstPrinter::printInst(const MCInst *MI, uint64_t Address, + StringRef Annot, const MCSubtargetInfo &STI, + raw_ostream &O) { + if (!printAliasInstr(MI, Address, O)) { + printInstruction(MI, Address, O); + } + printAnnotation(O, Annot); +} + +void M680x0InstPrinter::printOperand(const MCInst *MI, unsigned OpNo, + raw_ostream &O) { + const MCOperand &MO = MI->getOperand(OpNo); + if (MO.isReg()) { + printRegName(O, MO.getReg()); + return; + } + + if (MO.isImm()) { + printImmediate(MI, OpNo, O); + return; + } + + assert(MO.isExpr() && "Unknown operand kind in printOperand"); + MO.getExpr()->print(O, &MAI); +} + +void M680x0InstPrinter::printImmediate(const MCInst *MI, int opNum, + raw_ostream &O) { + const MCOperand &MO = MI->getOperand(opNum); + if (MO.isImm()) { + O << '#' << MO.getImm(); + } else if (MO.isExpr()) { + O << '#'; + MO.getExpr()->print(O, &MAI); + } else { + llvm_unreachable("Unknown immediate kind"); + } +} + +// +void M680x0InstPrinter::printMoveMask(const MCInst *MI, int opNum, + raw_ostream &O) { + unsigned Mask = MI->getOperand(opNum).getImm(); + assert((Mask & 0xFFFF) == Mask); + + unsigned HalfMask, Reg; + for (int s = 0; s < 8; s += 8) { + HalfMask = Mask >> s; + if (HalfMask && s != 0) { + O << ','; + } + + for (int i = 0; HalfMask; ++i) { + if ((HalfMask >> i) & 0x01) { + HalfMask ^= 1 << i; + Reg = M680x0II::getMaskedSpillRegister(i + s); + printRegName(O, Reg); + + int j = i; + while ((HalfMask >> (j + 1)) & 0x01) { + HalfMask ^= 1 << ++j; + } + + if (j != i) { + O << '-'; + Reg = M680x0II::getMaskedSpillRegister(j + s); + printRegName(O, Reg); + } + + i = j; + + if (HalfMask) { + O << ','; + } + } else { + } + } + } +} + +void M680x0InstPrinter::printDisp(const MCInst *MI, int opNum, raw_ostream &O) { + const MCOperand &Op = MI->getOperand(opNum); + if (Op.isImm()) { + O << Op.getImm(); + return; + } + assert(Op.isExpr() && "Unknown operand kind in printOperand"); + Op.getExpr()->print(O, &MAI); +} + +void M680x0InstPrinter::printARIMem(const MCInst *MI, int opNum, + raw_ostream &O) { + O << '('; + printOperand(MI, opNum, O); + O << ')'; +} + +void M680x0InstPrinter::printARIPIMem(const MCInst *MI, int opNum, + raw_ostream &O) { + O << "("; + printOperand(MI, opNum, O); + O << ")+"; +} + +void M680x0InstPrinter::printARIPDMem(const MCInst *MI, int opNum, + raw_ostream &O) { + O << "-("; + printOperand(MI, opNum, O); + O << ")"; +} + +void M680x0InstPrinter::printARIDMem(const MCInst *MI, int opNum, + raw_ostream &O) { + O << '('; + printDisp(MI, opNum + M680x0::MemDisp, O); + O << ','; + printOperand(MI, opNum + M680x0::MemBase, O); + O << ')'; +} + +void M680x0InstPrinter::printARIIMem(const MCInst *MI, int opNum, + raw_ostream &O) { + O << '('; + printDisp(MI, opNum + M680x0::MemDisp, O); + O << ','; + printOperand(MI, opNum + M680x0::MemBase, O); + O << ','; + printOperand(MI, opNum + M680x0::MemIndex, O); + O << ')'; +} + +// NOTE forcing (W,L) size available since M68020 only +void M680x0InstPrinter::printAbsMem(const MCInst *MI, int opNum, + raw_ostream &O) { + const MCOperand &MO = MI->getOperand(opNum); + if (MO.isImm()) { + // ??? Print it in hex? + O << (unsigned int)MO.getImm(); + } else { + printOperand(MI, opNum, O); + } +} + +void M680x0InstPrinter::printPCDMem(const MCInst *MI, uint64_t Address, + int opNum, raw_ostream &O) { + O << '('; + printDisp(MI, opNum + M680x0::PCRelDisp, O); + O << ",%pc)"; +} + +void M680x0InstPrinter::printPCIMem(const MCInst *MI, uint64_t Address, + int opNum, raw_ostream &O) { + O << '('; + printDisp(MI, opNum + M680x0::PCRelDisp, O); + O << ",%pc,"; + printOperand(MI, opNum + M680x0::PCRelIndex, O); + O << ')'; +} Index: llvm/lib/Target/M680x0/MCTargetDesc/M680x0MCAsmInfo.h =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/MCTargetDesc/M680x0MCAsmInfo.h @@ -0,0 +1,31 @@ +//===-- M680x0MCAsmInfo.h - M680x0 Asm Info --------------------*- C++ -*--===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the declarations of the M680x0 MCAsmInfo properties. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_M680X0_MCTARGETDESC_M680X0MCASMINFO_H +#define LLVM_LIB_TARGET_M680X0_MCTARGETDESC_M680X0MCASMINFO_H + +#include "llvm/MC/MCAsmInfoELF.h" + +namespace llvm { +class Triple; + +class M680x0ELFMCAsmInfo : public MCAsmInfoELF { + void anchor() override; + +public: + explicit M680x0ELFMCAsmInfo(const Triple &Triple); +}; + +} // namespace llvm + +#endif Index: llvm/lib/Target/M680x0/MCTargetDesc/M680x0MCAsmInfo.cpp =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/MCTargetDesc/M680x0MCAsmInfo.cpp @@ -0,0 +1,42 @@ +//===-- M680x0MCAsmInfo.cpp - M680x0 Asm Properties -------------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains the definitions of the M680x0 MCAsmInfo properties. +/// +//===----------------------------------------------------------------------===// + +#include "M680x0MCAsmInfo.h" + +#include "llvm/ADT/Triple.h" + +using namespace llvm; + +void M680x0ELFMCAsmInfo::anchor() {} + +// TODO get back to it when it comes to printing +M680x0ELFMCAsmInfo::M680x0ELFMCAsmInfo(const Triple &T) { + CodePointerSize = 4; + CalleeSaveStackSlotSize = 4; + + IsLittleEndian = false; + + TextAlignFillValue = 0x90; + + // Debug Information + SupportsDebugInformation = true; + + // Exceptions handling + ExceptionsType = ExceptionHandling::DwarfCFI; + + // Always enable the integrated assembler by default. + // Clang also enabled it when the OS is Solaris but that is redundant here. + UseIntegratedAssembler = true; + + CommentString = ";"; +} Index: llvm/lib/Target/M680x0/MCTargetDesc/M680x0MCCodeEmitter.cpp =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/MCTargetDesc/M680x0MCCodeEmitter.cpp @@ -0,0 +1,422 @@ +//===-- M680x0MCCodeEmitter.cpp - Convert M680x0 code emitter ---*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains defintions for M680x0 code emitter. +/// +//===----------------------------------------------------------------------===// + +#include "MCTargetDesc/M680x0BaseInfo.h" +#include "MCTargetDesc/M680x0FixupKinds.h" +#include "MCTargetDesc/M680x0MCTargetDesc.h" + +#include "llvm/MC/MCCodeEmitter.h" +#include "llvm/MC/MCContext.h" +#include "llvm/MC/MCExpr.h" +#include "llvm/MC/MCInst.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/Support/Debug.h" +#include "llvm/Support/raw_ostream.h" + +namespace llvm { +namespace M680x0 { +// Forward declarations +const uint8_t *getMCInstrBeads(unsigned); +} // end namespace M680x0 +} // end namespace llvm + +using namespace llvm; + +#define DEBUG_TYPE "m680x0-mccodeemitter" + +namespace { +class M680x0MCCodeEmitter : public MCCodeEmitter { + M680x0MCCodeEmitter(const M680x0MCCodeEmitter &) = delete; + void operator=(const M680x0MCCodeEmitter &) = delete; + const MCInstrInfo &MCII; + MCContext &Ctx; + +public: + M680x0MCCodeEmitter(const MCInstrInfo &mcii, MCContext &ctx) + : MCII(mcii), Ctx(ctx) {} + + ~M680x0MCCodeEmitter() override {} + + // TableGen'erated function + const uint8_t *getGenInstrBeads(const MCInst &MI) const { + return M680x0::getMCInstrBeads(MI.getOpcode()); + } + + unsigned EncodeBits(unsigned ThisByte, uint8_t Bead, const MCInst &MI, + const MCInstrDesc &Desc, uint64_t &Buffer, + unsigned Offset, SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + unsigned EncodeReg(unsigned ThisByte, uint8_t Bead, const MCInst &MI, + const MCInstrDesc &Desc, uint64_t &Buffer, unsigned Offset, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + unsigned EncodeImm(unsigned ThisByte, uint8_t Bead, const MCInst &MI, + const MCInstrDesc &Desc, uint64_t &Buffer, unsigned Offset, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const; + + void encodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const override; +}; + +} // end anonymous namespace + +unsigned M680x0MCCodeEmitter::EncodeBits(unsigned ThisByte, uint8_t Bead, + const MCInst &MI, + const MCInstrDesc &Desc, + uint64_t &Buffer, unsigned Offset, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + unsigned Num = 0; + switch (Bead & 0xF) { + case M680x0Beads::Bits1: + Num = 1; + break; + case M680x0Beads::Bits2: + Num = 2; + break; + case M680x0Beads::Bits3: + Num = 3; + break; + case M680x0Beads::Bits4: + Num = 4; + break; + } + unsigned char Val = (Bead & 0xF0) >> 4; + + LLVM_DEBUG(dbgs() << "\tEncodeBits" + << " Num: " << Num << " Val: 0x"); + LLVM_DEBUG(dbgs().write_hex(Val) << "\n"); + + Buffer |= (Val << Offset); + + return Num; +} + +unsigned M680x0MCCodeEmitter::EncodeReg(unsigned ThisByte, uint8_t Bead, + const MCInst &MI, + const MCInstrDesc &Desc, + uint64_t &Buffer, unsigned Offset, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + bool DA, Reg; + switch (Bead & 0xF) { + case M680x0Beads::DAReg: + Reg = true; + DA = true; + break; + case M680x0Beads::DA: + Reg = false; + DA = true; + break; + case M680x0Beads::Reg: + Reg = true; + DA = false; + break; + } + + unsigned Op = (Bead & 0x70) >> 4; + bool Alt = (Bead & 0x80); + LLVM_DEBUG(dbgs() << "\tEncodeReg" + << " Op: " << Op << ", DA: " << DA << ", Reg: " << Reg + << ", Alt: " << Alt << "\n"); + + auto MIOpIdx = M680x0::getLogicalOperandIdx(MI.getOpcode(), Op); + bool isPCRel = Desc.OpInfo[MIOpIdx].OperandType == MCOI::OPERAND_PCREL; + + MCOperand MCO; + if (M680x0II::hasMultiMIOperands(MI.getOpcode(), Op)) { + if (isPCRel) { + assert(Alt && + "PCRel addresses use Alt bead register encoding by default"); + MCO = MI.getOperand(MIOpIdx + M680x0::PCRelIndex); + } else { + MCO = MI.getOperand(MIOpIdx + (Alt ? M680x0::MemIndex : M680x0::MemBase)); + } + } else { + assert(!Alt && "You cannot use Alt register with a simple operand"); + MCO = MI.getOperand(MIOpIdx); + } + + unsigned RegNum = MCO.getReg(); + auto RI = Ctx.getRegisterInfo(); + + unsigned Written = 0; + if (Reg) { + uint32_t Val = RI->getEncodingValue(RegNum); + Buffer |= Val << Offset; + Offset += 3; + Written += 3; + } + + if (DA) { + Buffer |= (char)M680x0II::isAddressRegister(RegNum) << Offset; + Written++; + } + + return Written; +} +/// Checks if an unsigned integer fits into the given bit width. non-templated +/// version +constexpr static inline bool uintDoesFit(unsigned N, uint64_t x) { + return N >= 64 || x <= (UINT64_MAX >> (64 - N)); +} + +/// Checks if an integer fits into the given bit width. non-templated version +constexpr static inline bool intDoesFit(unsigned N, int64_t x) { + return N >= 64 || + (-(INT64_C(1) << (N - 1)) <= x && x < (INT64_C(1) << (N - 1))); +} + +static unsigned EmitConstant(uint64_t Val, unsigned Size, unsigned Pad, + uint64_t &Buffer, unsigned Offset) { + // assert (Size && (Size == 8 || Size == 16 || Size == 32)); + assert(Size + Offset <= 64 && "Value does not fit"); + assert(uintDoesFit(Size, Val)); + + // Pad the instruction with zeros if any + // FIXME #5 Actually emit zeros, since there might be trash in the buffer. + Size += Pad; + + // Writing Value in host's endianness + Buffer |= Val << Offset; + return Size; +} + +unsigned M680x0MCCodeEmitter::EncodeImm(unsigned ThisByte, uint8_t Bead, + const MCInst &MI, + const MCInstrDesc &Desc, + uint64_t &Buffer, unsigned Offset, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + unsigned ThisWord = ThisByte / 2; + unsigned Size = 0; + unsigned Pad = 0; + unsigned FixOffset = 0; + int64_t Addendum = 0; + bool NoExpr = false; + + unsigned Type = Bead & 0xF; + unsigned Op = (Bead & 0x70) >> 4; + bool Alt = (Bead & 0x80); + + auto MIOpIdx = M680x0::getLogicalOperandIdx(MI.getOpcode(), Op); + bool isPCRel = Desc.OpInfo[MIOpIdx].OperandType == MCOI::OPERAND_PCREL; + + // The PC value upon instruction reading of a short jump will point to the + // next instruction, thus we need to compensate 2 bytes, which is the diff + // between the patch point and the PC. + if (isPCRel && ThisWord == 0) { + Addendum -= 2; + } + + switch (Type) { + // ??? what happens if it is not byte aligned + // ??? is it even possible + case M680x0Beads::Disp8: + Size = 8; + Pad = 0; + FixOffset = ThisByte + 1; + Addendum += 1; + break; + case M680x0Beads::Imm8: + Size = 8; + Pad = 8; + FixOffset = ThisByte; + break; + case M680x0Beads::Imm16: + Size = 16; + Pad = 0; + FixOffset = ThisByte; + break; + case M680x0Beads::Imm32: + Size = 32; + Pad = 0; + FixOffset = ThisByte; + break; + case M680x0Beads::Imm3: + Size = 3; + Pad = 0; + NoExpr = true; + break; + } + + LLVM_DEBUG(dbgs() << "\tEncodeImm" + << " Op: " << Op << ", Size: " << Size << ", Alt: " << Alt + << "\n"); + + MCOperand MCO; + if (M680x0II::hasMultiMIOperands(MI.getOpcode(), Op)) { + + if (isPCRel) { + assert(!Alt && "You cannot use ALT operand with PCRel"); + MCO = MI.getOperand(MIOpIdx + M680x0::PCRelDisp); + } else { + MCO = MI.getOperand(MIOpIdx + (Alt ? M680x0::MemOuter : M680x0::MemDisp)); + } + + if (MCO.isExpr()) { + assert(!NoExpr && "Cannot use expression here"); + const MCExpr *Expr = MCO.getExpr(); + + // This only makes sense for PCRel instructions since PC points to the + // extension word and Disp8 for example is right justified and requires + // correction. E.g. R_M680x0_PC32 is calculated as S + A - P, P for Disp8 + // will be EXTENSION_WORD + 1 thus we need to have A equal to 1 to + // compensate. + // TODO count extension words + if (isPCRel && Addendum != 0) { + Expr = MCBinaryExpr::createAdd( + Expr, MCConstantExpr::create(Addendum, Ctx), Ctx); + } + + Fixups.push_back(MCFixup::create( + FixOffset, Expr, getFixupForSize(Size, isPCRel), MI.getLoc())); + // Write zeros + return EmitConstant(0, Size, Pad, Buffer, Offset); + } + + } else { + // assert (!Alt && "You cannot use Alt immediate with a simple operand"); + MCO = MI.getOperand(MIOpIdx); + if (MCO.isExpr()) { + assert(!NoExpr && "Cannot use expression here"); + const MCExpr *Expr = MCO.getExpr(); + + if (Addendum != 0) { + Expr = MCBinaryExpr::createAdd( + Expr, MCConstantExpr::create(Addendum, Ctx), Ctx); + } + + Fixups.push_back(MCFixup::create( + FixOffset, Expr, getFixupForSize(Size, isPCRel), MI.getLoc())); + // Write zeros + return EmitConstant(0, Size, Pad, Buffer, Offset); + } + } + + int64_t I = MCO.getImm(); + + // Store 8 as 0, thus making range 1-8 + if (Type == M680x0Beads::Imm3 && Alt) { + assert(I && "Cannot encode Alt Imm3 zero value"); + I %= 8; + } else { + assert(intDoesFit(Size, I)); + } + + uint64_t Imm = I; + + // 32 bit Imm requires HI16 first then LO16 + if (Size == 32) { + Offset += EmitConstant((Imm >> 16) & 0xFFFF, 16, Pad, Buffer, Offset); + EmitConstant(Imm & 0xFFFF, 16, Pad, Buffer, Offset); + return Size; + } + + return EmitConstant(Imm & (UINT64_MAX >> (64 - Size)), Size, Pad, Buffer, + Offset); +} + +#include "M680x0GenMCCodeBeads.inc" + +void M680x0MCCodeEmitter::encodeInstruction(const MCInst &MI, raw_ostream &OS, + SmallVectorImpl &Fixups, + const MCSubtargetInfo &STI) const { + unsigned Opcode = MI.getOpcode(); + const MCInstrDesc &Desc = MCII.get(Opcode); + // uint64_t TSFlags = Desc.TSFlags; + + LLVM_DEBUG(dbgs() << "EncodeInstruction: " << MCII.getName(Opcode) << "(" + << Opcode << ")\n"); + + const uint8_t *Beads = getGenInstrBeads(MI); + if (!*Beads) { + llvm_unreachable("*** Instruction does not have Beads defined"); + } + + uint64_t Buffer = 0; + unsigned Offset = 0; + unsigned ThisByte = 0; + + while (*Beads) { + uint8_t Bead = *Beads; + Beads++; + + // Check for control beads + if (!(Bead & 0xF)) { + switch (Bead >> 4) { + case M680x0Beads::Ignore: + continue; + } + } + + switch (Bead & 0xF) { + default: + llvm_unreachable("Unknown Bead code"); + break; + case M680x0Beads::Bits1: + case M680x0Beads::Bits2: + case M680x0Beads::Bits3: + case M680x0Beads::Bits4: + Offset += + EncodeBits(ThisByte, Bead, MI, Desc, Buffer, Offset, Fixups, STI); + break; + case M680x0Beads::DAReg: + case M680x0Beads::DA: + case M680x0Beads::Reg: + Offset += + EncodeReg(ThisByte, Bead, MI, Desc, Buffer, Offset, Fixups, STI); + break; + case M680x0Beads::Disp8: + case M680x0Beads::Imm8: + case M680x0Beads::Imm16: + case M680x0Beads::Imm32: + case M680x0Beads::Imm3: + Offset += + EncodeImm(ThisByte, Bead, MI, Desc, Buffer, Offset, Fixups, STI); + break; + } + + // Since M680x0 is Big Endian we need to rotate each instruction word + while (Offset / 16) { + OS.write((char)((Buffer >> 8) & 0xFF)); + OS.write((char)((Buffer >> 0) & 0xFF)); + Buffer >>= 16; + Offset -= 16; + ThisByte += 2; + } + } + + // while (Offset >= 8) { + // OS.write((char)(Buffer & 0xFF)); + // Buffer >>= 8; + // Offset -= 8; + // ThisByte++; + // } + + assert(Offset == 0 && "M680x0 Instructions are % 2 bytes"); + assert((ThisByte && !(ThisByte % 2)) && "M680x0 Instructions are % 2 bytes"); +} + +MCCodeEmitter *llvm::createM680x0MCCodeEmitter(const MCInstrInfo &MCII, + const MCRegisterInfo &MRI, + MCContext &Ctx) { + return new M680x0MCCodeEmitter(MCII, Ctx); +} Index: llvm/lib/Target/M680x0/MCTargetDesc/M680x0MCTargetDesc.h =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/MCTargetDesc/M680x0MCTargetDesc.h @@ -0,0 +1,65 @@ +//===-- M680x0MCTargetDesc.h - M680x0 Target Descriptions -------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file provides M680x0 specific target descriptions. +/// +//===----------------------------------------------------------------------===// + +#ifndef LLVM_LIB_TARGET_M680X0_MCTARGETDESC_M680X0MCTARGETDESC_H +#define LLVM_LIB_TARGET_M680X0_MCTARGETDESC_M680X0MCTARGETDESC_H + +#include "llvm/MC/MCInstrDesc.h" +#include "llvm/MC/MCObjectWriter.h" +#include "llvm/Support/DataTypes.h" + +namespace llvm { +class MCAsmBackend; +class MCCodeEmitter; +class MCContext; +class MCInstrInfo; +class MCRegisterInfo; +class MCSubtargetInfo; +class MCRelocationInfo; +class MCTargetOptions; +class Target; +class Triple; +class StringRef; +class raw_ostream; +class raw_pwrite_stream; + +extern Target TheM680x0Target; + +MCAsmBackend *createM680x0AsmBackend(const Target &T, + const MCSubtargetInfo &STI, + const MCRegisterInfo &MRI, + const MCTargetOptions &Options); + +MCCodeEmitter *createM680x0MCCodeEmitter(const MCInstrInfo &MCII, + const MCRegisterInfo &MRI, + MCContext &Ctx); + +/// Construct an M680x0 ELF object writer. +std::unique_ptr +createM680x0ELFObjectWriter(uint8_t OSABI); + +} // namespace llvm + +// Defines symbolic names for M680x0 registers. This defines a mapping from +// register name to register number. +#define GET_REGINFO_ENUM +#include "M680x0GenRegisterInfo.inc" + +// Defines symbolic names for the M680x0 instructions. +#define GET_INSTRINFO_ENUM +#include "M680x0GenInstrInfo.inc" + +#define GET_SUBTARGETINFO_ENUM +#include "M680x0GenSubtargetInfo.inc" + +#endif Index: llvm/lib/Target/M680x0/MCTargetDesc/M680x0MCTargetDesc.cpp =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/MCTargetDesc/M680x0MCTargetDesc.cpp @@ -0,0 +1,136 @@ +//===-- M680x0MCTargetDesc.cpp - M680x0 Target Descriptions -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file provides M680x0 target specific descriptions. +/// +//===----------------------------------------------------------------------===// + +#include "M680x0MCTargetDesc.h" + +#include "M680x0MCAsmInfo.h" + +#include "M680x0InstPrinter.h" + +#include "llvm/MC/MCELFStreamer.h" +#include "llvm/MC/MCInstPrinter.h" +#include "llvm/MC/MCInstrInfo.h" +#include "llvm/MC/MCRegisterInfo.h" +#include "llvm/MC/MCSubtargetInfo.h" +#include "llvm/MC/MCSymbol.h" +#include "llvm/MC/MachineLocation.h" +#include "llvm/Support/CommandLine.h" +#include "llvm/Support/ErrorHandling.h" +#include "llvm/Support/FormattedStream.h" +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +#define GET_INSTRINFO_MC_DESC +#include "M680x0GenInstrInfo.inc" + +#define GET_SUBTARGETINFO_MC_DESC +#include "M680x0GenSubtargetInfo.inc" + +#define GET_REGINFO_MC_DESC +#include "M680x0GenRegisterInfo.inc" + +static StringRef ParseM680x0Triple(const Triple &TT, StringRef CPU) { + std::string FS = ""; + return FS; +} + +static MCInstrInfo *createM680x0MCInstrInfo() { + MCInstrInfo *X = new MCInstrInfo(); + InitM680x0MCInstrInfo(X); // defined in M680x0GenInstrInfo.inc + return X; +} + +static MCRegisterInfo *createM680x0MCRegisterInfo(const Triple &TT) { + MCRegisterInfo *X = new MCRegisterInfo(); + InitM680x0MCRegisterInfo(X, llvm::M680x0::A0, 0, 0, llvm::M680x0::PC); + return X; +} + +static MCSubtargetInfo * +createM680x0MCSubtargetInfo(const Triple &TT, StringRef CPU, StringRef FS) { + auto ArchFS = ParseM680x0Triple(TT, CPU); + if (!FS.empty()) { + if (!ArchFS.empty()) { + ArchFS = (ArchFS + "," + FS).getSingleStringRef(); + } else { + ArchFS = FS; + } + } + return createM680x0MCSubtargetInfoImpl(TT, CPU, /*TuneCPU*/ CPU, ArchFS); +} + +static MCAsmInfo *createM680x0MCAsmInfo(const MCRegisterInfo &MRI, + const Triple &TT, + const MCTargetOptions &TO) { + MCAsmInfo *MAI = new M680x0ELFMCAsmInfo(TT); + + // Initialize initial frame state. + // Calculate amount of bytes used for return address storing + int stackGrowth = -4; + + // Initial state of the frame pointer is SP+stackGrowth. + MCCFIInstruction Inst = MCCFIInstruction::cfiDefCfa( + nullptr, MRI.getDwarfRegNum(llvm::M680x0::SP, true), -stackGrowth); + MAI->addInitialFrameState(Inst); + + //??? Do i need this? + // // Add return address to move list + // MCCFIInstruction Inst2 = MCCFIInstruction::createOffset( + // nullptr, MRI.getDwarfRegNum(M680x0::PC, true), stackGrowth); + // MAI->addInitialFrameState(Inst2); + + return MAI; +} + +static MCRelocationInfo *createM680x0MCRelocationInfo(const Triple &TheTriple, + MCContext &Ctx) { + // Default to the stock relocation info. + return llvm::createMCRelocationInfo(TheTriple, Ctx); +} + +static MCInstPrinter *createM680x0MCInstPrinter(const Triple &T, + unsigned SyntaxVariant, + const MCAsmInfo &MAI, + const MCInstrInfo &MII, + const MCRegisterInfo &MRI) { + return new M680x0InstPrinter(MAI, MII, MRI); +} + +extern "C" void LLVMInitializeM680x0TargetMC() { + Target &T = TheM680x0Target; + + // Register the MC asm info. + RegisterMCAsmInfoFn X(T, createM680x0MCAsmInfo); + + // Register the MC instruction info. + TargetRegistry::RegisterMCInstrInfo(T, createM680x0MCInstrInfo); + + // Register the MC register info. + TargetRegistry::RegisterMCRegInfo(T, createM680x0MCRegisterInfo); + + // Register the MC subtarget info. + TargetRegistry::RegisterMCSubtargetInfo(T, createM680x0MCSubtargetInfo); + + // Register the code emitter. + TargetRegistry::RegisterMCCodeEmitter(T, createM680x0MCCodeEmitter); + + // Register the MCInstPrinter. + TargetRegistry::RegisterMCInstPrinter(T, createM680x0MCInstPrinter); + + // Register the MC relocation info. + TargetRegistry::RegisterMCRelocationInfo(T, createM680x0MCRelocationInfo); + + // Register the asm backend. + TargetRegistry::RegisterMCAsmBackend(T, createM680x0AsmBackend); +} Index: llvm/lib/Target/M680x0/TargetInfo/CMakeLists.txt =================================================================== --- llvm/lib/Target/M680x0/TargetInfo/CMakeLists.txt +++ llvm/lib/Target/M680x0/TargetInfo/CMakeLists.txt @@ -1,3 +1,3 @@ add_llvm_component_library(LLVMM680x0Info - M680x0DummyInfo.cpp + M680x0TargetInfo.cpp ) Index: llvm/lib/Target/M680x0/TargetInfo/M680x0DummyInfo.cpp =================================================================== --- llvm/lib/Target/M680x0/TargetInfo/M680x0DummyInfo.cpp +++ /dev/null @@ -1,6 +0,0 @@ -// WARNING: This file is created only for patch review -// In order to build this patch w/o errors, some libraris like -// LLVMCodeGen need to be present and some APIs -// like `LLVMInitializeM680x0Target` need to be there - -extern "C" void LLVMInitializeM680x0TargetInfo() {} Index: llvm/lib/Target/M680x0/TargetInfo/M680x0TargetInfo.cpp =================================================================== --- /dev/null +++ llvm/lib/Target/M680x0/TargetInfo/M680x0TargetInfo.cpp @@ -0,0 +1,27 @@ +//===-- M680x0TargetInfo.cpp - M680x0 Target Implementation -----*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +/// +/// \file +/// This file contains M680x0 target initializer. +/// +//===----------------------------------------------------------------------===// + +#include "M680x0.h" + +#include "MCTargetDesc/M680x0MCTargetDesc.h" + +#include "llvm/Support/TargetRegistry.h" + +using namespace llvm; + +Target llvm::TheM680x0Target; + +extern "C" void LLVMInitializeM680x0TargetInfo() { + RegisterTarget X( + TheM680x0Target, "m680x0", "Motorola 68000 family", "M680x0"); +}