[llvm] [Mips][nanoMIPS] Add initial nanoMIPS target support (PR #223032)
via llvm-commits
llvm-commits at lists.llvm.org
Mon Oct 5 12:46:54 PDT 2026
https://github.com/nrakovic updated https://github.com/llvm/llvm-project/pull/223032
>From 689ba30b90dddd7046b3ac68343044dae55a4308 Mon Sep 17 00:00:00 2001
From: Nemanja Rakovic <ot_nemanja.rakovic at mediatek.com>
Date: Mon, 7 Sep 2026 19:53:49 +0200
Subject: [PATCH 01/15] [nanoMIPS 1/7] Add nanoMIPS target triple
Part of the initial batch of changes upstreaming nanoMIPS support to
LLVM. More details in the RFC:
https://discourse.llvm.org/t/rfc-upstreaming-nanomips-support-to-llvm/91713
Co-authored-by: Stefan Pejic <ot_stefan.pejic at mediatek.com>
---
llvm/include/llvm/TargetParser/Triple.h | 4 ++++
llvm/lib/TargetParser/Triple.cpp | 12 ++++++++++++
llvm/unittests/TargetParser/TripleTest.cpp | 20 ++++++++++++++++++++
3 files changed, 36 insertions(+)
diff --git a/llvm/include/llvm/TargetParser/Triple.h b/llvm/include/llvm/TargetParser/Triple.h
index 90e2ce8e37a51..84f95487be14e 100644
--- a/llvm/include/llvm/TargetParser/Triple.h
+++ b/llvm/include/llvm/TargetParser/Triple.h
@@ -70,6 +70,7 @@ class Triple {
mips64, // MIPS64: mips64, mips64r6, mipsn32, mipsn32r6
mips64el, // MIPS64EL: mips64el, mips64r6el, mipsn32el, mipsn32r6el
msp430, // MSP430: msp430
+ nanomips, // nanoMIPS: nanomips
ppc, // PPC: powerpc
ppcle, // PPCLE: powerpc (little endian)
ppc64, // PPC64: powerpc64, ppu
@@ -1130,6 +1131,9 @@ class Triple {
return getArch() == Triple::mips64 || getArch() == Triple::mips64el;
}
+ /// Tests whether the target is nanoMIPS.
+ bool isNanoMips() const { return getArch() == Triple::nanomips; }
+
/// Tests whether the target is MIPS (little and big endian, 32- or 64-bit).
bool isMIPS() const { return isMIPS32() || isMIPS64(); }
diff --git a/llvm/lib/TargetParser/Triple.cpp b/llvm/lib/TargetParser/Triple.cpp
index dd52c182b8f1f..8600ea13b1ec3 100644
--- a/llvm/lib/TargetParser/Triple.cpp
+++ b/llvm/lib/TargetParser/Triple.cpp
@@ -93,6 +93,8 @@ StringRef Triple::getArchTypeName(ArchType Kind) {
return "mipsel";
case msp430:
return "msp430";
+ case nanomips:
+ return "nanomips";
case nvptx64:
return "nvptx64";
case nvptx:
@@ -286,6 +288,7 @@ StringRef Triple::getArchTypePrefix(ArchType Kind) {
case m68k:
return "m68k";
+ case nanomips:
case mips:
case mipsel:
case mips64:
@@ -473,6 +476,7 @@ Triple::ArchType Triple::getArchTypeForLLVMName(StringRef Name) {
.Case("mips64", mips64)
.Case("mips64el", mips64el)
.Case("msp430", msp430)
+ .Case("nanomips", nanomips)
.Case("ppc64", ppc64)
.Case("ppc32", ppc)
.Case("ppc", ppc)
@@ -680,6 +684,7 @@ Triple::ArchType Triple::parseArch(StringRef ArchName) {
"dxilv1.9"},
Triple::dxil)
.Case("xtensa", Triple::xtensa)
+ .Case("nanomips", Triple::nanomips)
.Default(Triple::UnknownArch);
// Some architectures require special parsing logic just to compute the
@@ -984,6 +989,7 @@ static Triple::ObjectFormatType getDefaultFormat(const Triple &T) {
case Triple::mips64el:
case Triple::mips:
case Triple::msp430:
+ case Triple::nanomips:
case Triple::nvptx64:
case Triple::nvptx:
case Triple::ppc64le:
@@ -1754,6 +1760,7 @@ unsigned Triple::getArchPointerBitWidth(llvm::Triple::ArchType Arch) {
case llvm::Triple::m68k:
case llvm::Triple::mips:
case llvm::Triple::mipsel:
+ case llvm::Triple::nanomips:
case llvm::Triple::nvptx:
case llvm::Triple::ppc:
case llvm::Triple::ppcle:
@@ -1865,6 +1872,7 @@ Triple Triple::get32BitArchVariant() const {
case Triple::m68k:
case Triple::mips:
case Triple::mipsel:
+ case Triple::nanomips:
case Triple::nvptx:
case Triple::ppc:
case Triple::ppcle:
@@ -1963,6 +1971,7 @@ Triple Triple::get64BitArchVariant() const {
case Triple::lanai:
case Triple::m68k:
case Triple::msp430:
+ case Triple::nanomips:
case Triple::r600:
case Triple::shave:
case Triple::sparcel:
@@ -2089,6 +2098,7 @@ Triple Triple::getBigEndianArchVariant() const {
case Triple::loongarch32:
case Triple::loongarch64:
case Triple::msp430:
+ case Triple::nanomips:
case Triple::nvptx64:
case Triple::nvptx:
case Triple::r600:
@@ -2229,6 +2239,7 @@ bool Triple::isLittleEndian() const {
case Triple::mips64el:
case Triple::mipsel:
case Triple::msp430:
+ case Triple::nanomips:
case Triple::nvptx64:
case Triple::nvptx:
case Triple::ppcle:
@@ -2502,6 +2513,7 @@ ExceptionHandling Triple::getDefaultExceptionHandling() const {
case Triple::lanai:
case Triple::m68k:
case Triple::msp430:
+ case Triple::nanomips:
case Triple::systemz:
case Triple::xcore:
case Triple::xtensa:
diff --git a/llvm/unittests/TargetParser/TripleTest.cpp b/llvm/unittests/TargetParser/TripleTest.cpp
index a81801dc97a77..5be4047349c27 100644
--- a/llvm/unittests/TargetParser/TripleTest.cpp
+++ b/llvm/unittests/TargetParser/TripleTest.cpp
@@ -1157,6 +1157,13 @@ TEST(TripleTest, ParsedIDs) {
EXPECT_EQ(Triple::Musl, T.getEnvironment());
EXPECT_EQ(Triple::MipsSubArch_r6, T.getSubArch());
+ T = Triple("nanomips-unknown-elf");
+ EXPECT_EQ(Triple::nanomips, T.getArch());
+ EXPECT_EQ(Triple::UnknownVendor, T.getVendor());
+ EXPECT_EQ(Triple::UnknownOS, T.getOS());
+ EXPECT_EQ(Triple::UnknownEnvironment, T.getEnvironment());
+ EXPECT_EQ(Triple::ELF, T.getObjectFormat());
+
T = Triple("arm-oe-linux-gnueabi");
EXPECT_EQ(Triple::arm, T.getArch());
EXPECT_EQ(Triple::OpenEmbedded, T.getVendor());
@@ -2372,6 +2379,11 @@ TEST(TripleTest, BitWidthChecks) {
EXPECT_FALSE(T.isArch16Bit());
EXPECT_TRUE(T.isArch32Bit());
EXPECT_FALSE(T.isArch64Bit());
+
+ T.setArch(Triple::nanomips);
+ EXPECT_FALSE(T.isArch16Bit());
+ EXPECT_TRUE(T.isArch32Bit());
+ EXPECT_FALSE(T.isArch64Bit());
}
TEST(TripleTest, BitWidthArchVariants) {
@@ -2574,6 +2586,10 @@ TEST(TripleTest, BitWidthArchVariants) {
T.setArch(Triple::xtensa);
EXPECT_EQ(Triple::xtensa, T.get32BitArchVariant().getArch());
EXPECT_EQ(Triple::UnknownArch, T.get64BitArchVariant().getArch());
+
+ T.setArch(Triple::nanomips);
+ EXPECT_EQ(Triple::nanomips, T.get32BitArchVariant().getArch());
+ EXPECT_EQ(Triple::UnknownArch, T.get64BitArchVariant().getArch());
}
TEST(TripleTest, EndianArchVariants) {
@@ -2669,6 +2685,10 @@ TEST(TripleTest, EndianArchVariants) {
EXPECT_EQ(Triple::MipsSubArch_r6,
T.getLittleEndianArchVariant().getSubArch());
+ T.setArch(Triple::nanomips);
+ EXPECT_EQ(Triple::UnknownArch, T.getBigEndianArchVariant().getArch());
+ EXPECT_EQ(Triple::nanomips, T.getLittleEndianArchVariant().getArch());
+
T.setArch(Triple::ppc);
EXPECT_EQ(Triple::ppc, T.getBigEndianArchVariant().getArch());
EXPECT_EQ(Triple::ppcle, T.getLittleEndianArchVariant().getArch());
>From add2ed62fa304f873a4ca4ad1dce3ad4d24cc5d8 Mon Sep 17 00:00:00 2001
From: Nemanja Rakovic <ot_nemanja.rakovic at mediatek.com>
Date: Mon, 7 Sep 2026 19:54:16 +0200
Subject: [PATCH 02/15] [nanoMIPS 2/7] Add ELF and relocation support
Add the EM_NANOMIPS machine type, the nanoMIPS e_flags and the nanoMIPS
ELF relocations, and recognize them in the ELF object readers, ELFYAML
and llvm-readobj.
Co-authored-by: Faraz Shahbazker <faraz.shahbazker at mediatek.com>
---
llvm/include/llvm/BinaryFormat/ELF.h | 32 ++++
.../llvm/BinaryFormat/ELFRelocs/NanoMips.def | 79 +++++++++
llvm/include/llvm/Object/ELFObjectFile.h | 5 +
llvm/include/module.modulemap | 1 +
llvm/lib/Object/ELF.cpp | 8 +
llvm/lib/ObjectYAML/ELFYAML.cpp | 13 ++
.../ELF/reloc-types-nanomips.test | 167 ++++++++++++++++++
llvm/tools/llvm-readobj/ELFDumper.cpp | 1 +
llvm/unittests/Object/ELFObjectFileTest.cpp | 7 +
9 files changed, 313 insertions(+)
create mode 100644 llvm/include/llvm/BinaryFormat/ELFRelocs/NanoMips.def
create mode 100644 llvm/test/tools/llvm-readobj/ELF/reloc-types-nanomips.test
diff --git a/llvm/include/llvm/BinaryFormat/ELF.h b/llvm/include/llvm/BinaryFormat/ELF.h
index 6bb387799c4a1..807cbfbaae947 100644
--- a/llvm/include/llvm/BinaryFormat/ELF.h
+++ b/llvm/include/llvm/BinaryFormat/ELF.h
@@ -322,6 +322,7 @@ enum {
EM_RISCV = 243, // RISC-V
EM_LANAI = 244, // Lanai 32-bit processor
EM_BPF = 247, // Linux kernel bpf virtual machine
+ EM_NANOMIPS = 249, // MIPS Tech nanoMIPS architecture
EM_VE = 251, // NEC SX-Aurora VE
EM_CSKY = 252, // C-SKY 32-bit processor
EM_LOONGARCH = 258, // LoongArch
@@ -1105,6 +1106,37 @@ enum {
#include "ELFRelocs/Xtensa.def"
};
+// nanoMIPS specific e_flags
+enum : unsigned {
+ // File may be relaxed by the linker.
+ EF_NANOMIPS_LINKRELAX = 0x00000001,
+ // File contains position independent code.
+ EF_NANOMIPS_PIC = 0x00000002,
+ // Indicates code compiled for a 64-bit machine in 32-bit mode
+ // (regs are 32-bits wide).
+ EF_NANOMIPS_32BITMODE = 0x00000004,
+ // Indicate that all data access in this object is GP-relative
+ EF_NANOMIPS_PID = 0x00000008,
+ // Indicate that this object does not use absolute addressing.
+ EF_NANOMIPS_PCREL = 0x00000010,
+ // Four bit nanoMIPS architecture field.
+ EF_NANOMIPS_ARCH = 0xf0000000,
+ // -march=32r6 code.
+ EF_NANOMIPS_ARCH_32R6 = 0x00000000,
+ // The ABI of the file.
+ EF_NANOMIPS_ABI = 0x0000f000,
+ // nanoMIPS ABI in 32 bit mode.
+ EF_NANOMIPS_ABI_P32 = 0x00001000,
+
+ // Machine variant if we know it.
+ EF_NANOMIPS_MACH = 0x00ff0000
+};
+
+// ELF Relocation types for nanoMIPS
+enum {
+#include "ELFRelocs/NanoMips.def"
+};
+
#undef ELF_RELOC
// Section header.
diff --git a/llvm/include/llvm/BinaryFormat/ELFRelocs/NanoMips.def b/llvm/include/llvm/BinaryFormat/ELFRelocs/NanoMips.def
new file mode 100644
index 0000000000000..d0e5d690e571e
--- /dev/null
+++ b/llvm/include/llvm/BinaryFormat/ELFRelocs/NanoMips.def
@@ -0,0 +1,79 @@
+#ifndef ELF_RELOC
+#error "ELF_RELOC must be defined"
+#endif
+
+ELF_RELOC(R_NANOMIPS_NONE, 0)
+ELF_RELOC(R_NANOMIPS_32, 1)
+ELF_RELOC(R_NANOMIPS_64, 2)
+ELF_RELOC(R_NANOMIPS_NEG, 3)
+ELF_RELOC(R_NANOMIPS_ASHIFTR_1, 4)
+ELF_RELOC(R_NANOMIPS_UNSIGNED_8, 5)
+ELF_RELOC(R_NANOMIPS_SIGNED_8, 6)
+ELF_RELOC(R_NANOMIPS_UNSIGNED_16, 7)
+ELF_RELOC(R_NANOMIPS_SIGNED_16, 8)
+ELF_RELOC(R_NANOMIPS_RELATIVE, 9)
+ELF_RELOC(R_NANOMIPS_GLOBAL, 10)
+ELF_RELOC(R_NANOMIPS_JUMP_SLOT, 11)
+ELF_RELOC(R_NANOMIPS_IRELATIVE, 12)
+ELF_RELOC(R_NANOMIPS_PC25_S1, 13)
+ELF_RELOC(R_NANOMIPS_PC21_S1, 14)
+ELF_RELOC(R_NANOMIPS_PC14_S1, 15)
+ELF_RELOC(R_NANOMIPS_PC11_S1, 16)
+ELF_RELOC(R_NANOMIPS_PC10_S1, 17)
+ELF_RELOC(R_NANOMIPS_PC7_S1, 18)
+ELF_RELOC(R_NANOMIPS_PC4_S1, 19)
+ELF_RELOC(R_NANOMIPS_GPREL19_S2, 20)
+ELF_RELOC(R_NANOMIPS_GPREL18_S3, 21)
+ELF_RELOC(R_NANOMIPS_GPREL18, 22)
+ELF_RELOC(R_NANOMIPS_GPREL17_S1, 23)
+ELF_RELOC(R_NANOMIPS_GPREL16_S2, 24)
+ELF_RELOC(R_NANOMIPS_GPREL7_S2, 25)
+ELF_RELOC(R_NANOMIPS_GPREL_HI20, 26)
+ELF_RELOC(R_NANOMIPS_PC_HI20, 27)
+ELF_RELOC(R_NANOMIPS_HI20, 28)
+ELF_RELOC(R_NANOMIPS_LO12, 29)
+ELF_RELOC(R_NANOMIPS_GPREL_I32, 30)
+ELF_RELOC(R_NANOMIPS_PC_I32, 31)
+ELF_RELOC(R_NANOMIPS_I32, 32)
+ELF_RELOC(R_NANOMIPS_GOT_DISP, 33)
+ELF_RELOC(R_NANOMIPS_GOTPC_I32, 34)
+ELF_RELOC(R_NANOMIPS_GOTPC_HI20, 35)
+ELF_RELOC(R_NANOMIPS_GOT_LO12, 36)
+ELF_RELOC(R_NANOMIPS_GOT_CALL, 37)
+ELF_RELOC(R_NANOMIPS_GOT_PAGE, 38)
+ELF_RELOC(R_NANOMIPS_GOT_OFST, 39)
+ELF_RELOC(R_NANOMIPS_LO4_S2, 40)
+ELF_RELOC(R_NANOMIPS_RESERVED1, 41)
+ELF_RELOC(R_NANOMIPS_GPREL_LO12, 42)
+ELF_RELOC(R_NANOMIPS_SCN_DISP, 43)
+ELF_RELOC(R_NANOMIPS_COPY, 44)
+ELF_RELOC(R_NANOMIPS_ALIGN, 64)
+ELF_RELOC(R_NANOMIPS_FILL, 65)
+ELF_RELOC(R_NANOMIPS_MAX, 66)
+ELF_RELOC(R_NANOMIPS_INSN32, 67)
+ELF_RELOC(R_NANOMIPS_FIXED, 68)
+ELF_RELOC(R_NANOMIPS_NORELAX, 69)
+ELF_RELOC(R_NANOMIPS_RELAX, 70)
+ELF_RELOC(R_NANOMIPS_SAVERESTORE, 71)
+ELF_RELOC(R_NANOMIPS_INSN16, 72)
+ELF_RELOC(R_NANOMIPS_JALR32, 73)
+ELF_RELOC(R_NANOMIPS_JALR16, 74)
+ELF_RELOC(R_NANOMIPS_JUMPTABLE_LOAD, 75)
+ELF_RELOC(R_NANOMIPS_FRAME_REG, 76)
+ELF_RELOC(R_NANOMIPS_NOTRAMP, 77)
+ELF_RELOC(R_NANOMIPS_TLS_DTPMOD, 80)
+ELF_RELOC(R_NANOMIPS_TLS_DTPREL, 81)
+ELF_RELOC(R_NANOMIPS_TLS_TPREL, 82)
+ELF_RELOC(R_NANOMIPS_TLS_GD, 83)
+ELF_RELOC(R_NANOMIPS_TLS_GD_I32, 84)
+ELF_RELOC(R_NANOMIPS_TLS_LD, 85)
+ELF_RELOC(R_NANOMIPS_TLS_LD_I32, 86)
+ELF_RELOC(R_NANOMIPS_TLS_DTPREL12, 87)
+ELF_RELOC(R_NANOMIPS_TLS_DTPREL16, 88)
+ELF_RELOC(R_NANOMIPS_TLS_DTPREL_I32, 89)
+ELF_RELOC(R_NANOMIPS_TLS_GOTTPREL, 90)
+ELF_RELOC(R_NANOMIPS_TLS_GOTTPREL_PC_I32, 91)
+ELF_RELOC(R_NANOMIPS_TLS_TPREL12, 92)
+ELF_RELOC(R_NANOMIPS_TLS_TPREL16, 93)
+ELF_RELOC(R_NANOMIPS_TLS_TPREL_I32, 94)
+ELF_RELOC(R_NANOMIPS_PC32, 248)
diff --git a/llvm/include/llvm/Object/ELFObjectFile.h b/llvm/include/llvm/Object/ELFObjectFile.h
index 6d72741c3bde0..d13f1b7b66e2a 100644
--- a/llvm/include/llvm/Object/ELFObjectFile.h
+++ b/llvm/include/llvm/Object/ELFObjectFile.h
@@ -1323,6 +1323,8 @@ StringRef ELFObjectFile<ELFT>::getFileFormatName() const {
return "elf32-loongarch";
case ELF::EM_XTENSA:
return "elf32-xtensa";
+ case ELF::EM_NANOMIPS:
+ return "elf32-nanomips";
default:
return "elf32-unknown";
}
@@ -1456,6 +1458,9 @@ template <class ELFT> Triple::ArchType ELFObjectFile<ELFT>::getArch() const {
case ELF::EM_XTENSA:
return Triple::xtensa;
+ case ELF::EM_NANOMIPS:
+ return Triple::nanomips;
+
default:
return Triple::UnknownArch;
}
diff --git a/llvm/include/module.modulemap b/llvm/include/module.modulemap
index 69836bf2e3158..1ff73be1df5b9 100644
--- a/llvm/include/module.modulemap
+++ b/llvm/include/module.modulemap
@@ -93,6 +93,7 @@ module LLVM_BinaryFormat {
textual header "llvm/BinaryFormat/ELFRelocs/M68k.def"
textual header "llvm/BinaryFormat/ELFRelocs/Mips.def"
textual header "llvm/BinaryFormat/ELFRelocs/MSP430.def"
+ textual header "llvm/BinaryFormat/ELFRelocs/NanoMips.def"
textual header "llvm/BinaryFormat/ELFRelocs/PowerPC64.def"
textual header "llvm/BinaryFormat/ELFRelocs/PowerPC.def"
textual header "llvm/BinaryFormat/ELFRelocs/RISCV.def"
diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp
index 15e090cd29b74..3e020820be4f4 100644
--- a/llvm/lib/Object/ELF.cpp
+++ b/llvm/lib/Object/ELF.cpp
@@ -183,6 +183,13 @@ StringRef llvm::object::getELFRelocationTypeName(uint32_t Machine,
break;
}
break;
+ case ELF::EM_NANOMIPS:
+ switch (Type) {
+#include "llvm/BinaryFormat/ELFRelocs/NanoMips.def"
+ default:
+ break;
+ }
+ break;
default:
break;
}
@@ -212,6 +219,7 @@ uint32_t llvm::object::getELFRelativeRelocationType(uint32_t Machine) {
case ELF::EM_IAMCU:
return ELF::R_386_RELATIVE;
case ELF::EM_MIPS:
+ case ELF::EM_NANOMIPS:
break;
case ELF::EM_AARCH64:
return ELF::R_AARCH64_RELATIVE;
diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp
index 72b0ca52ae50a..722b50becaa6b 100644
--- a/llvm/lib/ObjectYAML/ELFYAML.cpp
+++ b/llvm/lib/ObjectYAML/ELFYAML.cpp
@@ -356,6 +356,7 @@ void ScalarEnumerationTraits<ELFYAML::ELF_EM>::enumeration(
ECase(EM_RISCV);
ECase(EM_LANAI);
ECase(EM_BPF);
+ ECase(EM_NANOMIPS);
ECase(EM_VE);
ECase(EM_CSKY);
ECase(EM_LOONGARCH);
@@ -481,6 +482,15 @@ void ScalarBitSetTraits<ELFYAML::ELF_EF>::bitset(IO &IO,
BCaseMask(EF_MIPS_ARCH_32R6, EF_MIPS_ARCH);
BCaseMask(EF_MIPS_ARCH_64R6, EF_MIPS_ARCH);
break;
+ case ELF::EM_NANOMIPS:
+ BCase(EF_NANOMIPS_LINKRELAX);
+ BCase(EF_NANOMIPS_PIC);
+ BCase(EF_NANOMIPS_32BITMODE);
+ BCase(EF_NANOMIPS_PID);
+ BCase(EF_NANOMIPS_PCREL);
+ BCaseMask(EF_NANOMIPS_ARCH_32R6, EF_NANOMIPS_ARCH);
+ BCaseMask(EF_NANOMIPS_ABI_P32, EF_NANOMIPS_ABI);
+ break;
case ELF::EM_HEXAGON:
BCaseMask(EF_HEXAGON_MACH_V2, EF_HEXAGON_MACH);
BCaseMask(EF_HEXAGON_MACH_V3, EF_HEXAGON_MACH);
@@ -873,6 +883,9 @@ void ScalarEnumerationTraits<ELFYAML::ELF_REL>::enumeration(
case ELF::EM_MIPS:
#include "llvm/BinaryFormat/ELFRelocs/Mips.def"
break;
+ case ELF::EM_NANOMIPS:
+#include "llvm/BinaryFormat/ELFRelocs/NanoMips.def"
+ break;
case ELF::EM_HEXAGON:
#include "llvm/BinaryFormat/ELFRelocs/Hexagon.def"
break;
diff --git a/llvm/test/tools/llvm-readobj/ELF/reloc-types-nanomips.test b/llvm/test/tools/llvm-readobj/ELF/reloc-types-nanomips.test
new file mode 100644
index 0000000000000..6ce8bc1e60234
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/ELF/reloc-types-nanomips.test
@@ -0,0 +1,167 @@
+## Test that llvm-readobj/llvm-readelf shows proper relocation type
+## names and values for the nanoMIPS target.
+
+# RUN: yaml2obj %s -o %t-nanomips.o
+# RUN: llvm-readobj -r --expand-relocs %t-nanomips.o | FileCheck %s
+
+# CHECK: Type: R_NANOMIPS_NONE (0)
+# CHECK: Type: R_NANOMIPS_32 (1)
+# CHECK: Type: R_NANOMIPS_64 (2)
+# CHECK: Type: R_NANOMIPS_NEG (3)
+# CHECK: Type: R_NANOMIPS_ASHIFTR_1 (4)
+# CHECK: Type: R_NANOMIPS_UNSIGNED_8 (5)
+# CHECK: Type: R_NANOMIPS_SIGNED_8 (6)
+# CHECK: Type: R_NANOMIPS_UNSIGNED_16 (7)
+# CHECK: Type: R_NANOMIPS_SIGNED_16 (8)
+# CHECK: Type: R_NANOMIPS_RELATIVE (9)
+# CHECK: Type: R_NANOMIPS_GLOBAL (10)
+# CHECK: Type: R_NANOMIPS_JUMP_SLOT (11)
+# CHECK: Type: R_NANOMIPS_IRELATIVE (12)
+# CHECK: Type: R_NANOMIPS_PC25_S1 (13)
+# CHECK: Type: R_NANOMIPS_PC21_S1 (14)
+# CHECK: Type: R_NANOMIPS_PC14_S1 (15)
+# CHECK: Type: R_NANOMIPS_PC11_S1 (16)
+# CHECK: Type: R_NANOMIPS_PC10_S1 (17)
+# CHECK: Type: R_NANOMIPS_PC7_S1 (18)
+# CHECK: Type: R_NANOMIPS_PC4_S1 (19)
+# CHECK: Type: R_NANOMIPS_GPREL19_S2 (20)
+# CHECK: Type: R_NANOMIPS_GPREL18_S3 (21)
+# CHECK: Type: R_NANOMIPS_GPREL18 (22)
+# CHECK: Type: R_NANOMIPS_GPREL17_S1 (23)
+# CHECK: Type: R_NANOMIPS_GPREL16_S2 (24)
+# CHECK: Type: R_NANOMIPS_GPREL7_S2 (25)
+# CHECK: Type: R_NANOMIPS_GPREL_HI20 (26)
+# CHECK: Type: R_NANOMIPS_PC_HI20 (27)
+# CHECK: Type: R_NANOMIPS_HI20 (28)
+# CHECK: Type: R_NANOMIPS_LO12 (29)
+# CHECK: Type: R_NANOMIPS_GPREL_I32 (30)
+# CHECK: Type: R_NANOMIPS_PC_I32 (31)
+# CHECK: Type: R_NANOMIPS_I32 (32)
+# CHECK: Type: R_NANOMIPS_GOT_DISP (33)
+# CHECK: Type: R_NANOMIPS_GOTPC_I32 (34)
+# CHECK: Type: R_NANOMIPS_GOTPC_HI20 (35)
+# CHECK: Type: R_NANOMIPS_GOT_LO12 (36)
+# CHECK: Type: R_NANOMIPS_GOT_CALL (37)
+# CHECK: Type: R_NANOMIPS_GOT_PAGE (38)
+# CHECK: Type: R_NANOMIPS_GOT_OFST (39)
+# CHECK: Type: R_NANOMIPS_LO4_S2 (40)
+# CHECK: Type: R_NANOMIPS_RESERVED1 (41)
+# CHECK: Type: R_NANOMIPS_GPREL_LO12 (42)
+# CHECK: Type: R_NANOMIPS_SCN_DISP (43)
+# CHECK: Type: R_NANOMIPS_COPY (44)
+# CHECK: Type: R_NANOMIPS_ALIGN (64)
+# CHECK: Type: R_NANOMIPS_FILL (65)
+# CHECK: Type: R_NANOMIPS_MAX (66)
+# CHECK: Type: R_NANOMIPS_INSN32 (67)
+# CHECK: Type: R_NANOMIPS_FIXED (68)
+# CHECK: Type: R_NANOMIPS_NORELAX (69)
+# CHECK: Type: R_NANOMIPS_RELAX (70)
+# CHECK: Type: R_NANOMIPS_SAVERESTORE (71)
+# CHECK: Type: R_NANOMIPS_INSN16 (72)
+# CHECK: Type: R_NANOMIPS_JALR32 (73)
+# CHECK: Type: R_NANOMIPS_JALR16 (74)
+# CHECK: Type: R_NANOMIPS_JUMPTABLE_LOAD (75)
+# CHECK: Type: R_NANOMIPS_FRAME_REG (76)
+# CHECK: Type: R_NANOMIPS_NOTRAMP (77)
+# CHECK: Type: R_NANOMIPS_TLS_DTPMOD (80)
+# CHECK: Type: R_NANOMIPS_TLS_DTPREL (81)
+# CHECK: Type: R_NANOMIPS_TLS_TPREL (82)
+# CHECK: Type: R_NANOMIPS_TLS_GD (83)
+# CHECK: Type: R_NANOMIPS_TLS_GD_I32 (84)
+# CHECK: Type: R_NANOMIPS_TLS_LD (85)
+# CHECK: Type: R_NANOMIPS_TLS_LD_I32 (86)
+# CHECK: Type: R_NANOMIPS_TLS_DTPREL12 (87)
+# CHECK: Type: R_NANOMIPS_TLS_DTPREL16 (88)
+# CHECK: Type: R_NANOMIPS_TLS_DTPREL_I32 (89)
+# CHECK: Type: R_NANOMIPS_TLS_GOTTPREL (90)
+# CHECK: Type: R_NANOMIPS_TLS_GOTTPREL_PC_I32 (91)
+# CHECK: Type: R_NANOMIPS_TLS_TPREL12 (92)
+# CHECK: Type: R_NANOMIPS_TLS_TPREL16 (93)
+# CHECK: Type: R_NANOMIPS_TLS_TPREL_I32 (94)
+# CHECK: Type: R_NANOMIPS_PC32 (248)
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_NANOMIPS
+Sections:
+ - Name: .rel.text
+ Type: SHT_REL
+ Relocations:
+ - Type: R_NANOMIPS_NONE
+ - Type: R_NANOMIPS_32
+ - Type: R_NANOMIPS_64
+ - Type: R_NANOMIPS_NEG
+ - Type: R_NANOMIPS_ASHIFTR_1
+ - Type: R_NANOMIPS_UNSIGNED_8
+ - Type: R_NANOMIPS_SIGNED_8
+ - Type: R_NANOMIPS_UNSIGNED_16
+ - Type: R_NANOMIPS_SIGNED_16
+ - Type: R_NANOMIPS_RELATIVE
+ - Type: R_NANOMIPS_GLOBAL
+ - Type: R_NANOMIPS_JUMP_SLOT
+ - Type: R_NANOMIPS_IRELATIVE
+ - Type: R_NANOMIPS_PC25_S1
+ - Type: R_NANOMIPS_PC21_S1
+ - Type: R_NANOMIPS_PC14_S1
+ - Type: R_NANOMIPS_PC11_S1
+ - Type: R_NANOMIPS_PC10_S1
+ - Type: R_NANOMIPS_PC7_S1
+ - Type: R_NANOMIPS_PC4_S1
+ - Type: R_NANOMIPS_GPREL19_S2
+ - Type: R_NANOMIPS_GPREL18_S3
+ - Type: R_NANOMIPS_GPREL18
+ - Type: R_NANOMIPS_GPREL17_S1
+ - Type: R_NANOMIPS_GPREL16_S2
+ - Type: R_NANOMIPS_GPREL7_S2
+ - Type: R_NANOMIPS_GPREL_HI20
+ - Type: R_NANOMIPS_PC_HI20
+ - Type: R_NANOMIPS_HI20
+ - Type: R_NANOMIPS_LO12
+ - Type: R_NANOMIPS_GPREL_I32
+ - Type: R_NANOMIPS_PC_I32
+ - Type: R_NANOMIPS_I32
+ - Type: R_NANOMIPS_GOT_DISP
+ - Type: R_NANOMIPS_GOTPC_I32
+ - Type: R_NANOMIPS_GOTPC_HI20
+ - Type: R_NANOMIPS_GOT_LO12
+ - Type: R_NANOMIPS_GOT_CALL
+ - Type: R_NANOMIPS_GOT_PAGE
+ - Type: R_NANOMIPS_GOT_OFST
+ - Type: R_NANOMIPS_LO4_S2
+ - Type: R_NANOMIPS_RESERVED1
+ - Type: R_NANOMIPS_GPREL_LO12
+ - Type: R_NANOMIPS_SCN_DISP
+ - Type: R_NANOMIPS_COPY
+ - Type: R_NANOMIPS_ALIGN
+ - Type: R_NANOMIPS_FILL
+ - Type: R_NANOMIPS_MAX
+ - Type: R_NANOMIPS_INSN32
+ - Type: R_NANOMIPS_FIXED
+ - Type: R_NANOMIPS_NORELAX
+ - Type: R_NANOMIPS_RELAX
+ - Type: R_NANOMIPS_SAVERESTORE
+ - Type: R_NANOMIPS_INSN16
+ - Type: R_NANOMIPS_JALR32
+ - Type: R_NANOMIPS_JALR16
+ - Type: R_NANOMIPS_JUMPTABLE_LOAD
+ - Type: R_NANOMIPS_FRAME_REG
+ - Type: R_NANOMIPS_NOTRAMP
+ - Type: R_NANOMIPS_TLS_DTPMOD
+ - Type: R_NANOMIPS_TLS_DTPREL
+ - Type: R_NANOMIPS_TLS_TPREL
+ - Type: R_NANOMIPS_TLS_GD
+ - Type: R_NANOMIPS_TLS_GD_I32
+ - Type: R_NANOMIPS_TLS_LD
+ - Type: R_NANOMIPS_TLS_LD_I32
+ - Type: R_NANOMIPS_TLS_DTPREL12
+ - Type: R_NANOMIPS_TLS_DTPREL16
+ - Type: R_NANOMIPS_TLS_DTPREL_I32
+ - Type: R_NANOMIPS_TLS_GOTTPREL
+ - Type: R_NANOMIPS_TLS_GOTTPREL_PC_I32
+ - Type: R_NANOMIPS_TLS_TPREL12
+ - Type: R_NANOMIPS_TLS_TPREL16
+ - Type: R_NANOMIPS_TLS_TPREL_I32
+ - Type: R_NANOMIPS_PC32
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index ab81de626e1d3..4961a192bb57b 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -1328,6 +1328,7 @@ constexpr EnumStringDef<unsigned, 2> ElfMachineTypeDefs[] = {
ENUM_ENT(EM_RISCV, "RISC-V"),
ENUM_ENT(EM_LANAI, "EM_LANAI"),
ENUM_ENT(EM_BPF, "EM_BPF"),
+ ENUM_ENT(EM_NANOMIPS, "nanoMIPS"),
ENUM_ENT(EM_VE, "NEC SX-Aurora Vector Engine"),
ENUM_ENT(EM_LOONGARCH, "LoongArch"),
ENUM_ENT(EM_INTELGT, "Intel Graphics Technology"),
diff --git a/llvm/unittests/Object/ELFObjectFileTest.cpp b/llvm/unittests/Object/ELFObjectFileTest.cpp
index f30aaa1e96afa..f16fed17df92b 100644
--- a/llvm/unittests/Object/ELFObjectFileTest.cpp
+++ b/llvm/unittests/Object/ELFObjectFileTest.cpp
@@ -134,6 +134,13 @@ TEST(ELFObjectFileTest, MachineTestForMIPS) {
checkFormatAndArch(Data, Formats[Idx], Archs[Idx]);
}
+TEST(ELFObjectFileTest, MachineTestForNanomips) {
+ std::array<StringRef, 4> Formats = {"elf32-nanomips", "elf32-nanomips",
+ "elf64-unknown", "elf64-unknown"};
+ for (auto [Idx, Data] : enumerate(generateData(ELF::EM_NANOMIPS)))
+ checkFormatAndArch(Data, Formats[Idx], Triple::nanomips);
+}
+
TEST(ELFObjectFileTest, MachineTestForAMDGPU) {
std::array<StringRef, 4> Formats = {"elf32-amdgpu", "elf32-amdgpu",
"elf64-amdgpu", "elf64-amdgpu"};
>From 48cc30e7ae292f95f865b8eabcadaa6dcab062ab Mon Sep 17 00:00:00 2001
From: Nemanja Rakovic <ot_nemanja.rakovic at mediatek.com>
Date: Mon, 7 Sep 2026 19:54:23 +0200
Subject: [PATCH 03/15] [nanoMIPS 3/7] Add basic subtarget support
Register nanomips as a target in the Mips backend: a NanoMips subtarget
feature and processor, HasNanoMips/NotNanoMips predicates and a
NanoMipsTargetMachine, reusing the MIPS MC layer.
Co-authored-by: Stefan Pejic <ot_stefan.pejic at mediatek.com>
Co-authored-by: Faraz Shahbazker <faraz.shahbazker at mediatek.com>
---
llvm/lib/MC/MCObjectFileInfo.cpp | 1 +
.../Target/Mips/AsmParser/MipsAsmParser.cpp | 23 +++---
.../Mips/MCTargetDesc/MipsABIFlagsSection.h | 5 +-
.../Mips/MCTargetDesc/MipsMCCodeEmitter.cpp | 4 +
.../Mips/MCTargetDesc/MipsMCCodeEmitter.h | 1 +
.../Mips/MCTargetDesc/MipsMCTargetDesc.cpp | 9 ++-
.../Mips/MCTargetDesc/MipsTargetStreamer.cpp | 74 +++++++++++--------
.../Mips/MCTargetDesc/MipsTargetStreamer.h | 2 +
llvm/lib/Target/Mips/Mips.td | 4 +
llvm/lib/Target/Mips/MipsAsmPrinter.cpp | 1 +
llvm/lib/Target/Mips/MipsInstrInfo.td | 17 ++++-
llvm/lib/Target/Mips/MipsScheduleGeneric.td | 2 +-
llvm/lib/Target/Mips/MipsScheduleP5600.td | 2 +-
llvm/lib/Target/Mips/MipsSubtarget.h | 24 +++++-
llvm/lib/Target/Mips/MipsTargetMachine.cpp | 13 ++++
llvm/lib/Target/Mips/MipsTargetMachine.h | 13 ++++
.../Target/Mips/TargetInfo/MipsTargetInfo.cpp | 8 ++
.../Target/Mips/TargetInfo/MipsTargetInfo.h | 1 +
18 files changed, 152 insertions(+), 52 deletions(-)
diff --git a/llvm/lib/MC/MCObjectFileInfo.cpp b/llvm/lib/MC/MCObjectFileInfo.cpp
index 65534186edbac..f9e140c8ef289 100644
--- a/llvm/lib/MC/MCObjectFileInfo.cpp
+++ b/llvm/lib/MC/MCObjectFileInfo.cpp
@@ -354,6 +354,7 @@ void MCObjectFileInfo::initELFMCObjectFileInfo(const Triple &T, bool Large) {
case Triple::mipsel:
case Triple::mips64:
case Triple::mips64el:
+ case Triple::nanomips:
// We cannot use DW_EH_PE_sdata8 for the large PositionIndependent case
// since there is no R_MIPS_PC64 relocation (only a 32-bit version).
// In fact DW_EH_PE_sdata4 is enough for us now, and GNU ld doesn't
diff --git a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
index 0fe6b95e71148..9d3cf539ee254 100644
--- a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
+++ b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
@@ -121,16 +121,15 @@ class MipsAssemblerOptions {
} // end anonymous namespace
const FeatureBitset MipsAssemblerOptions::AllArchRelatedMask = {
- Mips::FeatureMips1, Mips::FeatureMips2, Mips::FeatureMips3,
- Mips::FeatureMips3_32, Mips::FeatureMips3_32r2, Mips::FeatureMips4,
- Mips::FeatureMips4_32, Mips::FeatureMips4_32r2, Mips::FeatureMips5,
- Mips::FeatureMips5_32r2, Mips::FeatureMips32, Mips::FeatureMips32r2,
- Mips::FeatureMips32r3, Mips::FeatureMips32r5, Mips::FeatureMips32r6,
- Mips::FeatureMips64, Mips::FeatureMips64r2, Mips::FeatureMips64r3,
- Mips::FeatureMips64r5, Mips::FeatureMips64r6, Mips::FeatureCnMips,
- Mips::FeatureCnMipsP, Mips::FeatureFP64Bit, Mips::FeatureGP64Bit,
- Mips::FeatureNaN2008
-};
+ Mips::FeatureMips1, Mips::FeatureMips2, Mips::FeatureMips3,
+ Mips::FeatureMips3_32, Mips::FeatureMips3_32r2, Mips::FeatureMips4,
+ Mips::FeatureMips4_32, Mips::FeatureMips4_32r2, Mips::FeatureMips5,
+ Mips::FeatureMips5_32r2, Mips::FeatureMips32, Mips::FeatureMips32r2,
+ Mips::FeatureMips32r3, Mips::FeatureMips32r5, Mips::FeatureMips32r6,
+ Mips::FeatureMips64, Mips::FeatureMips64r2, Mips::FeatureMips64r3,
+ Mips::FeatureMips64r5, Mips::FeatureMips64r6, Mips::FeatureCnMips,
+ Mips::FeatureCnMipsP, Mips::FeatureFP64Bit, Mips::FeatureGP64Bit,
+ Mips::FeatureNaN2008, Mips::FeatureNanoMips};
namespace {
@@ -671,6 +670,10 @@ class MipsAsmParser : public MCTargetAsmParser {
return getSTI().hasFeature(Mips::FeatureMips64r6);
}
+ bool hasNanoMips() const {
+ return getSTI().hasFeature(Mips::FeatureNanoMips);
+ }
+
bool hasDSP() const {
return getSTI().hasFeature(Mips::FeatureDSP);
}
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.h
index 53fda3e9efbcb..2c4aa7611db0e 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.h
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsABIFlagsSection.h
@@ -81,7 +81,10 @@ struct MipsABIFlagsSection {
template <class PredicateLibrary>
void setISALevelAndRevisionFromPredicates(const PredicateLibrary &P) {
- if (P.hasMips64()) {
+ if (P.hasNanoMips()) {
+ ISALevel = 32;
+ ISARevision = 6;
+ } else if (P.hasMips64()) {
ISALevel = 64;
if (P.hasMips64r6())
ISARevision = 6;
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp
index bbfd0872cc4cd..e8bf4d61c92f3 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp
@@ -148,6 +148,10 @@ bool MipsMCCodeEmitter::isMips32r6(const MCSubtargetInfo &STI) const {
return STI.hasFeature(Mips::FeatureMips32r6);
}
+bool MipsMCCodeEmitter::isNanoMips(const MCSubtargetInfo &STI) const {
+ return STI.hasFeature(Mips::FeatureNanoMips);
+}
+
void MipsMCCodeEmitter::EmitByte(unsigned char C, raw_ostream &OS) const {
OS << (char)C;
}
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h
index 497b3e64df533..3f66b78ddd476 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.h
@@ -34,6 +34,7 @@ class MipsMCCodeEmitter : public MCCodeEmitter {
bool isMicroMips(const MCSubtargetInfo &STI) const;
bool isMips32r6(const MCSubtargetInfo &STI) const;
+ bool isNanoMips(const MCSubtargetInfo &STI) const;
public:
MipsMCCodeEmitter(const MCInstrInfo &mcii, MCContext &Ctx_, bool IsLittle)
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp
index ef73fd3288836..bc661f82da049 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp
@@ -141,7 +141,9 @@ StringRef MIPS_MC::selectMipsCPU(const Triple &TT, StringRef CPU) {
else
CPU = "mips64r6";
} else {
- if (TT.isMIPS32())
+ if (TT.isNanoMips())
+ CPU = "nanomips";
+ else if (TT.isMIPS32())
CPU = "mips32";
else
CPU = "mips64";
@@ -256,8 +258,9 @@ static MCInstrAnalysis *createMipsMCInstrAnalysis(const MCInstrInfo *Info) {
}
extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeMipsTargetMC() {
- for (Target *T : {&getTheMipsTarget(), &getTheMipselTarget(),
- &getTheMips64Target(), &getTheMips64elTarget()}) {
+ for (Target *T :
+ {&getTheMipsTarget(), &getTheMipselTarget(), &getTheMips64Target(),
+ &getTheMips64elTarget(), &getTheNanoMipsTarget()}) {
// Register the MC asm info.
RegisterMCAsmInfoFn X(*T, createMipsMCAsmInfo);
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
index abdb9778e8233..e3cc91f7c3cd6 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
@@ -851,7 +851,8 @@ void MipsTargetAsmStreamer::emitDirectiveModuleNoGINV() {
// This part is for ELF object output.
MipsTargetELFStreamer::MipsTargetELFStreamer(MCStreamer &S,
const MCSubtargetInfo &STI)
- : MipsTargetStreamer(S), MicroMipsEnabled(false), STI(STI) {
+ : MipsTargetStreamer(S), MicroMipsEnabled(false), NanoMipsEnabled(false),
+ STI(STI) {
MCAssembler &MCA = getStreamer().getAssembler();
ELFObjectWriter &W = getStreamer().getWriter();
@@ -886,7 +887,8 @@ MipsTargetELFStreamer::MipsTargetELFStreamer(MCStreamer &S,
ABI = MipsABIInfo(
STI.getTargetTriple().getArch() == Triple::ArchType::mipsel ||
- STI.getTargetTriple().getArch() == Triple::ArchType::mips
+ STI.getTargetTriple().getArch() == Triple::ArchType::mips ||
+ STI.getTargetTriple().getArch() == Triple::ArchType::nanomips
? MipsABIInfo::O32()
: MipsABIInfo::N64());
@@ -928,6 +930,11 @@ MipsTargetELFStreamer::MipsTargetELFStreamer(MCStreamer &S,
if (Features[Mips::FeatureNaN2008])
EFlags |= ELF::EF_MIPS_NAN2008;
+ if (STI.getTargetTriple().getArch() == Triple::ArchType::nanomips) {
+ NanoMipsEnabled = true;
+ Pic = false; // PIC not supported yet on nanoMIPS
+ }
+
W.setELFHeaderEFlags(EFlags);
}
@@ -996,21 +1003,27 @@ void MipsTargetELFStreamer::finish() {
} else if (Features[Mips::FeatureMips64r2] || Features[Mips::FeatureMips64])
EFlags |= ELF::EF_MIPS_32BITMODE;
- // -mplt is not implemented but we should act as if it was
- // given.
- if (!Features[Mips::FeatureNoABICalls])
- EFlags |= ELF::EF_MIPS_CPIC;
-
- if (Pic)
- EFlags |= ELF::EF_MIPS_PIC | ELF::EF_MIPS_CPIC;
+ if (!isNanoMipsEnabled()) {
+ // -mplt is not implemented but we should act as if it was
+ // given.
+ if (!Features[Mips::FeatureNoABICalls])
+ EFlags |= ELF::EF_MIPS_CPIC;
+ if (Pic)
+ EFlags |= ELF::EF_MIPS_PIC | ELF::EF_MIPS_CPIC;
+ } else {
+ if (Pic)
+ EFlags |= ELF::EF_NANOMIPS_PIC;
+ }
W.setELFHeaderEFlags(EFlags);
- // Emit all the option records.
- // At the moment we are only emitting .Mips.options (ODK_REGINFO) and
- // .reginfo.
- MipsELFStreamer &MEF = static_cast<MipsELFStreamer &>(Streamer);
- MEF.EmitMipsOptionRecords();
+ if (!isNanoMipsEnabled()) {
+ // Emit all the option records.
+ // At the moment we are only emitting .Mips.options (ODK_REGINFO) and
+ // .reginfo.
+ MipsELFStreamer &MEF = static_cast<MipsELFStreamer &>(Streamer);
+ MEF.EmitMipsOptionRecords();
+ }
emitMipsAbiFlags();
}
@@ -1114,31 +1127,34 @@ void MipsTargetELFStreamer::emitDirectiveEnd(StringRef Name) {
MCContext &Context = MCA.getContext();
MCStreamer &OS = getStreamer();
- OS.pushSection();
- MCSectionELF *Sec = Context.getELFSection(".pdr", ELF::SHT_PROGBITS, 0);
- OS.switchSection(Sec);
- Sec->setAlignment(Align(4));
-
MCSymbol *Sym = Context.getOrCreateSymbol(Name);
const auto *ExprRef = MCSymbolRefExpr::create(Sym, Context);
- OS.emitValueImpl(ExprRef, 4);
- OS.emitIntValue(GPRInfoSet ? GPRBitMask : 0, 4); // reg_mask
- OS.emitIntValue(GPRInfoSet ? GPROffset : 0, 4); // reg_offset
+ if (!isNanoMipsEnabled()) {
+ OS.pushSection();
+ MCSectionELF *Sec = Context.getELFSection(".pdr", ELF::SHT_PROGBITS, 0);
+ OS.switchSection(Sec);
+ Sec->setAlignment(Align(4));
+
+ OS.emitValueImpl(ExprRef, 4);
+
+ OS.emitIntValue(GPRInfoSet ? GPRBitMask : 0, 4); // reg_mask
+ OS.emitIntValue(GPRInfoSet ? GPROffset : 0, 4); // reg_offset
- OS.emitIntValue(FPRInfoSet ? FPRBitMask : 0, 4); // fpreg_mask
- OS.emitIntValue(FPRInfoSet ? FPROffset : 0, 4); // fpreg_offset
+ OS.emitIntValue(FPRInfoSet ? FPRBitMask : 0, 4); // fpreg_mask
+ OS.emitIntValue(FPRInfoSet ? FPROffset : 0, 4); // fpreg_offset
- OS.emitIntValue(FrameInfoSet ? FrameOffset : 0, 4); // frame_offset
- OS.emitIntValue(FrameInfoSet ? FrameReg : 0, 4); // frame_reg
- OS.emitIntValue(FrameInfoSet ? ReturnReg : 0, 4); // return_reg
+ OS.emitIntValue(FrameInfoSet ? FrameOffset : 0, 4); // frame_offset
+ OS.emitIntValue(FrameInfoSet ? FrameReg : 0, 4); // frame_reg
+ OS.emitIntValue(FrameInfoSet ? ReturnReg : 0, 4); // return_reg
+
+ OS.popSection();
+ }
// The .end directive marks the end of a procedure. Invalidate
// the information gathered up until this point.
GPRInfoSet = FPRInfoSet = FrameInfoSet = false;
- OS.popSection();
-
// .end also implicitly sets the size.
MCSymbol *CurPCSym = Context.createTempSymbol();
OS.emitLabel(CurPCSym);
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.h
index 71b5d165a9cb3..83f10d0879b77 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.h
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.h
@@ -328,11 +328,13 @@ class MipsTargetAsmStreamer : public MipsTargetStreamer {
// This part is for ELF object output
class MipsTargetELFStreamer : public MipsTargetStreamer {
bool MicroMipsEnabled;
+ bool NanoMipsEnabled;
const MCSubtargetInfo &STI;
bool Pic;
public:
bool isMicroMipsEnabled() const { return MicroMipsEnabled; }
+ bool isNanoMipsEnabled() const { return NanoMipsEnabled; }
MCELFStreamer &getStreamer();
MipsTargetELFStreamer(MCStreamer &S, const MCSubtargetInfo &STI);
diff --git a/llvm/lib/Target/Mips/Mips.td b/llvm/lib/Target/Mips/Mips.td
index 3b78de8ec43ad..ca78907f7a28b 100644
--- a/llvm/lib/Target/Mips/Mips.td
+++ b/llvm/lib/Target/Mips/Mips.td
@@ -148,6 +148,9 @@ def FeatureMips64r6 : SubtargetFeature<"mips64r6", "MipsArchVersion",
"Mips64r6 ISA Support [experimental]",
[FeatureMips32r6, FeatureMips64r5,
FeatureNaN2008, FeatureAbs2008]>;
+def FeatureNanoMips : SubtargetFeature<"nanomips", "MipsArchVersion",
+ "NanoMips",
+ "NanoMips ISA Support [experimental]">;
def FeatureSym32 : SubtargetFeature<"sym32", "HasSym32", "true",
"Symbols are 32 bit on Mips64">;
@@ -311,6 +314,7 @@ def : ProcessorModel<"p5600", MipsP5600Model, [ImplP5600]>;
def : Proc<"r5900", [FeatureR5900]>;
def : ProcessorModel<"i6400", MipsI6400Model, [ImplI6400]>;
def : ProcessorModel<"i6500", MipsI6400Model, [ImplI6500]>;
+def : Proc<"nanomips", [FeatureNanoMips]>;
def MipsAsmParser : AsmParser {
let ShouldEmitMatchRegisterName = 0;
diff --git a/llvm/lib/Target/Mips/MipsAsmPrinter.cpp b/llvm/lib/Target/Mips/MipsAsmPrinter.cpp
index adda6154e15a5..a0531fa76392b 100644
--- a/llvm/lib/Target/Mips/MipsAsmPrinter.cpp
+++ b/llvm/lib/Target/Mips/MipsAsmPrinter.cpp
@@ -1277,4 +1277,5 @@ LLVMInitializeMipsAsmPrinter() {
RegisterAsmPrinter<MipsAsmPrinter> Y(getTheMipselTarget());
RegisterAsmPrinter<MipsAsmPrinter> A(getTheMips64Target());
RegisterAsmPrinter<MipsAsmPrinter> B(getTheMips64elTarget());
+ RegisterAsmPrinter<MipsAsmPrinter> C(getTheNanoMipsTarget());
}
diff --git a/llvm/lib/Target/Mips/MipsInstrInfo.td b/llvm/lib/Target/Mips/MipsInstrInfo.td
index ccbf2d5f2aa05..05ab68e06efa6 100644
--- a/llvm/lib/Target/Mips/MipsInstrInfo.td
+++ b/llvm/lib/Target/Mips/MipsInstrInfo.td
@@ -198,6 +198,10 @@ def HasMips32r6 : Predicate<"Subtarget->hasMips32r6()">,
AssemblerPredicate<(all_of FeatureMips32r6)>;
def NotMips32r6 : Predicate<"!Subtarget->hasMips32r6()">,
AssemblerPredicate<(all_of (not FeatureMips32r6))>;
+def HasNanoMips : Predicate<"Subtarget->hasNanoMips()">,
+ AssemblerPredicate<(all_of FeatureNanoMips)>;
+def NotNanoMips : Predicate<"!Subtarget->hasNanoMips()">,
+ AssemblerPredicate<(all_of (not FeatureNanoMips))>;
def IsGP64bit : Predicate<"Subtarget->isGP64bit()">,
AssemblerPredicate<(all_of FeatureGP64Bit)>;
def IsGP32bit : Predicate<"!Subtarget->isGP64bit()">,
@@ -235,7 +239,8 @@ def IsNotN64 : Predicate<"!Subtarget->isABI_N64()">;
def RelocNotPIC : Predicate<"!TM.isPositionIndependent()">;
def RelocPIC : Predicate<"TM.isPositionIndependent()">;
def HasStdEnc : Predicate<"Subtarget->hasStandardEncoding()">,
- AssemblerPredicate<(all_of (not FeatureMips16))>;
+ AssemblerPredicate<(all_of (not FeatureMips16),
+ (not FeatureNanoMips))>;
def NotDSP : Predicate<"!Subtarget->hasDSP()">;
def InMicroMips : Predicate<"Subtarget->inMicroMipsMode()">,
AssemblerPredicate<(all_of FeatureMicroMips)>;
@@ -407,6 +412,9 @@ class ISA_MICROMIPS32_NOT_MIPS32R6 {
list<Predicate> InsnPredicates = [NotMips32r6];
list<Predicate> EncodingPredicates = [InMicroMips];
}
+class ISA_NANOMIPS {
+ list<Predicate> InsnPredicates = [HasNanoMips];
+}
class ASE_EVA { list<Predicate> ASEPredicate = [HasEVA]; }
// The portions of MIPS-III that were also added to MIPS32
@@ -2533,7 +2541,8 @@ class JALR_HB_ENC : JALR_HB_FM<9>;
def JR_HB : JR_HB_DESC<GPR32Opnd>, JR_HB_ENC, ISA_MIPS32R2_NOT_32R6_64R6;
def JALR_HB : JALR_HB_DESC<GPR32Opnd>, JALR_HB_ENC, ISA_MIPS32;
-let AdditionalPredicates = [NotInMicroMips, UseIndirectJumpsHazard] in
+let AdditionalPredicates = [NotInMicroMips, NotNanoMips,
+ UseIndirectJumpsHazard] in
def JALRHBPseudo : JumpLinkRegPseudo<GPR32Opnd, JALR_HB, RA>;
@@ -2712,7 +2721,7 @@ multiclass OneOrTwoOperandMacroImmediateAlias<string Memnomic,
Imm:$imm), 0>;
}
-let AdditionalPredicates = [NotInMicroMips] in {
+let AdditionalPredicates = [NotInMicroMips, NotNanoMips] in {
def : MipsInstAlias<"move $dst, $src",
(OR GPR32Opnd:$dst, GPR32Opnd:$src, ZERO), 1>,
GPR_32, ISA_MIPS1;
@@ -2921,7 +2930,7 @@ def : MipsInstAlias<"subu, $rd, $rs, $imm",
InvertedImOperand:$imm), 0>;
def : MipsInstAlias<"subu $rs, $imm", (ADDiu GPR32Opnd:$rs, GPR32Opnd:$rs,
InvertedImOperand:$imm), 0>;
-let AdditionalPredicates = [NotInMicroMips] in {
+let AdditionalPredicates = [NotInMicroMips, NotNanoMips] in {
def : MipsInstAlias<"sll $rd, $rt, $rs",
(SLLV GPR32Opnd:$rd, GPR32Opnd:$rt, GPR32Opnd:$rs), 0>;
def : MipsInstAlias<"sra $rd, $rt, $rs",
diff --git a/llvm/lib/Target/Mips/MipsScheduleGeneric.td b/llvm/lib/Target/Mips/MipsScheduleGeneric.td
index ec0c0d03ae4ee..4b376c9167785 100644
--- a/llvm/lib/Target/Mips/MipsScheduleGeneric.td
+++ b/llvm/lib/Target/Mips/MipsScheduleGeneric.td
@@ -22,7 +22,7 @@ def MipsGenericModel : SchedMachineModel {
int MispredictPenalty = 4;
int HighLatency = 37;
- list<Predicate> UnsupportedFeatures = [];
+ list<Predicate> UnsupportedFeatures = [HasNanoMips];
let CompleteModel = 1;
let PostRAScheduler = 1;
diff --git a/llvm/lib/Target/Mips/MipsScheduleP5600.td b/llvm/lib/Target/Mips/MipsScheduleP5600.td
index dce05df0f609a..4b219793c0b75 100644
--- a/llvm/lib/Target/Mips/MipsScheduleP5600.td
+++ b/llvm/lib/Target/Mips/MipsScheduleP5600.td
@@ -21,7 +21,7 @@ def MipsP5600Model : SchedMachineModel {
InMicroMips, InMips16Mode,
HasCnMips, HasCnMipsP,
HasDSP, HasDSPR2, HasMips3D, HasMT,
- HasCRC];
+ HasCRC, HasNanoMips];
}
let SchedModel = MipsP5600Model in {
diff --git a/llvm/lib/Target/Mips/MipsSubtarget.h b/llvm/lib/Target/Mips/MipsSubtarget.h
index 58011de3dbd8a..6391a52561aee 100644
--- a/llvm/lib/Target/Mips/MipsSubtarget.h
+++ b/llvm/lib/Target/Mips/MipsSubtarget.h
@@ -49,8 +49,23 @@ class MipsSubtarget : public MipsGenSubtargetInfo {
enum MipsArchEnum {
MipsDefault,
- Mips1, Mips2, Mips32, Mips32r2, Mips32r3, Mips32r5, Mips32r6, Mips32Max,
- Mips3, Mips4, Mips5, Mips64, Mips64r2, Mips64r3, Mips64r5, Mips64r6
+ NanoMips,
+ Mips1,
+ Mips2,
+ Mips32,
+ Mips32r2,
+ Mips32r3,
+ Mips32r5,
+ Mips32r6,
+ Mips32Max,
+ Mips3,
+ Mips4,
+ Mips5,
+ Mips64,
+ Mips64r2,
+ Mips64r3,
+ Mips64r5,
+ Mips64r6
};
enum class CPU { Others, P5600, I6400, I6500 };
@@ -306,6 +321,7 @@ class MipsSubtarget : public MipsGenSubtargetInfo {
bool hasMips64r3() const { return MipsArchVersion >= Mips64r3; }
bool hasMips64r5() const { return MipsArchVersion >= Mips64r5; }
bool hasMips64r6() const { return MipsArchVersion >= Mips64r6; }
+ bool hasNanoMips() const { return MipsArchVersion == NanoMips; }
bool hasCnMips() const { return HasCnMips; }
bool hasCnMipsP() const { return HasCnMipsP; }
@@ -367,7 +383,9 @@ class MipsSubtarget : public MipsGenSubtargetInfo {
return UseCompactBranches && hasMips32r6();
}
- bool hasStandardEncoding() const { return !InMips16Mode && !InMicroMipsMode; }
+ bool hasStandardEncoding() const {
+ return !InMips16Mode && !InMicroMipsMode && !hasNanoMips();
+ }
bool useSoftFloat() const { return IsSoftFloat; }
diff --git a/llvm/lib/Target/Mips/MipsTargetMachine.cpp b/llvm/lib/Target/Mips/MipsTargetMachine.cpp
index 3b4a6aa0b7a54..5d0d0d503db3b 100644
--- a/llvm/lib/Target/Mips/MipsTargetMachine.cpp
+++ b/llvm/lib/Target/Mips/MipsTargetMachine.cpp
@@ -58,6 +58,7 @@ extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeMipsTarget() {
RegisterTargetMachine<MipselTargetMachine> Y(getTheMipselTarget());
RegisterTargetMachine<MipsebTargetMachine> A(getTheMips64Target());
RegisterTargetMachine<MipselTargetMachine> B(getTheMips64elTarget());
+ RegisterTargetMachine<NanoMipsTargetMachine> C(getTheNanoMipsTarget());
PassRegistry *PR = PassRegistry::getPassRegistry();
initializeGlobalISel(*PR);
@@ -138,6 +139,16 @@ MipselTargetMachine::MipselTargetMachine(const Target &T, const Triple &TT,
CodeGenOptLevel OL, bool JIT)
: MipsTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, JIT, true) {}
+void NanoMipsTargetMachine::anchor() {}
+
+NanoMipsTargetMachine::NanoMipsTargetMachine(const Target &T, const Triple &TT,
+ StringRef CPU, StringRef FS,
+ const TargetOptions &Options,
+ std::optional<Reloc::Model> RM,
+ std::optional<CodeModel::Model> CM,
+ CodeGenOptLevel OL, bool JIT)
+ : MipsTargetMachine(T, TT, CPU, FS, Options, RM, CM, OL, JIT, true) {}
+
const MipsSubtarget *
MipsTargetMachine::getSubtargetImpl(const Function &F) const {
Attribute CPUAttr = F.getFnAttribute("target-cpu");
@@ -157,6 +168,8 @@ MipsTargetMachine::getSubtargetImpl(const Function &F) const {
// we need to know whether or not the soft float flag is set on the
// function, so we can enable it as a subtarget feature.
bool softFloat = F.getFnAttribute("use-soft-float").getValueAsBool();
+ if (getTargetTriple().isNanoMips())
+ softFloat = true;
if (hasMips16Attr)
FS += FS.empty() ? "+mips16" : ",+mips16";
diff --git a/llvm/lib/Target/Mips/MipsTargetMachine.h b/llvm/lib/Target/Mips/MipsTargetMachine.h
index 321d149f3f7fb..19ba70abe0a92 100644
--- a/llvm/lib/Target/Mips/MipsTargetMachine.h
+++ b/llvm/lib/Target/Mips/MipsTargetMachine.h
@@ -106,6 +106,19 @@ class MipselTargetMachine : public MipsTargetMachine {
bool JIT);
};
+/// nanoMIPS target machine.
+///
+class NanoMipsTargetMachine : public MipsTargetMachine {
+ virtual void anchor();
+
+public:
+ NanoMipsTargetMachine(const Target &T, const Triple &TT, StringRef CPU,
+ StringRef FS, const TargetOptions &Options,
+ std::optional<Reloc::Model> RM,
+ std::optional<CodeModel::Model> CM, CodeGenOptLevel OL,
+ bool JIT);
+};
+
} // end namespace llvm
#endif // LLVM_LIB_TARGET_MIPS_MIPSTARGETMACHINE_H
diff --git a/llvm/lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp b/llvm/lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp
index 458032042e15f..f1b773e2a39e3 100644
--- a/llvm/lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp
+++ b/llvm/lib/Target/Mips/TargetInfo/MipsTargetInfo.cpp
@@ -27,6 +27,10 @@ Target &llvm::getTheMips64elTarget() {
static Target TheMips64elTarget;
return TheMips64elTarget;
}
+Target &llvm::getTheNanoMipsTarget() {
+ static Target TheNanoMipsTarget;
+ return TheNanoMipsTarget;
+}
extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void
LLVMInitializeMipsTargetInfo() {
@@ -46,4 +50,8 @@ LLVMInitializeMipsTargetInfo() {
/*HasJIT=*/true>
B(getTheMips64elTarget(), "mips64el", "MIPS (64-bit little endian)",
"Mips");
+ RegisterTarget<Triple::nanomips,
+ /*HasJIT=*/false>
+ C(getTheNanoMipsTarget(), "nanomips", "nanoMIPS (32-bit little endian)",
+ "Mips");
}
diff --git a/llvm/lib/Target/Mips/TargetInfo/MipsTargetInfo.h b/llvm/lib/Target/Mips/TargetInfo/MipsTargetInfo.h
index d91a2719108d2..d721debe92f74 100644
--- a/llvm/lib/Target/Mips/TargetInfo/MipsTargetInfo.h
+++ b/llvm/lib/Target/Mips/TargetInfo/MipsTargetInfo.h
@@ -17,6 +17,7 @@ Target &getTheMipsTarget();
Target &getTheMipselTarget();
Target &getTheMips64Target();
Target &getTheMips64elTarget();
+Target &getTheNanoMipsTarget();
} // namespace llvm
>From 2159e0b11caf214dbbda6a68ae65a8a9b977607c Mon Sep 17 00:00:00 2001
From: Nemanja Rakovic <ot_nemanja.rakovic at mediatek.com>
Date: Mon, 7 Sep 2026 19:54:26 +0200
Subject: [PATCH 04/15] [nanoMIPS 4/7] Add register definitions
Define the nanoMIPS general purpose and COP0 registers (suffixed _NM, to
differentiate from Mips registers). Besides the full GPRNM32 class, add
the register classes needed for the compact nanoMIPS encodings.
Co-authored-by: Faraz Shahbazker <faraz.shahbazker at mediatek.com>
Co-authored-by: Stefan Pejic <ot_stefan.pejic at mediatek.com>
---
llvm/lib/Target/Mips/MipsRegisterInfo.td | 345 +++++++++++++++++++++++
1 file changed, 345 insertions(+)
diff --git a/llvm/lib/Target/Mips/MipsRegisterInfo.td b/llvm/lib/Target/Mips/MipsRegisterInfo.td
index 765179a43980d..18b30b24024f4 100644
--- a/llvm/lib/Target/Mips/MipsRegisterInfo.td
+++ b/llvm/lib/Target/Mips/MipsRegisterInfo.td
@@ -153,6 +153,41 @@ let Namespace = "Mips" in {
def FP_64 : Mips64GPRReg< 30, "fp", [FP]>, DwarfRegNum<[30]>;
def RA_64 : Mips64GPRReg< 31, "ra", [RA]>, DwarfRegNum<[31]>;
+ // General Purpose nanoMIPS Registers
+ let isConstant = true in
+ def ZERO_NM : MipsGPRReg< 0, "zero">, DwarfRegNum<[0]>;
+ def AT_NM : MipsGPRReg< 1, "at">, DwarfRegNum<[1]>;
+ def T4_NM : MipsGPRReg< 2, "t4">, DwarfRegNum<[2]>;
+ def T5_NM : MipsGPRReg< 3, "t5">, DwarfRegNum<[3]>;
+ def A0_NM : MipsGPRReg< 4, "a0">, DwarfRegNum<[4]>;
+ def A1_NM : MipsGPRReg< 5, "a1">, DwarfRegNum<[5]>;
+ def A2_NM : MipsGPRReg< 6, "a2">, DwarfRegNum<[6]>;
+ def A3_NM : MipsGPRReg< 7, "a3">, DwarfRegNum<[7]>;
+ def A4_NM : MipsGPRReg< 8, "a4">, DwarfRegNum<[8]>;
+ def A5_NM : MipsGPRReg< 9, "a5">, DwarfRegNum<[9]>;
+ def A6_NM : MipsGPRReg< 10, "a6">, DwarfRegNum<[10]>;
+ def A7_NM : MipsGPRReg< 11, "a7">, DwarfRegNum<[11]>;
+ def T0_NM : MipsGPRReg< 12, "t0">, DwarfRegNum<[12]>;
+ def T1_NM : MipsGPRReg< 13, "t1">, DwarfRegNum<[13]>;
+ def T2_NM : MipsGPRReg< 14, "t2">, DwarfRegNum<[14]>;
+ def T3_NM : MipsGPRReg< 15, "t3">, DwarfRegNum<[15]>;
+ def S0_NM : MipsGPRReg< 16, "s0">, DwarfRegNum<[16]>;
+ def S1_NM : MipsGPRReg< 17, "s1">, DwarfRegNum<[17]>;
+ def S2_NM : MipsGPRReg< 18, "s2">, DwarfRegNum<[18]>;
+ def S3_NM : MipsGPRReg< 19, "s3">, DwarfRegNum<[19]>;
+ def S4_NM : MipsGPRReg< 20, "s4">, DwarfRegNum<[20]>;
+ def S5_NM : MipsGPRReg< 21, "s5">, DwarfRegNum<[21]>;
+ def S6_NM : MipsGPRReg< 22, "s6">, DwarfRegNum<[22]>;
+ def S7_NM : MipsGPRReg< 23, "s7">, DwarfRegNum<[23]>;
+ def T8_NM : MipsGPRReg< 24, "t8">, DwarfRegNum<[24]>;
+ def T9_NM : MipsGPRReg< 25, "t9">, DwarfRegNum<[25]>;
+ def K0_NM : MipsGPRReg< 26, "k0">, DwarfRegNum<[26]>;
+ def K1_NM : MipsGPRReg< 27, "k1">, DwarfRegNum<[27]>;
+ def GP_NM : MipsGPRReg< 28, "gp">, DwarfRegNum<[28]>;
+ def SP_NM : MipsGPRReg< 29, "sp">, DwarfRegNum<[29]>;
+ def FP_NM : MipsGPRReg< 30, "fp">, DwarfRegNum<[30]>;
+ def RA_NM : MipsGPRReg< 31, "ra">, DwarfRegNum<[31]>;
+
/// Mips Single point precision FPU Registers
foreach I = 0-31 in
def F#I : FPR<I, "f"#I>, DwarfRegNum<[!add(I, 32)]>;
@@ -274,6 +309,168 @@ let Namespace = "Mips" in {
def P1 : MipsReg<1, "p1">;
def P2 : MipsReg<2, "p2">;
+ // COP0 registers with fixed selects
+ def COP0Sel_INDEX : MipsReg< !or(!shl(0, 5), 0), "index">;
+ def COP0Sel_MVPCONTROL : MipsReg< !or(!shl(0, 5), 1), "mvpcontrol">;
+ def COP0Sel_MVPCONF0 : MipsReg< !or(!shl(0, 5), 2), "mvpconf0">;
+ def COP0Sel_MVPCONF1 : MipsReg< !or(!shl(0, 5), 3), "mvpconf1">;
+ def COP0Sel_VPCONTROL : MipsReg< !or(!shl(0, 5), 4), "vpcontrol">;
+ def COP0Sel_RANDOM : MipsReg< !or(!shl(1, 5), 0), "random">;
+ def COP0Sel_VPECONTROL : MipsReg< !or(!shl(1, 5), 1), "vpecontrol">;
+ def COP0Sel_VPECONF0 : MipsReg< !or(!shl(1, 5), 2), "vpeconf0">;
+ def COP0Sel_VPECONF1 : MipsReg< !or(!shl(1, 5), 3), "vpeconf1">;
+ def COP0Sel_YQMASK : MipsReg< !or(!shl(1, 5), 4), "yqmask">;
+ def COP0Sel_VPESCHEDULE : MipsReg< !or(!shl(1, 5), 5), "vpeschedule">;
+ def COP0Sel_VPESCHEFBACK : MipsReg< !or(!shl(1, 5), 6), "vpeschefback">;
+ def COP0Sel_VPEOPT : MipsReg< !or(!shl(1, 5), 7), "vpeopt">;
+ def COP0Sel_ENTRYLO0 : MipsReg< !or(!shl(2, 5), 0), "entrylo0">;
+ def COP0Sel_TCSTATUS : MipsReg< !or(!shl(2, 5), 1), "tcstatus">;
+ def COP0Sel_TCBIND : MipsReg< !or(!shl(2, 5), 2), "tcbind">;
+ def COP0Sel_TCRESTART : MipsReg< !or(!shl(2, 5), 3), "tcrestart">;
+ def COP0Sel_TCHALT : MipsReg< !or(!shl(2, 5), 4), "tchalt">;
+ def COP0Sel_TCCONTEXT : MipsReg< !or(!shl(2, 5), 5), "tccontext">;
+ def COP0Sel_TCSCHEDULE : MipsReg< !or(!shl(2, 5), 6), "tcschedule">;
+ def COP0Sel_TCSCHEFBACK : MipsReg< !or(!shl(2, 5), 7), "tcschefback">;
+ def COP0Sel_ENTRYLO1 : MipsReg< !or(!shl(3, 5), 0), "entrylo1">;
+ def COP0Sel_GLOBALNUMBER : MipsReg< !or(!shl(3, 5), 1), "globalnumber">;
+ def COP0Sel_TCOPT : MipsReg< !or(!shl(3, 5), 7), "tcopt">;
+ def COP0Sel_CONTEXT : MipsReg< !or(!shl(4, 5), 0), "context">;
+ def COP0Sel_CONTEXTCONFIG : MipsReg< !or(!shl(4, 5), 1), "contextconfig">;
+ def COP0Sel_USERLOCAL : MipsReg< !or(!shl(4, 5), 2), "userlocal">;
+ def COP0Sel_XCONTEXTCONFIG : MipsReg< !or(!shl(4, 5), 3), "xcontextconfig">;
+ def COP0Sel_DEBUGCONTEXTID : MipsReg< !or(!shl(4, 5), 4), "debugcontextid">;
+ def COP0Sel_MEMORYMAPID : MipsReg< !or(!shl(4, 5), 5), "memorymapid">;
+ def COP0Sel_PAGEMASK : MipsReg< !or(!shl(5, 5), 0), "pagemask">;
+ def COP0Sel_PAGEGRAIN : MipsReg< !or(!shl(5, 5), 1), "pagegrain">;
+ def COP0Sel_SEGCTL0 : MipsReg< !or(!shl(5, 5), 2), "segctl0">;
+ def COP0Sel_SEGCTL1 : MipsReg< !or(!shl(5, 5), 3), "segctl1">;
+ def COP0Sel_SEGCTL2 : MipsReg< !or(!shl(5, 5), 4), "segctl2">;
+ def COP0Sel_PWBASE : MipsReg< !or(!shl(5, 5), 5), "pwbase">;
+ def COP0Sel_PWFIELD : MipsReg< !or(!shl(5, 5), 6), "pwfield">;
+ def COP0Sel_PWSIZE : MipsReg< !or(!shl(5, 5), 7), "pwsize">;
+ def COP0Sel_WIRED : MipsReg< !or(!shl(6, 5), 0), "wired">;
+ def COP0Sel_SRSCONF0 : MipsReg< !or(!shl(6, 5), 1), "srsconf0">;
+ def COP0Sel_SRSCONF1 : MipsReg< !or(!shl(6, 5), 2), "srsconf1">;
+ def COP0Sel_SRSCONF2 : MipsReg< !or(!shl(6, 5), 3), "srsconf2">;
+ def COP0Sel_SRSCONF3 : MipsReg< !or(!shl(6, 5), 4), "srsconf3">;
+ def COP0Sel_SRSCONF4 : MipsReg< !or(!shl(6, 5), 5), "srsconf4">;
+ def COP0Sel_PWCTL : MipsReg< !or(!shl(6, 5), 6), "pwctl">;
+ def COP0Sel_HWRENA : MipsReg< !or(!shl(7, 5), 0), "hwrena">;
+ def COP0Sel_BADVADDR : MipsReg< !or(!shl(8, 5), 0), "badvaddr">;
+ def COP0Sel_BADINST : MipsReg< !or(!shl(8, 5), 1), "badinst">;
+ def COP0Sel_BADINSTRP : MipsReg< !or(!shl(8, 5), 2), "badinstrp">;
+ def COP0Sel_BADINSTRX : MipsReg< !or(!shl(8, 5), 3), "badinstrx">;
+ def COP0Sel_COUNT : MipsReg< !or(!shl(9, 5), 0), "count">;
+ def COP0Sel_ENTRYHI : MipsReg< !or(!shl(10, 5), 0), "entryhi">;
+ def COP0Sel_GUESTCTL1 : MipsReg< !or(!shl(10, 5), 4), "guestctl1">;
+ def COP0Sel_GUESTCTL2 : MipsReg< !or(!shl(10, 5), 5), "guestctl2">;
+ def COP0Sel_GUESTCTL3 : MipsReg< !or(!shl(10, 5), 6), "guestctl3">;
+ def COP0Sel_COMPARE : MipsReg< !or(!shl(11, 5), 0), "compare">;
+ def COP0Sel_GUESTCTL0EXT : MipsReg< !or(!shl(11, 5), 4), "guestctl0ext">;
+ def COP0Sel_STATUS : MipsReg< !or(!shl(12, 5), 0), "status">;
+ def COP0Sel_INTCTL : MipsReg< !or(!shl(12, 5), 1), "intctl">;
+ def COP0Sel_SRSCTL : MipsReg< !or(!shl(12, 5), 2), "srsctl">;
+ def COP0Sel_SRSMAP : MipsReg< !or(!shl(12, 5), 3), "srsmap">;
+ def COP0Sel_VIEW_IPL : MipsReg< !or(!shl(12, 5), 4), "view_ipl">;
+ def COP0Sel_SRSMAP2 : MipsReg< !or(!shl(12, 5), 5), "srsmap2">;
+ def COP0Sel_GUESTCTL0 : MipsReg< !or(!shl(12, 5), 6), "guestctl0">;
+ def COP0Sel_GTOFFSET : MipsReg< !or(!shl(12, 5), 7), "gtoffset">;
+ def COP0Sel_CAUSE : MipsReg< !or(!shl(13, 5), 0), "cause">;
+ def COP0Sel_VIEW_RIPL : MipsReg< !or(!shl(13, 5), 4), "view_ripl">;
+ def COP0Sel_NESTEDEXC : MipsReg< !or(!shl(13, 5), 5), "nestedexc">;
+ def COP0Sel_EPC : MipsReg< !or(!shl(14, 5), 0), "epc">;
+ def COP0Sel_NESTEDEPC : MipsReg< !or(!shl(14, 5), 2), "nestedepc">;
+ def COP0Sel_PRID : MipsReg< !or(!shl(15, 5), 0), "prid">;
+ def COP0Sel_EBASE : MipsReg< !or(!shl(15, 5), 1), "ebase">;
+ def COP0Sel_CDMMBASE : MipsReg< !or(!shl(15, 5), 2), "cdmmbase">;
+ def COP0Sel_CMGCRBASE : MipsReg< !or(!shl(15, 5), 3), "cmgcrbase">;
+ def COP0Sel_BEVVA : MipsReg< !or(!shl(15, 5), 4), "bevva">;
+ def COP0Sel_CONFIG : MipsReg< !or(!shl(16, 5), 0), "config">;
+ def COP0Sel_CONFIG1 : MipsReg< !or(!shl(16, 5), 1), "config1">;
+ def COP0Sel_CONFIG2 : MipsReg< !or(!shl(16, 5), 2), "config2">;
+ def COP0Sel_CONFIG3 : MipsReg< !or(!shl(16, 5), 3), "config3">;
+ def COP0Sel_CONFIG4 : MipsReg< !or(!shl(16, 5), 4), "config4">;
+ def COP0Sel_CONFIG5 : MipsReg< !or(!shl(16, 5), 5), "config5">;
+ def COP0Sel_LLADDR : MipsReg< !or(!shl(17, 5), 0), "lladdr">;
+ def COP0Sel_MAAR : MipsReg< !or(!shl(17, 5), 1), "maar">;
+ def COP0Sel_MAARI : MipsReg< !or(!shl(17, 5), 2), "maari">;
+ def COP0Sel_WATCHLO0 : MipsReg< !or(!shl(18, 5), 0), "watchlo0">;
+ def COP0Sel_WATCHLO1 : MipsReg< !or(!shl(18, 5), 1), "watchlo1">;
+ def COP0Sel_WATCHLO2 : MipsReg< !or(!shl(18, 5), 2), "watchlo2">;
+ def COP0Sel_WATCHLO3 : MipsReg< !or(!shl(18, 5), 3), "watchlo3">;
+ def COP0Sel_WATCHLO4 : MipsReg< !or(!shl(18, 5), 4), "watchlo4">;
+ def COP0Sel_WATCHLO5 : MipsReg< !or(!shl(18, 5), 5), "watchlo5">;
+ def COP0Sel_WATCHLO6 : MipsReg< !or(!shl(18, 5), 6), "watchlo6">;
+ def COP0Sel_WATCHLO7 : MipsReg< !or(!shl(18, 5), 7), "watchlo7">;
+ def COP0Sel_WATCHLO8 : MipsReg< !or(!shl(18, 5), 8), "watchlo8">;
+ def COP0Sel_WATCHLO9 : MipsReg< !or(!shl(18, 5), 9), "watchlo9">;
+ def COP0Sel_WATCHLO10 : MipsReg< !or(!shl(18, 5), 10), "watchlo10">;
+ def COP0Sel_WATCHLO11 : MipsReg< !or(!shl(18, 5), 11), "watchlo11">;
+ def COP0Sel_WATCHLO12 : MipsReg< !or(!shl(18, 5), 12), "watchlo12">;
+ def COP0Sel_WATCHLO13 : MipsReg< !or(!shl(18, 5), 13), "watchlo13">;
+ def COP0Sel_WATCHLO14 : MipsReg< !or(!shl(18, 5), 14), "watchlo14">;
+ def COP0Sel_WATCHLO15 : MipsReg< !or(!shl(18, 5), 15), "watchlo15">;
+ def COP0Sel_WATCHHI0 : MipsReg< !or(!shl(19, 5), 0), "watchhi0">;
+ def COP0Sel_WATCHHI1 : MipsReg< !or(!shl(19, 5), 1), "watchhi1">;
+ def COP0Sel_WATCHHI2 : MipsReg< !or(!shl(19, 5), 2), "watchhi2">;
+ def COP0Sel_WATCHHI3 : MipsReg< !or(!shl(19, 5), 3), "watchhi3">;
+ def COP0Sel_WATCHHI4 : MipsReg< !or(!shl(19, 5), 4), "watchhi4">;
+ def COP0Sel_WATCHHI5 : MipsReg< !or(!shl(19, 5), 5), "watchhi5">;
+ def COP0Sel_WATCHHI6 : MipsReg< !or(!shl(19, 5), 6), "watchhi6">;
+ def COP0Sel_WATCHHI7 : MipsReg< !or(!shl(19, 5), 7), "watchhi7">;
+ def COP0Sel_WATCHHI8 : MipsReg< !or(!shl(19, 5), 8), "watchhi8">;
+ def COP0Sel_WATCHHI9 : MipsReg< !or(!shl(19, 5), 9), "watchhi9">;
+ def COP0Sel_WATCHHI10 : MipsReg< !or(!shl(19, 5), 10), "watchhi10">;
+ def COP0Sel_WATCHHI11 : MipsReg< !or(!shl(19, 5), 11), "watchhi11">;
+ def COP0Sel_WATCHHI12 : MipsReg< !or(!shl(19, 5), 12), "watchhi12">;
+ def COP0Sel_WATCHHI13 : MipsReg< !or(!shl(19, 5), 13), "watchhi13">;
+ def COP0Sel_WATCHHI14 : MipsReg< !or(!shl(19, 5), 14), "watchhi14">;
+ def COP0Sel_WATCHHI15 : MipsReg< !or(!shl(19, 5), 15), "watchhi15">;
+ def COP0Sel_XCONTEXT : MipsReg< !or(!shl(20, 5), 0), "xcontext">;
+ def COP0Sel_DEBUG : MipsReg< !or(!shl(23, 5), 0), "debug">;
+ def COP0Sel_TRACECONTROL : MipsReg< !or(!shl(23, 5), 1), "tracecontrol">;
+ def COP0Sel_TRACECONTROL2 : MipsReg< !or(!shl(23, 5), 2), "tracecontrol2">;
+ def COP0Sel_USERTRACEDATA1 : MipsReg< !or(!shl(23, 5), 3), "usertracedata1">;
+ def COP0Sel_TRACEIBPC : MipsReg< !or(!shl(23, 5), 4), "traceibpc">;
+ def COP0Sel_TRACEDBPC : MipsReg< !or(!shl(23, 5), 5), "tracedbpc">;
+ def COP0Sel_DEBUG2 : MipsReg< !or(!shl(23, 5), 6), "debug2">;
+ def COP0Sel_DEPC : MipsReg< !or(!shl(24, 5), 0), "depc">;
+ def COP0Sel_TRACECONTROL3 : MipsReg< !or(!shl(24, 5), 2), "tracecontrol3">;
+ def COP0Sel_USERTRACEDATA2 : MipsReg< !or(!shl(24, 5), 3), "usertracedata2">;
+ def COP0Sel_PERFCTL0 : MipsReg< !or(!shl(25, 5), 0), "perfctl0">;
+ def COP0Sel_PERFCNT0 : MipsReg< !or(!shl(25, 5), 1), "perfcnt0">;
+ def COP0Sel_PERFCTL1 : MipsReg< !or(!shl(25, 5), 2), "perfctl1">;
+ def COP0Sel_PERFCNT1 : MipsReg< !or(!shl(25, 5), 3), "perfcnt1">;
+ def COP0Sel_PERFCTL2 : MipsReg< !or(!shl(25, 5), 4), "perfctl2">;
+ def COP0Sel_PERFCNT2 : MipsReg< !or(!shl(25, 5), 5), "perfcnt2">;
+ def COP0Sel_PERFCTL3 : MipsReg< !or(!shl(25, 5), 6), "perfctl3">;
+ def COP0Sel_PERFCNT3 : MipsReg< !or(!shl(25, 5), 7), "perfcnt3">;
+ def COP0Sel_PERFCTL4 : MipsReg< !or(!shl(25, 5), 8), "perfctl4">;
+ def COP0Sel_PERFCNT4 : MipsReg< !or(!shl(25, 5), 9), "perfcnt4">;
+ def COP0Sel_PERFCTL5 : MipsReg< !or(!shl(25, 5), 10), "perfctl5">;
+ def COP0Sel_PERFCNT5 : MipsReg< !or(!shl(25, 5), 11), "perfcnt5">;
+ def COP0Sel_PERFCTL6 : MipsReg< !or(!shl(25, 5), 12), "perfctl6">;
+ def COP0Sel_PERFCNT6 : MipsReg< !or(!shl(25, 5), 13), "perfcnt6">;
+ def COP0Sel_PERFCTL7 : MipsReg< !or(!shl(25, 5), 14), "perfctl7">;
+ def COP0Sel_PERFCNT7 : MipsReg< !or(!shl(25, 5), 15), "perfcnt7">;
+ def COP0Sel_ERRCTL : MipsReg< !or(!shl(26, 5), 0), "errctl">;
+ def COP0Sel_CACHEERR : MipsReg< !or(!shl(27, 5), 0), "cacheerr">;
+ def COP0Sel_ITAGLO : MipsReg< !or(!shl(28, 5), 0), "itaglo">;
+ def COP0Sel_IDATALO : MipsReg< !or(!shl(28, 5), 1), "idatalo">;
+ def COP0Sel_DTAGLO : MipsReg< !or(!shl(28, 5), 2), "dtaglo">;
+ def COP0Sel_DDATALO : MipsReg< !or(!shl(28, 5), 3), "ddatalo">;
+ def COP0Sel_ITAGHI : MipsReg< !or(!shl(29, 5), 0), "itaghi">;
+ def COP0Sel_IDATAHI : MipsReg< !or(!shl(29, 5), 1), "idatahi">;
+ def COP0Sel_DTAGHI : MipsReg< !or(!shl(29, 5), 2), "dtaghi">;
+ def COP0Sel_DDATAHI : MipsReg< !or(!shl(29, 5), 3), "ddatahi">;
+ def COP0Sel_ERROREPC : MipsReg< !or(!shl(30, 5), 0), "errorepc">;
+ def COP0Sel_DESAVE : MipsReg< !or(!shl(31, 5), 0), "desave">;
+ def COP0Sel_KSCRATCH1 : MipsReg< !or(!shl(31, 5), 2), "kscratch1">;
+ def COP0Sel_KSCRATCH2 : MipsReg< !or(!shl(31, 5), 3), "kscratch2">;
+ def COP0Sel_KSCRATCH3 : MipsReg< !or(!shl(31, 5), 4), "kscratch3">;
+ def COP0Sel_KSCRATCH4 : MipsReg< !or(!shl(31, 5), 5), "kscratch4">;
+ def COP0Sel_KSCRATCH5 : MipsReg< !or(!shl(31, 5), 6), "kscratch5">;
+ def COP0Sel_KSCRATCH6 : MipsReg< !or(!shl(31, 5), 7), "kscratch6">;
}
//===----------------------------------------------------------------------===//
@@ -351,6 +548,154 @@ def GPRMM16MovePPairSecond : RegisterClass<"Mips", [i32], 32, (add
// Callee save
S5, S6)>;
+class GPRNM32Class<list<ValueType> regTypes> :
+ RegisterClass<"Mips", regTypes, 32, (add
+ // Reserved
+ ZERO_NM, AT_NM,
+ // Not preserved across procedure calls
+ T4_NM, T5_NM,
+ // Return Values and Arguments
+ A0_NM, A1_NM, A2_NM, A3_NM, A4_NM, A5_NM, A6_NM, A7_NM,
+ // Not preserved across procedure calls
+ T0_NM, T1_NM, T2_NM, T3_NM,
+ // Callee save
+ S0_NM, S1_NM, S2_NM, S3_NM, S4_NM, S5_NM, S6_NM, S7_NM,
+ // Not preserved across procedure calls
+ T8_NM, T9_NM,
+ // Reserved
+ K0_NM, K1_NM, GP_NM, SP_NM, FP_NM, RA_NM)>;
+
+def GPRNM32 : GPRNM32Class<[i32]>;
+
+class COP0SelRegClassNM<list<ValueType> regTypes> :
+ RegisterClass<"Mips", regTypes, 32, (add
+ COP0Sel_INDEX, COP0Sel_MVPCONTROL, COP0Sel_MVPCONF0, COP0Sel_MVPCONF1,
+ COP0Sel_VPCONTROL, COP0Sel_RANDOM, COP0Sel_VPECONTROL, COP0Sel_VPECONF0,
+ COP0Sel_VPECONF1, COP0Sel_YQMASK, COP0Sel_VPESCHEDULE, COP0Sel_VPESCHEFBACK,
+ COP0Sel_VPEOPT, COP0Sel_ENTRYLO0, COP0Sel_TCSTATUS, COP0Sel_TCBIND,
+ COP0Sel_TCRESTART, COP0Sel_TCHALT, COP0Sel_TCCONTEXT, COP0Sel_TCSCHEDULE,
+ COP0Sel_TCSCHEFBACK, COP0Sel_ENTRYLO1, COP0Sel_GLOBALNUMBER, COP0Sel_TCOPT,
+ COP0Sel_CONTEXT, COP0Sel_CONTEXTCONFIG, COP0Sel_USERLOCAL,
+ COP0Sel_XCONTEXTCONFIG, COP0Sel_DEBUGCONTEXTID, COP0Sel_MEMORYMAPID,
+ COP0Sel_PAGEMASK, COP0Sel_PAGEGRAIN, COP0Sel_SEGCTL0, COP0Sel_SEGCTL1,
+ COP0Sel_SEGCTL2, COP0Sel_PWBASE, COP0Sel_PWFIELD, COP0Sel_PWSIZE,
+ COP0Sel_WIRED, COP0Sel_SRSCONF0, COP0Sel_SRSCONF1, COP0Sel_SRSCONF2,
+ COP0Sel_SRSCONF3, COP0Sel_SRSCONF4, COP0Sel_PWCTL, COP0Sel_HWRENA,
+ COP0Sel_BADVADDR, COP0Sel_BADINST, COP0Sel_BADINSTRP, COP0Sel_BADINSTRX,
+ COP0Sel_COUNT, COP0Sel_ENTRYHI, COP0Sel_GUESTCTL1, COP0Sel_GUESTCTL2,
+ COP0Sel_GUESTCTL3, COP0Sel_COMPARE, COP0Sel_GUESTCTL0EXT, COP0Sel_STATUS,
+ COP0Sel_INTCTL, COP0Sel_SRSCTL, COP0Sel_SRSMAP, COP0Sel_VIEW_IPL,
+ COP0Sel_SRSMAP2, COP0Sel_GUESTCTL0, COP0Sel_GTOFFSET, COP0Sel_CAUSE,
+ COP0Sel_VIEW_RIPL, COP0Sel_NESTEDEXC, COP0Sel_EPC, COP0Sel_NESTEDEPC,
+ COP0Sel_PRID, COP0Sel_EBASE, COP0Sel_CDMMBASE, COP0Sel_CMGCRBASE,
+ COP0Sel_BEVVA, COP0Sel_CONFIG, COP0Sel_CONFIG1, COP0Sel_CONFIG2,
+ COP0Sel_CONFIG3, COP0Sel_CONFIG4, COP0Sel_CONFIG5, COP0Sel_LLADDR,
+ COP0Sel_MAAR, COP0Sel_MAARI, COP0Sel_WATCHLO0, COP0Sel_WATCHLO1,
+ COP0Sel_WATCHLO2, COP0Sel_WATCHLO3, COP0Sel_WATCHLO4, COP0Sel_WATCHLO5,
+ COP0Sel_WATCHLO6, COP0Sel_WATCHLO7, COP0Sel_WATCHLO8, COP0Sel_WATCHLO9,
+ COP0Sel_WATCHLO10, COP0Sel_WATCHLO11, COP0Sel_WATCHLO12, COP0Sel_WATCHLO13,
+ COP0Sel_WATCHLO14, COP0Sel_WATCHLO15, COP0Sel_WATCHHI0, COP0Sel_WATCHHI1,
+ COP0Sel_WATCHHI2, COP0Sel_WATCHHI3, COP0Sel_WATCHHI4, COP0Sel_WATCHHI5,
+ COP0Sel_WATCHHI6, COP0Sel_WATCHHI7, COP0Sel_WATCHHI8, COP0Sel_WATCHHI9,
+ COP0Sel_WATCHHI10, COP0Sel_WATCHHI11, COP0Sel_WATCHHI12, COP0Sel_WATCHHI13,
+ COP0Sel_WATCHHI14, COP0Sel_WATCHHI15, COP0Sel_XCONTEXT, COP0Sel_DEBUG,
+ COP0Sel_TRACECONTROL, COP0Sel_TRACECONTROL2, COP0Sel_USERTRACEDATA1,
+ COP0Sel_TRACEIBPC, COP0Sel_TRACEDBPC, COP0Sel_DEBUG2, COP0Sel_DEPC,
+ COP0Sel_TRACECONTROL3, COP0Sel_USERTRACEDATA2, COP0Sel_PERFCTL0,
+ COP0Sel_PERFCNT0, COP0Sel_PERFCTL1, COP0Sel_PERFCNT1, COP0Sel_PERFCTL2,
+ COP0Sel_PERFCNT2, COP0Sel_PERFCTL3, COP0Sel_PERFCNT3, COP0Sel_PERFCTL4,
+ COP0Sel_PERFCNT4, COP0Sel_PERFCTL5, COP0Sel_PERFCNT5, COP0Sel_PERFCTL6,
+ COP0Sel_PERFCNT6, COP0Sel_PERFCTL7, COP0Sel_PERFCNT7, COP0Sel_ERRCTL,
+ COP0Sel_CACHEERR, COP0Sel_ITAGLO, COP0Sel_IDATALO, COP0Sel_DTAGLO,
+ COP0Sel_DDATALO, COP0Sel_ITAGHI, COP0Sel_IDATAHI, COP0Sel_DTAGHI,
+ COP0Sel_DDATAHI, COP0Sel_ERROREPC, COP0Sel_DESAVE, COP0Sel_KSCRATCH1,
+ COP0Sel_KSCRATCH2, COP0Sel_KSCRATCH3, COP0Sel_KSCRATCH4, COP0Sel_KSCRATCH5,
+ COP0Sel_KSCRATCH6)>;
+
+def COP0Sel : COP0SelRegClassNM<[i32]>, Unallocatable;
+
+def GPRNM32_TAIL : RegisterClass<"Mips", [i32], 32, (add
+ // Not preserved across procedure calls
+ T4_NM, T5_NM,
+ // Return Values and Arguments
+ A0_NM, A1_NM, A2_NM, A3_NM, A4_NM, A5_NM, A6_NM, A7_NM,
+ // Not preserved across procedure calls
+ T0_NM, T1_NM, T2_NM, T3_NM,
+ // Not preserved across procedure calls
+ T8_NM, T9_NM)>;
+
+// nanoMIPS "gpr3" register encoding type.
+def GPRNM3 : RegisterClass<"Mips", [i32], 32, (add
+ // Callee save
+ S0_NM, S1_NM, S2_NM, S3_NM,
+ // Return Values and Arguments
+ A0_NM, A1_NM, A2_NM, A3_NM)>;
+
+// nanoMIPS "gpr3.zero" register encoding type.
+def GPRNM3Z : RegisterClass<"Mips", [i32], 32, (add
+ // Reserved
+ ZERO_NM,
+ // Callee save
+ S1_NM, S2_NM, S3_NM,
+ // Return Values and Arguments
+ A0_NM, A1_NM, A2_NM, A3_NM)>;
+
+// nanoMIPS "gpr4x4" register encoding type.
+def GPRNM4 : RegisterClass<"Mips", [i32], 32, (add
+ // Return Values and Arguments
+ A4_NM, A5_NM, A6_NM, A7_NM, A0_NM, A1_NM, A2_NM, A3_NM,
+ // Callee save
+ S0_NM, S1_NM, S2_NM, S3_NM, S4_NM, S5_NM, S6_NM, S7_NM)>;
+
+// nanoMIPS "gpr4x4.zero" register encoding type.
+def GPRNM4Z : RegisterClass<"Mips", [i32], 32, (add
+ // Return Values and Arguments
+ A4_NM, A5_NM, A6_NM,
+ // Reserved
+ ZERO_NM,
+ // Return Values and Arguments
+ A0_NM, A1_NM, A2_NM, A3_NM,
+ // Callee save
+ S0_NM, S1_NM, S2_NM, S3_NM, S4_NM, S5_NM, S6_NM, S7_NM)>;
+
+// nanoMIPS non-zero gpr register encoding type.
+def GPRNM32NZ : RegisterClass<"Mips", [i32], 32, (add
+ // Reserved
+ AT_NM,
+ // Not preserved across procedure calls
+ T4_NM, T5_NM,
+ // Return Values and Arguments
+ A0_NM, A1_NM, A2_NM, A3_NM, A4_NM, A5_NM, A6_NM, A7_NM,
+ // Not preserved across procedure calls
+ T0_NM, T1_NM, T2_NM, T3_NM,
+ // Callee save
+ S0_NM, S1_NM, S2_NM, S3_NM, S4_NM, S5_NM, S6_NM, S7_NM,
+ // Not preserved across procedure calls
+ T8_NM, T9_NM,
+ // Reserved
+ K0_NM, K1_NM, GP_NM, SP_NM, FP_NM, RA_NM)>;
+
+// nanoMIPS: Stack pointer, global pointer and return address classes for
+// instructions that are limited to a single register
+def GPRNMSP : RegisterClass<"Mips", [i32], 32, (add SP_NM)>, Unallocatable;
+
+def GPRNMGP : RegisterClass<"Mips", [i32], 32, (add GP_NM)>, Unallocatable;
+
+def GPRNMRA : RegisterClass<"Mips", [i32], 32, (add RA_NM)>, Unallocatable;
+
+// nanoMIPS "gpr2.reg1" & "gpr2.reg2" register encoding types.
+def GPRNM2R1 : RegisterClass<"Mips", [i32], 32, (add
+ // Return Values and Arguments
+ A0_NM, A1_NM, A2_NM, A3_NM)>;
+
+def GPRNM2R2 : RegisterClass<"Mips", [i32], 32, (add
+ // Return Values and Arguments
+ A1_NM, A2_NM, A3_NM, A4_NM)>;
+
+def GPRNM1R1 : RegisterClass<"Mips", [i32], 32, (add
+ // Return Values and Arguments
+ A0_NM, A1_NM)>;
+
def GPR64 : RegisterClass<"Mips", [i64], 64, (add
// Reserved
ZERO_64, AT_64,
>From e46c8f19a80699ad5cc92667acb29f2e806ac6e9 Mon Sep 17 00:00:00 2001
From: Nemanja Rakovic <ot_nemanja.rakovic at mediatek.com>
Date: Mon, 7 Sep 2026 19:54:29 +0200
Subject: [PATCH 05/15] [nanoMIPS 5/7] Introduce P32 ABI
Add the P32 ABI used by nanoMIPS: argument and return registers,
callee-saved set, ELF ABI flag and data layout.
Co-authored-by: Stefan Pejic <ot_stefan.pejic at mediatek.com>
Co-authored-by: Faraz Shahbazker <faraz.shahbazker at mediatek.com>
---
.../Target/Mips/MCTargetDesc/MipsABIInfo.cpp | 30 ++++++--
.../Target/Mips/MCTargetDesc/MipsABIInfo.h | 5 +-
.../Mips/MCTargetDesc/MipsTargetStreamer.cpp | 9 ++-
llvm/lib/Target/Mips/Mips.td | 3 +-
llvm/lib/Target/Mips/MipsAsmPrinter.cpp | 2 +
llvm/lib/Target/Mips/MipsCallingConv.td | 36 +++++++++-
llvm/lib/Target/Mips/MipsISelLowering.cpp | 6 +-
llvm/lib/Target/Mips/MipsRegisterInfo.cpp | 31 ++++++--
llvm/lib/Target/Mips/MipsRegisterInfo.h | 1 +
llvm/lib/Target/Mips/MipsSEFrameLowering.cpp | 9 +--
llvm/lib/Target/Mips/MipsSEISelLowering.cpp | 5 +-
llvm/lib/Target/Mips/MipsSubtarget.cpp | 70 +++++++++++--------
llvm/lib/Target/Mips/MipsSubtarget.h | 1 +
llvm/lib/TargetParser/TargetDataLayout.cpp | 9 ++-
14 files changed, 161 insertions(+), 56 deletions(-)
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp
index 59c8e7c72224e..aa2a3117db691 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp
@@ -31,6 +31,10 @@ static const MCPhysReg O32IntRegs[4] = {Mips::A0, Mips::A1, Mips::A2, Mips::A3};
static const MCPhysReg Mips64IntRegs[8] = {
Mips::A0_64, Mips::A1_64, Mips::A2_64, Mips::A3_64,
Mips::T0_64, Mips::T1_64, Mips::T2_64, Mips::T3_64};
+
+static const MCPhysReg P32IntRegs[8] = {Mips::A0_NM, Mips::A1_NM, Mips::A2_NM,
+ Mips::A3_NM, Mips::A4_NM, Mips::A5_NM,
+ Mips::A6_NM, Mips::A7_NM};
}
ArrayRef<MCPhysReg> MipsABIInfo::GetByValArgRegs() const {
@@ -38,6 +42,8 @@ ArrayRef<MCPhysReg> MipsABIInfo::GetByValArgRegs() const {
return ArrayRef(O32IntRegs);
if (IsN32() || IsN64())
return ArrayRef(Mips64IntRegs);
+ if (IsP32())
+ return ArrayRef(P32IntRegs);
llvm_unreachable("Unhandled ABI");
}
@@ -50,13 +56,15 @@ ArrayRef<MCPhysReg> MipsABIInfo::getVarArgRegs(bool isGP64bit) const {
}
if (IsN32() || IsN64())
return ArrayRef(Mips64IntRegs);
+ if (IsP32())
+ return ArrayRef(P32IntRegs);
llvm_unreachable("Unhandled ABI");
}
unsigned MipsABIInfo::GetCalleeAllocdArgSizeInBytes(CallingConv::ID CC) const {
if (IsO32())
return CC != CallingConv::Fast ? 16 : 0;
- if (IsN32() || IsN64())
+ if (IsN32() || IsN64() || IsP32())
return 0;
llvm_unreachable("Unhandled ABI");
}
@@ -68,37 +76,45 @@ MipsABIInfo MipsABIInfo::computeTargetABI(const Triple &TT, StringRef ABIName) {
return MipsABIInfo::N32();
if (ABIName.starts_with("n64"))
return MipsABIInfo::N64();
+ if (ABIName.starts_with("p32"))
+ return MipsABIInfo::P32();
if (TT.isABIN32())
return MipsABIInfo::N32();
assert(ABIName.empty() && "Unknown ABI option for MIPS");
if (TT.isMIPS64())
return MipsABIInfo::N64();
+ if (TT.isNanoMips())
+ return MipsABIInfo::P32();
return MipsABIInfo::O32();
}
unsigned MipsABIInfo::GetStackPtr() const {
- return ArePtrs64bit() ? Mips::SP_64 : Mips::SP;
+ return ArePtrs64bit() ? Mips::SP_64 : IsP32() ? Mips::SP_NM : Mips::SP;
}
unsigned MipsABIInfo::GetFramePtr() const {
- return ArePtrs64bit() ? Mips::FP_64 : Mips::FP;
+ return ArePtrs64bit() ? Mips::FP_64 : IsP32() ? Mips::FP_NM : Mips::FP;
}
unsigned MipsABIInfo::GetBasePtr() const {
- return ArePtrs64bit() ? Mips::S7_64 : Mips::S7;
+ return ArePtrs64bit() ? Mips::S7_64 : IsP32() ? Mips::S7_NM : Mips::S7;
}
unsigned MipsABIInfo::GetGlobalPtr() const {
- return ArePtrs64bit() ? Mips::GP_64 : Mips::GP;
+ return ArePtrs64bit() ? Mips::GP_64 : IsP32() ? Mips::GP_NM : Mips::GP;
}
unsigned MipsABIInfo::GetNullPtr() const {
- return ArePtrs64bit() ? Mips::ZERO_64 : Mips::ZERO;
+ return ArePtrs64bit() ? Mips::ZERO_64 : IsP32() ? Mips::ZERO_NM : Mips::ZERO;
+}
+
+unsigned MipsABIInfo::GetRetReg() const {
+ return ArePtrs64bit() ? Mips::RA_64 : IsP32() ? Mips::RA_NM : Mips::RA;
}
unsigned MipsABIInfo::GetZeroReg() const {
- return AreGprs64bit() ? Mips::ZERO_64 : Mips::ZERO;
+ return AreGprs64bit() ? Mips::ZERO_64 : IsP32() ? Mips::ZERO_NM : Mips::ZERO;
}
unsigned MipsABIInfo::GetPtrAdduOp() const {
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.h b/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.h
index d8003d2fcc164..a00e7c3e26e5d 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.h
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.h
@@ -21,7 +21,7 @@ class StringRef;
class MipsABIInfo {
public:
- enum class ABI { Unknown, O32, N32, N64 };
+ enum class ABI { Unknown, O32, N32, N64, P32 };
protected:
ABI ThisABI;
@@ -33,12 +33,14 @@ class MipsABIInfo {
static MipsABIInfo O32() { return MipsABIInfo(ABI::O32); }
static MipsABIInfo N32() { return MipsABIInfo(ABI::N32); }
static MipsABIInfo N64() { return MipsABIInfo(ABI::N64); }
+ static MipsABIInfo P32() { return MipsABIInfo(ABI::P32); }
static MipsABIInfo computeTargetABI(const Triple &TT, StringRef ABIName);
bool IsKnown() const { return ThisABI != ABI::Unknown; }
bool IsO32() const { return ThisABI == ABI::O32; }
bool IsN32() const { return ThisABI == ABI::N32; }
bool IsN64() const { return ThisABI == ABI::N64; }
+ bool IsP32() const { return ThisABI == ABI::P32; }
ABI GetEnumValue() const { return ThisABI; }
/// The registers to use for byval arguments.
@@ -63,6 +65,7 @@ class MipsABIInfo {
unsigned GetBasePtr() const;
unsigned GetGlobalPtr() const;
unsigned GetNullPtr() const;
+ unsigned GetRetReg() const;
unsigned GetZeroReg() const;
unsigned GetPtrAdduOp() const;
unsigned GetPtrAddiuOp() const;
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
index e3cc91f7c3cd6..9c8610e876735 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsTargetStreamer.cpp
@@ -886,9 +886,10 @@ MipsTargetELFStreamer::MipsTargetELFStreamer(MCStreamer &S,
// would otherwise crash on assertion failure.
ABI = MipsABIInfo(
- STI.getTargetTriple().getArch() == Triple::ArchType::mipsel ||
- STI.getTargetTriple().getArch() == Triple::ArchType::mips ||
- STI.getTargetTriple().getArch() == Triple::ArchType::nanomips
+ STI.getTargetTriple().getArch() == Triple::ArchType::nanomips
+ ? MipsABIInfo::P32()
+ : (STI.getTargetTriple().getArch() == Triple::ArchType::mipsel ||
+ STI.getTargetTriple().getArch() == Triple::ArchType::mips)
? MipsABIInfo::O32()
: MipsABIInfo::N64());
@@ -996,6 +997,8 @@ void MipsTargetELFStreamer::finish() {
EFlags |= ELF::EF_MIPS_ABI_O32;
else if (getABI().IsN32())
EFlags |= ELF::EF_MIPS_ABI2;
+ else if (getABI().IsP32())
+ EFlags |= ELF::EF_NANOMIPS_ABI_P32;
if (Features[Mips::FeatureGP64Bit]) {
if (getABI().IsO32())
diff --git a/llvm/lib/Target/Mips/Mips.td b/llvm/lib/Target/Mips/Mips.td
index ca78907f7a28b..b55125b30b088 100644
--- a/llvm/lib/Target/Mips/Mips.td
+++ b/llvm/lib/Target/Mips/Mips.td
@@ -150,7 +150,8 @@ def FeatureMips64r6 : SubtargetFeature<"mips64r6", "MipsArchVersion",
FeatureNaN2008, FeatureAbs2008]>;
def FeatureNanoMips : SubtargetFeature<"nanomips", "MipsArchVersion",
"NanoMips",
- "NanoMips ISA Support [experimental]">;
+ "NanoMips ISA Support [experimental]",
+ [FeatureNoABICalls]>;
def FeatureSym32 : SubtargetFeature<"sym32", "HasSym32", "true",
"Symbols are 32 bit on Mips64">;
diff --git a/llvm/lib/Target/Mips/MipsAsmPrinter.cpp b/llvm/lib/Target/Mips/MipsAsmPrinter.cpp
index a0531fa76392b..701dbb5670ffb 100644
--- a/llvm/lib/Target/Mips/MipsAsmPrinter.cpp
+++ b/llvm/lib/Target/Mips/MipsAsmPrinter.cpp
@@ -388,6 +388,8 @@ const char *MipsAsmPrinter::getCurrentABIString() const {
case MipsABIInfo::ABI::O32: return "abi32";
case MipsABIInfo::ABI::N32: return "abiN32";
case MipsABIInfo::ABI::N64: return "abi64";
+ case MipsABIInfo::ABI::P32:
+ return "abiP32";
default: llvm_unreachable("Unknown Mips ABI");
}
}
diff --git a/llvm/lib/Target/Mips/MipsCallingConv.td b/llvm/lib/Target/Mips/MipsCallingConv.td
index d3e552bc71ca9..ddb0913a03ea5 100644
--- a/llvm/lib/Target/Mips/MipsCallingConv.td
+++ b/llvm/lib/Target/Mips/MipsCallingConv.td
@@ -107,6 +107,31 @@ def CC_MipsO32_FP : CallingConv<[
CCIfSubtarget<"isFP64bit()", CCDelegateTo<CC_MipsO32_FP64>>
]>;
+//===----------------------------------------------------------------------===//
+// nanoMIPS P32 Calling Convention
+//===----------------------------------------------------------------------===//
+
+def CC_NanoMipsP32 : CallingConv<[
+ // Promote i8/i16 arguments to i32.
+ CCIfType<[i1, i8, i16], CCPromoteToType<i32>>,
+
+ // Pass arguments in A0_NM...A7_NM.
+ CCIfType<[i32], CCAssignToReg<[A0_NM, A1_NM, A2_NM, A3_NM, A4_NM, A5_NM,
+ A6_NM, A7_NM]>>,
+
+ // Integer values get stored in stack slots that are 4 bytes in
+ // size and 4-byte aligned.
+ CCIfType<[i32], CCAssignToStack<4, 4>>
+]>;
+
+def RetCC_NanoMipsP32 : CallingConv<[
+ // Promote i1/i8/i16 return values to i32.
+ CCIfType<[i1, i8, i16], CCPromoteToType<i32>>,
+
+ // i32 are returned in registers A0_NM, A1_NM.
+ CCIfType<[i32], CCAssignToReg<[A0_NM, A1_NM]>>
+]>;
+
//===----------------------------------------------------------------------===//
// Mips N32/64 Calling Convention
//===----------------------------------------------------------------------===//
@@ -274,6 +299,7 @@ def CC_Mips_FastCC : CallingConv<[
CCIfType<[i32, f32], CCAssignToStack<4, 4>>,
CCIfSubtarget<"isABI_O32()", CCDelegateTo<CC_MipsO32_FastCC>>,
+ CCIfSubtarget<"isABI_P32()", CCDelegateTo<CC_NanoMipsP32>>,
CCDelegateTo<CC_MipsN_FastCC>
]>;
@@ -284,11 +310,14 @@ def CC_Mips_FastCC : CallingConv<[
def RetCC_Mips : CallingConv<[
CCIfSubtarget<"isABI_N32()", CCDelegateTo<RetCC_MipsN>>,
CCIfSubtarget<"isABI_N64()", CCDelegateTo<RetCC_MipsN>>,
- CCDelegateTo<RetCC_MipsO32>
+ CCIfSubtarget<"isABI_P32()", CCDelegateTo<RetCC_NanoMipsP32>>,
+ // nanoMIPS cannot fall back to O32 for return values using more than 2 regs.
+ CCIfSubtargetNot<"isABI_P32()", CCDelegateTo<RetCC_MipsO32>>,
]>;
def CC_Mips_ByVal : CallingConv<[
CCIfSubtarget<"isABI_O32()", CCIfByVal<CCPassByVal<4, 4>>>,
+ CCIfSubtarget<"isABI_P32()", CCIfByVal<CCPassByVal<4, 4>>>,
CCIfByVal<CCPassByVal<8, 8>>
]>;
@@ -322,6 +351,7 @@ def CC_Mips_FixedArg : CallingConv<[
CCIfSubtargetNot<"useSoftFloat()",
CCIfOrigArgWasF128<CCBitConvertToType<f64>>>>>,
+ CCIfSubtarget<"isABI_P32()", CCDelegateTo<CC_NanoMipsP32>>,
CCIfCC<"CallingConv::Fast", CCDelegateTo<CC_Mips_FastCC>>,
CCIfSubtarget<"isABI_O32()", CCIfSubtargetNot<"isGP64bit()", CCDelegateTo<CC_MipsO32_FP>>>,
@@ -332,6 +362,7 @@ def CC_Mips_VarArg : CallingConv<[
CCIfByVal<CCDelegateTo<CC_Mips_ByVal>>,
CCIfSubtarget<"isABI_O32()", CCDelegateTo<CC_MipsO32_FP>>,
+ CCIfSubtarget<"isABI_P32()", CCDelegateTo<CC_NanoMipsP32>>,
CCDelegateTo<CC_MipsN_VarArg>
]>;
@@ -414,3 +445,6 @@ def CSR_Interrupt_64 : CalleeSavedRegs<(add (sequence "A%u_64", 3, 0),
(sequence "V%u_64", 1, 0),
RA_64, FP_64, GP_64, AT_64,
LO0_64, HI0_64)>;
+
+def CSR_P32 :
+ CalleeSavedRegs<(add RA_NM, FP_NM, GP_NM, (sequence "S%u_NM", 7, 0))>;
diff --git a/llvm/lib/Target/Mips/MipsISelLowering.cpp b/llvm/lib/Target/Mips/MipsISelLowering.cpp
index bfbcad786c965..802431d872d5b 100644
--- a/llvm/lib/Target/Mips/MipsISelLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsISelLowering.cpp
@@ -432,7 +432,7 @@ MipsTargetLowering::MipsTargetLowering(const MipsTargetMachine &TM,
setMinStackArgumentAlignment((ABI.IsN32() || ABI.IsN64()) ? Align(8)
: Align(4));
- setStackPointerRegisterToSaveRestore(ABI.IsN64() ? Mips::SP_64 : Mips::SP);
+ setStackPointerRegisterToSaveRestore(ABI.GetStackPtr());
MaxStoresPerMemcpy = 16;
@@ -4047,7 +4047,9 @@ MipsTargetLowering::LowerReturn(SDValue Chain, CallingConv::ID CallConv,
llvm_unreachable("sret virtual register not created in the entry block");
SDValue Val =
DAG.getCopyFromReg(Chain, DL, Reg, getPointerTy(DAG.getDataLayout()));
- unsigned V0 = ABI.IsN64() ? Mips::V0_64 : Mips::V0;
+ unsigned V0 = ABI.IsN64() ? Mips::V0_64
+ : ABI.IsP32() ? Mips::A0_NM
+ : Mips::V0;
Chain = DAG.getCopyToReg(Chain, DL, V0, Val, Glue);
Glue = Chain.getValue(1);
diff --git a/llvm/lib/Target/Mips/MipsRegisterInfo.cpp b/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
index ed5f2d48902f2..3aa3c14dc6d4b 100644
--- a/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
+++ b/llvm/lib/Target/Mips/MipsRegisterInfo.cpp
@@ -15,7 +15,6 @@
#include "Mips.h"
#include "MipsMachineFunction.h"
#include "MipsSubtarget.h"
-#include "MipsTargetMachine.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/CodeGen/MachineFrameInfo.h"
#include "llvm/CodeGen/MachineFunction.h"
@@ -39,7 +38,8 @@ using namespace llvm;
#include "MipsGenRegisterInfo.inc"
MipsRegisterInfo::MipsRegisterInfo(const MipsSubtarget &STI)
- : MipsGenRegisterInfo(Mips::RA), ArePtrs64bit(STI.getABI().ArePtrs64bit()) {
+ : MipsGenRegisterInfo(Mips::RA), ArePtrs64bit(STI.getABI().ArePtrs64bit()),
+ IsP32ABI(STI.getABI().IsP32()) {
MIPS_MC::initLLVMToCVRegMapping(this);
}
@@ -48,7 +48,9 @@ unsigned MipsRegisterInfo::getPICCallReg() { return Mips::T9; }
const TargetRegisterClass *
MipsRegisterInfo::getPointerRegClass(unsigned Kind) const {
assert(Kind == 0 && "this should only be used for default case");
- return ArePtrs64bit ? &Mips::GPR64RegClass : &Mips::GPR32RegClass;
+ return ArePtrs64bit ? &Mips::GPR64RegClass
+ : IsP32ABI ? &Mips::GPRNM32RegClass
+ : &Mips::GPR32RegClass;
}
unsigned
@@ -116,6 +118,10 @@ MipsRegisterInfo::getCalleeSavedRegs(const MachineFunction *MF) const {
return GPIsGlobal ? CSR_N32_NoGP_SaveList : CSR_N32_SaveList;
}
+ // P32 ABI
+ if (Subtarget.isABI_P32())
+ return CSR_P32_SaveList;
+
// O32 ABI
if (Subtarget.isSingleFloat())
return CSR_O32_SingleFloat_SaveList;
@@ -149,6 +155,10 @@ MipsRegisterInfo::getCallPreservedMask(const MachineFunction &MF,
return CSR_N32_RegMask;
}
+ // P32 ABI
+ if (Subtarget.isABI_P32())
+ return CSR_P32_RegMask;
+
// O32 ABI
if (Subtarget.isSingleFloat())
return CSR_O32_SingleFloat_RegMask;
@@ -176,6 +186,9 @@ getReservedRegs(const MachineFunction &MF) const {
Mips::ZERO_64, Mips::K0_64, Mips::K1_64, Mips::SP_64
};
+ static const MCPhysReg ReservedGPRNM32[] = {
+ Mips::ZERO_NM, Mips::K0_NM, Mips::K1_NM, Mips::SP_NM, Mips::AT_NM};
+
BitVector Reserved(getNumRegs());
const MipsSubtarget &Subtarget = MF.getSubtarget<MipsSubtarget>();
@@ -185,6 +198,9 @@ getReservedRegs(const MachineFunction &MF) const {
for (MCPhysReg R : ReservedGPR64)
Reserved.set(R);
+ for (MCPhysReg R : ReservedGPRNM32)
+ Reserved.set(R);
+
// Mark user-reserved GPRs and their 64-bit super-registers.
for (unsigned I = 1; I < 32; ++I)
if (Subtarget.isGPRReservedByUser(I))
@@ -195,6 +211,7 @@ getReservedRegs(const MachineFunction &MF) const {
if (!Subtarget.isABICalls() || GPIsGlobal) {
Reserved.set(Mips::GP);
Reserved.set(Mips::GP_64);
+ Reserved.set(Mips::GP_NM);
}
if (Subtarget.isFP64bit()) {
@@ -213,6 +230,7 @@ getReservedRegs(const MachineFunction &MF) const {
else {
Reserved.set(Mips::FP);
Reserved.set(Mips::FP_64);
+ Reserved.set(Mips::FP_NM);
// Reserve the base register if we need to both realign the stack and
// allocate variable-sized objects at runtime. This should test the
@@ -256,6 +274,7 @@ getReservedRegs(const MachineFunction &MF) const {
if (Subtarget.useSmallSection()) {
Reserved.set(Mips::GP);
Reserved.set(Mips::GP_64);
+ Reserved.set(Mips::GP_NM);
}
return Reserved;
@@ -293,14 +312,12 @@ Register MipsRegisterInfo::
getFrameRegister(const MachineFunction &MF) const {
const MipsSubtarget &Subtarget = MF.getSubtarget<MipsSubtarget>();
const TargetFrameLowering *TFI = Subtarget.getFrameLowering();
- bool IsN64 =
- static_cast<const MipsTargetMachine &>(MF.getTarget()).getABI().IsN64();
+ const MipsABIInfo &ABI = Subtarget.getABI();
if (Subtarget.inMips16Mode())
return TFI->hasFP(MF) ? Mips::S0 : Mips::SP;
else
- return TFI->hasFP(MF) ? (IsN64 ? Mips::FP_64 : Mips::FP) :
- (IsN64 ? Mips::SP_64 : Mips::SP);
+ return TFI->hasFP(MF) ? ABI.GetFramePtr() : ABI.GetStackPtr();
}
bool MipsRegisterInfo::canRealignStack(const MachineFunction &MF) const {
diff --git a/llvm/lib/Target/Mips/MipsRegisterInfo.h b/llvm/lib/Target/Mips/MipsRegisterInfo.h
index 9e6ef66163bd9..ab9c647174316 100644
--- a/llvm/lib/Target/Mips/MipsRegisterInfo.h
+++ b/llvm/lib/Target/Mips/MipsRegisterInfo.h
@@ -28,6 +28,7 @@ using TargetRegisterClass = MCRegisterClass;
class MipsRegisterInfo : public MipsGenRegisterInfo {
private:
const bool ArePtrs64bit;
+ const bool IsP32ABI;
public:
explicit MipsRegisterInfo(const MipsSubtarget &STI);
diff --git a/llvm/lib/Target/Mips/MipsSEFrameLowering.cpp b/llvm/lib/Target/Mips/MipsSEFrameLowering.cpp
index 937e33bd840e6..ea0652cf6adbe 100644
--- a/llvm/lib/Target/Mips/MipsSEFrameLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsSEFrameLowering.cpp
@@ -819,9 +819,9 @@ void MipsSEFrameLowering::determineCalleeSaves(MachineFunction &MF,
const TargetRegisterInfo *TRI = MF.getSubtarget().getRegisterInfo();
MipsFunctionInfo *MipsFI = MF.getInfo<MipsFunctionInfo>();
MipsABIInfo ABI = STI.getABI();
- unsigned RA = ABI.IsN64() ? Mips::RA_64 : Mips::RA;
+ unsigned RA = ABI.GetRetReg();
unsigned FP = ABI.GetFramePtr();
- unsigned BP = ABI.IsN64() ? Mips::S7_64 : Mips::S7;
+ unsigned BP = ABI.GetBasePtr();
// Mark $ra and $fp as used if function has dedicated frame pointer.
if (hasFP(MF)) {
@@ -862,8 +862,9 @@ void MipsSEFrameLowering::determineCalleeSaves(MachineFunction &MF,
!MF.getFrameInfo().hasVarSizedObjects())
return;
- const TargetRegisterClass &RC =
- ABI.ArePtrs64bit() ? Mips::GPR64RegClass : Mips::GPR32RegClass;
+ const TargetRegisterClass &RC = ABI.ArePtrs64bit() ? Mips::GPR64RegClass
+ : ABI.IsP32() ? Mips::GPRNM32RegClass
+ : Mips::GPR32RegClass;
int FI = MF.getFrameInfo().CreateSpillStackObject(TRI->getSpillSize(RC),
TRI->getSpillAlign(RC));
RS->addScavengingFrameIndex(FI);
diff --git a/llvm/lib/Target/Mips/MipsSEISelLowering.cpp b/llvm/lib/Target/Mips/MipsSEISelLowering.cpp
index 474e956e9ca02..4ba9949d75928 100644
--- a/llvm/lib/Target/Mips/MipsSEISelLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsSEISelLowering.cpp
@@ -99,7 +99,10 @@ MipsSETargetLowering::MipsSETargetLowering(const MipsTargetMachine &TM,
const MipsSubtarget &STI)
: MipsTargetLowering(TM, STI) {
// Set up the register classes
- addRegisterClass(MVT::i32, &Mips::GPR32RegClass);
+ if (STI.isABI_P32())
+ addRegisterClass(MVT::i32, &Mips::GPRNM32RegClass);
+ else
+ addRegisterClass(MVT::i32, &Mips::GPR32RegClass);
if (Subtarget.isGP64bit())
addRegisterClass(MVT::i64, &Mips::GPR64RegClass);
diff --git a/llvm/lib/Target/Mips/MipsSubtarget.cpp b/llvm/lib/Target/Mips/MipsSubtarget.cpp
index 287a4cbbf5af4..0f6764ee9b560 100644
--- a/llvm/lib/Target/Mips/MipsSubtarget.cpp
+++ b/llvm/lib/Target/Mips/MipsSubtarget.cpp
@@ -115,9 +115,15 @@ MipsSubtarget::MipsSubtarget(const Triple &TT, StringRef CPU, StringRef FS,
if (MipsArchVersion == Mips5)
report_fatal_error("Code generation for MIPS-V is not implemented", false);
- // Check if Architecture and ABI are compatible.
- assert(((!isGP64bit() && isABI_O32()) || isGP64bit()) &&
- "Invalid Arch & ABI pair.");
+ // nanoMIPS is 32-bit architecture and always uses the P32 ABI.
+ // Other MIPS 32-bit architectures supports only O32 ABI.
+ // 64-bit MIPS architectures supports all ABIs except P32.
+ const bool IsValidArchABI =
+ (hasNanoMips() && isABI_P32()) ||
+ (!hasNanoMips() && ((!isGP64bit() && isABI_O32()) || isGP64bit()));
+
+ if (!IsValidArchABI)
+ report_fatal_error("Invalid Arch & ABI pair.", false);
if (hasMSA() && !isFP64bit())
report_fatal_error("MSA requires a 64-bit FPU register file (FR=1 mode). "
@@ -129,17 +135,19 @@ MipsSubtarget::MipsSubtarget(const Triple &TT, StringRef CPU, StringRef FS,
"FPU with 64-bit registers is not available on MIPS32 pre revision 2. "
"Use -mcpu=mips32r2 or greater.", false);
- if (!isABI_O32() && !useOddSPReg())
- report_fatal_error("-mattr=+nooddspreg requires the O32 ABI.", false);
-
if (IsFPXX && (isABI_N32() || isABI_N64()))
report_fatal_error("FPXX is not permitted for the N32/N64 ABI's.", false);
if (hasMips64r6() && InMicroMipsMode)
report_fatal_error("microMIPS64R6 is not supported", false);
- if (!isABI_O32() && InMicroMipsMode)
- report_fatal_error("microMIPS64 is not supported.", false);
+ if (!hasNanoMips()) {
+ if (!isABI_O32() && !useOddSPReg())
+ report_fatal_error("-mattr=+nooddspreg requires the O32 ABI.", false);
+
+ if (!isABI_O32() && InMicroMipsMode)
+ report_fatal_error("microMIPS64 is not supported.", false);
+ }
if (UseIndirectJumpsHazard) {
if (InMicroMipsMode)
@@ -165,6 +173,9 @@ MipsSubtarget::MipsSubtarget(const Triple &TT, StringRef CPU, StringRef FS,
report_fatal_error(ISA + " is not compatible with the DSP ASE", false);
}
+ if (!NoABICalls && hasNanoMips())
+ report_fatal_error("nanoMIPS requires '-mno-abicalls'");
+
if (NoABICalls && TM.isPositionIndependent())
report_fatal_error("position-independent code requires '-mabicalls'");
@@ -203,25 +214,27 @@ MipsSubtarget::MipsSubtarget(const Triple &TT, StringRef CPU, StringRef FS,
StringRef ArchName = hasMips64() ? "MIPS64" : "MIPS32";
- if (!hasMips32r5() && hasMSA() && !MSAWarningPrinted) {
- errs() << "warning: the 'msa' ASE requires " << ArchName
- << " revision 5 or greater\n";
- MSAWarningPrinted = true;
- }
- if (!hasMips32r5() && hasVirt() && !VirtWarningPrinted) {
- errs() << "warning: the 'virt' ASE requires " << ArchName
- << " revision 5 or greater\n";
- VirtWarningPrinted = true;
- }
- if (!hasMips32r6() && hasCRC() && !CRCWarningPrinted) {
- errs() << "warning: the 'crc' ASE requires " << ArchName
- << " revision 6 or greater\n";
- CRCWarningPrinted = true;
- }
- if (!hasMips32r6() && hasGINV() && !GINVWarningPrinted) {
- errs() << "warning: the 'ginv' ASE requires " << ArchName
- << " revision 6 or greater\n";
- GINVWarningPrinted = true;
+ if (!hasNanoMips()) {
+ if (!hasMips32r5() && hasMSA() && !MSAWarningPrinted) {
+ errs() << "warning: the 'msa' ASE requires " << ArchName
+ << " revision 5 or greater\n";
+ MSAWarningPrinted = true;
+ }
+ if (!hasMips32r5() && hasVirt() && !VirtWarningPrinted) {
+ errs() << "warning: the 'virt' ASE requires " << ArchName
+ << " revision 5 or greater\n";
+ VirtWarningPrinted = true;
+ }
+ if (!hasMips32r6() && hasCRC() && !CRCWarningPrinted) {
+ errs() << "warning: the 'crc' ASE requires " << ArchName
+ << " revision 6 or greater\n";
+ CRCWarningPrinted = true;
+ }
+ if (!hasMips32r6() && hasGINV() && !GINVWarningPrinted) {
+ errs() << "warning: the 'ginv' ASE requires " << ArchName
+ << " revision 6 or greater\n";
+ GINVWarningPrinted = true;
+ }
}
TSInfo = std::make_unique<MipsSelectionDAGInfo>();
@@ -265,7 +278,7 @@ MipsSubtarget::initializeSubtargetDependencies(StringRef CPU, StringRef FS,
if (StackAlignOverride)
stackAlignment = *StackAlignOverride;
- else if (isABI_N32() || isABI_N64())
+ else if (isABI_N32() || isABI_N64() || isABI_P32())
stackAlignment = Align(16);
else {
assert(isABI_O32() && "Unknown ABI for stack alignment!");
@@ -292,6 +305,7 @@ Reloc::Model MipsSubtarget::getRelocationModel() const {
bool MipsSubtarget::isABI_N64() const { return getABI().IsN64(); }
bool MipsSubtarget::isABI_N32() const { return getABI().IsN32(); }
bool MipsSubtarget::isABI_O32() const { return getABI().IsO32(); }
+bool MipsSubtarget::isABI_P32() const { return getABI().IsP32(); }
const MipsABIInfo &MipsSubtarget::getABI() const { return TM.getABI(); }
const SelectionDAGTargetInfo *MipsSubtarget::getSelectionDAGInfo() const {
diff --git a/llvm/lib/Target/Mips/MipsSubtarget.h b/llvm/lib/Target/Mips/MipsSubtarget.h
index 6391a52561aee..f27ddadada2f2 100644
--- a/llvm/lib/Target/Mips/MipsSubtarget.h
+++ b/llvm/lib/Target/Mips/MipsSubtarget.h
@@ -268,6 +268,7 @@ class MipsSubtarget : public MipsGenSubtargetInfo {
bool isABI_N64() const;
bool isABI_N32() const;
bool isABI_O32() const;
+ bool isABI_P32() const;
const MipsABIInfo &getABI() const;
bool isABI_FPXX() const { return isABI_O32() && IsFPXX; }
diff --git a/llvm/lib/TargetParser/TargetDataLayout.cpp b/llvm/lib/TargetParser/TargetDataLayout.cpp
index c4de5d50bb8e3..b5ca49b41729b 100644
--- a/llvm/lib/TargetParser/TargetDataLayout.cpp
+++ b/llvm/lib/TargetParser/TargetDataLayout.cpp
@@ -149,7 +149,7 @@ static std::string computeM68kDataLayout(const Triple &TT) {
}
namespace {
-enum class MipsABI { Unknown, O32, N32, N64 };
+enum class MipsABI { Unknown, O32, N32, N64, P32 };
}
// FIXME: This duplicates MipsABIInfo::computeTargetABI, but duplicating this is
@@ -161,12 +161,16 @@ static MipsABI getMipsABI(const Triple &TT, StringRef ABIName) {
return MipsABI::O32;
if (ABIName.starts_with("n32"))
return MipsABI::N32;
+ if (ABIName.starts_with("p32"))
+ return MipsABI::P32;
if (ABIName.starts_with("n64"))
return MipsABI::N64;
if (TT.isABIN32())
return MipsABI::N32;
assert(ABIName.empty() && "Unknown ABI option for MIPS");
+ if (TT.isNanoMips())
+ return MipsABI::P32;
if (TT.isMIPS64())
return MipsABI::N64;
return MipsABI::O32;
@@ -200,6 +204,8 @@ static std::string computeMipsDataLayout(const Triple &TT, StringRef ABIName) {
// 128 bit aligned.
if (ABI == MipsABI::N64 || ABI == MipsABI::N32)
Ret += "-i128:128-n32:64-S128";
+ else if (ABI == MipsABI::P32)
+ Ret += "-n32-S128";
else
Ret += "-n32-S64";
@@ -601,6 +607,7 @@ std::string Triple::computeDataLayout(StringRef ABIName) const {
case Triple::mipsel:
case Triple::mips64:
case Triple::mips64el:
+ case Triple::nanomips:
return computeMipsDataLayout(*this, ABIName);
case Triple::msp430:
return "e-m:e-p:16:16-i32:16-i64:16-f32:16-f64:16-a:8-n8:16-S16";
>From cf8303c26ba3629e49e61c578b3a786658078677 Mon Sep 17 00:00:00 2001
From: Nemanja Rakovic <ot_nemanja.rakovic at mediatek.com>
Date: Mon, 7 Sep 2026 19:54:36 +0200
Subject: [PATCH 06/15] [nanoMIPS 6/7] Add instructions
Add nanoMIPS instructions and instruction encodings, along with basic
assembler parser and disassembler support, and the MC changes needed to
enable the .mir tests coming in commit 7/7.
Co-authored-by: Faraz Shahbazker <faraz.shahbazker at mediatek.com>
Co-authored-by: Stefan Pejic <ot_stefan.pejic at mediatek.com>
---
.../Target/Mips/AsmParser/MipsAsmParser.cpp | 84 ++
.../Mips/Disassembler/MipsDisassembler.cpp | 121 +++
.../Target/Mips/MCTargetDesc/MipsABIInfo.cpp | 10 +-
.../Mips/MCTargetDesc/MipsMCCodeEmitter.cpp | 9 +-
.../Mips/MCTargetDesc/MipsMCTargetDesc.cpp | 3 +-
llvm/lib/Target/Mips/MipsAsmPrinter.cpp | 5 +-
llvm/lib/Target/Mips/MipsCP0RegisterMap.h | 217 ++++
llvm/lib/Target/Mips/MipsInstrInfo.td | 10 +-
llvm/lib/Target/Mips/MipsRegisterInfo.td | 103 ++
llvm/lib/Target/Mips/MipsSEFrameLowering.cpp | 2 +-
llvm/lib/Target/Mips/MipsSEInstrInfo.cpp | 7 +
llvm/lib/Target/Mips/NanoMipsInstrFormats.td | 975 +++++++++++++++++
llvm/lib/Target/Mips/NanoMipsInstrInfo.td | 997 ++++++++++++++++++
13 files changed, 2530 insertions(+), 13 deletions(-)
create mode 100644 llvm/lib/Target/Mips/MipsCP0RegisterMap.h
create mode 100644 llvm/lib/Target/Mips/NanoMipsInstrFormats.td
create mode 100644 llvm/lib/Target/Mips/NanoMipsInstrInfo.td
diff --git a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
index 9d3cf539ee254..5dd4984404b25 100644
--- a/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
+++ b/llvm/lib/Target/Mips/AsmParser/MipsAsmParser.cpp
@@ -1669,6 +1669,90 @@ class MipsOperand : public MCParsedAsmOperand {
return isRegIdx() && RegIdx.Kind & RegKind_MSACtrl && RegIdx.Index <= 7;
}
+ bool isNM16AsmReg() const {
+ if (!(isRegIdx() && RegIdx.Kind))
+ return false;
+ return ((RegIdx.Index >= 4 && RegIdx.Index <= 7) ||
+ (RegIdx.Index >= 16 && RegIdx.Index <= 19));
+ }
+
+ bool isNM16ZeroAsmReg() const {
+ if (!(isRegIdx() && RegIdx.Kind))
+ return false;
+ return ((RegIdx.Index == 0) || (RegIdx.Index >= 4 && RegIdx.Index <= 7) ||
+ (RegIdx.Index >= 17 && RegIdx.Index <= 19));
+ }
+
+ bool isNM4AsmReg() const {
+ if (!(isRegIdx() && RegIdx.Kind))
+ return false;
+ return ((RegIdx.Index >= 4 && RegIdx.Index <= 11) ||
+ (RegIdx.Index >= 16 && RegIdx.Index <= 23));
+ }
+
+ bool isCOP0SelAsmReg() const {
+ if (!(isRegIdx() && RegIdx.Kind))
+ return false;
+ return RegIdx.Index <= 160;
+ }
+
+ bool isNM4ZeroAsmReg() const {
+ if (!(isRegIdx() && RegIdx.Kind))
+ return false;
+ return ((RegIdx.Index == 0) || (RegIdx.Index >= 4 && RegIdx.Index <= 10) ||
+ (RegIdx.Index >= 16 && RegIdx.Index <= 23));
+ }
+
+ bool isNM2R1AsmReg() const {
+ if (!(isRegIdx() && RegIdx.Kind))
+ return false;
+ return RegIdx.Index >= 4 && RegIdx.Index <= 7;
+ }
+
+ bool isNM2R2AsmReg() const {
+ if (!(isRegIdx() && RegIdx.Kind))
+ return false;
+ return RegIdx.Index >= 5 && RegIdx.Index <= 8;
+ }
+
+ bool isNM1R1AsmReg() const {
+ if (!(isRegIdx() && RegIdx.Kind))
+ return false;
+ return RegIdx.Index == 4 || RegIdx.Index == 5;
+ }
+
+ template <unsigned RegClassID = Mips::GPRNM32RegClassID>
+ bool isGPRNMAsmReg() const {
+ if (!(isRegIdx() && RegIdx.Kind))
+ return false;
+ switch (RegClassID) {
+ case Mips::GPRNMGPRegClassID:
+ return (RegIdx.Index == 28);
+ case Mips::GPRNMSPRegClassID:
+ return (RegIdx.Index == 29);
+ case Mips::GPRNMRARegClassID:
+ return (RegIdx.Index == 31);
+ case Mips::GPRNM32NZRegClassID:
+ return (RegIdx.Index > 0 && RegIdx.Index < 32);
+ case Mips::GPRNM3RegClassID:
+ return isNM16AsmReg();
+ case Mips::GPRNM3ZRegClassID:
+ return isNM16ZeroAsmReg();
+ case Mips::GPRNM4RegClassID:
+ return isNM4AsmReg();
+ case Mips::GPRNM4ZRegClassID:
+ return isNM4ZeroAsmReg();
+ case Mips::GPRNM2R1RegClassID:
+ return isNM2R1AsmReg();
+ case Mips::GPRNM2R2RegClassID:
+ return isNM2R2AsmReg();
+ case Mips::GPRNM1R1RegClassID:
+ return isNM1R1AsmReg();
+ default:
+ return RegIdx.Index < 32;
+ }
+ }
+
/// getStartLoc - Get the location of the first token of this operand.
SMLoc getStartLoc() const override { return StartLoc; }
/// getEndLoc - Get the location of the last token of this operand.
diff --git a/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp b/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp
index bbd614fc64423..32a3ecb663925 100644
--- a/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp
+++ b/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp
@@ -11,6 +11,7 @@
//===----------------------------------------------------------------------===//
#include "MCTargetDesc/MipsMCTargetDesc.h"
+#include "MipsCP0RegisterMap.h"
#include "TargetInfo/MipsTargetInfo.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/MC/MCContext.h"
@@ -227,6 +228,40 @@ static DecodeStatus DecodeCOP0RegisterClass(MCInst &Inst, unsigned RegNo,
return MCDisassembler::Success;
}
+static DecodeStatus DecodeCOP0SelRegisterClass(MCInst &Inst, unsigned RegNo,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ static MipsCP0SelMap COP0Map;
+ int COP0SelIdx = COP0Map.getEncIndexMap(RegNo);
+
+ if (COP0SelIdx != -1) {
+ MCRegister Reg = getReg(Decoder, Mips::COP0SelRegClassID, COP0SelIdx);
+ Inst.addOperand(MCOperand::createReg(Reg));
+ } else {
+ // Not a named register encoding - print numeric register and select value
+ switch (Inst.getOpcode()) {
+ case Mips::MFC0Sel_NM:
+ Inst.setOpcode(Mips::MFC0_NM);
+ break;
+ case Mips::MFHC0Sel_NM:
+ Inst.setOpcode(Mips::MFHC0_NM);
+ break;
+ case Mips::MTC0Sel_NM:
+ Inst.setOpcode(Mips::MTC0_NM);
+ break;
+ case Mips::MTHC0Sel_NM:
+ Inst.setOpcode(Mips::MTHC0_NM);
+ break;
+ default:
+ llvm_unreachable("Unknown instruction!");
+ }
+ MCRegister Reg = getReg(Decoder, Mips::COP0RegClassID, RegNo >> 5);
+ Inst.addOperand(MCOperand::createReg(Reg));
+ Inst.addOperand(MCOperand::createImm(RegNo & 0x1f));
+ }
+ return MCDisassembler::Success;
+}
+
static DecodeStatus DecodeCOP2RegisterClass(MCInst &Inst, unsigned RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
@@ -938,6 +973,92 @@ static DecodeStatus DecodeGPR32RegisterClass(MCInst &Inst, unsigned RegNo,
return MCDisassembler::Success;
}
+static DecodeStatus DecodeGPRNM32RegisterClass(MCInst &Inst, unsigned RegNo,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ if (RegNo > 31)
+ return MCDisassembler::Fail;
+ MCRegister Reg = getReg(Decoder, Mips::GPRNM32RegClassID, RegNo);
+ Inst.addOperand(MCOperand::createReg(Reg));
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus DecodeGPRNM3RegisterClass(MCInst &Inst, unsigned RegNo,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ if (RegNo > 7)
+ return MCDisassembler::Fail;
+ RegNo |= ((RegNo & 0x4) ^ 0x4) << 2;
+ return DecodeGPRNM32RegisterClass(Inst, RegNo, Address, Decoder);
+}
+
+static DecodeStatus DecodeGPRNMRARegisterClass(MCInst &Inst, unsigned RegNo,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ if (RegNo != 1)
+ return MCDisassembler::Fail;
+ Inst.addOperand(MCOperand::createReg(Mips::RA_NM));
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus DecodeGPRNM3ZRegisterClass(MCInst &Inst, unsigned RegNo,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ if (RegNo > 7)
+ return MCDisassembler::Fail;
+ if (RegNo != 0)
+ RegNo |= ((RegNo & 0x4) ^ 0x4) << 2;
+ return DecodeGPRNM32RegisterClass(Inst, RegNo, Address, Decoder);
+}
+
+static DecodeStatus DecodeGPRNM4RegisterClass(MCInst &Inst, unsigned RegNo,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ RegNo &= ~0x8;
+ RegNo += (RegNo < 4 ? 8 : 0);
+ return DecodeGPRNM32RegisterClass(Inst, RegNo, Address, Decoder);
+}
+
+static DecodeStatus DecodeGPRNM4ZRegisterClass(MCInst &Inst, unsigned RegNo,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ RegNo &= ~0x8;
+ if (RegNo == 3)
+ RegNo = 0;
+ else
+ RegNo += (RegNo < 3 ? 8 : 0);
+ return DecodeGPRNM32RegisterClass(Inst, RegNo, Address, Decoder);
+}
+
+static DecodeStatus
+DecodeGPRNM32NZRegisterClass(MCInst &Inst, unsigned RegNo, uint64_t Address,
+ const MCDisassembler *Decoder) {
+ if (RegNo == 0)
+ return MCDisassembler::Fail;
+ return DecodeGPRNM32RegisterClass(Inst, RegNo, Address, Decoder);
+}
+
+static DecodeStatus DecodeGPRNM2R1RegisterClass(MCInst &Inst, unsigned RegNo,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ if (RegNo > 31)
+ return MCDisassembler::Fail;
+ RegNo += 4;
+ MCRegister Reg = getReg(Decoder, Mips::GPRNM32RegClassID, RegNo);
+ Inst.addOperand(MCOperand::createReg(Reg));
+ Inst.addOperand(MCOperand::createReg(Reg + 1));
+ return MCDisassembler::Success;
+}
+
+static DecodeStatus DecodeGPRNM1R1RegisterClass(MCInst &Inst, unsigned RegNo,
+ uint64_t Address,
+ const MCDisassembler *Decoder) {
+ if (RegNo != 0 && RegNo != 1)
+ return MCDisassembler::Fail;
+ RegNo += 4;
+ return DecodeGPRNM32RegisterClass(Inst, RegNo, Address, Decoder);
+}
+
static DecodeStatus DecodePtrRegisterClass(MCInst &Inst, unsigned RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp
index aa2a3117db691..ddda52b7e8faf 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsABIInfo.cpp
@@ -118,23 +118,23 @@ unsigned MipsABIInfo::GetZeroReg() const {
}
unsigned MipsABIInfo::GetPtrAdduOp() const {
- return ArePtrs64bit() ? Mips::DADDu : Mips::ADDu;
+ return ArePtrs64bit() ? Mips::DADDu : IsP32() ? Mips::ADDu_NM : Mips::ADDu;
}
unsigned MipsABIInfo::GetPtrAddiuOp() const {
- return ArePtrs64bit() ? Mips::DADDiu : Mips::ADDiu;
+ return ArePtrs64bit() ? Mips::DADDiu : IsP32() ? Mips::ADDIU_NM : Mips::ADDiu;
}
unsigned MipsABIInfo::GetPtrSubuOp() const {
- return ArePtrs64bit() ? Mips::DSUBu : Mips::SUBu;
+ return ArePtrs64bit() ? Mips::DSUBu : IsP32() ? Mips::SUBu_NM : Mips::SUBu;
}
unsigned MipsABIInfo::GetPtrAndOp() const {
- return ArePtrs64bit() ? Mips::AND64 : Mips::AND;
+ return ArePtrs64bit() ? Mips::AND64 : IsP32() ? Mips::AND_NM : Mips::AND;
}
unsigned MipsABIInfo::GetGPRMoveOp() const {
- return ArePtrs64bit() ? Mips::OR64 : Mips::OR;
+ return ArePtrs64bit() ? Mips::OR64 : IsP32() ? Mips::OR_NM : Mips::OR;
}
unsigned MipsABIInfo::GetEhDataReg(unsigned I) const {
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp
index e8bf4d61c92f3..073c3dc23616b 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCCodeEmitter.cpp
@@ -188,7 +188,7 @@ void MipsMCCodeEmitter::encodeInstruction(const MCInst &MI,
}
size_t N = Fixups.size();
- uint32_t Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI);
+ uint64_t Binary = getBinaryCodeForInstr(TmpInst, Fixups, STI);
// Check for unimplemented opcodes.
// Unfortunately in MIPS both NOP and SLL will come in with Binary == 0
@@ -238,7 +238,12 @@ void MipsMCCodeEmitter::encodeInstruction(const MCInst &MI,
IsLittleEndian ? llvm::endianness::little : llvm::endianness::big;
if (Size == 2) {
support::endian::write<uint16_t>(CB, Binary, Endian);
- } else if (IsLittleEndian && isMicroMips(STI)) {
+ } else if (IsLittleEndian && Size == 4 &&
+ (isMicroMips(STI) || isNanoMips(STI))) {
+ support::endian::write<uint16_t>(CB, Binary >> 16, Endian);
+ support::endian::write<uint16_t>(CB, Binary & 0xffff, Endian);
+ } else if (IsLittleEndian && Size == 6 && isNanoMips(STI)) {
+ support::endian::write<uint16_t>(CB, Binary >> 32, Endian);
support::endian::write<uint16_t>(CB, Binary >> 16, Endian);
support::endian::write<uint16_t>(CB, Binary & 0xffff, Endian);
} else {
diff --git a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp
index bc661f82da049..90843b3ad4ef3 100644
--- a/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp
+++ b/llvm/lib/Target/Mips/MCTargetDesc/MipsMCTargetDesc.cpp
@@ -301,6 +301,7 @@ extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeMipsTargetMC() {
for (Target *T : {&getTheMipsTarget(), &getTheMips64Target()})
TargetRegistry::RegisterMCCodeEmitter(*T, createMipsMCCodeEmitterEB);
- for (Target *T : {&getTheMipselTarget(), &getTheMips64elTarget()})
+ for (Target *T : {&getTheMipselTarget(), &getTheMips64elTarget(),
+ &getTheNanoMipsTarget()})
TargetRegistry::RegisterMCCodeEmitter(*T, createMipsMCCodeEmitterEL);
}
diff --git a/llvm/lib/Target/Mips/MipsAsmPrinter.cpp b/llvm/lib/Target/Mips/MipsAsmPrinter.cpp
index 701dbb5670ffb..0a95378630487 100644
--- a/llvm/lib/Target/Mips/MipsAsmPrinter.cpp
+++ b/llvm/lib/Target/Mips/MipsAsmPrinter.cpp
@@ -122,7 +122,10 @@ void MipsAsmPrinter::emitPseudoIndirectBranch(MCStreamer &OutStreamer,
} else if (Subtarget->inMicroMipsMode())
// microMIPS should use (JR_MM $rs)
TmpInst0.setOpcode(Mips::JR_MM);
- else {
+ else if (Subtarget->hasNanoMips()) {
+ // nanoMIPS should use (JRC_NM $rs)
+ TmpInst0.setOpcode(Mips::JRC_NM);
+ } else {
// Everything else should use (JR $rs)
TmpInst0.setOpcode(Mips::JR);
}
diff --git a/llvm/lib/Target/Mips/MipsCP0RegisterMap.h b/llvm/lib/Target/Mips/MipsCP0RegisterMap.h
new file mode 100644
index 0000000000000..9d1135d72b4c1
--- /dev/null
+++ b/llvm/lib/Target/Mips/MipsCP0RegisterMap.h
@@ -0,0 +1,217 @@
+//===- MipsCP0RegisterMap.h - Co-processor register names -------*- 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 defines the mapping between MIPS CP0 register names and their
+/// (register, select) encodings.
+///
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_LIB_TARGET_MIPS_MIPSCP0REGMAP_H
+#define LLVM_LIB_TARGET_MIPS_MIPSCP0REGMAP_H
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+
+namespace llvm {
+
+struct CP0SelRegister {
+ StringRef Name;
+ int RegNum;
+ int Select;
+};
+
+class MipsCP0SelMap {
+ DenseMap<unsigned, int> EncIndexMap;
+ StringMap<int> NameIndexMap;
+
+public:
+ int getEncIndexMap(unsigned Reg) {
+ auto It = EncIndexMap.find(Reg);
+ return It != EncIndexMap.end() ? It->second : -1;
+ }
+
+ int getNameIndexMap(StringRef Name) {
+ auto It = NameIndexMap.find(Name);
+ return It != NameIndexMap.end() ? It->second : -1;
+ }
+
+ MipsCP0SelMap() {
+ static const struct CP0SelRegister Regs[] = {{"index", 0, 0},
+ {"mvpcontrol", 0, 1},
+ {"mvpconf0", 0, 2},
+ {"mvpconf1", 0, 3},
+ {"vpcontrol", 0, 4},
+ {"random", 1, 0},
+ {"vpecontrol", 1, 1},
+ {"vpeconf0", 1, 2},
+ {"vpeconf1", 1, 3},
+ {"yqmask", 1, 4},
+ {"vpeschedule", 1, 5},
+ {"vpeschefback", 1, 6},
+ {"vpeopt", 1, 7},
+ {"entrylo0", 2, 0},
+ {"tcstatus", 2, 1},
+ {"tcbind", 2, 2},
+ {"tcrestart", 2, 3},
+ {"tchalt", 2, 4},
+ {"tccontext", 2, 5},
+ {"tcschedule", 2, 6},
+ {"tcschefback", 2, 7},
+ {"entrylo1", 3, 0},
+ {"globalnumber", 3, 1},
+ {"tcopt", 3, 7},
+ {"context", 4, 0},
+ {"contextconfig", 4, 1},
+ {"userlocal", 4, 2},
+ {"xcontextconfig", 4, 3},
+ {"debugcontextid", 4, 4},
+ {"memorymapid", 4, 5},
+ {"pagemask", 5, 0},
+ {"pagegrain", 5, 1},
+ {"segctl0", 5, 2},
+ {"segctl1", 5, 3},
+ {"segctl2", 5, 4},
+ {"pwbase", 5, 5},
+ {"pwfield", 5, 6},
+ {"pwsize", 5, 7},
+ {"wired", 6, 0},
+ {"srsconf0", 6, 1},
+ {"srsconf1", 6, 2},
+ {"srsconf2", 6, 3},
+ {"srsconf3", 6, 4},
+ {"srsconf4", 6, 5},
+ {"pwctl", 6, 6},
+ {"hwrena", 7, 0},
+ {"badvaddr", 8, 0},
+ {"badinst", 8, 1},
+ {"badinstrp", 8, 2},
+ {"badinstrx", 8, 3},
+ {"count", 9, 0},
+ {"entryhi", 10, 0},
+ {"guestctl1", 10, 4},
+ {"guestctl2", 10, 5},
+ {"guestctl3", 10, 6},
+ {"compare", 11, 0},
+ {"guestctl0ext", 11, 4},
+ {"status", 12, 0},
+ {"intctl", 12, 1},
+ {"srsctl", 12, 2},
+ {"srsmap", 12, 3},
+ {"view_ipl", 12, 4},
+ {"srsmap2", 12, 5},
+ {"guestctl0", 12, 6},
+ {"gtoffset", 12, 7},
+ {"cause", 13, 0},
+ {"view_ripl", 13, 4},
+ {"nestedexc", 13, 5},
+ {"epc", 14, 0},
+ {"nestedepc", 14, 2},
+ {"prid", 15, 0},
+ {"ebase", 15, 1},
+ {"cdmmbase", 15, 2},
+ {"cmgcrbase", 15, 3},
+ {"bevva", 15, 4},
+ {"config", 16, 0},
+ {"config1", 16, 1},
+ {"config2", 16, 2},
+ {"config3", 16, 3},
+ {"config4", 16, 4},
+ {"config5", 16, 5},
+ {"lladdr", 17, 0},
+ {"maar", 17, 1},
+ {"maari", 17, 2},
+ {"watchlo0", 18, 0},
+ {"watchlo1", 18, 1},
+ {"watchlo2", 18, 2},
+ {"watchlo3", 18, 3},
+ {"watchlo4", 18, 4},
+ {"watchlo5", 18, 5},
+ {"watchlo6", 18, 6},
+ {"watchlo7", 18, 7},
+ {"watchlo8", 18, 8},
+ {"watchlo9", 18, 9},
+ {"watchlo10", 18, 10},
+ {"watchlo11", 18, 11},
+ {"watchlo12", 18, 12},
+ {"watchlo13", 18, 13},
+ {"watchlo14", 18, 14},
+ {"watchlo15", 18, 15},
+ {"watchhi0", 19, 0},
+ {"watchhi1", 19, 1},
+ {"watchhi2", 19, 2},
+ {"watchhi3", 19, 3},
+ {"watchhi4", 19, 4},
+ {"watchhi5", 19, 5},
+ {"watchhi6", 19, 6},
+ {"watchhi7", 19, 7},
+ {"watchhi8", 19, 8},
+ {"watchhi9", 19, 9},
+ {"watchhi10", 19, 10},
+ {"watchhi11", 19, 11},
+ {"watchhi12", 19, 12},
+ {"watchhi13", 19, 13},
+ {"watchhi14", 19, 14},
+ {"watchhi15", 19, 15},
+ {"xcontext", 20, 0},
+ {"debug", 23, 0},
+ {"tracecontrol", 23, 1},
+ {"tracecontrol2", 23, 2},
+ {"usertracedata1", 23, 3},
+ {"traceibpc", 23, 4},
+ {"tracedbpc", 23, 5},
+ {"debug2", 23, 6},
+ {"depc", 24, 0},
+ {"tracecontrol3", 24, 2},
+ {"usertracedata2", 24, 3},
+ {"perfctl0", 25, 0},
+ {"perfcnt0", 25, 1},
+ {"perfctl1", 25, 2},
+ {"perfcnt1", 25, 3},
+ {"perfctl2", 25, 4},
+ {"perfcnt2", 25, 5},
+ {"perfctl3", 25, 6},
+ {"perfcnt3", 25, 7},
+ {"perfctl4", 25, 8},
+ {"perfcnt4", 25, 9},
+ {"perfctl5", 25, 10},
+ {"perfcnt5", 25, 11},
+ {"perfctl6", 25, 12},
+ {"perfcnt6", 25, 13},
+ {"perfctl7", 25, 14},
+ {"perfcnt7", 25, 15},
+ {"errctl", 26, 0},
+ {"cacheerr", 27, 0},
+ {"itaglo", 28, 0},
+ {"idatalo", 28, 1},
+ {"dtaglo", 28, 2},
+ {"ddatalo", 28, 3},
+ {"itaghi", 29, 0},
+ {"idatahi", 29, 1},
+ {"dtaghi", 29, 2},
+ {"ddatahi", 29, 3},
+ {"errorepc", 30, 0},
+ {"desave", 31, 0},
+ {"kscratch1", 31, 2},
+ {"kscratch2", 31, 3},
+ {"kscratch3", 31, 4},
+ {"kscratch4", 31, 5},
+ {"kscratch5", 31, 6},
+ {"kscratch6", 31, 7}};
+ int Index = 0;
+ for (auto Reg : Regs) {
+ NameIndexMap[Reg.Name] = Index;
+ unsigned RegEnc = (Reg.RegNum << 5) | Reg.Select;
+ EncIndexMap[RegEnc] = Index++;
+ }
+ }
+};
+
+} // namespace llvm
+
+#endif // LLVM_LIB_TARGET_MIPS_MIPSCP0REGMAP_H
diff --git a/llvm/lib/Target/Mips/MipsInstrInfo.td b/llvm/lib/Target/Mips/MipsInstrInfo.td
index 05ab68e06efa6..4897ce6c5eb93 100644
--- a/llvm/lib/Target/Mips/MipsInstrInfo.td
+++ b/llvm/lib/Target/Mips/MipsInstrInfo.td
@@ -2344,9 +2344,9 @@ let AdditionalPredicates = [NotInMips16Mode, NotInMicroMips,
ISA_MIPS1_NOT_32R6_64R6;
// Return instructions are matched as a RetRA instruction, then are expanded
-// into PseudoReturn/PseudoReturn64 after register allocation. Finally,
-// MipsAsmPrinter expands this into JR, JR64, JALR, or JALR64 depending on the
-// ISA.
+// into PseudoReturn/PseudoReturn64 after register allocation.
+// Finally, MipsAsmPrinter expands this into JR, JR64, JALR, JALR64 or JRC_NM
+// depending on the ISA.
class PseudoReturnBase<RegisterOperand RO> : MipsPseudo<(outs), (ins RO:$rs),
[]> {
let isTerminator = 1;
@@ -3464,3 +3464,7 @@ include "MicroMips32r6InstrInfo.td"
// Micromips DSP
include "MicroMipsDSPInstrFormats.td"
include "MicroMipsDSPInstrInfo.td"
+
+// nanoMIPS
+include "NanoMipsInstrFormats.td"
+include "NanoMipsInstrInfo.td"
diff --git a/llvm/lib/Target/Mips/MipsRegisterInfo.td b/llvm/lib/Target/Mips/MipsRegisterInfo.td
index 18b30b24024f4..51f9ce394cfbc 100644
--- a/llvm/lib/Target/Mips/MipsRegisterInfo.td
+++ b/llvm/lib/Target/Mips/MipsRegisterInfo.td
@@ -895,6 +895,26 @@ def GPRMM16AsmOperandMovePPairSecond : MipsAsmRegOperand {
let PredicateMethod = "isMM16AsmRegMovePPairSecond";
}
+def GPRNM32AsmOperand : MipsAsmRegOperand {
+ let Name = "GPRNM32AsmReg";
+ let PredicateMethod = "isGPRAsmReg";
+}
+
+class GPRNMAsmOperandClass<string Cname, string RegClass,
+ list<AsmOperandClass> Supers = []>
+ : MipsAsmRegOperand {
+ let Name = "GPRNM" # Cname;
+ let PredicateMethod = "isGPRNMAsmReg<Mips::" # RegClass # ">";
+ let SuperClasses = Supers;
+}
+
+class COP0SelAsmOperandClass<string Cname, list<AsmOperandClass> Supers = []>
+ : MipsAsmRegOperand {
+ let Name = Cname;
+ let PredicateMethod = "isCOP0SelAsmReg";
+ let SuperClasses = Supers;
+}
+
def ACC64DSPAsmOperand : MipsAsmRegOperand {
let Name = "ACC64DSPAsmReg";
let PredicateMethod = "isACCAsmReg";
@@ -989,6 +1009,89 @@ def GPRMM16OpndMovePPairSecond : RegisterOperand<GPRMM16MovePPairSecond> {
let ParserMatchClass = GPRMM16AsmOperandMovePPairSecond;
}
+// In the following nanoMIPS operand definitions, the SuperClasses list passed
+// to GPRNMAsmOperandClass indirectly controls mnemonic-matching priority by
+// dictating the order in which instructions appear in the MatchTable.
+def GPRNM48Opnd : RegisterOperand<GPRNM32> {
+ let ParserMatchClass = GPRNMAsmOperandClass<"48Reg5", "GPRNM32RegClassID",
+ []>;
+}
+
+def GPRNM32NZOpnd : RegisterOperand<GPRNM32NZ> {
+ let ParserMatchClass = GPRNMAsmOperandClass<"32Reg5NZ", "GPRNM32NZRegClassID",
+ [GPRNM48Opnd.ParserMatchClass]>;
+}
+
+def GPRNM32Opnd : RegisterOperand<GPRNM32> {
+ let ParserMatchClass = GPRNMAsmOperandClass<"32Reg5", "GPRNM32RegClassID",
+ [GPRNM32NZOpnd.ParserMatchClass]>;
+}
+
+def COP0SelOpnd : RegisterOperand<COP0Sel> {
+ let ParserMatchClass =
+ COP0SelAsmOperandClass<"COP0SelReg", [GPRNM32Opnd.ParserMatchClass]>;
+}
+
+def GPRNM4Opnd : RegisterOperand<GPRNM4> {
+ let ParserMatchClass = GPRNMAsmOperandClass<"16Reg4x4", "GPRNM4RegClassID",
+ [GPRNM32Opnd.ParserMatchClass]>;
+}
+
+def GPRNM4ZOpnd : RegisterOperand<GPRNM4Z> {
+ let ParserMatchClass = GPRNMAsmOperandClass<"16Reg4x4Z", "GPRNM4ZRegClassID",
+ [GPRNM32Opnd.ParserMatchClass]>;
+}
+
+def GPRNM16R5Opnd : RegisterOperand<GPRNM32> {
+ let ParserMatchClass = GPRNMAsmOperandClass<"16Reg5", "GPRNM32RegClassID",
+ [GPRNM4Opnd.ParserMatchClass]>;
+}
+
+def GPRNM16R5NZOpnd : RegisterOperand<GPRNM32> {
+ let ParserMatchClass = GPRNMAsmOperandClass<"16Reg5NZ", "GPRNM32NZRegClassID",
+ [GPRNM4Opnd.ParserMatchClass]>;
+}
+
+def GPRNM16R3Opnd : RegisterOperand<GPRNM3> {
+ let ParserMatchClass = GPRNMAsmOperandClass<"16Reg3", "GPRNM3RegClassID",
+ [GPRNM16R5Opnd.ParserMatchClass]>;
+}
+
+def GPRNM16R3ZOpnd : RegisterOperand<GPRNM3Z> {
+ let ParserMatchClass = GPRNMAsmOperandClass<"16Reg3Z", "GPRNM3ZRegClassID",
+ [GPRNM16R5Opnd.ParserMatchClass]>;
+}
+
+def GPRNMSPOpnd : RegisterOperand<GPRNMSP> {
+ let ParserMatchClass = GPRNMAsmOperandClass<"RegSP", "GPRNMSPRegClassID",
+ [GPRNM16R3Opnd.ParserMatchClass]>;
+}
+
+def GPRNMGPOpnd : RegisterOperand<GPRNMGP> {
+ let ParserMatchClass = GPRNMAsmOperandClass<"RegGP", "GPRNMGPRegClassID",
+ [GPRNM16R3Opnd.ParserMatchClass]>;
+}
+
+def GPRNMRAOpnd : RegisterOperand<GPRNMRA> {
+ let ParserMatchClass = GPRNMAsmOperandClass<"RegRA", "GPRNMRARegClassID",
+ [GPRNM16R3Opnd.ParserMatchClass]>;
+}
+
+def GPRNM2R1Opnd : RegisterOperand<GPRNM2R1> {
+ let ParserMatchClass = GPRNMAsmOperandClass<"2Reg1", "GPRNM2R1RegClassID",
+ [GPRNM4Opnd.ParserMatchClass]>;
+}
+
+def GPRNM2R2Opnd : RegisterOperand<GPRNM2R2> {
+ let ParserMatchClass = GPRNMAsmOperandClass<"2Reg2", "GPRNM2R2RegClassID",
+ [GPRNM4Opnd.ParserMatchClass]>;
+}
+
+def GPRNM1R1Opnd : RegisterOperand<GPRNM1R1> {
+ let ParserMatchClass = GPRNMAsmOperandClass<"1Reg1", "GPRNM1R1RegClassID",
+ [GPRNM4Opnd.ParserMatchClass]>;
+}
+
def GPR64Opnd : RegisterOperand<GPR64> {
let ParserMatchClass = GPR64AsmOperand;
}
diff --git a/llvm/lib/Target/Mips/MipsSEFrameLowering.cpp b/llvm/lib/Target/Mips/MipsSEFrameLowering.cpp
index ea0652cf6adbe..2680e5c02b93e 100644
--- a/llvm/lib/Target/Mips/MipsSEFrameLowering.cpp
+++ b/llvm/lib/Target/Mips/MipsSEFrameLowering.cpp
@@ -411,7 +411,7 @@ void MipsSEFrameLowering::emitPrologue(MachineFunction &MF,
unsigned ZERO = ABI.GetNullPtr();
unsigned MOVE = ABI.GetGPRMoveOp();
unsigned ADDiu = ABI.GetPtrAddiuOp();
- unsigned AND = ABI.IsN64() ? Mips::AND64 : Mips::AND;
+ unsigned AND = ABI.GetPtrAndOp();
const TargetRegisterClass *RC = ABI.ArePtrs64bit() ?
&Mips::GPR64RegClass : &Mips::GPR32RegClass;
diff --git a/llvm/lib/Target/Mips/MipsSEInstrInfo.cpp b/llvm/lib/Target/Mips/MipsSEInstrInfo.cpp
index b16341dcec0b9..e269b310212ac 100644
--- a/llvm/lib/Target/Mips/MipsSEInstrInfo.cpp
+++ b/llvm/lib/Target/Mips/MipsSEInstrInfo.cpp
@@ -231,6 +231,9 @@ void MipsSEInstrInfo::copyPhysReg(MachineBasicBlock &MBB,
} else if (Mips::MSA128BRegClass.contains(DestReg)) { // Copy to MSA reg
if (Mips::MSA128BRegClass.contains(SrcReg))
Opc = Mips::MOVE_V;
+ } else if (Mips::GPRNM32RegClass.contains(SrcReg)) { // Copy nanoMIPS CPU Reg.
+ if (Mips::GPRNM32NZRegClass.contains(DestReg))
+ Opc = Mips::MOVE_NM;
}
// FCMP + FSEL for MIPSr6 may emit
@@ -350,6 +353,8 @@ void MipsSEInstrInfo::storeRegToStack(MachineBasicBlock &MBB,
Opc = Mips::SD;
else if (Mips::DSPRRegClass.hasSubClassEq(RC))
Opc = Mips::SWDSP;
+ else if (Mips::GPRNM32RegClass.hasSubClassEq(RC))
+ Opc = Mips::SW_NM;
// Hi, Lo are normally caller save but they are callee save
// for interrupt handling.
@@ -430,6 +435,8 @@ void MipsSEInstrInfo::loadRegFromStack(MachineBasicBlock &MBB,
Opc = Mips::LD;
else if (Mips::DSPRRegClass.hasSubClassEq(RC))
Opc = Mips::LWDSP;
+ else if (Mips::GPRNM32RegClass.hasSubClassEq(RC))
+ Opc = Mips::LW_NM;
assert(Opc && "Register class not handled!");
diff --git a/llvm/lib/Target/Mips/NanoMipsInstrFormats.td b/llvm/lib/Target/Mips/NanoMipsInstrFormats.td
new file mode 100644
index 0000000000000..022c0efb0a886
--- /dev/null
+++ b/llvm/lib/Target/Mips/NanoMipsInstrFormats.td
@@ -0,0 +1,975 @@
+//===-- NanoMipsInstrFormats.td - nanoMIPS Instr Formats --*- tablegen -*--===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file describes the formats of the nanoMIPS instruction set.
+//
+//===----------------------------------------------------------------------===//
+
+class InstNM_Enc : Instruction, PredicateControl, ISA_NANOMIPS {
+ let Namespace = "Mips";
+ let DecoderNamespace = "NanoMips";
+
+ let EncodingPredicates = [HasNanoMips];
+ string Arch = "nanomips";
+ let AsmVariantName = "nanomips";
+}
+
+class InstNM<dag outs, dag ins, string asmstr, list<dag> pattern = [],
+ InstrItinClass itin = NoItinerary,
+ bit FastISelIgnore = 1>
+ : InstNM_Enc {
+ let OutOperandList = outs;
+ let InOperandList = ins;
+ let AsmString = asmstr;
+ let Pattern = pattern;
+ let FastISelShouldIgnore = FastISelIgnore;
+ bit isCTI = 0; // Any form of Control Transfer Instruction.
+
+ let Itinerary = itin;
+}
+
+class InstSize16 {
+ bits<16> Inst;
+ int Size = 2;
+ bits<16> SoftFail = 0;
+}
+
+class InstSize32 {
+ bits<32> Inst;
+ int Size = 4;
+ bits<32> SoftFail = 0;
+}
+
+class InstSize48 {
+ bits<48> Inst;
+ int Size = 6;
+ bits<48> SoftFail = 0;
+}
+
+class RegConstraint<string C> {
+ string Constraints = C;
+}
+
+class NoEncode<string E> {
+ string DisableEncoding = E;
+}
+
+//===----------------------------------------------------------------------===//
+// Opcode Pools, as specified in the ISA document.
+//===----------------------------------------------------------------------===//
+
+class _Pool_P32<bits<5> psel> : InstSize32 {
+ let Inst{31-26} = {psel{4-2}, 0b0, psel{1-0}};
+}
+
+class _Pool_P_ADDIU<bits<5> psel> : _Pool_P32<0b00000> {
+ let Inst{25-21} = psel;
+}
+
+class _Pool_P32A<bits<3> psel> : _Pool_P32<0b00100> {
+ let Inst{2-0} = psel;
+}
+
+class _Pool_P_GP_W<bits<2> psel> : _Pool_P32<0b01000> {
+ let Inst{1-0} = psel;
+}
+
+class _Pool_P_U12<bits<4> psel> : _Pool_P32<0b10000> {
+ let Inst{15-12} = psel;
+}
+
+class _Pool_P_LUI<bits<1> psel> : _Pool_P32<0b11100> {
+ let Inst{1} = psel;
+}
+
+class _Pool_P48I<bits<5> psel> : InstSize48 {
+ let Inst{47-42} = 0b011000;
+ let Inst{36-32} = psel;
+}
+
+class _Pool_P_GP_BH<bits<3> psel> : _Pool_P32<0b01001> {
+ let Inst{20-18} = psel;
+}
+
+class _Pool_P_LS_U12<bits<4> psel> : _Pool_P32<0b10001> {
+ let Inst{15-12} = psel;
+}
+
+class _Pool_P_LS_S9<bits<3> psel> : _Pool_P32<0b10101> {
+ let Inst{10-8} = psel;
+}
+
+class _Pool_P_BAL<bits<1> psel> : _Pool_P32<0b00110> {
+ let Inst{25} = psel;
+}
+
+class _Pool_P_J<bits<4> psel> : _Pool_P32<0b01010> {
+ let Inst{15-12} = psel;
+}
+
+// Covers both the P.BR1 and P.BR2 pools.
+class _Pool_P_BR12<bits<3> psel> : _Pool_P32<0b10010> {
+ let Inst{29} = psel{2};
+ let Inst{15-14} = psel{1-0};
+}
+
+class _Pool_P_BRI<bits<3> psel> : _Pool_P32<0b11010> {
+ let Inst{20-18} = psel;
+}
+
+class _Pool_P_SHIFT<bits<4> psel> : _Pool_P_U12<0b1100> {
+ bits<5> shift;
+ bits<5> rs;
+ bits<5> rt;
+
+ let Inst{25-21} = rt;
+ let Inst{20-16} = rs;
+ let Inst{8-5} = psel;
+ let Inst{4-0} = shift;
+}
+
+class _Pool_P_EXT_INS<bits<4> psel> : _Pool_P_U12<psel> {
+ let Inst{11} = 0;
+ let Inst{5} = 0;
+}
+
+class _Pool_P_LS_E0<bits<4> psel> : _Pool_P_LS_S9<0b010> {
+ let Inst{14-11} = psel;
+}
+
+class _Pool_P16<bits<5> psel> : InstSize16 {
+ let Inst{15-10} = {psel{4-2}, 0b1, psel{1-0}};
+}
+
+class _Pool_P16_MV : _Pool_P16<0b00000>;
+
+class _Pool_P16_SR<bits<1> psel> : _Pool_P16<0b00011> {
+ let Inst{8} = psel;
+}
+
+class _Pool_P16_SHIFT<bits<1> isel> : _Pool_P16<0b00100> {
+ let Inst{3} = isel;
+}
+
+class _Pool_P16_4X4<bits<2> psel> : _Pool_P16<0b00111> {
+ let Inst{8} = psel{1};
+ let Inst{3} = psel{0};
+}
+
+class _Pool_P16C<bits<1> psel> : _Pool_P16<0b01000> {
+ let Inst{0} = psel;
+}
+
+class _Pool_POOL16C_00<bits<2> psel> : _Pool_P16<0b01000> {
+ let Inst{3-2} = psel;
+ let Inst{1-0} = 0b00;
+}
+
+class _Pool_P16_LB<bits<2> psel> : _Pool_P16<0b01011> {
+ let Inst{3-2} = psel;
+}
+
+class _Pool_P16_A1<bits<1> psel> : _Pool_P16<0b01100> {
+ let Inst{6} = psel;
+}
+
+class _Pool_P16_LH<bits<2> psel> : _Pool_P16<0b01111> {
+ let Inst{3} = psel{1};
+ let Inst{0} = psel{0};
+}
+
+class _Pool_P16_A2<bits<1> psel> : _Pool_P16<0b10000> {
+ let Inst{3} = psel;
+}
+
+class _Pool_P16_ADDU<bits<1> psel> : _Pool_P16<0b10100> {
+ let Inst{0} = psel;
+}
+
+class _Pool_P16_BR<bits<4> psel> : _Pool_P16<0b11010> {
+ let Inst{3-0} = psel;
+}
+
+class _Pool_P16_RI<bits<2> psel> : _Pool_P16_MV {
+ let Inst{4-3} = psel;
+ let Inst{9-5} = 0b00000;
+}
+
+class _Pool_P_RI<bits<2> psel> : _Pool_P_ADDIU<0b00000> {
+ let Inst{20-19} = psel;
+}
+
+class _Pool_POOL32A0<bits<1> psel> : _Pool_P32A<0b000> {
+ let Inst{5} = psel;
+}
+
+class _Pool_POOL32A0_0<bits<6> psel> : _Pool_POOL32A0<0b0> {
+ let Inst{9-6} = psel{5-2};
+ let Inst{4-3} = psel{1-0};
+}
+
+class _Pool_P_TRAP<bits<1> isel> : _Pool_POOL32A0_0<0b000000> {
+ let Inst{10} = isel;
+}
+
+class _Pool_P_CMOVE<bits<1> isel> : _Pool_POOL32A0_0<0b100010> {
+ let Inst{10} = isel;
+}
+
+class _Pool_POOL32A7<bits<3> psel> : _Pool_P32A<0b111> {
+ let Inst{5-3} = psel;
+}
+
+class _Pool_POOL32Axf_4<bits<7> isel> : _Pool_POOL32A7<0b111> {
+ let Inst{15-9} = isel;
+ let Inst{8-6} = 0b100;
+}
+
+class _Pool_POOL32Axf_5<bits<2> psel> : _Pool_POOL32A7<0b111> {
+ let Inst{8-6} = 0b101;
+ let Inst{15-14} = psel;
+}
+
+class _Pool_POOL32Axf_5_group0<bits<5> isel> : _Pool_POOL32Axf_5<0b00> {
+ let Inst{13-9} = isel;
+}
+
+class _Pool_POOL32Axf_5_group1<bits<5> isel> : _Pool_POOL32Axf_5<0b01> {
+ let Inst{13-9} = isel;
+}
+
+class _Pool_POOL32Axf_5_group3<bits<5> isel> : _Pool_POOL32Axf_5<0b11> {
+ let Inst{13-9} = isel;
+}
+
+class _Pool_PP_LSX<bit scaled, bits<4> isel> : _Pool_POOL32A7<0b000> {
+ let Inst{6} = scaled;
+ let Inst{10-7} = isel;
+}
+
+class _Pool_POOL32A0_1<bits<6> psel> : _Pool_POOL32A0<0b1> {
+ let Inst{9-6} = psel{5-2};
+ let Inst{4-3} = psel{1-0};
+}
+
+class _Pool_PP_SR<bits<2> isel> : _Pool_P_U12<0b0011> {
+ let Inst{20} = 0;
+ let Inst{1-0} = isel;
+}
+
+//===----------------------------------------------------------------------===//
+// nanoMIPS Instruction Formats
+//===----------------------------------------------------------------------===//
+
+class Arith4x4_Enc<bits<2> isel> : _Pool_P16_4X4<isel> {
+ bits<5> dst;
+ bits<5> rs;
+ bits<5> rt;
+
+ let Inst{9} = dst{4};
+ let Inst{7-5} = dst{2-0};
+ let Inst{4} = rs{4};
+ let Inst{2-0} = rs{2-0};
+}
+
+class ArithLogicR32_Enc<bits<6> psel> : _Pool_POOL32A0_0<psel> {
+ bits<5> rd;
+ bits<5> rs;
+ bits<5> rt;
+ let Inst{25-21} = rt;
+ let Inst{20-16} = rs;
+ let Inst{15-11} = rd;
+}
+
+class ArithLogicR16_Enc<bits<2> isel> : _Pool_POOL16C_00<isel> {
+ bits<3> rs;
+ bits<3> rd;
+ let Inst{9-7} = rd;
+ let Inst{6-4} = rs;
+}
+
+class CLZO_Enc<bits<7> isel> : _Pool_POOL32Axf_4<isel> {
+ bits<5> rs;
+ bits<5> rt;
+ let Inst{25-21} = rt;
+ let Inst{20-16} = rs;
+}
+
+class LogicU32_Enc<bits<6> isel> : _Pool_POOL32A0_0<isel> {
+ bits<5> rs;
+ bits<5> rt;
+ let Inst{25-21} = rt;
+ let Inst{20-16} = rs;
+}
+
+class IndirectBranch32_Enc : _Pool_P_J<0b1000> {
+ bits<5> rs;
+ let Inst{25-21} = 0b00000;
+ let Inst{20-16} = rs;
+}
+
+class IndirectBranch16_Enc<bits<1> isel> : _Pool_P16_BR<0b0000> {
+ bits<5> rs;
+ let Inst{9-5} = rs;
+ let Inst{4} = isel;
+}
+
+class IndirectCall32_Enc<bits<4> isel> : _Pool_P_J<isel> {
+ bits<5> rt;
+ bits<5> rs;
+ let Inst{25-21} = rt;
+ let Inst{20-16} = rs;
+}
+
+class IndirectCall16_Enc : _Pool_P16_BR<0b0000> {
+ bits<5> rt;
+ bits<5> rs;
+ let Inst{9-5} = rs;
+ let Inst{4} = rt{0}; // always 1, forced for disassembly of JALRC[16]
+}
+
+class LI16_Enc<bits<5> isel> : _Pool_P16<isel> {
+ bits<3> rt;
+ bits<7> eu;
+ let Inst{9-7} = rt;
+ let Inst{6-0} = eu;
+}
+
+class BC16_Enc<bits<5> isel> : _Pool_P16<isel> {
+ bits<11> addr;
+ let Inst{9-1} = addr{9-1};
+ let Inst{0} = addr{10};
+}
+
+class BC32_Enc<bits<1> isel> : _Pool_P_BAL<isel> {
+ bits<26> addr;
+ let Inst{24-1} = addr{24-1};
+ let Inst{0} = addr{25};
+}
+
+class AddSubR16_Enc<bits<1> isel> : _Pool_P16_ADDU<isel> {
+ bits<3> rd;
+ bits<3> rs;
+ bits<3> rt;
+ let Inst{15-10} = 0b101100;
+ let Inst{9-7} = rt;
+ let Inst{6-4} = rs;
+ let Inst{3-1} = rd;
+}
+
+class ANDI16_Enc<bits<5> isel> : _Pool_P16<isel> {
+ bits<3> rt;
+ bits<3> rs;
+ bits<4> imm;
+ let Inst{9-7} = rt;
+ let Inst{6-4} = rs;
+ let Inst{3-0} = imm;
+}
+
+class SaveRestore32_Enc<bits<2> isel> : _Pool_PP_SR<isel> {
+ bits<12> adj;
+ bits<10> regs;
+ let Inst{11-3} = adj{11-3};
+ let Inst{25-21} = regs{9-5};
+ let Inst{19-16} = regs{4-1};
+ let Inst{2} = regs{0};
+}
+
+class SaveRestore16_Enc<bits<1> isel> : _Pool_P16_SR<isel> {
+ bits<8> adj;
+ bits<5> regs;
+ let Inst{7-4} = adj{7-4};
+ let Inst{9} = regs{4};
+ let Inst{3-0} = regs{3-0};
+}
+
+class CondLogicI32_Enc<bits<4> psel> : _Pool_P_U12<psel> {
+ bits<5> rt;
+ bits<5> rs;
+ bits<12> imm;
+ let Inst{25-21} = rt;
+ let Inst{20-16} = rs;
+ let Inst{11-0} = imm;
+}
+
+class ShiftI16_Enc<bits<1> isel> : _Pool_P16_SHIFT<isel> {
+ bits<3> rt;
+ bits<3> rs;
+ bits<3> imm;
+ let Inst{9-7} = rt;
+ let Inst{6-4} = rs;
+ let Inst{2-0} = imm;
+}
+
+class ShiftI32_Enc<bits<4> psel> : _Pool_P_SHIFT<psel> {
+ bits<5> rt;
+ bits<5> rs;
+ bits<5> imm;
+ let Inst{25-21} = rt;
+ let Inst{20-16} = rs;
+ let Inst{4-0} = imm;
+}
+
+class ExtInsBase_Enc<bits<4> isel> : _Pool_P_EXT_INS<isel> {
+ bits<5> rt;
+ bits<5> rs;
+ bits<5> pos;
+ bits<5> size;
+
+ let Inst{25-21} = rt;
+ let Inst{20-16} = rs;
+ let Inst{4-0} = pos;
+ let Inst{10-6} = size;
+}
+
+class AddIU_Enc : _Pool_P32<0b00000> {
+ bits<5> rt;
+ bits<5> rs;
+ bits<16> imm;
+ let Inst{25-21} = rt;
+ let Inst{20-16} = rs;
+ let Inst{15-0} = imm;
+}
+
+class ADDIUR2_Enc : _Pool_P16_A2<0b0> {
+ bits<3> rt;
+ bits<3> rs;
+ bits<5> imm;
+ let Inst{9-7} = rt;
+ let Inst{6-4} = rs;
+ let Inst{2-0} = imm{4-2};
+}
+
+class ADDIURS5_Enc : _Pool_P16_A2<0b1> {
+ bits<5> rt;
+ bits<4> imm;
+ let Inst{9-5} = rt;
+ let Inst{4} = imm{3};
+ let Inst{2-0} = imm{2-0};
+}
+
+class ADDIUR1SP_Enc : _Pool_P16_A1<0b1> {
+ bits<3> rt;
+ bits<8> imm;
+ let Inst{9-7} = rt;
+ let Inst{5-0} = imm{7-2};
+}
+
+class ADDIUGPB_Enc : _Pool_P_GP_BH<0b011> {
+ bits<5> rt;
+ bits<18> offset;
+ let Inst{25-21} = rt;
+ let Inst{17-0} = offset;
+ }
+
+class ADDIUGPW_Enc : _Pool_P_GP_W<0b00> {
+ bits<5> rt;
+ bits<21> offset;
+ let Inst{25-21} = rt;
+ let Inst{20-2} = offset{20-2};
+}
+
+class Op48_Imm_Enc<bits<5> isel> : _Pool_P48I<isel> {
+ bits<5> rt;
+ bits<32> imm;
+ let Inst{41-37} = rt;
+ let Inst{31-16} = imm{15-0};
+ let Inst{15-0} = imm{31-16};
+}
+
+class Op32_Addr_Enc<bits<5> isel> : _Pool_P32<isel> {
+ bits<5> rt;
+ bits<22> addr;
+ let Inst{25-21} = rt;
+ let Inst{20-1} = addr{20-1};
+ let Inst{0} = addr{21};
+}
+
+class Op48_Addr_Enc<bits<5> isel> : _Pool_P48I<isel> {
+ bits<5> rt;
+ bits<32> addr;
+ let Inst{41-37} = rt;
+ let Inst{31-16} = addr{15-0};
+ let Inst{15-0} = addr{31-16};
+}
+
+class LoadScaledAddress_Enc: _Pool_POOL32A7<0b001> {
+ bits<5> rd;
+ bits<5> rs;
+ bits<5> rt;
+ bits<2> shift;
+ let Inst{25-21} = rt;
+ let Inst{20-16} = rs;
+ let Inst{15-11} = rd;
+ let Inst{10-9} = shift;
+}
+
+class Trap_Enc<bits<1> isel> : _Pool_P_TRAP<isel> {
+ bits<5> rt;
+ bits<5> rs;
+ bits<5> imm;
+ let Inst{25-21} = rt;
+ let Inst{20-16} = rs;
+ let Inst{15-11} = imm;
+}
+
+class LUI_Enc<bits<1> isel> : _Pool_P_LUI<isel> {
+ bits<5> rt;
+ bits<20> imm;
+ let Inst{25-21} = rt;
+ let Inst{20-12} = imm{8-0};
+ let Inst{11-2} = imm{18-9};
+ let Inst{0} = imm{19};
+}
+
+class RDHWR_Enc : _Pool_POOL32A0_0<0b011100> {
+ bits<5> rt;
+ bits<5> hs;
+ bits<5> sel;
+ let Inst{25-21} = rt;
+ let Inst{20-16} = hs;
+ let Inst{15-11} = sel;
+}
+
+class B14_Enc<bits<3> isel> : _Pool_P_BR12<isel> {
+ bits<5> rt;
+ bits<5> rs;
+ bits<15> offset;
+ let Inst{25-21} = rt;
+ let Inst{20-16} = rs;
+ let Inst{13-1} = offset{13-1};
+ let Inst{0} = offset{14};
+}
+
+class B4_Enc : _Pool_P16<0b11010> {
+ bits<3> rs;
+ bits<3> rt;
+ bits<4> offset;
+ let Inst{9-7} = rt;
+ let Inst{6-4} = rs;
+ let Inst{3-0} = offset;
+}
+
+class BZ16_Enc<bits<5> isel> : _Pool_P16<isel> {
+ bits<3> rs;
+ bits<8> offset;
+ let Inst{9-7} = rs;
+ let Inst{6-1} = offset{6-1};
+ let Inst{0} = offset{7};
+}
+
+class BRI_Enc<bits<3> isel> : _Pool_P_BRI<isel> {
+ bits<5> rt;
+ bits<7> u;
+ bits<12> offset;
+ let Inst{25-21} = rt;
+ let Inst{17-11} = u;
+ let Inst{10-1} = offset{10-1};
+ let Inst{0} = offset{11};
+}
+
+class BBit_Enc<bits<3> isel> : _Pool_P_BRI<isel> {
+ bits<5> rt;
+ bits<6> u;
+ bits<12> offset;
+ let Inst{25-21} = rt;
+ let Inst{16-11} = u;
+ let Inst{10-1} = offset{10-1};
+ let Inst{0} = offset{11};
+}
+
+class LSSPRegMem16_Enc<bits<5> isel> : _Pool_P16<isel> {
+ bits<5> rt;
+ bits<7> addr;
+ bits<5> offset = addr{6-2};
+ let Inst{9-5} = rt;
+ let Inst{4-0} = offset;
+}
+
+class LSGPRegMem16_Enc<bits<5> isel> : _Pool_P16<isel> {
+ bits<3> rt;
+ bits<9> addr;
+ bits<7> offset = addr{8-2};
+ let Inst{9-7} = rt;
+ let Inst{6-0} = offset;
+}
+
+class LSMem16_Enc<bits<5> isel> : _Pool_P16<isel> {
+ bits<3> rt;
+ bits<9> addr;
+ bits<3> base = addr{8-6};
+ bits<4> offset = addr{5-2};
+ let Inst{9-7} = rt;
+ let Inst{6-4} = base;
+ let Inst{3-0} = offset;
+}
+
+class LHMem16_Enc<bits<2> isel> : _Pool_P16_LH<isel> {
+ bits<3> rt;
+ bits<6> addr;
+ bits<3> base = addr{5-3};
+ bits<3> offset = addr{2-0};
+ let Inst{9-7} = rt;
+ let Inst{6-4} = base;
+ let Inst{2-1} = offset{2-1};
+}
+
+class LBMem16_Enc<bits<2> isel> : _Pool_P16_LB<isel> {
+ bits<3> rt;
+ bits<5> addr;
+ bits<3> base = addr{4-2};
+ bits<2> offset = addr{1-0};
+ let Inst{9-7} = rt;
+ let Inst{6-4} = base;
+ let Inst{1-0} = offset{1-0};
+}
+
+class LSMemGP19S2_Enc<bits<2> isel> : _Pool_P_GP_W<isel> {
+ bits<5> rt;
+ bits<21> addr;
+ let Inst{25-21} = rt;
+ let Inst{20-2} = addr{20-2};
+}
+
+class LSMemGP18_Enc<bits<3> isel> : _Pool_P_GP_BH<isel> {
+ bits<5> rt;
+ bits<18> addr;
+ let Inst{25-21} = rt;
+ let Inst{17-0} = addr;
+}
+
+class LSMemGP17S1_Enc<bits<4> isel> : _Pool_P_GP_BH<isel{3-1}> {
+ bits<5> rt;
+ bits<18> addr;
+ let Inst{25-21} = rt;
+ let Inst{17-1} = addr{17-1};
+ let Inst{0} = isel{0};
+}
+
+class LSMem_U12_Enc<bits<4> isel> : _Pool_P_LS_U12<isel> {
+ bits<5> rt;
+ bits<17> addr;
+ bits<5> base = addr{16-12};
+ bits<12> offset = addr{11-0};
+ let Inst{25-21} = rt;
+ let Inst{20-16} = base;
+ let Inst{11-0} = offset;
+}
+
+class LSMemX_Enc<bit scaled, bits<4> isel> : _Pool_PP_LSX<scaled, isel> {
+ bits<5> rt;
+ bits<10> addr;
+ let Inst{25-21} = addr{9-5};
+ let Inst{20-16} = addr{4-0};
+ let Inst{15-11} = rt;
+}
+
+class LSMemXS16_Enc : _Pool_P16C<0b1> {
+ bits<3> rt;
+ // Uses same encoding method as LWXS to get 5+5 register bits
+ // but only needs the lower 3 bits of each register.
+ bits<10> addr;
+ let Inst{9-7} = addr{7-5}; // Discard {9-8}
+ let Inst{6-4} = addr{2-0}; // Discard {4-3}
+ let Inst{3-1} = rt;
+}
+
+class LSMem_S9_Enc<bits<3> psel, bits<4> isel> : _Pool_P_LS_S9<psel> {
+ bits<5> rt;
+ bits<14> addr;
+ bits<5> base = addr{13-9};
+ bits<9> offset = addr{8-0};
+ let Inst{25-21} = rt;
+ let Inst{20-16} = base;
+ let Inst{14-11} = isel;
+ let Inst{15} = offset{8};
+ let Inst{7-0} = offset{7-0};
+}
+
+class LSMem_S9_Mult_Enc<bits<4> isel> : _Pool_P_LS_S9<isel{2-0}> {
+ bits<5> rt;
+ bits<14> addr;
+ bits<5> base = addr{13-9};
+ bits<9> offset = addr{8-0};
+ bits<3> rcount;
+ let Inst{25-21} = rt;
+ let Inst{20-16} = base;
+ let Inst{11} = isel{3};
+ let Inst{15} = offset{8};
+ let Inst{7-0} = offset{7-0};
+ let Inst{14-12} = rcount;
+}
+
+class LSMem4x4_Enc<bits<5> isel> : _Pool_P16<isel> {
+ bits<5> rt;
+ bits<9> addr;
+ bits<5> rs = addr{8-4};
+ bits<4> offset = addr{3-0};
+ let Inst{9} = rt{4};
+ let Inst{7-5} = rt{2-0};
+ let Inst{4} = rs{4};
+ let Inst{2-0} = rs{2-0};
+ let Inst{3} = offset{3};
+ let Inst{8} = offset{2};
+}
+
+class MOVE_Enc : _Pool_P16_MV {
+ bits<5> rt;
+ bits<5> rs;
+ let Inst{9-5} = rt;
+ let Inst{4-0} = rs;
+}
+
+class MOVEP_Enc<bits<5> isel> : _Pool_P16<isel> {
+ bits<2> dst1;
+ bits<5> src1;
+ bits<5> src2;
+
+ let Inst{9} = src2{4};
+ let Inst{7-5} = src2{2-0};
+ let Inst{4} = src1{4};
+ let Inst{2-0} = src1{2-0};
+ let Inst{8} = dst1{0};
+ let Inst{3} = dst1{1};
+}
+
+class MOVEPREV_Enc<bits<5> isel> : _Pool_P16<isel> {
+ bits<2> src1;
+ bits<5> dst1;
+ bits<5> dst2;
+
+ let Inst{9} = dst2{4};
+ let Inst{7-5} = dst2{2-0};
+ let Inst{4} = dst1{4};
+ let Inst{2-0} = dst1{2-0};
+ let Inst{8} = src1{0};
+ let Inst{3} = src1{1};
+}
+
+class MOVEBALC_Enc : _Pool_P32<0b00010> {
+ bits<5> rt;
+ bits<1> rd;
+ bits<22> addr;
+ let Inst{25} = rt{4};
+ let Inst{24} = rd;
+ let Inst{23-21} = rt{2-0};
+ let Inst{20-1} = addr{20-1};
+ let Inst{0} = addr{21};
+}
+
+class LLSC_Enc<bits<3> psel, bits<4>isel> : _Pool_P_LS_S9<psel> {
+ bits<5> rt;
+ bits<14> addr;
+ bits<5> base = addr{13-9};
+ bits<9> offset = addr{8-0};
+ let Inst{25-21} = rt;
+ let Inst{20-16} = base;
+ let Inst{15} = offset{8};
+ let Inst{14-11} = isel;
+ let Inst{7-2} = offset{7-2};
+ let Inst{1-0} = 0b00;
+}
+
+class LLSCWP_Enc<bits<3> psel, bits<4> isel> : _Pool_P_LS_S9<psel> {
+ bits<5> rt;
+ bits<5> ru;
+ bits<5> addr;
+ let Inst{25-21} = rt;
+ let Inst{20-16} = addr;
+ let Inst{14-11} = isel;
+ let Inst{7-3} = ru;
+ let Inst{1-0} = 0b01;
+}
+
+class CondMove_Enc<bits<1> isel> : _Pool_P_CMOVE<isel> {
+ bits<5> rd;
+ bits<5> rs;
+ bits<5> rt;
+ let Inst{25-21} = rt;
+ let Inst{20-16} = rs;
+ let Inst{15-11} = rd;
+}
+
+class ToggleInterrupts_Enc<bits<5> isel> : _Pool_POOL32Axf_5_group1<isel> {
+ bits<5> rt;
+ let Inst{25-21} = rt;
+}
+
+class ERET_Enc<bits<5> psel, bits<1> isel> : _Pool_POOL32Axf_5_group3<psel> {
+ let Inst{16} = isel;
+}
+
+class SLL_VAR_Enc<bits<5> sh> : _Pool_P_SHIFT<0b0000> {
+ let Inst{25-21} = 0b00000;
+ let Inst{20-16} = 0b00000;
+ let Inst{4-0} = sh;
+}
+
+class NOP_Enc : _Pool_P16_A2<0b1> {
+ let Inst{9-5} = 0b00000;
+ let Inst{4} = 0b0;
+ let Inst{2-0} = 0b000;
+}
+
+class IntExcpFlow_Enc<bits<2> isel, int immsize = 19> : _Pool_P_RI<isel> {
+ bits<19> imm;
+ let Inst{18} = !if(!eq(immsize, 19), imm{18}, 0b0);
+ let Inst{17-0} = imm{17-0};
+}
+
+class IntExcpFlow16_Enc<bits<2> isel, int immsize = 3> : _Pool_P16_RI<isel> {
+ bits<3> imm;
+ let Inst{2} = !if(!eq(immsize, 3), imm{2}, 0b0);
+ let Inst{1-0} = imm{1-0};
+}
+
+class ShadowRW_Enc<bits<5> isel> : _Pool_POOL32Axf_5_group3<isel> {
+ bits<5> rs;
+ bits<5> rt;
+ let Inst{25-21} = rt;
+ let Inst{20-16} = rs;
+}
+
+class EXTW_Enc : _Pool_POOL32A7<0b011> {
+ bits<5> rd;
+ bits<5> rs;
+ bits<5> rt;
+ bits<5> shift;
+ let Inst{25-21} = rt;
+ let Inst{20-16} = rs;
+ let Inst{15-11} = rd;
+ let Inst{10-6} = shift;
+}
+
+class RotxAliasBase_Enc : _Pool_P_U12<0b1101> {
+ bits<5> rt;
+ bits<5> rs;
+ let Inst{25-21} = rt;
+ let Inst{20-16} = rs;
+ let Inst{11} = 0;
+ let Inst{5} = 0;
+}
+
+class RotxAlias_Enc<bits<5> shift, bits<5> shiftx, bit stripe>
+ : RotxAliasBase_Enc {
+ let Inst{10-7} = shiftx{4-1};
+ let Inst{4-0} = shift;
+ let Inst{6} = stripe;
+}
+
+class ROTX_Enc : RotxAliasBase_Enc {
+ bits<5> shift;
+ bits<5> shiftx;
+ bits<1> stripe;
+ let Inst{10-7} = shiftx{4-1};
+ let Inst{4-0} = shift;
+ let Inst{6} = stripe;
+}
+
+class CACHE_PREFs9_Enc<bits<3> psel, bits<4> isel> : _Pool_P_LS_S9<psel> {
+ bits<5> op;
+ bits<14> addr;
+ bits<5> base = addr{13-9};
+ bits<9> offset = addr{8-0};
+ let Inst{25-21} = op;
+ let Inst{20-16} = base;
+ let Inst{15} = offset{8};
+ let Inst{14-11} = isel;
+ let Inst{7-0} = offset{7-0};
+}
+
+class PREF_Enc : _Pool_P_LS_U12<0b0011> {
+ bits<5> op;
+ bits<17> addr;
+ bits<5> base = addr{16-12};
+ bits<12> offset = addr{11-0};
+ let Inst{25-21} = op;
+ let Inst{20-16} = base;
+ let Inst{11-0} = offset{11-0};
+}
+
+class SYNC_Enc : _Pool_P_SHIFT<0b0000> {
+ bits<5> stype;
+
+ let Inst{25-21} = 0b00000;
+ let Inst{20-16} = stype;
+ let Inst{4-0} = 0b00110;
+}
+
+class SYNCIs9_SYNCIE_Enc<bits<3> psel, bits<4> isel> : _Pool_P_LS_S9<psel> {
+ bits<14> addr;
+ bits<5> base = addr{13-9};
+ bits<9> offset = addr{8-0};
+ let Inst{25-21} = 0b11111;
+ let Inst{20-16} = base;
+ let Inst{15} = offset{8};
+ let Inst{14-11} = isel;
+ let Inst{7-0} = offset{7-0};
+}
+
+class SYNCI_Enc : _Pool_P_LS_U12<0b0011> {
+ bits<17> addr;
+ bits<5> base = addr{16-12};
+ bits<12> offset = addr{11-0};
+ let Inst{25-21} = 0b11111;
+ let Inst{20-16} = base;
+ let Inst{11-0} = offset;
+}
+
+class WAIT_Enc : _Pool_POOL32Axf_5_group3<0b00001> {
+ bits<10> cd;
+ let Inst{25-16} = cd;
+}
+
+class ReadWriteCP0_Enc<bits<6> isel> : _Pool_POOL32A0_1<isel> {
+ bits<5> rt;
+ bits<5> c0s;
+ bits<5> sel;
+
+ let Inst{25-21} = rt;
+ let Inst{20-16} = c0s;
+ let Inst{15-11} = sel;
+}
+
+class ReadWriteCP0Sel_Enc<bits<6> isel> : _Pool_POOL32A0_1<isel> {
+ bits<5> rt;
+ bits<10> c0s;
+
+ let Inst{25-21} = rt;
+ let Inst{20-11} = c0s;
+}
+
+class GINVI_Enc<bits<5> isel> : _Pool_POOL32Axf_5_group0<isel> {
+ bits<5> rs;
+
+ let Inst{20-16} = rs;
+}
+
+class GINVT_Enc<bits<5> isel> : GINVI_Enc<isel> {
+ bits<2> type;
+
+ let Inst{22-21} = type;
+}
+
+class CRC_Enc<bits<3> isel> : _Pool_POOL32A0_1<0b111101> {
+ bits<5> rt;
+ bits<5> rs;
+
+ let Inst{25-21} = rt;
+ let Inst{20-16} = rs;
+ let Inst{12-10} = isel;
+}
+
+class VP_Enc<bits<1> p> : _Pool_POOL32A0_0<0b111010> {
+ bits<5> rt;
+
+ let Inst{25-21} = rt;
+ let Inst{20-16} = 0b00000;
+ let Inst{15-11} = 0b00000;
+ let Inst{10} = p;
+}
diff --git a/llvm/lib/Target/Mips/NanoMipsInstrInfo.td b/llvm/lib/Target/Mips/NanoMipsInstrInfo.td
new file mode 100644
index 0000000000000..16fb42c84898d
--- /dev/null
+++ b/llvm/lib/Target/Mips/NanoMipsInstrInfo.td
@@ -0,0 +1,997 @@
+//===-- NanoMipsInstrInfo.td - nanoMIPS Instr Information --*- tablegen -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file describes NanoMips instructions.
+//
+//===----------------------------------------------------------------------===//
+
+//===----------------------------------------------------------------------===//
+// Mips profiles and nodes
+//===----------------------------------------------------------------------===//
+
+// TODO: Add nodes
+
+//===----------------------------------------------------------------------===//
+// nanoMIPS Operand, Complex Patterns and Transformations Definitions.
+//===----------------------------------------------------------------------===//
+
+def uimm2_nm : Operand<i32>;
+def uimm2code_nm : Operand<i32>;
+def uimm3_nm : Operand<i32>;
+def uimm3shift_nm : Operand<i32>;
+def uimm4mask_nm : Operand<i32>;
+def uimm3plus1_nm : Operand<i32>;
+def uimm5s2_nm : Operand<i32>;
+def uimm6_nm : Operand<i32>;
+def uimm8s2_nm : Operand<i32>;
+def uimm8s4_nm : Operand<i32>;
+def uimm12_nm : Operand<i32>;
+def uimm12mask_nm : Operand<i32>;
+def uimm12s3_nm : Operand<i32>;
+def uimm16_nm : Operand<i32>;
+def uimm18_nm : Operand<i32>;
+def uimm19_nm : Operand<i32>;
+def uimm5s1_nm : Operand<i32>;
+def simm22s1_nm : Operand<i32>;
+def simm32_nm : Operand<i32>;
+def simm32s12_nm : Operand<i32>;
+def simm32s12_pcrel_nm : Operand<i32>;
+def nimm7_nm : Operand<i32>;
+def nimm12_nm : Operand<i32>;
+
+def mem_nm_sp5s2 : Operand<iPTR>;
+def mem_nm_gp7s2 : Operand<iPTR>;
+def mem_nm_6s2 : Operand<iPTR>;
+def mem_nm_3s1 : Operand<iPTR>;
+def mem_nm_2 : Operand<iPTR>;
+def mem_nm_gp19s2 : Operand<iPTR>;
+def mem_nm_gp18 : Operand<iPTR>;
+def mem_nm_gp17s1 : Operand<iPTR>;
+def mem_nm_u12 : Operand<iPTR>;
+def mem_nm_s9 : Operand<iPTR>;
+def mem_nm_rx : Operand<iPTR>;
+def mem_nm_rx16 : Operand<iPTR>;
+def mem_nm_4s2 : Operand<iPTR>;
+def mem_nm_7s2 : Operand<iPTR>;
+def mem_nm_0 : Operand<iPTR>;
+def mem_nm_0_no_offset : Operand<iPTR>;
+
+def reglist16_nm : Operand<OtherVT>;
+def reglist_nm : Operand<OtherVT>;
+
+foreach I = {7, 10, 11, 14, 25} in
+ def brtarget # I # _nm : Operand<OtherVT>;
+
+def brtarget4s1_nm : Operand<OtherVT>;
+
+def calltarget21_nm : Operand<iPTR>;
+def calltarget10_nm : Operand<iPTR>;
+def calltarget25_nm : Operand<iPTR>;
+
+def sym32_pc_nm : Operand<pAny>;
+def sym32_pc22_nm : Operand<pAny>;
+def sym32_gp_nm : Operand<pAny>;
+def sym32_gp18_nm : Operand<pAny>;
+def sym32_gp19s2_nm : Operand<pAny>;
+def sym32_nm : Operand<pAny>;
+
+//===----------------------------------------------------------------------===//
+// Instruction Descriptions
+//===----------------------------------------------------------------------===//
+
+// 16-bit arithmetic and logical instructions with 4x4 register operands
+// P16_4X4
+class Arith4x4_Desc<string opstr, RegisterOperand RO>
+ : InstNM<(outs RO:$dst), (ins RO:$rt, RO:$rs),
+ !strconcat(opstr, "\t$dst, $rt, $rs")>;
+
+// 32-bit arithmetic and logical instructions with 3 register operands.
+class ArithLogicR32_Desc<string opstr, RegisterOperand RO>
+ : InstNM<(outs RO:$rd), (ins RO:$rs, RO:$rt),
+ !strconcat(opstr, "\t$rd, $rs, $rt")>;
+
+// 16-bit arithmetic and logical instructions with 2 register operands
+// POOL16C_0
+class ArithLogicR16_Desc<string opstr, RegisterOperand RO>
+ : InstNM<(outs RO:$rd), (ins RO:$rs, RO:$rt),
+ !strconcat(opstr, "\t$rd, $rs, $rt")>;
+
+class ArithLogicR16U_Desc<string opstr, RegisterOperand RO>
+ : InstNM<(outs RO:$rd), (ins RO:$rs),
+ !strconcat(opstr, "\t$rd, $rs")>;
+
+// 16-bit arithmetic instructions with 2 register operands, POOL16C_0
+class AddSubR16_Desc<string opstr, RegisterOperand RO>
+ : InstNM<(outs RO:$rd), (ins RO:$rs, RO:$rt),
+ !strconcat(opstr, "\t$rd, $rs, $rt")>;
+
+class ArithLogicINM2Reg_Desc<string opstr, Operand Od, RegisterOperand DRO,
+ RegisterOperand SRO>
+ : InstNM<(outs DRO:$rt), (ins SRO:$rs, Od:$imm),
+ !strconcat(opstr, "\t$rt, $rs, $imm")>;
+
+// Arithmetic and logical instructions with 2 register operands and immediate.
+class ArithLogicINM_Desc<string opstr, Operand Od, RegisterOperand RO>
+ : ArithLogicINM2Reg_Desc<opstr, Od, RO, RO>;
+
+class ShiftI_Desc<string opstr, Operand Od, RegisterOperand RO>
+ : ArithLogicINM_Desc<opstr, Od, RO>;
+
+class ExtBase_Desc<RegisterOperand RO = GPRNM32Opnd>
+ : InstNM<(outs RO:$rt), (ins RO:$rs, uimm5:$pos, uimm5_plus1:$size),
+ "ext\t$rt, $rs, $pos, $size">;
+
+class InsBase_Desc<RegisterOperand RO = GPRNM32Opnd>
+ : InstNM<(outs RO:$rt),
+ (ins RO:$rs, uimm5:$pos, uimm5_inssize_plus1:$size, RO:$src),
+ "ins \t$rt, $rs, $pos, $size">, RegConstraint<"$src = $rt">;
+
+class AddImmediate_Desc<string opstr, Operand Od,
+ RegisterOperand DRO, RegisterOperand SRO>
+ : ArithLogicINM2Reg_Desc<opstr, Od, DRO, SRO>;
+
+class CondLogicI32_Desc<string opstr, Operand Od, RegisterOperand RO>
+ : ArithLogicINM_Desc<opstr, Od, RO>;
+
+let isMoveReg = 1 in {
+ class MoveBase_Desc
+ : InstNM<(outs GPRNM32NZOpnd:$rt), (ins GPRNM32Opnd:$rs),
+ "move\t$rt, $rs">;
+
+ class MovePBase_Desc<RegisterOperand SR1O, RegisterOperand SR2O,
+ RegisterOperand DR1O, RegisterOperand DR2O>
+ : InstNM<(outs DR1O:$dst1, DR2O:$dst2), (ins SR1O:$src1, SR2O:$src2),
+ "movep\t$dst1, $dst2, $src1, $src2">;
+}
+
+class Call_Desc<string opstr, DAGOperand calltarget>
+ : InstNM<(outs), (ins calltarget:$addr), !strconcat(opstr, "\t$addr")> {
+ let isCall = 1;
+ let isCTI = 1;
+ let Defs = [RA_NM];
+}
+
+// Indirect branch instruction.
+class IndirectBranch_Desc<string opstr, RegisterOperand RO>
+ : InstNM<(outs), (ins RO:$rs), !strconcat(opstr, "\t$rs")> {
+ let isTerminator = 1;
+ let isBarrier = 1;
+ let isCTI = 1;
+ let isBranch = 1;
+ let isIndirectBranch = 1;
+}
+
+class BCBase_Desc<DAGOperand brtarget>
+ : InstNM<(outs), (ins brtarget:$addr), "bc\t$addr"> {
+ let isTerminator = 1;
+ let isBarrier = 1;
+ let isBranch = 1;
+ let isCTI = 1;
+}
+
+class LoadImmAsm_Desc<string opstr, RegisterOperand RO, Operand Od>
+ : InstNM<(outs RO:$rt), (ins Od:$eu), !strconcat(opstr, "\t$rt, $eu")>;
+
+class LoadAddressAbs_Desc<string opstr, RegisterOperand RO, DAGOperand MO>
+ : InstNM<(outs RO:$rt), (ins MO:$imm), !strconcat(opstr, "\t$rt, $imm")>;
+
+//===----------------------------------------------------------------------===//
+// Instruction Definitions
+//===----------------------------------------------------------------------===//
+
+// 16-bit register operations
+def NOT16_NM : ArithLogicR16U_Desc<"not", GPRNM16R3Opnd>,
+ ArithLogicR16_Enc<0b00>;
+let isCommutable = 1, TwoOperandAliasConstraint = "$rt = $rd" in {
+ def XOR16_NM : ArithLogicR16_Desc<"xor", GPRNM16R3Opnd>,
+ ArithLogicR16_Enc<0b01>;
+ def AND16_NM : ArithLogicR16_Desc<"and", GPRNM16R3Opnd>,
+ ArithLogicR16_Enc<0b10>;
+ def OR16_NM : ArithLogicR16_Desc<"or", GPRNM16R3Opnd>,
+ ArithLogicR16_Enc<0b11>;
+}
+
+let TwoOperandAliasConstraint = "$rs = $rt" in
+def ANDI16_NM : ArithLogicINM2Reg_Desc<"andi", uimm4mask_nm,
+ GPRNM16R3Opnd, GPRNM16R3Opnd>,
+ ANDI16_Enc<0b11100>;
+
+// _POOL32A0_0 pool of instructions.
+let TwoOperandAliasConstraint = "$rs = $rd" in {
+ def SLLV_NM : ArithLogicR32_Desc<"sllv", GPRNM32Opnd>,
+ ArithLogicR32_Enc<0b000010>;
+ def SRLV_NM : ArithLogicR32_Desc<"srlv", GPRNM32Opnd>,
+ ArithLogicR32_Enc<0b000110>;
+ def SRAV_NM : ArithLogicR32_Desc<"srav", GPRNM32Opnd>,
+ ArithLogicR32_Enc<0b001010>;
+ def ROTRV_NM: ArithLogicR32_Desc<"rotrv", GPRNM32Opnd>,
+ ArithLogicR32_Enc<0b001110>;
+ def ADD_NM : ArithLogicR32_Desc<"add", GPRNM32Opnd>,
+ ArithLogicR32_Enc<0b010010>;
+ def ADDu_NM : ArithLogicR32_Desc<"addu", GPRNM32Opnd>,
+ ArithLogicR32_Enc<0b010110>;
+ def SUB_NM : ArithLogicR32_Desc<"sub", GPRNM32Opnd>,
+ ArithLogicR32_Enc<0b011010>;
+ def SUBu_NM : ArithLogicR32_Desc<"subu", GPRNM32Opnd>,
+ ArithLogicR32_Enc<0b011110>;
+ def AND_NM : ArithLogicR32_Desc<"and", GPRNM32Opnd>,
+ ArithLogicR32_Enc<0b100110>;
+ def OR_NM : ArithLogicR32_Desc<"or", GPRNM32Opnd>,
+ ArithLogicR32_Enc<0b101010>;
+ def NOR_NM : ArithLogicR32_Desc<"nor", GPRNM32Opnd>,
+ ArithLogicR32_Enc<0b101110>;
+ def XOR_NM : ArithLogicR32_Desc<"xor", GPRNM32Opnd>,
+ ArithLogicR32_Enc<0b110010>;
+ def SLT_NM : ArithLogicR32_Desc<"slt", GPRNM32Opnd>,
+ ArithLogicR32_Enc<0b110110>;
+ def SLTU_NM : ArithLogicR32_Desc<"sltu", GPRNM32Opnd>,
+ ArithLogicR32_Enc<0b111010>;
+ def MUL_NM : ArithLogicR32_Desc<"mul", GPRNM32Opnd>,
+ ArithLogicR32_Enc<0b000011>;
+ def MUH_NM : ArithLogicR32_Desc<"muh", GPRNM32Opnd>,
+ ArithLogicR32_Enc<0b000111>;
+ def MULU_NM : ArithLogicR32_Desc<"mulu", GPRNM32Opnd>,
+ ArithLogicR32_Enc<0b001011>;
+ def MUHU_NM : ArithLogicR32_Desc<"muhu", GPRNM32Opnd>,
+ ArithLogicR32_Enc<0b001111>;
+ def DIV_NM : ArithLogicR32_Desc<"div", GPRNM32Opnd>,
+ ArithLogicR32_Enc<0b010011>;
+ def MOD_NM : ArithLogicR32_Desc<"mod", GPRNM32Opnd>,
+ ArithLogicR32_Enc<0b010111>;
+ def DIVU_NM : ArithLogicR32_Desc<"divu", GPRNM32Opnd>,
+ ArithLogicR32_Enc<0b011011>;
+ def MODU_NM : ArithLogicR32_Desc<"modu", GPRNM32Opnd>,
+ ArithLogicR32_Enc<0b011111>;
+ def SOV_NM : ArithLogicR32_Desc<"sov", GPRNM32Opnd>,
+ ArithLogicR32_Enc<0b111110>;
+}
+
+// 16-bit register operations
+def SUBu16_NM : AddSubR16_Desc<"subu", GPRNM16R3Opnd>,
+ AddSubR16_Enc<0b1>;
+let isCommutable = 1 in {
+ def ADDu16_NM : AddSubR16_Desc<"addu", GPRNM16R3Opnd>,
+ AddSubR16_Enc<0b0>;
+ def ADDu4x4_NM : Arith4x4_Desc<"addu", GPRNM4Opnd>,
+ Arith4x4_Enc<0b00>;
+ def MUL4x4_NM : Arith4x4_Desc<"mul", GPRNM4Opnd>,
+ Arith4x4_Enc<0b01>;
+}
+
+let TwoOperandAliasConstraint = "$rs = $rt" in
+def ORI_NM : CondLogicI32_Desc<"ori", uimm12mask_nm, GPRNM32Opnd>,
+ CondLogicI32_Enc<0b0000>;
+
+def XORI_NM : CondLogicI32_Desc<"xori", uimm12mask_nm, GPRNM32Opnd>,
+ CondLogicI32_Enc<0b0001>;
+def ANDI_NM : CondLogicI32_Desc<"andi", uimm12mask_nm, GPRNM32Opnd>,
+ CondLogicI32_Enc<0b0010>;
+def SLTI_NM : CondLogicI32_Desc<"slti", uimm12_nm, GPRNM32Opnd>,
+ CondLogicI32_Enc<0b0100>;
+def SLTIU_NM : CondLogicI32_Desc<"sltiu", uimm12_nm, GPRNM32Opnd>,
+ CondLogicI32_Enc<0b0101>;
+def SEQI_NM : CondLogicI32_Desc<"seqi", uimm12_nm, GPRNM32Opnd>,
+ CondLogicI32_Enc<0b0110>;
+
+// P.SHIFT pool of instructions
+def SLL16_NM : ArithLogicINM2Reg_Desc<"sll", uimm3shift_nm,
+ GPRNM16R3Opnd, GPRNM16R3Opnd>,
+ ShiftI16_Enc<0b0>;
+def SLL_NM : ShiftI_Desc<"sll", uimm5, GPRNM32Opnd>, ShiftI32_Enc<0b0000>;
+def SRL16_NM : ArithLogicINM2Reg_Desc<"srl", uimm3shift_nm,
+ GPRNM16R3Opnd, GPRNM16R3Opnd>,
+ ShiftI16_Enc<0b1>;
+def SRL_NM : ShiftI_Desc<"srl", uimm5, GPRNM32Opnd>, ShiftI32_Enc<0b0010>;
+def SRA_NM : ShiftI_Desc<"sra", uimm5, GPRNM32Opnd>, ShiftI32_Enc<0b0100>;
+def ROTR_NM : ShiftI_Desc<"rotr", uimm5, GPRNM32Opnd>, ShiftI32_Enc<0b0110>;
+
+def EXT_NM : ExtBase_Desc, ExtInsBase_Enc<0b1111>;
+def INS_NM : InsBase_Desc, ExtInsBase_Enc<0b1110>;
+
+let TwoOperandAliasConstraint = "$rs = $rt" in
+def ADDIU_NM : AddImmediate_Desc<"addiu", uimm16_nm, GPRNM32Opnd, GPRNM32Opnd>,
+ AddIU_Enc;
+
+def ADDIUNEG_NM : AddImmediate_Desc<"addiu", nimm12_nm,
+ GPRNM32Opnd, GPRNM32Opnd>,
+ CondLogicI32_Enc<0b1000>;
+
+def ADDIUR2_NM : ArithLogicINM2Reg_Desc<"addiu", uimm5s2_nm,
+ GPRNM16R3Opnd, GPRNM16R3Opnd>,
+ ADDIUR2_Enc;
+
+def ADDIURS5_NM : AddImmediate_Desc<"addiu", simm4,
+ GPRNM16R5NZOpnd, GPRNM16R5NZOpnd>,
+ ADDIURS5_Enc, RegConstraint<"$rs = $rt">;
+
+def ADDIUR1SP_NM : ArithLogicINM2Reg_Desc<"addiu", uimm8s2_nm,
+ GPRNM16R3Opnd, GPRNMSPOpnd>,
+ ADDIUR1SP_Enc;
+
+def ADDIU48_NM : ArithLogicINM_Desc<"addiu", sym32_nm, GPRNM48Opnd>,
+ Op48_Imm_Enc<0b00001>, RegConstraint<"$rs = $rt">;
+
+class AddImmediateGP_Desc<string opstr, Operand Od, RegisterOperand RO>
+ : InstNM<(outs RO:$rt), (ins GPRNMGPOpnd:$rs, Od:$offset),
+ !strconcat(opstr, "\t$rt, $rs, $offset")>;
+
+def ADDIUGPB_NM : AddImmediateGP_Desc<"addiu", sym32_gp18_nm, GPRNM32Opnd>,
+ ADDIUGPB_Enc;
+
+def ADDIUGPW_NM : AddImmediateGP_Desc<"addiu", sym32_gp19s2_nm, GPRNM32Opnd>,
+ ADDIUGPW_Enc;
+
+class LoadAddressPCRel_Desc<string opstr, RegisterOperand RO, DAGOperand MO>
+ : InstNM<(outs RO:$rt), (ins MO:$addr),
+ !strconcat(opstr, "\t$rt, $addr")>;
+
+let isReMaterializable = 1 in {
+ def LAPC32_NM : LoadAddressPCRel_Desc<"lapc.h", GPRNM32Opnd, sym32_pc22_nm>,
+ Op32_Addr_Enc<0b00001>;
+ def LAPC48_NM : LoadAddressPCRel_Desc<"lapc.b", GPRNM48Opnd, sym32_pc_nm>,
+ Op48_Addr_Enc<0b00011>;
+}
+
+class LoadAddressPCRelImm_Desc<string opstr, RegisterOperand RO, DAGOperand MO>
+ : InstNM<(outs RO:$rt), (ins MO:$addr), !strconcat(opstr, "\t$rt, $addr")>;
+
+let isAsmParserOnly = 1 in {
+ def ADDIUPC_NM : LoadAddressPCRelImm_Desc<"addiupc", GPRNM32Opnd,
+ simm22s1_nm>,
+ Op32_Addr_Enc<0b00001>;
+ def ADDIUPC48_NM : LoadAddressPCRelImm_Desc<"addiupc", GPRNM48Opnd,
+ simm32_nm>,
+ Op48_Addr_Enc<0b00011>;
+}
+
+class LoadScaledAddress_Desc<string opstr, RegisterOperand RO>
+ : InstNM<(outs RO:$rd), (ins RO:$rs, RO:$rt, uimm2:$shift),
+ !strconcat(opstr, "\t$rd, $rs, $rt, $shift")>;
+
+def LSA_NM : LoadScaledAddress_Desc<"lsa", GPRNM32Opnd>, LoadScaledAddress_Enc;
+
+class SignExtInReg_Desc<string opstr, RegisterOperand RO>
+ : InstNM<(outs RO:$rt), (ins RO:$rs), !strconcat(opstr, "\t$rt, $rs")>;
+
+def SEB_NM : SignExtInReg_Desc<"seb", GPRNM32Opnd>, LogicU32_Enc<0b000001>;
+def SEH_NM : SignExtInReg_Desc<"seh", GPRNM32Opnd>, LogicU32_Enc<0b000101>;
+
+class CountLeading0_Desc<string opstr, RegisterOperand RO>
+ : InstNM<(outs RO:$rt), (ins RO:$rs), !strconcat(opstr, "\t$rt, $rs")>;
+
+class CountLeading1_Desc<string opstr, RegisterOperand RO>
+ : InstNM<(outs RO:$rt), (ins RO:$rs), !strconcat(opstr, "\t$rt, $rs")>;
+
+def CLZ_NM : CountLeading0_Desc<"clz", GPRNM32Opnd>, CLZO_Enc<0b0101101>;
+def CLO_NM : CountLeading1_Desc<"clo", GPRNM32Opnd>, CLZO_Enc<0b0100101>;
+
+// P.TRAP pool of instructions.
+class Trap_Desc<string opstr, RegisterOperand RO, Operand ImmOp>
+ : InstNM<(outs), (ins RO:$rs, RO:$rt, ImmOp:$imm),
+ !strconcat(opstr, "\t$rs, $rt, $imm")> {
+ let hasSideEffects = 1;
+ let isCTI = 1;
+}
+
+def TEQ_NM : Trap_Desc<"teq", GPRNM32Opnd, uimm5>, Trap_Enc<0b0>;
+def TNE_NM : Trap_Desc<"tne", GPRNM32Opnd, uimm5>, Trap_Enc<0b1>;
+
+class MOVEBALC_Desc : InstNM<(outs GPRNM1R1Opnd:$rd),
+ (ins GPRNM4ZOpnd:$rt, calltarget21_nm:$addr),
+ "move.balc\t$rd, $rt, $addr"> {
+ let isCall = 1;
+ let isCTI = 1;
+ let Defs = [RA_NM];
+}
+
+def MOVEBALC_NM : MOVEBALC_Desc, MOVEBALC_Enc;
+
+def LI16_NM : LoadImmAsm_Desc<"li", GPRNM16R3Opnd, nimm7_nm>,
+ LI16_Enc<0b11000>;
+
+let isReMaterializable = 1 in {
+ def LI48_NM : LoadAddressAbs_Desc<"li", GPRNM48Opnd, sym32_nm>,
+ Op48_Imm_Enc<0b00000>;
+}
+
+class LoadAddressGPRel_Desc<string opstr, RegisterOperand RO, DAGOperand MO>
+ : InstNM<(outs RO:$rt), (ins RO:$rs, MO:$addr),
+ !strconcat(opstr, "\t$rt, $rs, $addr")>;
+
+def ADDIUGP48_NM : LoadAddressGPRel_Desc<"addiu.b32", GPRNM48Opnd,
+ sym32_gp_nm>,
+ Op48_Addr_Enc<0b00010>;
+
+// Instructions with 1 register (dest) and 1 immediate operand.
+class RegImm_Desc<string opstr, Operand Od, RegisterOperand RO>
+ : InstNM<(outs RO:$rt), (ins Od:$imm), !strconcat(opstr, "\t$rt, $imm")>;
+
+let isReMaterializable = 1 in
+def LUI_NM : RegImm_Desc<"lui", simm32s12_nm, GPRNM32Opnd>,
+ LUI_Enc<0b0>;
+
+def ALUIPC_NM : RegImm_Desc<"aluipc", simm32s12_pcrel_nm, GPRNM32Opnd>,
+ LUI_Enc<0b1>;
+
+class ReadHardware_Desc<RegisterOperand CPURegOperand, RegisterOperand RO>
+ : InstNM<(outs CPURegOperand:$rt), (ins RO:$hs, uimm5:$sel),
+ "rdhwr\t$rt, $hs, $sel">;
+
+def RDHWR_NM : ReadHardware_Desc<GPRNM32Opnd, COP0Opnd>,
+ RDHWR_Enc;
+
+def JRC_NM : IndirectBranch_Desc<"jrc", GPRNM32Opnd>, IndirectBranch16_Enc<0>;
+
+class IndirectCall_Desc<string opstr, RegisterOperand DRO, RegisterOperand SRO>
+ : InstNM<(outs DRO:$rt), (ins SRO:$rs), !strconcat(opstr, "\t$rt, $rs")> {
+ let isCall = 1;
+ let isCTI = 1;
+}
+
+// TODO: check let ... in, isCall and isCTI is already in IndirectCall_Desc
+let Defs = [RA_NM] in {
+ def JALRC16_NM : IndirectCall_Desc<"jalrc", GPRNMRAOpnd, GPRNM32Opnd>,
+ IndirectCall16_Enc;
+ def JALRC_NM : IndirectCall_Desc<"jalrc", GPRNM32Opnd, GPRNM32Opnd>,
+ IndirectCall32_Enc<0b0000>;
+ def JALRCHB_NM : IndirectCall_Desc<"jalrc.hb", GPRNM32Opnd, GPRNM32Opnd>,
+ IndirectCall32_Enc<0b0001>;
+}
+
+def BC_NM : BCBase_Desc<brtarget25_nm>, BC32_Enc<0b0>;
+def BALC_NM : Call_Desc<"balc", calltarget25_nm>, BC32_Enc<0b1>;
+def BC16_NM : BCBase_Desc<brtarget10_nm>, BC16_Enc<0b00010>;
+def BALC16_NM : Call_Desc<"balc", calltarget10_nm>, BC16_Enc<0b00110>;
+
+// This class is missing instruction size, because these instructions can be
+// encoded in formats of different size (eg. BEQC16 and BEQC32).
+class CBranch_Desc<string opstr, DAGOperand opnd, RegisterOperand RO>
+ : InstNM<(outs), (ins RO:$rs, RO:$rt, opnd:$offset),
+ !strconcat(opstr, "\t$rs, $rt, $offset")> {
+ let isBranch = 1;
+ let isTerminator = 1;
+ let hasDelaySlot = 0;
+ let isCTI = 1;
+}
+
+class CBranchAsm_Desc<string opstr, DAGOperand opnd,
+ RegisterOperand RS, RegisterOperand RT>
+ : InstNM<(outs), (ins RS:$rs, RT:$rt, opnd:$offset),
+ !strconcat(opstr, "\t$rs, $rt, $offset")> {
+ let isBranch = 1;
+ let isTerminator = 1;
+ let hasDelaySlot = 0;
+ let isCTI = 1;
+}
+
+// NOTE: BEQC[16] / BNEC[16] are intentionally *not* defined.
+//
+// Both instructions share the same 16-bit encoding:
+//
+// 110110 rt3 rs3 u[4:1]
+//
+// BEQC[16]: rs3 < rt3 && u != 0
+// BNEC[16]: rs3 >= rt3 && u != 0
+//
+// Adding both BEQC[16] and BNEC[16] with this encoding causes a decoding
+// conflict: the two instructions differ only by semantic conditions on
+// (rs3, rt3, u), which the decoder cannot represent. Until a special
+// mechanism is added, these instructions are intentionally omitted from
+// the nanoMIPS backend.
+
+def BEQC_NM : CBranch_Desc<"beqc", brtarget14_nm, GPRNM32Opnd>, B14_Enc<0b000>;
+// def BEQC16_NM : CBranchAsm_Desc<"beqc", brtarget4s1_nm, GPRNM16R3Opnd,
+// GPRNM16R3Opnd>, B4_Enc;
+def BGEC_NM : CBranch_Desc<"bgec", brtarget14_nm, GPRNM32Opnd>,
+ B14_Enc<0b010>;
+def BGEUC_NM : CBranch_Desc<"bgeuc", brtarget14_nm, GPRNM32Opnd>,
+ B14_Enc<0b011>;
+
+def BNEC_NM : CBranch_Desc<"bnec", brtarget14_nm, GPRNM32Opnd>,
+ B14_Enc<0b100>;
+// def BNEC16_NM : CBranchAsm_Desc<"bnec", brtarget4s1_nm,
+// GPRNM16R3Opnd, GPRNM16R3Opnd>, B4_Enc;
+
+def BLTC_NM : CBranch_Desc<"bltc", brtarget14_nm, GPRNM32Opnd>,
+ B14_Enc<0b110>;
+def BLTUC_NM : CBranch_Desc<"bltuc", brtarget14_nm, GPRNM32Opnd>,
+ B14_Enc<0b111>;
+
+class CBranchZeroAsm_Desc<string opstr, DAGOperand opnd, RegisterOperand RO>
+ : InstNM<(outs), (ins RO:$rs, opnd:$offset),
+ !strconcat(opstr, "\t$rs, $offset")> {
+ let isBranch = 1;
+ let isTerminator = 1;
+ let isCTI = 1;
+}
+
+def BEQZC16_NM : CBranchZeroAsm_Desc<"beqzc", brtarget7_nm, GPRNM16R3Opnd>,
+ BZ16_Enc<0b10010>;
+def BNEZC16_NM : CBranchZeroAsm_Desc<"bnezc", brtarget7_nm, GPRNM16R3Opnd>,
+ BZ16_Enc<0b10110>;
+
+class CBranchImm_Desc<string opstr, DAGOperand opnd,
+ RegisterOperand RO, Operand imm_type>
+ : InstNM<(outs), (ins RO:$rt, imm_type:$u, opnd:$offset),
+ !strconcat(opstr, "\t$rt, $u, $offset")> {
+ let isBranch = 1;
+ let isTerminator = 1;
+ let hasDelaySlot = 0;
+ let isCTI = 1;
+}
+
+class CBranchRegScaled_Desc<string opstr>
+ : InstNM<(outs), (ins GPRNM32Opnd:$rs, i32imm:$jti),
+ !strconcat(opstr, "\t$rs")> {
+ let hasNoSchedulingInfo = 1;
+ let hasDelaySlot = 0;
+ let isBranch = 1;
+ let isBarrier = 1;
+ let isTerminator = 1;
+ let isCTI = 1;
+}
+
+def BEQIC_NM : CBranchImm_Desc<"beqic", brtarget11_nm, GPRNM32Opnd, uimm7>,
+ BRI_Enc<0b000>;
+def BGEIC_NM : CBranchImm_Desc<"bgeic", brtarget11_nm, GPRNM32Opnd, uimm7>,
+ BRI_Enc<0b010>;
+def BLTIC_NM : CBranchImm_Desc<"bltic", brtarget11_nm, GPRNM32Opnd, uimm7>,
+ BRI_Enc<0b110>;
+def BNEIC_NM : CBranchImm_Desc<"bneic", brtarget11_nm, GPRNM32Opnd, uimm7>,
+ BRI_Enc<0b100>;
+def BGEIUC_NM : CBranchImm_Desc<"bgeiuc", brtarget11_nm, GPRNM32Opnd, uimm7>,
+ BRI_Enc<0b011>;
+def BLTIUC_NM : CBranchImm_Desc<"bltiuc", brtarget11_nm, GPRNM32Opnd, uimm7>,
+ BRI_Enc<0b111>;
+
+def BRSC_NM : CBranchRegScaled_Desc<"brsc">, IndirectBranch32_Enc;
+def BALRSC_NM : IndirectCall_Desc<"balrsc", GPRNM32NZOpnd, GPRNM32Opnd>,
+ IndirectCall32_Enc<0b1000>;
+
+class CBranchBit_Desc<string opstr, DAGOperand opnd,
+ RegisterOperand RO, Operand imm_type>
+ : InstNM<(outs), (ins RO:$rt, imm_type:$u, opnd:$offset),
+ !strconcat(opstr, "\t$rt, $u, $offset")> {
+ let isBranch = 1;
+ let isTerminator = 1;
+ let hasDelaySlot = 0;
+ let isCTI = 1;
+}
+
+// Bit-test branches
+let hasNoSchedulingInfo = 1, hasDelaySlot = 0 in {
+ def BBNEZC_NM : CBranchBit_Desc<"bbnezc", brtarget11_nm,
+ GPRNM32Opnd, uimm6_nm>,
+ BBit_Enc<0b101>;
+ def BBEQZC_NM : CBranchBit_Desc<"bbeqzc", brtarget11_nm,
+ GPRNM32Opnd, uimm6_nm>,
+ BBit_Enc<0b001>;
+}
+
+//===----------------------------------------------------------------------===//
+//
+// Load / store instructions
+//
+//===----------------------------------------------------------------------===//
+class LoadAsm_Desc<string opstr, RegisterOperand RO, DAGOperand MO>
+ : InstNM<(outs RO:$rt), (ins MO:$addr), !strconcat(opstr, "\t$rt, $addr")>;
+
+class StoreAsm_Desc<string opstr, RegisterOperand RO, DAGOperand MO>
+ : InstNM<(outs), (ins RO:$rt, MO:$addr), !strconcat(opstr, "\t$rt, $addr")>;
+
+def LWSP16_NM : LoadAsm_Desc<"lw", GPRNM32Opnd, mem_nm_sp5s2>,
+ LSSPRegMem16_Enc<0b00101>;
+def SWSP16_NM : StoreAsm_Desc<"sw", GPRNM32Opnd, mem_nm_sp5s2>,
+ LSSPRegMem16_Enc<0b10101>;
+def LWGP16_NM : LoadAsm_Desc<"lw", GPRNM16R3Opnd, mem_nm_gp7s2>,
+ LSGPRegMem16_Enc<0b01001>;
+def SWGP16_NM : StoreAsm_Desc<"sw", GPRNM16R3ZOpnd, mem_nm_gp7s2>,
+ LSGPRegMem16_Enc<0b11001>;
+
+def LW16_NM : LoadAsm_Desc<"lw", GPRNM16R3Opnd, mem_nm_6s2>,
+ LSMem16_Enc<0b00001>;
+def SW16_NM : StoreAsm_Desc<"sw", GPRNM16R3ZOpnd, mem_nm_6s2>,
+ LSMem16_Enc<0b10001>;
+def LH16_NM : LoadAsm_Desc<"lh", GPRNM16R3Opnd, mem_nm_3s1>,
+ LHMem16_Enc<0b00>;
+def LHU16_NM : LoadAsm_Desc<"lhu", GPRNM16R3Opnd, mem_nm_3s1>,
+ LHMem16_Enc<0b10>;
+def SH16_NM : StoreAsm_Desc<"sh", GPRNM16R3ZOpnd, mem_nm_3s1>,
+ LHMem16_Enc<0b01>;
+
+def LB16_NM : LoadAsm_Desc<"lb", GPRNM16R3Opnd, mem_nm_2>,
+ LBMem16_Enc<0b00>;
+def LBU16_NM : LoadAsm_Desc<"lbu", GPRNM16R3Opnd, mem_nm_2>,
+ LBMem16_Enc<0b10>;
+def SB16_NM : StoreAsm_Desc<"sb", GPRNM16R3ZOpnd, mem_nm_2>,
+ LBMem16_Enc<0b01>;
+
+class LoadMemory_Desc<string opstr, RegisterOperand RO, DAGOperand MO>
+ : InstNM<(outs RO:$rt), (ins MO:$addr), !strconcat(opstr, "\t$rt, $addr")> {
+ let canFoldAsLoad = 1;
+ let mayLoad = 1;
+ string BaseOpcode = opstr;
+}
+
+class StoreMemory_Desc<string opstr, RegisterOperand RO, DAGOperand MO>
+ : InstNM<(outs), (ins RO:$rt, MO:$addr), !strconcat(opstr, "\t$rt, $addr")> {
+ let mayStore = 1;
+ string BaseOpcode = opstr;
+}
+
+def LWGP_NM : LoadMemory_Desc<"lw", GPRNM32Opnd, mem_nm_gp19s2>,
+ LSMemGP19S2_Enc<0b10>;
+def SWGP_NM : StoreMemory_Desc<"sw", GPRNM32Opnd, mem_nm_gp19s2>,
+ LSMemGP19S2_Enc<0b11>;
+
+def LBGP_NM : LoadMemory_Desc<"lb", GPRNM32Opnd, mem_nm_gp18>,
+ LSMemGP18_Enc<0b000>;
+def SBGP_NM : StoreMemory_Desc<"sb", GPRNM32Opnd, mem_nm_gp18>,
+ LSMemGP18_Enc<0b001>;
+def LBUGP_NM : LoadMemory_Desc<"lbu", GPRNM32Opnd, mem_nm_gp18>,
+ LSMemGP18_Enc<0b010>;
+
+def LHGP_NM : LoadMemory_Desc<"lh", GPRNM32Opnd, mem_nm_gp17s1>,
+ LSMemGP17S1_Enc<0b1000>;
+def SHGP_NM : StoreMemory_Desc<"sh", GPRNM32Opnd, mem_nm_gp17s1>,
+ LSMemGP17S1_Enc<0b1010>;
+def LHUGP_NM : LoadMemory_Desc<"lhu", GPRNM32Opnd, mem_nm_gp17s1>,
+ LSMemGP17S1_Enc<0b1001>;
+
+def LB_NM : LoadMemory_Desc<"lb", GPRNM32Opnd, mem_nm_u12>,
+ LSMem_U12_Enc<0b0000>;
+def SB_NM : StoreMemory_Desc<"sb", GPRNM32Opnd, mem_nm_u12>,
+ LSMem_U12_Enc<0b0001>;
+def LH_NM : LoadMemory_Desc<"lh", GPRNM32Opnd, mem_nm_u12>,
+ LSMem_U12_Enc<0b0100>;
+def SH_NM : StoreMemory_Desc<"sh", GPRNM32Opnd, mem_nm_u12>,
+ LSMem_U12_Enc<0b0101>;
+def LW_NM : LoadMemory_Desc<"lw", GPRNM32Opnd, mem_nm_u12>,
+ LSMem_U12_Enc<0b1000>;
+def SW_NM : StoreMemory_Desc<"sw", GPRNM32Opnd, mem_nm_u12>,
+ LSMem_U12_Enc<0b1001>;
+def LBU_NM : LoadMemory_Desc<"lbu", GPRNM32Opnd, mem_nm_u12>,
+ LSMem_U12_Enc<0b0010>;
+def LHU_NM : LoadMemory_Desc<"lhu", GPRNM32Opnd, mem_nm_u12>,
+ LSMem_U12_Enc<0b0110>;
+
+def LBs9_NM : LoadMemory_Desc<"lb", GPRNM32Opnd, mem_nm_s9>,
+ LSMem_S9_Enc<0b000, 0b0000>;
+def SBs9_NM : StoreMemory_Desc<"sb", GPRNM32Opnd, mem_nm_s9>,
+ LSMem_S9_Enc<0b000, 0b0001>;
+def LHs9_NM : LoadMemory_Desc<"lh", GPRNM32Opnd, mem_nm_s9>,
+ LSMem_S9_Enc<0b000, 0b0100>;
+def SHs9_NM : StoreMemory_Desc<"sh", GPRNM32Opnd, mem_nm_s9>,
+ LSMem_S9_Enc<0b000, 0b0101>;
+def LWs9_NM : LoadMemory_Desc<"lw", GPRNM32Opnd, mem_nm_s9>,
+ LSMem_S9_Enc<0b000, 0b1000>;
+def SWs9_NM : StoreMemory_Desc<"sw", GPRNM32Opnd, mem_nm_s9>,
+ LSMem_S9_Enc<0b000, 0b1001>;
+def LBUs9_NM : LoadMemory_Desc<"lbu", GPRNM32Opnd, mem_nm_s9>,
+ LSMem_S9_Enc<0b000, 0b0010>;
+def LHUs9_NM : LoadMemory_Desc<"lhu", GPRNM32Opnd, mem_nm_s9>,
+ LSMem_S9_Enc<0b000, 0b0110>;
+
+def LBX_NM : LoadMemory_Desc<"lbx", GPRNM32Opnd, mem_nm_rx>,
+ LSMemX_Enc<0, 0b0000>;
+def SBX_NM : StoreMemory_Desc<"sbx", GPRNM32Opnd, mem_nm_rx>,
+ LSMemX_Enc<0, 0b0001>;
+def LHX_NM : LoadMemory_Desc<"lhx", GPRNM32Opnd, mem_nm_rx>,
+ LSMemX_Enc<0, 0b0100>;
+def SHX_NM : StoreMemory_Desc<"shx", GPRNM32Opnd, mem_nm_rx>,
+ LSMemX_Enc<0, 0b0101>;
+def LWX_NM : LoadMemory_Desc<"lwx", GPRNM32Opnd, mem_nm_rx>,
+ LSMemX_Enc<0, 0b1000>;
+def SWX_NM : StoreMemory_Desc<"swx", GPRNM32Opnd, mem_nm_rx>,
+ LSMemX_Enc<0, 0b1001>;
+def LBUX_NM : LoadMemory_Desc<"lbux", GPRNM32Opnd, mem_nm_rx>,
+ LSMemX_Enc<0, 0b0010>;
+def LHUX_NM : LoadMemory_Desc<"lhux", GPRNM32Opnd, mem_nm_rx>,
+ LSMemX_Enc<0, 0b0110>;
+
+def LHXS_NM : LoadMemory_Desc<"lhxs", GPRNM32Opnd, mem_nm_rx>,
+ LSMemX_Enc<0b1, 0b0100>;
+def SHXS_NM : StoreMemory_Desc<"shxs", GPRNM32Opnd, mem_nm_rx>,
+ LSMemX_Enc<0b1, 0b0101>;
+def LHUXS_NM : LoadMemory_Desc<"lhuxs", GPRNM32Opnd, mem_nm_rx>,
+ LSMemX_Enc<0b1, 0b0110>;
+def LWXS16_NM : LoadAsm_Desc<"lwxs", GPRNM16R3Opnd, mem_nm_rx16>,
+ LSMemXS16_Enc;
+def LWXS_NM : LoadMemory_Desc<"lwxs", GPRNM32Opnd, mem_nm_rx>,
+ LSMemX_Enc<0b1, 0b1000>;
+def SWXS_NM : StoreMemory_Desc<"swxs", GPRNM32Opnd, mem_nm_rx>,
+ LSMemX_Enc<0b1, 0b1001>;
+
+class UnalignedLoad_Desc<string opstr, RegisterOperand RO = GPRNM32Opnd>
+ : InstNM<(outs RO:$rt), (ins mem_nm_s9:$addr, RO:$src),
+ !strconcat(opstr, "\t$rt, $addr")>,
+ RegConstraint<"$src = $rt"> {
+ let mayLoad = 1;
+ let canFoldAsLoad = 1;
+}
+
+class UnalignedStore_Desc<string opstr, RegisterOperand RO = GPRNM32Opnd>
+ : InstNM<(outs), (ins RO:$rt, mem_nm_s9:$addr),
+ !strconcat(opstr, "\t$rt, $addr")> {
+ let mayStore = 1;
+}
+
+class SaveRestore_Desc<string opstr, Operand Od, Operand RL>
+ : InstNM<(outs), (ins Od:$adj, RL:$regs, variable_ops),
+ !strconcat(opstr, "\t$adj$regs")> {
+ let Defs = [SP_NM];
+ let Uses = [SP_NM];
+ let hasSideEffects = 1;
+}
+
+def SAVE16_NM : SaveRestore_Desc<"save", uimm8s4_nm, reglist16_nm>,
+ SaveRestore16_Enc<0b0>;
+def RESTOREJRC16_NM : SaveRestore_Desc<"restore.jrc", uimm8s4_nm,
+ reglist16_nm>,
+ SaveRestore16_Enc<0b1>;
+
+def SAVE_NM : SaveRestore_Desc<"save", uimm12s3_nm, reglist_nm>,
+ SaveRestore32_Enc<0b00>;
+def RESTORE_NM : SaveRestore_Desc<"restore", uimm12s3_nm, reglist_nm>,
+ SaveRestore32_Enc<0b10>;
+def RESTOREJRC_NM : SaveRestore_Desc<"restore.jrc", uimm12s3_nm, reglist_nm>,
+ SaveRestore32_Enc<0b11>;
+
+class LoadMultiple_Desc<string opstr>
+ : InstNM<(outs GPRNM32Opnd:$rt),
+ (ins mem_nm_s9:$addr, uimm3plus1_nm:$rcount),
+ !strconcat(opstr, "\t$rt, $addr, $rcount")> {
+ let mayLoad = 1;
+}
+
+class StoreMultiple_Desc<string opstr>
+ : InstNM<(outs),
+ (ins GPRNM32Opnd:$rt, mem_nm_s9:$addr, uimm3plus1_nm:$rcount),
+ !strconcat(opstr, "\t$rt, $addr, $rcount")> {
+ let mayStore = 1;
+}
+
+def LWM_NM : LoadMultiple_Desc<"lwm">, LSMem_S9_Mult_Enc<0b0100>;
+def SWM_NM : StoreMultiple_Desc<"swm">, LSMem_S9_Mult_Enc<0b1100>;
+def UALWM_NM : LoadMultiple_Desc<"ualwm">, LSMem_S9_Mult_Enc<0b0101>;
+def UASWM_NM : StoreMultiple_Desc<"uaswm">, LSMem_S9_Mult_Enc<0b1101>;
+
+def UALH_NM : UnalignedLoad_Desc<"ualh">, LSMem_S9_Enc<0b001, 0b0100>;
+def UASH_NM : UnalignedStore_Desc<"uash">, LSMem_S9_Enc<0b001, 0b0101>;
+def UALW_NM : UnalignedLoad_Desc<"ualw">, LSMem_S9_Enc<0b101, 0b0010>;
+def UASW_NM : UnalignedStore_Desc<"uasw">, LSMem_S9_Enc<0b101, 0b0011>;
+
+class LoadPCBase_Desc<DAGOperand RO, DAGOperand MO>
+ : InstNM<(outs RO:$rt), (ins MO:$addr), "lwpc\t$rt, $addr"> {
+ let mayLoad = 1;
+}
+
+class StorePCBase_Desc<DAGOperand RO, DAGOperand MO>
+ : InstNM<(outs), (ins RO:$rt, MO:$addr), "swpc\t$rt, $addr"> {
+ let mayStore = 1;
+}
+
+def SWPC_NM : StorePCBase_Desc<GPRNM32Opnd, sym32_pc_nm>,
+ Op48_Addr_Enc<0b01111>;
+def LWPC_NM : LoadPCBase_Desc<GPRNM32Opnd, sym32_pc_nm>,
+ Op48_Addr_Enc<0b01011>;
+
+def LW4x4_NM : LoadAsm_Desc<"lw", GPRNM4Opnd, mem_nm_4s2>,
+ LSMem4x4_Enc<0b01101>;
+def SW4x4_NM : StoreAsm_Desc<"sw", GPRNM4ZOpnd, mem_nm_4s2>,
+ LSMem4x4_Enc<0b11101>;
+
+def MOVE_NM : MoveBase_Desc, MOVE_Enc;
+
+def MOVEP_NM : MovePBase_Desc<GPRNM4ZOpnd, GPRNM4ZOpnd,
+ GPRNM2R1Opnd, GPRNM2R2Opnd>,
+ MOVEP_Enc<0b10111>;
+def MOVEPREV_NM : MovePBase_Desc<GPRNM2R1Opnd, GPRNM2R2Opnd,
+ GPRNM4Opnd, GPRNM4Opnd>,
+ MOVEPREV_Enc<0b11111>;
+
+class SC_Desc<string opstr>
+ : InstNM<(outs GPRNM32Opnd:$dst), (ins GPRNM32Opnd:$rt, mem_nm_7s2:$addr),
+ !strconcat(opstr, "\t$rt, $addr")>,
+ RegConstraint<"$rt = $dst"> {
+ let mayStore = 1;
+}
+
+let hasNoSchedulingInfo = 1 in {
+ def LL_NM : LoadMemory_Desc<"ll", GPRNM32Opnd, mem_nm_7s2>,
+ LLSC_Enc<0b001, 0b1010>;
+ def SC_NM : SC_Desc<"sc">, LLSC_Enc<0b001, 0b1011>;
+}
+
+class LLWP_Desc<string opstr, DAGOperand MO>
+ : InstNM<(outs GPRNM32Opnd:$rt, GPRNM32Opnd:$ru), (ins MO:$addr),
+ !strconcat(opstr, "\t$rt, $ru, $addr")> {
+ let canFoldAsLoad = 1;
+ let mayLoad = 1;
+ string BaseOpcode = "llwp";
+}
+
+def LLWP_NM : LLWP_Desc<"llwp", mem_nm_0_no_offset>, LLSCWP_Enc<0b001, 0b1010>;
+
+class SCWP_Desc<string opstr>
+ : InstNM<(outs GPRNM32Opnd:$dst),
+ (ins GPRNM32Opnd:$rt, GPRNM32Opnd:$ru, mem_nm_0:$addr),
+ !strconcat(opstr, "\t$rt, $ru, $addr")>,
+ RegConstraint<"$dst = $rt"> {
+ let mayStore = 1;
+ string BaseOpcode = "scwp";
+}
+
+def SCWP_NM : SCWP_Desc<"scwp">, LLSCWP_Enc<0b001, 0b1011>;
+
+class CondMove_Desc<string opstr>
+ : InstNM<(outs GPRNM32Opnd:$rd),
+ (ins GPRNM32Opnd:$rs, GPRNM32Opnd:$rt, GPRNM32Opnd:$F),
+ !strconcat(opstr, "\t$rd, $rs, $rt")>,
+ RegConstraint<"$F = $rd">, IsCommutable;
+
+def MOVZ_NM : CondMove_Desc<"movz">, CondMove_Enc<0b0>;
+def MOVN_NM : CondMove_Desc<"movn">, CondMove_Enc<0b1>;
+
+class ToggleInterrupts_Desc<string opstr>
+ : InstNM<(outs GPRNM32Opnd:$rt), (ins), !strconcat(opstr, "\t$rt")>;
+
+def DI_NM : ToggleInterrupts_Desc<"di">, ToggleInterrupts_Enc<0b00011>;
+def EI_NM : ToggleInterrupts_Desc<"ei">, ToggleInterrupts_Enc<0b01011>;
+
+// Instruction with no operands
+class MnemonicOnly_Desc<string opstr> : InstNM<(outs), (ins), opstr>;
+
+def ERET_NM : MnemonicOnly_Desc<"eret">, ERET_Enc<0b11001, 0b0>;
+def ERETNC_NM : MnemonicOnly_Desc<"eretnc">, ERET_Enc<0b11001, 0b1>;
+def DERET_NM : MnemonicOnly_Desc<"deret">, ERET_Enc<0b10001, 0b0>;
+
+def EHB_NM : MnemonicOnly_Desc<"ehb">, SLL_VAR_Enc<3>;
+
+def PAUSE_NM : MnemonicOnly_Desc<"pause">, SLL_VAR_Enc<5>;
+
+def NOP32_NM : MnemonicOnly_Desc<"nop32">, SLL_VAR_Enc<0>;
+def NOP_NM : MnemonicOnly_Desc<"nop">, NOP_Enc;
+
+class ImmOnly_Desc<string opstr, Operand Od>
+ : InstNM<(outs), (ins Od:$imm), !strconcat(opstr, "\t$imm")>;
+
+def SIGRIE_NM : ImmOnly_Desc<"sigrie", uimm19_nm>, IntExcpFlow_Enc<0b00>;
+
+def BREAK_NM : ImmOnly_Desc<"break", uimm19_nm>, IntExcpFlow_Enc<0b10>;
+def BREAK16_NM : ImmOnly_Desc<"break", uimm3_nm>, IntExcpFlow16_Enc<0b10>;
+
+def SDBBP_NM : ImmOnly_Desc<"sdbbp", uimm19_nm>, IntExcpFlow_Enc<0b11>;
+def SDBBP16_NM : ImmOnly_Desc<"sdbbp", uimm3_nm>, IntExcpFlow16_Enc<0b11>;
+
+def SYSCALL_NM : ImmOnly_Desc<"syscall", uimm18_nm>,
+ IntExcpFlow_Enc<0b01, 18>;
+def SYSCALL16_NM : ImmOnly_Desc<"syscall", uimm2code_nm>,
+ IntExcpFlow16_Enc<0b01, 2>;
+
+class ShadowRW_Desc<string opstr>
+ : InstNM<(outs GPRNM32Opnd:$rt), (ins GPRNM32Opnd:$rs),
+ !strconcat(opstr, "\t$rt, $rs")>;
+
+def WRPGPR_NM : ShadowRW_Desc<"wrpgpr">, ShadowRW_Enc<0b11000>;
+def RDPGPR_NM : ShadowRW_Desc<"rdpgpr">, ShadowRW_Enc<0b10000>;
+
+class EXTW_Desc
+ : InstNM<(outs GPRNM32Opnd:$rd),
+ (ins GPRNM32Opnd:$rs, GPRNM32Opnd:$rt, uimm5:$shift),
+ "extw\t$rd, $rs, $rt, $shift">;
+
+def EXTW_NM : EXTW_Desc, EXTW_Enc;
+
+// TODO: Define ALIGN_NM.
+// NOTE: ALIGN will be added later as an assembly pseudo-instruction.
+// It is intended to expand into EXTW/MOVE instructions (depending on bp).
+
+class RotxAlias_Desc<string opstr>
+ : InstNM<(outs GPRNM32Opnd:$rt), (ins GPRNM32Opnd:$rs),
+ !strconcat(opstr, "\t$rt, $rs")>;
+
+class ROTX_Desc
+ : InstNM<(outs GPRNM32Opnd:$rt),
+ (ins GPRNM32Opnd:$rs, uimm5:$shift,
+ uimm5s1_nm:$shiftx, uimm1:$stripe),
+ "rotx\t$rt, $rs, $shift, $shiftx, $stripe">;
+
+def BITREVW_NM : RotxAlias_Desc<"bitrevw">, RotxAlias_Enc<31, 0, 0>;
+def BYTEREVW_NM : RotxAlias_Desc<"byterevw">, RotxAlias_Enc<24, 8, 0>;
+
+def ROTX_NM : ROTX_Desc, ROTX_Enc;
+
+class CacheOp_Desc<string opstr, Operand Od, DAGOperand MO>
+ : InstNM<(outs), (ins Od:$op, MO:$addr), !strconcat(opstr, "\t$op, $addr")>;
+
+def CACHE_NM : CacheOp_Desc<"cache", uimm5, mem_nm_s9>,
+ CACHE_PREFs9_Enc<0b001, 0b0111>;
+
+def PREFs9_NM : CacheOp_Desc<"pref", uimm5, mem_nm_s9>,
+ CACHE_PREFs9_Enc<0b000, 0b0011>;
+
+def PREF_NM : CacheOp_Desc<"pref", uimm5, mem_nm_u12>, PREF_Enc;
+
+class SyncOp_Desc<string opstr, DAGOperand MO>
+ : InstNM<(outs), (ins MO:$stype), !strconcat(opstr, "\t$stype")>;
+
+class SyncIOp_Desc<string opstr, DAGOperand MO>
+ : InstNM<(outs), (ins MO:$addr), !strconcat(opstr, "\t$addr")>;
+
+def SYNC_NM : SyncOp_Desc<"sync", uimm5>, SYNC_Enc;
+
+def SYNCIs9_NM : SyncIOp_Desc<"synci", mem_nm_s9>,
+ SYNCIs9_SYNCIE_Enc<0b000, 0b0011>;
+
+def SYNCI_NM : SyncIOp_Desc<"synci", mem_nm_u12>, SYNCI_Enc;
+
+class WaitOp_Desc<string opstr, DAGOperand MO>
+ : InstNM<(outs), (ins MO:$cd), !strconcat(opstr, "\t$cd")>;
+
+def WAIT_NM : WaitOp_Desc<"wait", uimm10>, WAIT_Enc;
+
+class WriteToCP0_Desc<string opstr, RegisterOperand RO, RegisterOperand CO>
+ : InstNM<(outs), (ins RO:$rt, CO:$c0s, uimm5:$sel),
+ !strconcat(opstr, "\t$rt, $c0s, $sel")>;
+
+class WriteToCP0Sel_Desc<string opstr, RegisterOperand RO, RegisterOperand CO>
+ : InstNM<(outs), (ins RO:$rt, CO:$c0s),
+ !strconcat(opstr, "\t$rt, $c0s")>;
+
+class ReadFromCP0_Desc<string opstr, RegisterOperand RO, RegisterOperand CO>
+ : InstNM<(outs RO:$rt), (ins CO:$c0s, uimm5:$sel),
+ !strconcat(opstr, "\t$rt, $c0s, $sel")>;
+
+class ReadFromCP0Sel_Desc<string opstr, RegisterOperand RO, RegisterOperand CO>
+ : InstNM<(outs RO:$rt), (ins CO:$c0s),
+ !strconcat(opstr, "\t$rt, $c0s")>;
+
+def MFC0Sel_NM : ReadFromCP0Sel_Desc<"mfc0", GPRNM32Opnd, COP0SelOpnd>,
+ ReadWriteCP0Sel_Enc<0b000010>;
+def MFHC0Sel_NM : ReadFromCP0Sel_Desc<"mfhc0", GPRNM32Opnd, COP0SelOpnd>,
+ ReadWriteCP0Sel_Enc<0b000011>;
+def MTC0Sel_NM : WriteToCP0Sel_Desc<"mtc0", GPRNM32Opnd, COP0SelOpnd>,
+ ReadWriteCP0Sel_Enc<0b000110>;
+def MTHC0Sel_NM : WriteToCP0Sel_Desc<"mthc0", GPRNM32Opnd, COP0SelOpnd>,
+ ReadWriteCP0Sel_Enc<0b000111>;
+
+let isAsmParserOnly = 1 in {
+ def MFC0_NM : ReadFromCP0_Desc<"mfc0", GPRNM32Opnd, COP0Opnd>,
+ ReadWriteCP0_Enc<0b000010>;
+ def MFHC0_NM : ReadFromCP0_Desc<"mfhc0", GPRNM32Opnd, COP0Opnd>,
+ ReadWriteCP0_Enc<0b000011>;
+ def MTC0_NM : WriteToCP0_Desc<"mtc0", GPRNM32Opnd, COP0Opnd>,
+ ReadWriteCP0_Enc<0b000110>;
+ def MTHC0_NM : WriteToCP0_Desc<"mthc0", GPRNM32Opnd, COP0Opnd>,
+ ReadWriteCP0_Enc<0b000111>;
+}
+
+class GINVI_Desc : InstNM<(outs), (ins GPRNM32Opnd:$rs), "ginvi\t$rs">;
+class GINVT_Desc : InstNM<(outs), (ins GPRNM32Opnd:$rs, uimm2:$type),
+ "ginvt\t$rs, $type">;
+
+def GINVI_NM : GINVI_Desc, GINVI_Enc<0b01111>, ASE_GINV;
+def GINVT_NM : GINVT_Desc, GINVT_Enc<0b00111>, ASE_GINV;
+
+class CRC_Op_Desc<string opstr>
+ : InstNM<(outs GPRNM32Opnd:$rt), (ins GPRNM32Opnd:$val, GPRNM32Opnd:$rs),
+ !strconcat(opstr, "\t$rt, $rs")>, RegConstraint<"$val = $rt">;
+
+def CRC32B_NM : CRC_Op_Desc<"crc32b">, CRC_Enc<0b000>, ASE_CRC;
+def CRC32H_NM : CRC_Op_Desc<"crc32h">, CRC_Enc<0b001>, ASE_CRC;
+def CRC32W_NM : CRC_Op_Desc<"crc32w">, CRC_Enc<0b010>, ASE_CRC;
+def CRC32CB_NM : CRC_Op_Desc<"crc32cb">, CRC_Enc<0b100>, ASE_CRC;
+def CRC32CH_NM : CRC_Op_Desc<"crc32ch">, CRC_Enc<0b101>, ASE_CRC;
+def CRC32CW_NM : CRC_Op_Desc<"crc32cw">, CRC_Enc<0b110>, ASE_CRC;
+
+class VP_Desc<string opstr>
+ : InstNM<(outs GPRNM32Opnd:$rt), (ins), !strconcat(opstr, "\t$rt")>;
+
+def EVP_NM : VP_Desc<"evp">, VP_Enc<0b1>;
+def DVP_NM : VP_Desc<"dvp">, VP_Enc<0b0>;
>From 82a06cacc278a0623457cc5bea1855bf3716551c Mon Sep 17 00:00:00 2001
From: Nemanja Rakovic <ot_nemanja.rakovic at mediatek.com>
Date: Thu, 27 Aug 2026 19:16:44 +0200
Subject: [PATCH 07/15] [nanoMIPS 7/7][test] Add instruction encoding and
mnemonic tests
As a stopgap solution until assembly/disassembly support is implemented
in the next batch, we test encodings and mnemonics through MIR tests
using `llc -show-mc-encoding`. Operands that don't have an encoder yet
are set to 0, so that the opcode and register fields can still be
verified. These tests will be updated to reflect future additions, and
eventually replaced with .s tests.
---
llvm/test/CodeGen/Mips/nanomips/16bit.mir | 367 ++++++++++++++
llvm/test/CodeGen/Mips/nanomips/32bit-alu.mir | 473 ++++++++++++++++++
.../CodeGen/Mips/nanomips/32bit-branch.mir | 186 +++++++
.../Mips/nanomips/32bit-load-store.mir | 447 +++++++++++++++++
.../CodeGen/Mips/nanomips/32bit-system.mir | 336 +++++++++++++
llvm/test/CodeGen/Mips/nanomips/48bit.mir | 73 +++
6 files changed, 1882 insertions(+)
create mode 100644 llvm/test/CodeGen/Mips/nanomips/16bit.mir
create mode 100644 llvm/test/CodeGen/Mips/nanomips/32bit-alu.mir
create mode 100644 llvm/test/CodeGen/Mips/nanomips/32bit-branch.mir
create mode 100644 llvm/test/CodeGen/Mips/nanomips/32bit-load-store.mir
create mode 100644 llvm/test/CodeGen/Mips/nanomips/32bit-system.mir
create mode 100644 llvm/test/CodeGen/Mips/nanomips/48bit.mir
diff --git a/llvm/test/CodeGen/Mips/nanomips/16bit.mir b/llvm/test/CodeGen/Mips/nanomips/16bit.mir
new file mode 100644
index 0000000000000..bbbc8c457f26d
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/nanomips/16bit.mir
@@ -0,0 +1,367 @@
+# RUN: llc %s -mtriple=nanomips-elf -start-after=mips-branch-expansion -show-mc-encoding -o - \
+# RUN: | FileCheck %s
+
+# Encoding tests for 16-bit nanoMIPS instructions (compact ALU, moves,
+# arithmetic, load/store, jumps, branches, save/restore)
+#
+# Since load/store and branch-target operands will be fully supported in the
+# next upstreaming batch, they are set to 0 to allow confirming the mnemonics
+# and encoding of the remaining instruction parts.
+# Encoding bytes are shown in on-disk order: each halfword is little-endian,
+# more significant halfword first.
+
+# --- alu / logic / move ---
+---
+# CHECK-LABEL: addiur1sp:
+# CHECK: addiu $a0, $sp, 4 # encoding: [0x41,0x72]
+name: addiur1sp
+body: |
+ bb.0:
+ $a0_nm = ADDIUR1SP_NM $sp_nm, 4
+...
+---
+# CHECK-LABEL: addiur2:
+# CHECK: addiu $a0, $a1, 4 # encoding: [0x51,0x92]
+name: addiur2
+body: |
+ bb.0:
+ $a0_nm = ADDIUR2_NM $a1_nm, 4
+...
+---
+# CHECK-LABEL: and16:
+# CHECK: and $a0, $a0, $a1 # encoding: [0x48,0x52]
+name: and16
+body: |
+ bb.0:
+ $a0_nm = AND16_NM $a0_nm, $a1_nm
+...
+---
+# CHECK-LABEL: andi16:
+# CHECK: andi $a0, $a1, 3 # encoding: [0x53,0xf2]
+name: andi16
+body: |
+ bb.0:
+ $a0_nm = ANDI16_NM $a1_nm, 3
+...
+---
+# CHECK-LABEL: break16:
+# CHECK: break 3 # encoding: [0x13,0x10]
+name: break16
+body: |
+ bb.0:
+ BREAK16_NM 3
+...
+---
+# CHECK-LABEL: li16:
+# CHECK: li $a0, 5 # encoding: [0x05,0xd2]
+name: li16
+body: |
+ bb.0:
+ $a0_nm = LI16_NM 5
+...
+---
+# CHECK-LABEL: move:
+# CHECK: move $a0, $a1 # encoding: [0x85,0x10]
+name: move
+body: |
+ bb.0:
+ $a0_nm = MOVE_NM $a1_nm
+...
+---
+# CHECK-LABEL: not16:
+# CHECK: not $a0, $a1 # encoding: [0x50,0x52]
+name: not16
+body: |
+ bb.0:
+ $a0_nm = NOT16_NM $a1_nm
+...
+---
+# CHECK-LABEL: or16:
+# CHECK: or $a0, $a0, $a1 # encoding: [0x4c,0x52]
+name: or16
+body: |
+ bb.0:
+ $a0_nm = OR16_NM $a0_nm, $a1_nm
+...
+---
+# CHECK-LABEL: sdbbp16:
+# CHECK: sdbbp 3 # encoding: [0x1b,0x10]
+name: sdbbp16
+body: |
+ bb.0:
+ SDBBP16_NM 3
+...
+---
+# CHECK-LABEL: sll16:
+# CHECK: sll $a0, $a1, 3 # encoding: [0x53,0x32]
+name: sll16
+body: |
+ bb.0:
+ $a0_nm = SLL16_NM $a1_nm, 3
+...
+---
+# CHECK-LABEL: srl16:
+# CHECK: srl $a0, $a1, 3 # encoding: [0x5b,0x32]
+name: srl16
+body: |
+ bb.0:
+ $a0_nm = SRL16_NM $a1_nm, 3
+...
+---
+# CHECK-LABEL: syscall16:
+# CHECK: syscall 3 # encoding: [0x0b,0x10]
+name: syscall16
+body: |
+ bb.0:
+ SYSCALL16_NM 3
+...
+---
+# CHECK-LABEL: xor16:
+# CHECK: xor $a0, $a0, $a1 # encoding: [0x44,0x52]
+name: xor16
+body: |
+ bb.0:
+ $a0_nm = XOR16_NM $a0_nm, $a1_nm
+...
+
+# --- arithmetic ---
+---
+# CHECK-LABEL: addu16:
+# CHECK: addu $a0, $a1, $a2 # encoding: [0x58,0xb3]
+name: addu16
+body: |
+ bb.0:
+ $a0_nm = ADDu16_NM $a1_nm, $a2_nm
+...
+---
+# CHECK-LABEL: addu4x4:
+# CHECK: addu $a0, $a0, $a1 # encoding: [0x85,0x3c]
+name: addu4x4
+body: |
+ bb.0:
+ $a0_nm = ADDu4x4_NM $a0_nm, $a1_nm
+...
+---
+# CHECK-LABEL: movep:
+# CHECK: movep $a0, $a1, $a2, $a3 # encoding: [0xe6,0xbc]
+name: movep
+body: |
+ bb.0:
+ $a0_nm, $a1_nm = MOVEP_NM $a2_nm, $a3_nm
+...
+---
+# CHECK-LABEL: moveprev:
+# CHECK: movep $a0, $a1, $a2, $a3 # encoding: [0xac,0xfc]
+name: moveprev
+body: |
+ bb.0:
+ $a0_nm, $a1_nm = MOVEPREV_NM $a2_nm, $a3_nm
+...
+---
+# CHECK-LABEL: mul4x4:
+# CHECK: mul $a0, $a0, $a1 # encoding: [0x8d,0x3c]
+name: mul4x4
+body: |
+ bb.0:
+ $a0_nm = MUL4x4_NM $a0_nm, $a1_nm
+...
+---
+# CHECK-LABEL: subu16:
+# CHECK: subu $a0, $a1, $a2 # encoding: [0x59,0xb3]
+name: subu16
+body: |
+ bb.0:
+ $a0_nm = SUBu16_NM $a1_nm, $a2_nm
+...
+
+# --- load / store (with placeholder operands for now) ---
+---
+# CHECK-LABEL: lb16:
+# CHECK: lb $a0, 0 # encoding: [0x00,0x5e]
+name: lb16
+body: |
+ bb.0:
+ $a0_nm = LB16_NM 0
+...
+---
+# CHECK-LABEL: lbu16:
+# CHECK: lbu $a0, 0 # encoding: [0x08,0x5e]
+name: lbu16
+body: |
+ bb.0:
+ $a0_nm = LBU16_NM 0
+...
+---
+# CHECK-LABEL: lh16:
+# CHECK: lh $a0, 0 # encoding: [0x00,0x7e]
+name: lh16
+body: |
+ bb.0:
+ $a0_nm = LH16_NM 0
+...
+---
+# CHECK-LABEL: lhu16:
+# CHECK: lhu $a0, 0 # encoding: [0x08,0x7e]
+name: lhu16
+body: |
+ bb.0:
+ $a0_nm = LHU16_NM 0
+...
+---
+# CHECK-LABEL: lw16:
+# CHECK: lw $a0, 0 # encoding: [0x00,0x16]
+name: lw16
+body: |
+ bb.0:
+ $a0_nm = LW16_NM 0
+...
+---
+# CHECK-LABEL: lw4x4:
+# CHECK: lw $a0, 0 # encoding: [0x80,0x74]
+name: lw4x4
+body: |
+ bb.0:
+ $a0_nm = LW4x4_NM 0
+...
+---
+# CHECK-LABEL: lwgp16:
+# CHECK: lw $a0, 0 # encoding: [0x00,0x56]
+name: lwgp16
+body: |
+ bb.0:
+ $a0_nm = LWGP16_NM 0
+...
+---
+# CHECK-LABEL: lwsp16:
+# CHECK: lw $a0, 0 # encoding: [0x80,0x34]
+name: lwsp16
+body: |
+ bb.0:
+ $a0_nm = LWSP16_NM 0
+...
+---
+# CHECK-LABEL: lwxs16:
+# CHECK: lwxs $a0, 0 # encoding: [0x09,0x50]
+name: lwxs16
+body: |
+ bb.0:
+ $a0_nm = LWXS16_NM 0
+...
+---
+# CHECK-LABEL: sb16:
+# CHECK: sb $a0, 0 # encoding: [0x04,0x5e]
+name: sb16
+body: |
+ bb.0:
+ SB16_NM $a0_nm, 0
+...
+---
+# CHECK-LABEL: sh16:
+# CHECK: sh $a0, 0 # encoding: [0x01,0x7e]
+name: sh16
+body: |
+ bb.0:
+ SH16_NM $a0_nm, 0
+...
+---
+# CHECK-LABEL: sw16:
+# CHECK: sw $a0, 0 # encoding: [0x00,0x96]
+name: sw16
+body: |
+ bb.0:
+ SW16_NM $a0_nm, 0
+...
+---
+# CHECK-LABEL: sw4x4:
+# CHECK: sw $a0, 0 # encoding: [0x80,0xf4]
+name: sw4x4
+body: |
+ bb.0:
+ SW4x4_NM $a0_nm, 0
+...
+---
+# CHECK-LABEL: swgp16:
+# CHECK: sw $a0, 0 # encoding: [0x00,0xd6]
+name: swgp16
+body: |
+ bb.0:
+ SWGP16_NM $a0_nm, 0
+...
+---
+# CHECK-LABEL: swsp16:
+# CHECK: sw $a0, 0 # encoding: [0x80,0xb4]
+name: swsp16
+body: |
+ bb.0:
+ SWSP16_NM $a0_nm, 0
+...
+
+# --- jump ---
+---
+# CHECK-LABEL: jalrc16:
+# CHECK: jalrc $ra, $a1 # encoding: [0xb0,0xd8]
+name: jalrc16
+body: |
+ bb.0:
+ $ra_nm = JALRC16_NM $a1_nm
+...
+---
+# CHECK-LABEL: jrc:
+# CHECK: jrc $ra # encoding: [0xe0,0xdb]
+name: jrc
+body: |
+ bb.0:
+ JRC_NM $ra_nm
+...
+
+# --- branch (with placeholder operands for now) ---
+---
+# CHECK-LABEL: balc16:
+# CHECK: balc 0 # encoding: [0x00,0x38]
+name: balc16
+body: |
+ bb.0:
+ BALC16_NM 0
+...
+---
+# CHECK-LABEL: bc16:
+# CHECK: bc 0 # encoding: [0x00,0x18]
+name: bc16
+body: |
+ bb.0:
+ BC16_NM 0
+...
+---
+# CHECK-LABEL: beqzc16:
+# CHECK: beqzc $a0, 0 # encoding: [0x00,0x9a]
+name: beqzc16
+body: |
+ bb.0:
+ BEQZC16_NM $a0_nm, 0
+...
+---
+# CHECK-LABEL: bnezc16:
+# CHECK: bnezc $a0, 0 # encoding: [0x00,0xba]
+name: bnezc16
+body: |
+ bb.0:
+ BNEZC16_NM $a0_nm, 0
+...
+
+# --- save / restore ---
+---
+# CHECK-LABEL: restorejrc16:
+# CHECK: restore.jrc 00 # encoding: [0x00,0x1d]
+name: restorejrc16
+body: |
+ bb.0:
+ RESTOREJRC16_NM 0, 0
+...
+---
+# CHECK-LABEL: save16:
+# CHECK: save 00 # encoding: [0x00,0x1c]
+name: save16
+body: |
+ bb.0:
+ SAVE16_NM 0, 0
+...
diff --git a/llvm/test/CodeGen/Mips/nanomips/32bit-alu.mir b/llvm/test/CodeGen/Mips/nanomips/32bit-alu.mir
new file mode 100644
index 0000000000000..618d010f6ae4c
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/nanomips/32bit-alu.mir
@@ -0,0 +1,473 @@
+# RUN: llc %s -mtriple=nanomips-elf -start-after=mips-branch-expansion -show-mc-encoding -o - \
+# RUN: | FileCheck %s
+
+# Encoding tests for 32-bit nanoMIPS ALU instructions (arithmetic, logical,
+# shifts, bitfield, PC/GP-relative address computation)
+#
+# Since the PC/GP-relative symbol operand will be fully supported in the next
+# upstreaming batch, it is set to 0 to allow confirming the mnemonics and
+# encoding of the remaining instruction parts.
+# Encoding bytes are shown in on-disk order: each halfword is little-endian,
+# more significant halfword first.
+
+# --- three-register (ArithLogicR32) ---
+---
+# CHECK-LABEL: add:
+# CHECK: add $a0, $a1, $a2 # encoding: [0xc5,0x20,0x10,0x21]
+name: add
+body: |
+ bb.0:
+ $a0_nm = ADD_NM $a1_nm, $a2_nm
+...
+---
+# CHECK-LABEL: addu:
+# CHECK: addu $a0, $a1, $a2 # encoding: [0xc5,0x20,0x50,0x21]
+name: addu
+body: |
+ bb.0:
+ $a0_nm = ADDu_NM $a1_nm, $a2_nm
+...
+---
+# CHECK-LABEL: and:
+# CHECK: and $a0, $a1, $a2 # encoding: [0xc5,0x20,0x50,0x22]
+name: and
+body: |
+ bb.0:
+ $a0_nm = AND_NM $a1_nm, $a2_nm
+...
+---
+# CHECK-LABEL: div:
+# CHECK: div $a0, $a1, $a2 # encoding: [0xc5,0x20,0x18,0x21]
+name: div
+body: |
+ bb.0:
+ $a0_nm = DIV_NM $a1_nm, $a2_nm
+...
+---
+# CHECK-LABEL: divu:
+# CHECK: divu $a0, $a1, $a2 # encoding: [0xc5,0x20,0x98,0x21]
+name: divu
+body: |
+ bb.0:
+ $a0_nm = DIVU_NM $a1_nm, $a2_nm
+...
+---
+# CHECK-LABEL: mod:
+# CHECK: mod $a0, $a1, $a2 # encoding: [0xc5,0x20,0x58,0x21]
+name: mod
+body: |
+ bb.0:
+ $a0_nm = MOD_NM $a1_nm, $a2_nm
+...
+---
+# CHECK-LABEL: modu:
+# CHECK: modu $a0, $a1, $a2 # encoding: [0xc5,0x20,0xd8,0x21]
+name: modu
+body: |
+ bb.0:
+ $a0_nm = MODU_NM $a1_nm, $a2_nm
+...
+---
+# CHECK-LABEL: muh:
+# CHECK: muh $a0, $a1, $a2 # encoding: [0xc5,0x20,0x58,0x20]
+name: muh
+body: |
+ bb.0:
+ $a0_nm = MUH_NM $a1_nm, $a2_nm
+...
+---
+# CHECK-LABEL: muhu:
+# CHECK: muhu $a0, $a1, $a2 # encoding: [0xc5,0x20,0xd8,0x20]
+name: muhu
+body: |
+ bb.0:
+ $a0_nm = MUHU_NM $a1_nm, $a2_nm
+...
+---
+# CHECK-LABEL: mul:
+# CHECK: mul $a0, $a1, $a2 # encoding: [0xc5,0x20,0x18,0x20]
+name: mul
+body: |
+ bb.0:
+ $a0_nm = MUL_NM $a1_nm, $a2_nm
+...
+---
+# CHECK-LABEL: mulu:
+# CHECK: mulu $a0, $a1, $a2 # encoding: [0xc5,0x20,0x98,0x20]
+name: mulu
+body: |
+ bb.0:
+ $a0_nm = MULU_NM $a1_nm, $a2_nm
+...
+---
+# CHECK-LABEL: nor:
+# CHECK: nor $a0, $a1, $a2 # encoding: [0xc5,0x20,0xd0,0x22]
+name: nor
+body: |
+ bb.0:
+ $a0_nm = NOR_NM $a1_nm, $a2_nm
+...
+---
+# CHECK-LABEL: or:
+# CHECK: or $a0, $a1, $a2 # encoding: [0xc5,0x20,0x90,0x22]
+name: or
+body: |
+ bb.0:
+ $a0_nm = OR_NM $a1_nm, $a2_nm
+...
+---
+# CHECK-LABEL: rotrv:
+# CHECK: rotrv $a0, $a1, $a2 # encoding: [0xc5,0x20,0xd0,0x20]
+name: rotrv
+body: |
+ bb.0:
+ $a0_nm = ROTRV_NM $a1_nm, $a2_nm
+...
+---
+# CHECK-LABEL: sllv:
+# CHECK: sllv $a0, $a1, $a2 # encoding: [0xc5,0x20,0x10,0x20]
+name: sllv
+body: |
+ bb.0:
+ $a0_nm = SLLV_NM $a1_nm, $a2_nm
+...
+---
+# CHECK-LABEL: slt:
+# CHECK: slt $a0, $a1, $a2 # encoding: [0xc5,0x20,0x50,0x23]
+name: slt
+body: |
+ bb.0:
+ $a0_nm = SLT_NM $a1_nm, $a2_nm
+...
+---
+# CHECK-LABEL: sltu:
+# CHECK: sltu $a0, $a1, $a2 # encoding: [0xc5,0x20,0x90,0x23]
+name: sltu
+body: |
+ bb.0:
+ $a0_nm = SLTU_NM $a1_nm, $a2_nm
+...
+---
+# CHECK-LABEL: sov:
+# CHECK: sov $a0, $a1, $a2 # encoding: [0xc5,0x20,0xd0,0x23]
+name: sov
+body: |
+ bb.0:
+ $a0_nm = SOV_NM $a1_nm, $a2_nm
+...
+---
+# CHECK-LABEL: srav:
+# CHECK: srav $a0, $a1, $a2 # encoding: [0xc5,0x20,0x90,0x20]
+name: srav
+body: |
+ bb.0:
+ $a0_nm = SRAV_NM $a1_nm, $a2_nm
+...
+---
+# CHECK-LABEL: srlv:
+# CHECK: srlv $a0, $a1, $a2 # encoding: [0xc5,0x20,0x50,0x20]
+name: srlv
+body: |
+ bb.0:
+ $a0_nm = SRLV_NM $a1_nm, $a2_nm
+...
+---
+# CHECK-LABEL: sub:
+# CHECK: sub $a0, $a1, $a2 # encoding: [0xc5,0x20,0x90,0x21]
+name: sub
+body: |
+ bb.0:
+ $a0_nm = SUB_NM $a1_nm, $a2_nm
+...
+---
+# CHECK-LABEL: subu:
+# CHECK: subu $a0, $a1, $a2 # encoding: [0xc5,0x20,0xd0,0x21]
+name: subu
+body: |
+ bb.0:
+ $a0_nm = SUBu_NM $a1_nm, $a2_nm
+...
+---
+# CHECK-LABEL: xor:
+# CHECK: xor $a0, $a1, $a2 # encoding: [0xc5,0x20,0x10,0x23]
+name: xor
+body: |
+ bb.0:
+ $a0_nm = XOR_NM $a1_nm, $a2_nm
+...
+
+# --- register-only ---
+---
+# CHECK-LABEL: clo:
+# CHECK: clo $a0, $a1 # encoding: [0x85,0x20,0x3f,0x4b]
+name: clo
+body: |
+ bb.0:
+ $a0_nm = CLO_NM $a1_nm
+...
+---
+# CHECK-LABEL: clz:
+# CHECK: clz $a0, $a1 # encoding: [0x85,0x20,0x3f,0x5b]
+name: clz
+body: |
+ bb.0:
+ $a0_nm = CLZ_NM $a1_nm
+...
+---
+# CHECK-LABEL: movn:
+# CHECK: movn $a0, $a1, $a2 # encoding: [0xc5,0x20,0x10,0x26]
+name: movn
+body: |
+ bb.0:
+ $a0_nm = MOVN_NM $a1_nm, $a2_nm, $a0_nm
+...
+---
+# CHECK-LABEL: movz:
+# CHECK: movz $a0, $a1, $a2 # encoding: [0xc5,0x20,0x10,0x22]
+name: movz
+body: |
+ bb.0:
+ $a0_nm = MOVZ_NM $a1_nm, $a2_nm, $a0_nm
+...
+---
+# CHECK-LABEL: rdpgpr:
+# CHECK: rdpgpr $a0, $a1 # encoding: [0x85,0x20,0x7f,0xe1]
+name: rdpgpr
+body: |
+ bb.0:
+ $a0_nm = RDPGPR_NM $a1_nm
+...
+---
+# CHECK-LABEL: seb:
+# CHECK: seb $a0, $a1 # encoding: [0x85,0x20,0x08,0x00]
+name: seb
+body: |
+ bb.0:
+ $a0_nm = SEB_NM $a1_nm
+...
+---
+# CHECK-LABEL: seh:
+# CHECK: seh $a0, $a1 # encoding: [0x85,0x20,0x48,0x00]
+name: seh
+body: |
+ bb.0:
+ $a0_nm = SEH_NM $a1_nm
+...
+---
+# CHECK-LABEL: wrpgpr:
+# CHECK: wrpgpr $a0, $a1 # encoding: [0x85,0x20,0x7f,0xf1]
+name: wrpgpr
+body: |
+ bb.0:
+ $a0_nm = WRPGPR_NM $a1_nm
+...
+
+# --- register + immediate ---
+---
+# CHECK-LABEL: addiu:
+# CHECK: addiu $a0, $a1, 100 # encoding: [0x85,0x00,0x64,0x00]
+name: addiu
+body: |
+ bb.0:
+ $a0_nm = ADDIU_NM $a1_nm, 100
+...
+---
+# addiuneg's immediate (nimm12_nm) will be fully supported in the next
+# upstreaming batch. It is stored negated, so as a placeholder it is set
+# to 0 here to confirm the mnemonic and the opcode and register fields.
+
+# CHECK-LABEL: addiuneg:
+# CHECK: addiu $a0, $a1, 0 # encoding: [0x85,0x80,0x00,0x80]
+name: addiuneg
+body: |
+ bb.0:
+ $a0_nm = ADDIUNEG_NM $a1_nm, 0
+...
+---
+# CHECK-LABEL: addiurs5:
+# CHECK: addiu $a0, $a0, 4 # encoding: [0x8c,0x90]
+name: addiurs5
+body: |
+ bb.0:
+ $a0_nm = ADDIURS5_NM $a0_nm, 4
+...
+---
+# CHECK-LABEL: andi:
+# CHECK: andi $a0, $a1, 15 # encoding: [0x85,0x80,0x0f,0x20]
+name: andi
+body: |
+ bb.0:
+ $a0_nm = ANDI_NM $a1_nm, 15
+...
+---
+# CHECK-LABEL: lui:
+# CHECK: lui $a0, 15 # encoding: [0x80,0xe0,0x00,0xf0]
+name: lui
+body: |
+ bb.0:
+ $a0_nm = LUI_NM 15
+...
+---
+# CHECK-LABEL: ori:
+# CHECK: ori $a0, $a1, 15 # encoding: [0x85,0x80,0x0f,0x00]
+name: ori
+body: |
+ bb.0:
+ $a0_nm = ORI_NM $a1_nm, 15
+...
+---
+# CHECK-LABEL: rotr:
+# CHECK: rotr $a0, $a1, 3 # encoding: [0x85,0x80,0xc3,0xc0]
+name: rotr
+body: |
+ bb.0:
+ $a0_nm = ROTR_NM $a1_nm, 3
+...
+---
+# CHECK-LABEL: seqi:
+# CHECK: seqi $a0, $a1, 15 # encoding: [0x85,0x80,0x0f,0x60]
+name: seqi
+body: |
+ bb.0:
+ $a0_nm = SEQI_NM $a1_nm, 15
+...
+---
+# CHECK-LABEL: sll:
+# CHECK: sll $a0, $a1, 3 # encoding: [0x85,0x80,0x03,0xc0]
+name: sll
+body: |
+ bb.0:
+ $a0_nm = SLL_NM $a1_nm, 3
+...
+---
+# CHECK-LABEL: slti:
+# CHECK: slti $a0, $a1, 15 # encoding: [0x85,0x80,0x0f,0x40]
+name: slti
+body: |
+ bb.0:
+ $a0_nm = SLTI_NM $a1_nm, 15
+...
+---
+# CHECK-LABEL: sltiu:
+# CHECK: sltiu $a0, $a1, 15 # encoding: [0x85,0x80,0x0f,0x50]
+name: sltiu
+body: |
+ bb.0:
+ $a0_nm = SLTIU_NM $a1_nm, 15
+...
+---
+# CHECK-LABEL: sra:
+# CHECK: sra $a0, $a1, 3 # encoding: [0x85,0x80,0x83,0xc0]
+name: sra
+body: |
+ bb.0:
+ $a0_nm = SRA_NM $a1_nm, 3
+...
+---
+# CHECK-LABEL: srl:
+# CHECK: srl $a0, $a1, 3 # encoding: [0x85,0x80,0x43,0xc0]
+name: srl
+body: |
+ bb.0:
+ $a0_nm = SRL_NM $a1_nm, 3
+...
+---
+# CHECK-LABEL: xori:
+# CHECK: xori $a0, $a1, 15 # encoding: [0x85,0x80,0x0f,0x10]
+name: xori
+body: |
+ bb.0:
+ $a0_nm = XORI_NM $a1_nm, 15
+...
+
+# --- bitfield ---
+---
+# CHECK-LABEL: bitrevw:
+# CHECK: bitrevw $a0, $a1 # encoding: [0x85,0x80,0x1f,0xd0]
+name: bitrevw
+body: |
+ bb.0:
+ $a0_nm = BITREVW_NM $a1_nm
+...
+---
+# CHECK-LABEL: byterevw:
+# CHECK: byterevw $a0, $a1 # encoding: [0x85,0x80,0x18,0xd2]
+name: byterevw
+body: |
+ bb.0:
+ $a0_nm = BYTEREVW_NM $a1_nm
+...
+---
+# CHECK-LABEL: ext:
+# CHECK: ext $a0, $a1, 3, 5 # encoding: [0x85,0x80,0x03,0xf1]
+name: ext
+body: |
+ bb.0:
+ $a0_nm = EXT_NM $a1_nm, 3, 5
+...
+---
+# CHECK-LABEL: extw:
+# CHECK: extw $a0, $a1, $a2, 3 # encoding: [0xc5,0x20,0xdf,0x20]
+name: extw
+body: |
+ bb.0:
+ $a0_nm = EXTW_NM $a1_nm, $a2_nm, 3
+...
+---
+# CHECK-LABEL: ins:
+# CHECK: ins $a0, $a1, 3, 5 # encoding: [0x85,0x80,0xc3,0xe1]
+name: ins
+body: |
+ bb.0:
+ $a0_nm = INS_NM $a1_nm, 3, 5, $a0_nm
+...
+---
+# CHECK-LABEL: rotx:
+# CHECK: rotx $a0, $a1, 3, 5, 0 # encoding: [0x85,0x80,0x03,0xd1]
+name: rotx
+body: |
+ bb.0:
+ $a0_nm = ROTX_NM $a1_nm, 3, 5, 0
+...
+
+# --- PC/GP-relative address (with placeholder operands for now) ---
+---
+# CHECK-LABEL: addiugpb:
+# CHECK: addiu $a0, $gp, 0 # encoding: [0x8c,0x44,0x00,0x00]
+name: addiugpb
+body: |
+ bb.0:
+ $a0_nm = ADDIUGPB_NM $gp_nm, 0
+...
+---
+# CHECK-LABEL: addiugpw:
+# CHECK: addiu $a0, $gp, 0 # encoding: [0x80,0x40,0x00,0x00]
+name: addiugpw
+body: |
+ bb.0:
+ $a0_nm = ADDIUGPW_NM $gp_nm, 0
+...
+---
+# CHECK-LABEL: addiupc:
+# CHECK: addiupc $a0, 0 # encoding: [0x80,0x04,0x00,0x00]
+name: addiupc
+body: |
+ bb.0:
+ $a0_nm = ADDIUPC_NM 0
+...
+---
+# CHECK-LABEL: aluipc:
+# CHECK: aluipc $a0, 0 # encoding: [0x80,0xe0,0x02,0x00]
+name: aluipc
+body: |
+ bb.0:
+ $a0_nm = ALUIPC_NM 0
+...
+---
+# CHECK-LABEL: lapc32:
+# CHECK: lapc.h $a0, 0 # encoding: [0x80,0x04,0x00,0x00]
+name: lapc32
+body: |
+ bb.0:
+ $a0_nm = LAPC32_NM 0
+...
diff --git a/llvm/test/CodeGen/Mips/nanomips/32bit-branch.mir b/llvm/test/CodeGen/Mips/nanomips/32bit-branch.mir
new file mode 100644
index 0000000000000..8daa8502955a9
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/nanomips/32bit-branch.mir
@@ -0,0 +1,186 @@
+# RUN: llc %s -mtriple=nanomips-elf -start-after=mips-branch-expansion -show-mc-encoding -o - \
+# RUN: | FileCheck %s
+
+# Encoding tests for 32-bit nanoMIPS control-transfer instructions (indirect
+# jumps/calls, direct branches/calls, conditional branches)
+#
+# Since the branch and call target operands will be fully supported in the
+# next upstreaming batch, they are set to 0 to allow confirming the mnemonics
+# and encoding of the remaining instruction parts.
+#
+# Encoding bytes are shown in on-disk order: each halfword is little-endian,
+# more significant halfword first.
+
+# --- indirect jump / call (register) ---
+---
+# CHECK-LABEL: balrsc:
+# CHECK: balrsc $ra, $a1 # encoding: [0xe5,0x4b,0x00,0x80]
+name: balrsc
+body: |
+ bb.0:
+ $ra_nm = BALRSC_NM $a1_nm
+...
+---
+# CHECK-LABEL: jalrc:
+# CHECK: jalrc $ra, $a1 # encoding: [0xe5,0x4b,0x00,0x00]
+name: jalrc
+body: |
+ bb.0:
+ $ra_nm = JALRC_NM $a1_nm
+...
+---
+# CHECK-LABEL: jalrchb:
+# CHECK: jalrc.hb $ra, $a1 # encoding: [0xe5,0x4b,0x00,0x10]
+name: jalrchb
+body: |
+ bb.0:
+ $ra_nm = JALRCHB_NM $a1_nm
+...
+
+# --- direct branch / call (with placeholder operands for now) ---
+---
+# CHECK-LABEL: balc:
+# CHECK: balc 0 # encoding: [0x00,0x2a,0x00,0x00]
+name: balc
+body: |
+ bb.0:
+ BALC_NM 0
+...
+---
+# CHECK-LABEL: bc:
+# CHECK: bc 0 # encoding: [0x00,0x28,0x00,0x00]
+name: bc
+body: |
+ bb.0:
+ BC_NM 0
+...
+---
+# CHECK-LABEL: movebalc:
+# CHECK: move.balc $a0, $a1, 0 # encoding: [0xa0,0x08,0x00,0x00]
+name: movebalc
+body: |
+ bb.0:
+ $a0_nm = MOVEBALC_NM $a1_nm, 0
+...
+
+# --- conditional branch (with placeholder operands for now) ---
+---
+# CHECK-LABEL: bbeqzc:
+# CHECK: bbeqzc $a0, 3, 0 # encoding: [0x84,0xc8,0x00,0x18]
+name: bbeqzc
+body: |
+ bb.0:
+ BBEQZC_NM $a0_nm, 3, 0
+...
+---
+# CHECK-LABEL: bbnezc:
+# CHECK: bbnezc $a0, 3, 0 # encoding: [0x94,0xc8,0x00,0x18]
+name: bbnezc
+body: |
+ bb.0:
+ BBNEZC_NM $a0_nm, 3, 0
+...
+---
+# CHECK-LABEL: beqc:
+# CHECK: beqc $a0, $a1, 0 # encoding: [0xa4,0x88,0x00,0x00]
+name: beqc
+body: |
+ bb.0:
+ BEQC_NM $a0_nm, $a1_nm, 0
+...
+---
+# CHECK-LABEL: beqic:
+# CHECK: beqic $a0, 5, 0 # encoding: [0x80,0xc8,0x00,0x28]
+name: beqic
+body: |
+ bb.0:
+ BEQIC_NM $a0_nm, 5, 0
+...
+---
+# CHECK-LABEL: bgec:
+# CHECK: bgec $a0, $a1, 0 # encoding: [0xa4,0x88,0x00,0x80]
+name: bgec
+body: |
+ bb.0:
+ BGEC_NM $a0_nm, $a1_nm, 0
+...
+---
+# CHECK-LABEL: bgeic:
+# CHECK: bgeic $a0, 5, 0 # encoding: [0x88,0xc8,0x00,0x28]
+name: bgeic
+body: |
+ bb.0:
+ BGEIC_NM $a0_nm, 5, 0
+...
+---
+# CHECK-LABEL: bgeiuc:
+# CHECK: bgeiuc $a0, 5, 0 # encoding: [0x8c,0xc8,0x00,0x28]
+name: bgeiuc
+body: |
+ bb.0:
+ BGEIUC_NM $a0_nm, 5, 0
+...
+---
+# CHECK-LABEL: bgeuc:
+# CHECK: bgeuc $a0, $a1, 0 # encoding: [0xa4,0x88,0x00,0xc0]
+name: bgeuc
+body: |
+ bb.0:
+ BGEUC_NM $a0_nm, $a1_nm, 0
+...
+---
+# CHECK-LABEL: bltc:
+# CHECK: bltc $a0, $a1, 0 # encoding: [0xa4,0xa8,0x00,0x80]
+name: bltc
+body: |
+ bb.0:
+ BLTC_NM $a0_nm, $a1_nm, 0
+...
+---
+# CHECK-LABEL: bltic:
+# CHECK: bltic $a0, 5, 0 # encoding: [0x98,0xc8,0x00,0x28]
+name: bltic
+body: |
+ bb.0:
+ BLTIC_NM $a0_nm, 5, 0
+...
+---
+# CHECK-LABEL: bltiuc:
+# CHECK: bltiuc $a0, 5, 0 # encoding: [0x9c,0xc8,0x00,0x28]
+name: bltiuc
+body: |
+ bb.0:
+ BLTIUC_NM $a0_nm, 5, 0
+...
+---
+# CHECK-LABEL: bltuc:
+# CHECK: bltuc $a0, $a1, 0 # encoding: [0xa4,0xa8,0x00,0xc0]
+name: bltuc
+body: |
+ bb.0:
+ BLTUC_NM $a0_nm, $a1_nm, 0
+...
+---
+# CHECK-LABEL: bnec:
+# CHECK: bnec $a0, $a1, 0 # encoding: [0xa4,0xa8,0x00,0x00]
+name: bnec
+body: |
+ bb.0:
+ BNEC_NM $a0_nm, $a1_nm, 0
+...
+---
+# CHECK-LABEL: bneic:
+# CHECK: bneic $a0, 5, 0 # encoding: [0x90,0xc8,0x00,0x28]
+name: bneic
+body: |
+ bb.0:
+ BNEIC_NM $a0_nm, 5, 0
+...
+---
+# CHECK-LABEL: brsc:
+# CHECK: brsc $a0 # encoding: [0x04,0x48,0x00,0x80]
+name: brsc
+body: |
+ bb.0:
+ BRSC_NM $a0_nm, 0
+...
diff --git a/llvm/test/CodeGen/Mips/nanomips/32bit-load-store.mir b/llvm/test/CodeGen/Mips/nanomips/32bit-load-store.mir
new file mode 100644
index 0000000000000..24e0ff5ce97b5
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/nanomips/32bit-load-store.mir
@@ -0,0 +1,447 @@
+# RUN: llc %s -mtriple=nanomips-elf -start-after=mips-branch-expansion -show-mc-encoding -o - \
+# RUN: | FileCheck %s
+
+# Encoding tests for 32-bit nanoMIPS load, store and cache/prefetch/sync
+# instructions
+#
+# Since the memory address operands will be fully supported in the next
+# upstreaming batch, they are set to 0 to allow confirming the mnemonics and
+# encoding of the remaining instruction parts.
+# Encoding bytes are shown in on-disk order: each halfword is little-endian,
+# more significant halfword first.
+
+# --- load / store (with placeholder operands for now) ---
+---
+# CHECK-LABEL: lb:
+# CHECK: lb $a0, 0 # encoding: [0x80,0x84,0x00,0x00]
+name: lb
+body: |
+ bb.0:
+ $a0_nm = LB_NM 0
+...
+---
+# CHECK-LABEL: lbgp:
+# CHECK: lb $a0, 0 # encoding: [0x80,0x44,0x00,0x00]
+name: lbgp
+body: |
+ bb.0:
+ $a0_nm = LBGP_NM 0
+...
+---
+# CHECK-LABEL: lbs9:
+# CHECK: lb $a0, 0 # encoding: [0x80,0xa4,0x00,0x00]
+name: lbs9
+body: |
+ bb.0:
+ $a0_nm = LBs9_NM 0
+...
+---
+# CHECK-LABEL: lbu:
+# CHECK: lbu $a0, 0 # encoding: [0x80,0x84,0x00,0x20]
+name: lbu
+body: |
+ bb.0:
+ $a0_nm = LBU_NM 0
+...
+---
+# CHECK-LABEL: lbugp:
+# CHECK: lbu $a0, 0 # encoding: [0x88,0x44,0x00,0x00]
+name: lbugp
+body: |
+ bb.0:
+ $a0_nm = LBUGP_NM 0
+...
+---
+# CHECK-LABEL: lbus9:
+# CHECK: lbu $a0, 0 # encoding: [0x80,0xa4,0x00,0x10]
+name: lbus9
+body: |
+ bb.0:
+ $a0_nm = LBUs9_NM 0
+...
+---
+# CHECK-LABEL: lbux:
+# CHECK: lbux $a0, 0 # encoding: [0x00,0x20,0x07,0x21]
+name: lbux
+body: |
+ bb.0:
+ $a0_nm = LBUX_NM 0
+...
+---
+# CHECK-LABEL: lbx:
+# CHECK: lbx $a0, 0 # encoding: [0x00,0x20,0x07,0x20]
+name: lbx
+body: |
+ bb.0:
+ $a0_nm = LBX_NM 0
+...
+---
+# CHECK-LABEL: lh:
+# CHECK: lh $a0, 0 # encoding: [0x80,0x84,0x00,0x40]
+name: lh
+body: |
+ bb.0:
+ $a0_nm = LH_NM 0
+...
+---
+# CHECK-LABEL: lhgp:
+# CHECK: lh $a0, 0 # encoding: [0x90,0x44,0x00,0x00]
+name: lhgp
+body: |
+ bb.0:
+ $a0_nm = LHGP_NM 0
+...
+---
+# CHECK-LABEL: lhs9:
+# CHECK: lh $a0, 0 # encoding: [0x80,0xa4,0x00,0x20]
+name: lhs9
+body: |
+ bb.0:
+ $a0_nm = LHs9_NM 0
+...
+---
+# CHECK-LABEL: lhu:
+# CHECK: lhu $a0, 0 # encoding: [0x80,0x84,0x00,0x60]
+name: lhu
+body: |
+ bb.0:
+ $a0_nm = LHU_NM 0
+...
+---
+# CHECK-LABEL: lhugp:
+# CHECK: lhu $a0, 0 # encoding: [0x90,0x44,0x01,0x00]
+name: lhugp
+body: |
+ bb.0:
+ $a0_nm = LHUGP_NM 0
+...
+---
+# CHECK-LABEL: lhus9:
+# CHECK: lhu $a0, 0 # encoding: [0x80,0xa4,0x00,0x30]
+name: lhus9
+body: |
+ bb.0:
+ $a0_nm = LHUs9_NM 0
+...
+---
+# CHECK-LABEL: lhux:
+# CHECK: lhux $a0, 0 # encoding: [0x00,0x20,0x07,0x23]
+name: lhux
+body: |
+ bb.0:
+ $a0_nm = LHUX_NM 0
+...
+---
+# CHECK-LABEL: lhuxs:
+# CHECK: lhuxs $a0, 0 # encoding: [0x00,0x20,0x47,0x23]
+name: lhuxs
+body: |
+ bb.0:
+ $a0_nm = LHUXS_NM 0
+...
+---
+# CHECK-LABEL: lhx:
+# CHECK: lhx $a0, 0 # encoding: [0x00,0x20,0x07,0x22]
+name: lhx
+body: |
+ bb.0:
+ $a0_nm = LHX_NM 0
+...
+---
+# CHECK-LABEL: lhxs:
+# CHECK: lhxs $a0, 0 # encoding: [0x00,0x20,0x47,0x22]
+name: lhxs
+body: |
+ bb.0:
+ $a0_nm = LHXS_NM 0
+...
+---
+# CHECK-LABEL: ll:
+# CHECK: ll $a0, 0 # encoding: [0x80,0xa4,0x00,0x51]
+name: ll
+body: |
+ bb.0:
+ $a0_nm = LL_NM 0
+...
+---
+# CHECK-LABEL: lw:
+# CHECK: lw $a0, 0 # encoding: [0x80,0x84,0x00,0x80]
+name: lw
+body: |
+ bb.0:
+ $a0_nm = LW_NM 0
+...
+---
+# CHECK-LABEL: lwgp:
+# CHECK: lw $a0, 0 # encoding: [0x80,0x40,0x02,0x00]
+name: lwgp
+body: |
+ bb.0:
+ $a0_nm = LWGP_NM 0
+...
+---
+# CHECK-LABEL: lwm:
+# CHECK: lwm $a0, 0, 1 # encoding: [0x80,0xa4,0x00,0x14]
+name: lwm
+body: |
+ bb.0:
+ $a0_nm = LWM_NM 0, 1
+...
+---
+# CHECK-LABEL: lws9:
+# CHECK: lw $a0, 0 # encoding: [0x80,0xa4,0x00,0x40]
+name: lws9
+body: |
+ bb.0:
+ $a0_nm = LWs9_NM 0
+...
+---
+# CHECK-LABEL: lwx:
+# CHECK: lwx $a0, 0 # encoding: [0x00,0x20,0x07,0x24]
+name: lwx
+body: |
+ bb.0:
+ $a0_nm = LWX_NM 0
+...
+---
+# CHECK-LABEL: lwxs:
+# CHECK: lwxs $a0, 0 # encoding: [0x00,0x20,0x47,0x24]
+name: lwxs
+body: |
+ bb.0:
+ $a0_nm = LWXS_NM 0
+...
+---
+# CHECK-LABEL: sb:
+# CHECK: sb $a0, 0 # encoding: [0x80,0x84,0x00,0x10]
+name: sb
+body: |
+ bb.0:
+ SB_NM $a0_nm, 0
+...
+---
+# CHECK-LABEL: sbgp:
+# CHECK: sb $a0, 0 # encoding: [0x84,0x44,0x00,0x00]
+name: sbgp
+body: |
+ bb.0:
+ SBGP_NM $a0_nm, 0
+...
+---
+# CHECK-LABEL: sbs9:
+# CHECK: sb $a0, 0 # encoding: [0x80,0xa4,0x00,0x08]
+name: sbs9
+body: |
+ bb.0:
+ SBs9_NM $a0_nm, 0
+...
+---
+# CHECK-LABEL: sbx:
+# CHECK: sbx $a0, 0 # encoding: [0x00,0x20,0x87,0x20]
+name: sbx
+body: |
+ bb.0:
+ SBX_NM $a0_nm, 0
+...
+---
+# CHECK-LABEL: sc:
+# CHECK: sc $a0, 0 # encoding: [0x80,0xa4,0x00,0x59]
+name: sc
+body: |
+ bb.0:
+ $a0_nm = SC_NM $a0_nm, 0
+...
+---
+# CHECK-LABEL: scwp:
+# CHECK: scwp $a0, $a1, 0 # encoding: [0x80,0xa4,0x29,0x59]
+name: scwp
+body: |
+ bb.0:
+ $a0_nm = SCWP_NM $a0_nm, $a1_nm, 0
+...
+---
+# CHECK-LABEL: sh:
+# CHECK: sh $a0, 0 # encoding: [0x80,0x84,0x00,0x50]
+name: sh
+body: |
+ bb.0:
+ SH_NM $a0_nm, 0
+...
+---
+# CHECK-LABEL: shgp:
+# CHECK: sh $a0, 0 # encoding: [0x94,0x44,0x00,0x00]
+name: shgp
+body: |
+ bb.0:
+ SHGP_NM $a0_nm, 0
+...
+---
+# CHECK-LABEL: shs9:
+# CHECK: sh $a0, 0 # encoding: [0x80,0xa4,0x00,0x28]
+name: shs9
+body: |
+ bb.0:
+ SHs9_NM $a0_nm, 0
+...
+---
+# CHECK-LABEL: shx:
+# CHECK: shx $a0, 0 # encoding: [0x00,0x20,0x87,0x22]
+name: shx
+body: |
+ bb.0:
+ SHX_NM $a0_nm, 0
+...
+---
+# CHECK-LABEL: shxs:
+# CHECK: shxs $a0, 0 # encoding: [0x00,0x20,0xc7,0x22]
+name: shxs
+body: |
+ bb.0:
+ SHXS_NM $a0_nm, 0
+...
+---
+# CHECK-LABEL: sw:
+# CHECK: sw $a0, 0 # encoding: [0x80,0x84,0x00,0x90]
+name: sw
+body: |
+ bb.0:
+ SW_NM $a0_nm, 0
+...
+---
+# CHECK-LABEL: swgp:
+# CHECK: sw $a0, 0 # encoding: [0x80,0x40,0x03,0x00]
+name: swgp
+body: |
+ bb.0:
+ SWGP_NM $a0_nm, 0
+...
+---
+# CHECK-LABEL: swm:
+# CHECK: swm $a0, 0, 1 # encoding: [0x80,0xa4,0x00,0x1c]
+name: swm
+body: |
+ bb.0:
+ SWM_NM $a0_nm, 0, 1
+...
+---
+# CHECK-LABEL: sws9:
+# CHECK: sw $a0, 0 # encoding: [0x80,0xa4,0x00,0x48]
+name: sws9
+body: |
+ bb.0:
+ SWs9_NM $a0_nm, 0
+...
+---
+# CHECK-LABEL: swx:
+# CHECK: swx $a0, 0 # encoding: [0x00,0x20,0x87,0x24]
+name: swx
+body: |
+ bb.0:
+ SWX_NM $a0_nm, 0
+...
+---
+# CHECK-LABEL: swxs:
+# CHECK: swxs $a0, 0 # encoding: [0x00,0x20,0xc7,0x24]
+name: swxs
+body: |
+ bb.0:
+ SWXS_NM $a0_nm, 0
+...
+---
+# CHECK-LABEL: ualh:
+# CHECK: ualh $a0, 0 # encoding: [0x80,0xa4,0x00,0x21]
+name: ualh
+body: |
+ bb.0:
+ $a0_nm = UALH_NM 0, $a0_nm
+...
+---
+# CHECK-LABEL: ualw:
+# CHECK: ualw $a0, 0 # encoding: [0x80,0xa4,0x00,0x15]
+name: ualw
+body: |
+ bb.0:
+ $a0_nm = UALW_NM 0, $a0_nm
+...
+---
+# CHECK-LABEL: ualwm:
+# CHECK: ualwm $a0, 0, 1 # encoding: [0x80,0xa4,0x00,0x15]
+name: ualwm
+body: |
+ bb.0:
+ $a0_nm = UALWM_NM 0, 1
+...
+---
+# CHECK-LABEL: uash:
+# CHECK: uash $a0, 0 # encoding: [0x80,0xa4,0x00,0x29]
+name: uash
+body: |
+ bb.0:
+ UASH_NM $a0_nm, 0
+...
+---
+# CHECK-LABEL: uasw:
+# CHECK: uasw $a0, 0 # encoding: [0x80,0xa4,0x00,0x1d]
+name: uasw
+body: |
+ bb.0:
+ UASW_NM $a0_nm, 0
+...
+---
+# CHECK-LABEL: uaswm:
+# CHECK: uaswm $a0, 0, 1 # encoding: [0x80,0xa4,0x00,0x1d]
+name: uaswm
+body: |
+ bb.0:
+ UASWM_NM $a0_nm, 0, 1
+...
+
+# --- cache / prefetch / sync (with placeholder operands for now) ---
+---
+# CHECK-LABEL: cache:
+# CHECK: cache 0, 0 # encoding: [0x00,0xa4,0x00,0x39]
+name: cache
+body: |
+ bb.0:
+ CACHE_NM 0, 0
+...
+---
+# CHECK-LABEL: llwp:
+# CHECK: llwp $a0, $a1, 0 # encoding: [0x80,0xa4,0x29,0x51]
+name: llwp
+body: |
+ bb.0:
+ $a0_nm, $a1_nm = LLWP_NM 0
+...
+---
+# CHECK-LABEL: pref:
+# CHECK: pref 0, 0 # encoding: [0x00,0x84,0x00,0x30]
+name: pref
+body: |
+ bb.0:
+ PREF_NM 0, 0
+...
+---
+# CHECK-LABEL: prefs9:
+# CHECK: pref 0, 0 # encoding: [0x00,0xa4,0x00,0x18]
+name: prefs9
+body: |
+ bb.0:
+ PREFs9_NM 0, 0
+...
+---
+# CHECK-LABEL: synci:
+# CHECK: synci 0 # encoding: [0xe0,0x87,0x00,0x30]
+name: synci
+body: |
+ bb.0:
+ SYNCI_NM 0
+...
+---
+# CHECK-LABEL: syncis9:
+# CHECK: synci 0 # encoding: [0xe0,0xa7,0x00,0x18]
+name: syncis9
+body: |
+ bb.0:
+ SYNCIs9_NM 0
+...
diff --git a/llvm/test/CodeGen/Mips/nanomips/32bit-system.mir b/llvm/test/CodeGen/Mips/nanomips/32bit-system.mir
new file mode 100644
index 0000000000000..ea5531312cd19
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/nanomips/32bit-system.mir
@@ -0,0 +1,336 @@
+# RUN: llc %s -mtriple=nanomips-elf -start-after=mips-branch-expansion -show-mc-encoding -o - \
+# RUN: | FileCheck %s
+
+# Encoding tests for 32-bit nanoMIPS system and coprocessor instructions
+# (system control, CP0 access, misc/ASE ops, save/restore)
+#
+# Encoding bytes are shown in on-disk order: each halfword is little-endian,
+# more significant halfword first.
+
+# --- system control ---
+---
+# CHECK-LABEL: break:
+# CHECK: break 7 # encoding: [0x10,0x00,0x07,0x00]
+name: break
+body: |
+ bb.0:
+ BREAK_NM 7
+...
+---
+# CHECK-LABEL: crc32b:
+# CHECK: crc32b $a0, $a1 # encoding: [0x85,0x20,0xe8,0x03]
+name: crc32b
+body: |
+ bb.0:
+ $a0_nm = CRC32B_NM $a0_nm, $a1_nm
+...
+---
+# CHECK-LABEL: crc32cb:
+# CHECK: crc32cb $a0, $a1 # encoding: [0x85,0x20,0xe8,0x13]
+name: crc32cb
+body: |
+ bb.0:
+ $a0_nm = CRC32CB_NM $a0_nm, $a1_nm
+...
+---
+# CHECK-LABEL: crc32ch:
+# CHECK: crc32ch $a0, $a1 # encoding: [0x85,0x20,0xe8,0x17]
+name: crc32ch
+body: |
+ bb.0:
+ $a0_nm = CRC32CH_NM $a0_nm, $a1_nm
+...
+---
+# CHECK-LABEL: crc32cw:
+# CHECK: crc32cw $a0, $a1 # encoding: [0x85,0x20,0xe8,0x1b]
+name: crc32cw
+body: |
+ bb.0:
+ $a0_nm = CRC32CW_NM $a0_nm, $a1_nm
+...
+---
+# CHECK-LABEL: crc32h:
+# CHECK: crc32h $a0, $a1 # encoding: [0x85,0x20,0xe8,0x07]
+name: crc32h
+body: |
+ bb.0:
+ $a0_nm = CRC32H_NM $a0_nm, $a1_nm
+...
+---
+# CHECK-LABEL: crc32w:
+# CHECK: crc32w $a0, $a1 # encoding: [0x85,0x20,0xe8,0x0b]
+name: crc32w
+body: |
+ bb.0:
+ $a0_nm = CRC32W_NM $a0_nm, $a1_nm
+...
+---
+# CHECK-LABEL: deret:
+# CHECK: deret # encoding: [0x00,0x20,0x7f,0xe3]
+name: deret
+body: |
+ bb.0:
+ DERET_NM
+...
+---
+# CHECK-LABEL: ehb:
+# CHECK: ehb # encoding: [0x00,0x80,0x03,0xc0]
+name: ehb
+body: |
+ bb.0:
+ EHB_NM
+...
+---
+# CHECK-LABEL: eret:
+# CHECK: eret # encoding: [0x00,0x20,0x7f,0xf3]
+name: eret
+body: |
+ bb.0:
+ ERET_NM
+...
+---
+# CHECK-LABEL: eretnc:
+# CHECK: eretnc # encoding: [0x01,0x20,0x7f,0xf3]
+name: eretnc
+body: |
+ bb.0:
+ ERETNC_NM
+...
+---
+# CHECK-LABEL: nop:
+# CHECK: nop # encoding: [0x08,0x90]
+name: nop
+body: |
+ bb.0:
+ NOP_NM
+...
+---
+# CHECK-LABEL: nop32:
+# CHECK: nop32 # encoding: [0x00,0x80,0x00,0xc0]
+name: nop32
+body: |
+ bb.0:
+ NOP32_NM
+...
+---
+# CHECK-LABEL: pause:
+# CHECK: pause # encoding: [0x00,0x80,0x05,0xc0]
+name: pause
+body: |
+ bb.0:
+ PAUSE_NM
+...
+---
+# CHECK-LABEL: sdbbp:
+# CHECK: sdbbp 7 # encoding: [0x18,0x00,0x07,0x00]
+name: sdbbp
+body: |
+ bb.0:
+ SDBBP_NM 7
+...
+---
+# CHECK-LABEL: sigrie:
+# CHECK: sigrie 7 # encoding: [0x00,0x00,0x07,0x00]
+name: sigrie
+body: |
+ bb.0:
+ SIGRIE_NM 7
+...
+---
+# CHECK-LABEL: syscall:
+# CHECK: syscall 7 # encoding: [0x08,0x00,0x07,0x00]
+name: syscall
+body: |
+ bb.0:
+ SYSCALL_NM 7
+...
+---
+# CHECK-LABEL: teq:
+# CHECK: teq $a0, $a1, 0 # encoding: [0xa4,0x20,0x00,0x00]
+name: teq
+body: |
+ bb.0:
+ TEQ_NM $a0_nm, $a1_nm, 0
+...
+---
+# CHECK-LABEL: tne:
+# CHECK: tne $a0, $a1, 0 # encoding: [0xa4,0x20,0x00,0x04]
+name: tne
+body: |
+ bb.0:
+ TNE_NM $a0_nm, $a1_nm, 0
+...
+
+# --- coprocessor-0 access ---
+---
+# CHECK-LABEL: mfc0:
+# CHECK: mfc0 $a0, $0, 0 # encoding: [0x80,0x20,0x30,0x00]
+name: mfc0
+body: |
+ bb.0:
+ $a0_nm = MFC0_NM $cop00, 0
+...
+---
+# CHECK-LABEL: mfc0sel:
+# CHECK: mfc0 $a0, $index # encoding: [0x80,0x20,0x30,0x00]
+name: mfc0sel
+body: |
+ bb.0:
+ $a0_nm = MFC0Sel_NM $cop0sel_index
+...
+---
+# CHECK-LABEL: mfhc0:
+# CHECK: mfhc0 $a0, $0, 0 # encoding: [0x80,0x20,0x38,0x00]
+name: mfhc0
+body: |
+ bb.0:
+ $a0_nm = MFHC0_NM $cop00, 0
+...
+---
+# CHECK-LABEL: mfhc0sel:
+# CHECK: mfhc0 $a0, $index # encoding: [0x80,0x20,0x38,0x00]
+name: mfhc0sel
+body: |
+ bb.0:
+ $a0_nm = MFHC0Sel_NM $cop0sel_index
+...
+---
+# CHECK-LABEL: mtc0:
+# CHECK: mtc0 $a0, $0, 0 # encoding: [0x80,0x20,0x70,0x00]
+name: mtc0
+body: |
+ bb.0:
+ MTC0_NM $a0_nm, $cop00, 0
+...
+---
+# CHECK-LABEL: mtc0sel:
+# CHECK: mtc0 $a0, $index # encoding: [0x80,0x20,0x70,0x00]
+name: mtc0sel
+body: |
+ bb.0:
+ MTC0Sel_NM $a0_nm, $cop0sel_index
+...
+---
+# CHECK-LABEL: mthc0:
+# CHECK: mthc0 $a0, $0, 0 # encoding: [0x80,0x20,0x78,0x00]
+name: mthc0
+body: |
+ bb.0:
+ MTHC0_NM $a0_nm, $cop00, 0
+...
+---
+# CHECK-LABEL: mthc0sel:
+# CHECK: mthc0 $a0, $index # encoding: [0x80,0x20,0x78,0x00]
+name: mthc0sel
+body: |
+ bb.0:
+ MTHC0Sel_NM $a0_nm, $cop0sel_index
+...
+---
+# CHECK-LABEL: rdhwr:
+# CHECK: rdhwr $a0, $0, 0 # encoding: [0x80,0x20,0xc0,0x01]
+name: rdhwr
+body: |
+ bb.0:
+ $a0_nm = RDHWR_NM $cop00, 0
+...
+
+# --- misc / ASE ---
+---
+# CHECK-LABEL: di:
+# CHECK: di $a0 # encoding: [0x80,0x20,0x7f,0x47]
+name: di
+body: |
+ bb.0:
+ $a0_nm = DI_NM
+...
+---
+# CHECK-LABEL: dvp:
+# CHECK: dvp $a0 # encoding: [0x80,0x20,0x90,0x03]
+name: dvp
+body: |
+ bb.0:
+ $a0_nm = DVP_NM
+...
+---
+# CHECK-LABEL: ei:
+# CHECK: ei $a0 # encoding: [0x80,0x20,0x7f,0x57]
+name: ei
+body: |
+ bb.0:
+ $a0_nm = EI_NM
+...
+---
+# CHECK-LABEL: evp:
+# CHECK: evp $a0 # encoding: [0x80,0x20,0x90,0x07]
+name: evp
+body: |
+ bb.0:
+ $a0_nm = EVP_NM
+...
+---
+# CHECK-LABEL: ginvi:
+# CHECK: ginvi $a0 # encoding: [0x04,0x20,0x7f,0x1f]
+name: ginvi
+body: |
+ bb.0:
+ GINVI_NM $a0_nm
+...
+---
+# CHECK-LABEL: ginvt:
+# CHECK: ginvt $a0, 0 # encoding: [0x04,0x20,0x7f,0x0f]
+name: ginvt
+body: |
+ bb.0:
+ GINVT_NM $a0_nm, 0
+...
+---
+# CHECK-LABEL: lsa:
+# CHECK: lsa $a0, $a1, $a2, 1 # encoding: [0xc5,0x20,0x0f,0x22]
+name: lsa
+body: |
+ bb.0:
+ $a0_nm = LSA_NM $a1_nm, $a2_nm, 1
+...
+---
+# CHECK-LABEL: sync:
+# CHECK: sync 0 # encoding: [0x00,0x80,0x06,0xc0]
+name: sync
+body: |
+ bb.0:
+ SYNC_NM 0
+...
+---
+# CHECK-LABEL: wait:
+# CHECK: wait 0 # encoding: [0x00,0x20,0x7f,0xc3]
+name: wait
+body: |
+ bb.0:
+ WAIT_NM 0
+...
+
+# --- save / restore ---
+---
+# CHECK-LABEL: restore:
+# CHECK: restore 00 # encoding: [0x00,0x80,0x02,0x30]
+name: restore
+body: |
+ bb.0:
+ RESTORE_NM 0, 0
+...
+---
+# CHECK-LABEL: restorejrc:
+# CHECK: restore.jrc 00 # encoding: [0x00,0x80,0x03,0x30]
+name: restorejrc
+body: |
+ bb.0:
+ RESTOREJRC_NM 0, 0
+...
+---
+# CHECK-LABEL: save:
+# CHECK: save 00 # encoding: [0x00,0x80,0x00,0x30]
+name: save
+body: |
+ bb.0:
+ SAVE_NM 0, 0
+...
diff --git a/llvm/test/CodeGen/Mips/nanomips/48bit.mir b/llvm/test/CodeGen/Mips/nanomips/48bit.mir
new file mode 100644
index 0000000000000..8c1fcda4b34ba
--- /dev/null
+++ b/llvm/test/CodeGen/Mips/nanomips/48bit.mir
@@ -0,0 +1,73 @@
+# RUN: llc %s -mtriple=nanomips-elf -start-after=mips-branch-expansion -show-mc-encoding -o - \
+# RUN: | FileCheck %s
+
+# Encoding tests for 48-bit nanoMIPS instructions (wide immediates,
+# PC/GP-relative address computation, PC-relative load/store)
+#
+# Since the PC/GP-relative and PC-relative operands will be fully supported in
+# the next upstreaming batch, they are set to 0 to allow confirming the
+# mnemonics and encoding of the remaining instruction parts.
+# Encoding bytes are shown in on-disk order: each halfword is little-endian,
+# more significant halfword first.
+
+# --- arithmetic / immediate ---
+---
+# CHECK-LABEL: addiu48:
+# CHECK: addiu $a0, $a0, 305419896 # encoding: [0x81,0x60,0x78,0x56,0x34,0x12]
+name: addiu48
+body: |
+ bb.0:
+ $a0_nm = ADDIU48_NM $a0_nm, 305419896
+...
+---
+# CHECK-LABEL: li48:
+# CHECK: li $a0, 305419896 # encoding: [0x80,0x60,0x78,0x56,0x34,0x12]
+name: li48
+body: |
+ bb.0:
+ $a0_nm = LI48_NM 305419896
+...
+
+# --- PC/GP-relative address (with placeholder operands for now) ---
+---
+# CHECK-LABEL: addiugp48:
+# CHECK: addiu.b32 $a0, $gp, 0 # encoding: [0x82,0x60,0x00,0x00,0x00,0x00]
+name: addiugp48
+body: |
+ bb.0:
+ $a0_nm = ADDIUGP48_NM $gp_nm, 0
+...
+---
+# CHECK-LABEL: addiupc48:
+# CHECK: addiupc $a0, 0 # encoding: [0x83,0x60,0x00,0x00,0x00,0x00]
+name: addiupc48
+body: |
+ bb.0:
+ $a0_nm = ADDIUPC48_NM 0
+...
+---
+# CHECK-LABEL: lapc48:
+# CHECK: lapc.b $a0, 0 # encoding: [0x83,0x60,0x00,0x00,0x00,0x00]
+name: lapc48
+body: |
+ bb.0:
+ $a0_nm = LAPC48_NM 0
+...
+
+# --- PC-relative load / store (with placeholder operands for now) ---
+---
+# CHECK-LABEL: lwpc:
+# CHECK: lwpc $a0, 0 # encoding: [0x8b,0x60,0x00,0x00,0x00,0x00]
+name: lwpc
+body: |
+ bb.0:
+ $a0_nm = LWPC_NM 0
+...
+---
+# CHECK-LABEL: swpc:
+# CHECK: swpc $a0, 0 # encoding: [0x8f,0x60,0x00,0x00,0x00,0x00]
+name: swpc
+body: |
+ bb.0:
+ SWPC_NM $a0_nm, 0
+...
>From 60d1144fa2a80e925b11a240243ee4ab8627ea4c Mon Sep 17 00:00:00 2001
From: Nemanja Rakovic <ot_nemanja.rakovic at mediatek.com>
Date: Fri, 18 Sep 2026 20:09:27 +0200
Subject: [PATCH 08/15] fixup! [nanoMIPS 2/7] Add ELF and relocation support
---
.../ELF/file-header-machine-types.test | 3 +
.../llvm-readobj/ELF/nanomips-eflags.test | 66 +++++++++++++++++++
.../tools/obj2yaml/ELF/nanomips-eflags.yaml | 40 +++++++++++
llvm/tools/llvm-readobj/ELFDumper.cpp | 17 +++++
4 files changed, 126 insertions(+)
create mode 100644 llvm/test/tools/llvm-readobj/ELF/nanomips-eflags.test
create mode 100644 llvm/test/tools/obj2yaml/ELF/nanomips-eflags.yaml
diff --git a/llvm/test/tools/llvm-readobj/ELF/file-header-machine-types.test b/llvm/test/tools/llvm-readobj/ELF/file-header-machine-types.test
index 642532b39dfa5..f0c74eef3af51 100644
--- a/llvm/test/tools/llvm-readobj/ELF/file-header-machine-types.test
+++ b/llvm/test/tools/llvm-readobj/ELF/file-header-machine-types.test
@@ -477,6 +477,9 @@
# RUN: yaml2obj %s -o %t.bpf.o -D MACHINE=EM_BPF
# RUN: llvm-readelf --file-headers %t.bpf.o | FileCheck %s -DMACHINE="EM_BPF"
+# RUN: yaml2obj %s -o %t.nanomips.o -D MACHINE=EM_NANOMIPS
+# RUN: llvm-readelf --file-headers %t.nanomips.o | FileCheck %s -DMACHINE="nanoMIPS"
+
# RUN: yaml2obj %s -o %t.ve.o -D MACHINE=EM_VE
# RUN: llvm-readelf --file-headers %t.ve.o | FileCheck %s -DMACHINE="NEC SX-Aurora Vector Engine"
diff --git a/llvm/test/tools/llvm-readobj/ELF/nanomips-eflags.test b/llvm/test/tools/llvm-readobj/ELF/nanomips-eflags.test
new file mode 100644
index 0000000000000..ed18cfb109251
--- /dev/null
+++ b/llvm/test/tools/llvm-readobj/ELF/nanomips-eflags.test
@@ -0,0 +1,66 @@
+## Check llvm-readobj's ability to decode nanoMIPS e_flags field values.
+
+# RUN: yaml2obj %s -o %t-none -DFLAGS="[]"
+# RUN: llvm-readobj -h %t-none | FileCheck --check-prefixes=READOBJ-NONE %s
+# RUN: llvm-readelf -h %t-none | FileCheck --check-prefixes=READELF-NONE --match-full-lines %s
+
+# RUN: yaml2obj %s -o %t-p32 -DFLAGS="[ EF_NANOMIPS_ABI_P32 ]"
+# RUN: llvm-readobj -h %t-p32 | FileCheck --check-prefixes=READOBJ-P32 %s
+# RUN: llvm-readelf -h %t-p32 | FileCheck --check-prefixes=READELF-P32 --match-full-lines %s
+
+# RUN: yaml2obj %s -o %t-relax -DFLAGS="[ EF_NANOMIPS_LINKRELAX ]"
+# RUN: llvm-readobj -h %t-relax | FileCheck --check-prefixes=READOBJ-RELAX %s
+# RUN: llvm-readelf -h %t-relax | FileCheck --check-prefixes=READELF-RELAX --match-full-lines %s
+
+# RUN: yaml2obj %s -o %t-relax-pcrel -DFLAGS="[ EF_NANOMIPS_LINKRELAX, EF_NANOMIPS_PCREL, EF_NANOMIPS_ABI_P32 ]"
+# RUN: llvm-readobj -h %t-relax-pcrel | FileCheck --check-prefixes=READOBJ-RELAX-PCREL %s
+# RUN: llvm-readelf -h %t-relax-pcrel | FileCheck --check-prefixes=READELF-RELAX-PCREL --match-full-lines %s
+
+# RUN: yaml2obj %s -o %t-all \
+# RUN: -DFLAGS="[ EF_NANOMIPS_LINKRELAX, EF_NANOMIPS_PIC, EF_NANOMIPS_32BITMODE, EF_NANOMIPS_PID, EF_NANOMIPS_PCREL, EF_NANOMIPS_ABI_P32 ]"
+# RUN: llvm-readobj -h %t-all | FileCheck --check-prefixes=READOBJ-ALL %s
+# RUN: llvm-readelf -h %t-all | FileCheck --check-prefixes=READELF-ALL --match-full-lines %s
+
+
+# READOBJ-NONE: Class: 32-bit (0x1)
+# READOBJ-NONE: Flags [ (0x0)
+# READOBJ-NONE-NEXT: ]
+# READELF-NONE: Class: ELF32
+# READELF-NONE: Machine: nanoMIPS
+
+# READOBJ-P32: Flags [ (0x1000)
+# READOBJ-P32-NEXT: EF_NANOMIPS_ABI_P32 (0x1000)
+# READOBJ-P32-NEXT: ]
+
+# READOBJ-RELAX: Flags [ (0x1)
+# READOBJ-RELAX-NEXT: EF_NANOMIPS_LINKRELAX (0x1)
+# READOBJ-RELAX-NEXT: ]
+
+# READOBJ-RELAX-PCREL: Flags [ (0x1011)
+# READOBJ-RELAX-PCREL-NEXT: EF_NANOMIPS_ABI_P32 (0x1000)
+# READOBJ-RELAX-PCREL-NEXT: EF_NANOMIPS_LINKRELAX (0x1)
+# READOBJ-RELAX-PCREL-NEXT: EF_NANOMIPS_PCREL (0x10)
+# READOBJ-RELAX-PCREL-NEXT: ]
+
+# READOBJ-ALL: Flags [ (0x101F)
+# READOBJ-ALL-NEXT: EF_NANOMIPS_32BITMODE (0x4)
+# READOBJ-ALL-NEXT: EF_NANOMIPS_ABI_P32 (0x1000)
+# READOBJ-ALL-NEXT: EF_NANOMIPS_LINKRELAX (0x1)
+# READOBJ-ALL-NEXT: EF_NANOMIPS_PCREL (0x10)
+# READOBJ-ALL-NEXT: EF_NANOMIPS_PIC (0x2)
+# READOBJ-ALL-NEXT: EF_NANOMIPS_PID (0x8)
+# READOBJ-ALL-NEXT: ]
+
+# READELF-NONE: Flags: 0x0
+# READELF-P32: Flags: 0x1000, p32
+# READELF-RELAX: Flags: 0x1, relaxable
+# READELF-RELAX-PCREL: Flags: 0x1011, relaxable, PC-relative, p32
+# READELF-ALL: Flags: 0x101f, relaxable, pic, 32bitmode, pid, PC-relative, p32
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_NANOMIPS
+ Flags: [[FLAGS]]
diff --git a/llvm/test/tools/obj2yaml/ELF/nanomips-eflags.yaml b/llvm/test/tools/obj2yaml/ELF/nanomips-eflags.yaml
new file mode 100644
index 0000000000000..774449553c708
--- /dev/null
+++ b/llvm/test/tools/obj2yaml/ELF/nanomips-eflags.yaml
@@ -0,0 +1,40 @@
+## Check obj2yaml is able to decode nanoMIPS e_flags field values.
+
+# RUN: yaml2obj %s -o %t-none -DFLAGS="[]"
+# RUN: obj2yaml %t-none | FileCheck --check-prefixes=CHECK-NONE %s
+
+# RUN: yaml2obj %s -o %t-p32 -DFLAGS="[ EF_NANOMIPS_ABI_P32 ]"
+# RUN: obj2yaml %t-p32 | FileCheck --check-prefixes=CHECK-P32 %s
+
+# RUN: yaml2obj %s -o %t-relax -DFLAGS="[ EF_NANOMIPS_LINKRELAX ]"
+# RUN: obj2yaml %t-relax | FileCheck --check-prefixes=CHECK-RELAX %s
+
+# RUN: yaml2obj %s -o %t-relax-pcrel -DFLAGS="[ EF_NANOMIPS_LINKRELAX, EF_NANOMIPS_PCREL, EF_NANOMIPS_ABI_P32 ]"
+# RUN: obj2yaml %t-relax-pcrel | FileCheck --check-prefixes=CHECK-RELAX-PCREL %s
+
+# RUN: yaml2obj %s -o %t-all \
+# RUN: -DFLAGS="[ EF_NANOMIPS_LINKRELAX, EF_NANOMIPS_PIC, EF_NANOMIPS_32BITMODE, EF_NANOMIPS_PID, EF_NANOMIPS_PCREL, EF_NANOMIPS_ARCH_32R6, EF_NANOMIPS_ABI_P32 ]"
+# RUN: obj2yaml %t-all | FileCheck \
+# RUN: --check-prefixes=CHECK-ALL %s
+
+# CHECK-NONE: Class: ELFCLASS32
+
+# CHECK-P32: Class: ELFCLASS32
+# CHECK-P32: Flags: [ EF_NANOMIPS_ARCH_32R6, EF_NANOMIPS_ABI_P32 ]
+
+# CHECK-RELAX: Class: ELFCLASS32
+# CHECK-RELAX: Flags: [ EF_NANOMIPS_LINKRELAX, EF_NANOMIPS_ARCH_32R6 ]
+
+# CHECK-RELAX-PCREL: Class: ELFCLASS32
+# CHECK-RELAX-PCREL: Flags: [ EF_NANOMIPS_LINKRELAX, EF_NANOMIPS_PCREL, EF_NANOMIPS_ARCH_32R6, EF_NANOMIPS_ABI_P32 ]
+
+# CHECK-ALL: Class: ELFCLASS32
+# CHECK-ALL: Flags: [ EF_NANOMIPS_LINKRELAX, EF_NANOMIPS_PIC, EF_NANOMIPS_32BITMODE, EF_NANOMIPS_PID, EF_NANOMIPS_PCREL, EF_NANOMIPS_ARCH_32R6, EF_NANOMIPS_ABI_P32 ]
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS32
+ Data: ELFDATA2LSB
+ Type: ET_REL
+ Machine: EM_NANOMIPS
+ Flags: [[FLAGS]]
diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index 4961a192bb57b..19b63cd90c21d 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -1635,6 +1635,17 @@ constexpr EnumStringDef<unsigned, 2> ElfHeaderMipsFlagsDefs[] = {
};
constexpr auto ElfHeaderMipsFlags = BUILD_ENUM_STRINGS(ElfHeaderMipsFlagsDefs);
+constexpr EnumStringDef<unsigned, 2> ElfHeaderNanoMipsFlagsDefs[] = {
+ ENUM_ENT(EF_NANOMIPS_LINKRELAX, "relaxable"),
+ ENUM_ENT(EF_NANOMIPS_PIC, "pic"),
+ ENUM_ENT(EF_NANOMIPS_32BITMODE, "32bitmode"),
+ ENUM_ENT(EF_NANOMIPS_PID, "pid"),
+ ENUM_ENT(EF_NANOMIPS_PCREL, "PC-relative"),
+ ENUM_ENT(EF_NANOMIPS_ABI_P32, "p32"),
+};
+constexpr auto ElfHeaderNanoMipsFlags =
+ BUILD_ENUM_STRINGS(ElfHeaderNanoMipsFlagsDefs);
+
#define X(NUM, ENUM, NAME) ENUM_ENT(ENUM, NAME),
#define AMDGPU_MACH_ENUM_ENTS \
AMDGPU_MACH_LIST(X) ENUM_ENT(EF_AMDGPU_MACH_NONE, "none")
@@ -3816,6 +3827,9 @@ template <class ELFT> void GNUELFDumper<ELFT>::printFileHeaders() {
}
} break;
}
+ } else if (e.e_machine == EM_NANOMIPS) {
+ ElfFlags = printFlags(e.e_flags, EnumStrings(ElfHeaderNanoMipsFlags),
+ unsigned(EF_NANOMIPS_ABI));
}
Str = "0x" + utohexstr(e.e_flags, /*LowerCase=*/true);
if (!ElfFlags.empty())
@@ -7676,6 +7690,9 @@ template <class ELFT> void LLVMELFDumper<ELFT>::printFileHeaders() {
else if (E.e_machine == EM_CUDA)
W.printFlags("Flags", E.e_flags, EnumStrings(ElfHeaderNVPTXFlags),
unsigned(ELF::EF_CUDA_SM));
+ else if (E.e_machine == EM_NANOMIPS)
+ W.printFlags("Flags", E.e_flags, EnumStrings(ElfHeaderNanoMipsFlags),
+ unsigned(EF_NANOMIPS_ABI));
else
W.printFlags("Flags", E.e_flags);
W.printNumber("HeaderSize", E.e_ehsize);
>From 52b2192f3ce822f4bd2dca49b22cf9cf3abad3c6 Mon Sep 17 00:00:00 2001
From: Nemanja Rakovic <ot_nemanja.rakovic at mediatek.com>
Date: Mon, 5 Oct 2026 12:45:52 +0200
Subject: [PATCH 09/15] fixup! [nanoMIPS 6/7] Add instructions
---
.../Mips/Disassembler/MipsDisassembler.cpp | 54 ++---
llvm/lib/Target/Mips/MipsCP0RegisterMap.h | 217 ------------------
2 files changed, 27 insertions(+), 244 deletions(-)
delete mode 100644 llvm/lib/Target/Mips/MipsCP0RegisterMap.h
diff --git a/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp b/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp
index 32a3ecb663925..9c7fb8bfae2ac 100644
--- a/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp
+++ b/llvm/lib/Target/Mips/Disassembler/MipsDisassembler.cpp
@@ -11,7 +11,6 @@
//===----------------------------------------------------------------------===//
#include "MCTargetDesc/MipsMCTargetDesc.h"
-#include "MipsCP0RegisterMap.h"
#include "TargetInfo/MipsTargetInfo.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/MC/MCContext.h"
@@ -231,34 +230,35 @@ static DecodeStatus DecodeCOP0RegisterClass(MCInst &Inst, unsigned RegNo,
static DecodeStatus DecodeCOP0SelRegisterClass(MCInst &Inst, unsigned RegNo,
uint64_t Address,
const MCDisassembler *Decoder) {
- static MipsCP0SelMap COP0Map;
- int COP0SelIdx = COP0Map.getEncIndexMap(RegNo);
-
- if (COP0SelIdx != -1) {
- MCRegister Reg = getReg(Decoder, Mips::COP0SelRegClassID, COP0SelIdx);
- Inst.addOperand(MCOperand::createReg(Reg));
- } else {
- // Not a named register encoding - print numeric register and select value
- switch (Inst.getOpcode()) {
- case Mips::MFC0Sel_NM:
- Inst.setOpcode(Mips::MFC0_NM);
- break;
- case Mips::MFHC0Sel_NM:
- Inst.setOpcode(Mips::MFHC0_NM);
- break;
- case Mips::MTC0Sel_NM:
- Inst.setOpcode(Mips::MTC0_NM);
- break;
- case Mips::MTHC0Sel_NM:
- Inst.setOpcode(Mips::MTHC0_NM);
- break;
- default:
- llvm_unreachable("Unknown instruction!");
+ const MCRegisterInfo &MRI = *Decoder->getContext().getRegisterInfo();
+ for (MCRegister Reg : MRI.getRegClass(Mips::COP0SelRegClassID)) {
+ if (MRI.getEncodingValue(Reg) == RegNo) {
+ Inst.addOperand(MCOperand::createReg(Reg));
+ return MCDisassembler::Success;
}
- MCRegister Reg = getReg(Decoder, Mips::COP0RegClassID, RegNo >> 5);
- Inst.addOperand(MCOperand::createReg(Reg));
- Inst.addOperand(MCOperand::createImm(RegNo & 0x1f));
}
+
+ // Not a named register encoding - print numeric register and select value
+ switch (Inst.getOpcode()) {
+ case Mips::MFC0Sel_NM:
+ Inst.setOpcode(Mips::MFC0_NM);
+ break;
+ case Mips::MFHC0Sel_NM:
+ Inst.setOpcode(Mips::MFHC0_NM);
+ break;
+ case Mips::MTC0Sel_NM:
+ Inst.setOpcode(Mips::MTC0_NM);
+ break;
+ case Mips::MTHC0Sel_NM:
+ Inst.setOpcode(Mips::MTHC0_NM);
+ break;
+ default:
+ llvm_unreachable("Unknown instruction!");
+ }
+ MCRegister Reg = getReg(Decoder, Mips::COP0RegClassID, RegNo >> 5);
+ Inst.addOperand(MCOperand::createReg(Reg));
+ Inst.addOperand(MCOperand::createImm(RegNo & 0x1f));
+
return MCDisassembler::Success;
}
diff --git a/llvm/lib/Target/Mips/MipsCP0RegisterMap.h b/llvm/lib/Target/Mips/MipsCP0RegisterMap.h
deleted file mode 100644
index 9d1135d72b4c1..0000000000000
--- a/llvm/lib/Target/Mips/MipsCP0RegisterMap.h
+++ /dev/null
@@ -1,217 +0,0 @@
-//===- MipsCP0RegisterMap.h - Co-processor register names -------*- 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 defines the mapping between MIPS CP0 register names and their
-/// (register, select) encodings.
-///
-//===----------------------------------------------------------------------===//
-
-#ifndef LLVM_LIB_TARGET_MIPS_MIPSCP0REGMAP_H
-#define LLVM_LIB_TARGET_MIPS_MIPSCP0REGMAP_H
-#include "llvm/ADT/DenseMap.h"
-#include "llvm/ADT/StringMap.h"
-#include "llvm/ADT/StringRef.h"
-
-namespace llvm {
-
-struct CP0SelRegister {
- StringRef Name;
- int RegNum;
- int Select;
-};
-
-class MipsCP0SelMap {
- DenseMap<unsigned, int> EncIndexMap;
- StringMap<int> NameIndexMap;
-
-public:
- int getEncIndexMap(unsigned Reg) {
- auto It = EncIndexMap.find(Reg);
- return It != EncIndexMap.end() ? It->second : -1;
- }
-
- int getNameIndexMap(StringRef Name) {
- auto It = NameIndexMap.find(Name);
- return It != NameIndexMap.end() ? It->second : -1;
- }
-
- MipsCP0SelMap() {
- static const struct CP0SelRegister Regs[] = {{"index", 0, 0},
- {"mvpcontrol", 0, 1},
- {"mvpconf0", 0, 2},
- {"mvpconf1", 0, 3},
- {"vpcontrol", 0, 4},
- {"random", 1, 0},
- {"vpecontrol", 1, 1},
- {"vpeconf0", 1, 2},
- {"vpeconf1", 1, 3},
- {"yqmask", 1, 4},
- {"vpeschedule", 1, 5},
- {"vpeschefback", 1, 6},
- {"vpeopt", 1, 7},
- {"entrylo0", 2, 0},
- {"tcstatus", 2, 1},
- {"tcbind", 2, 2},
- {"tcrestart", 2, 3},
- {"tchalt", 2, 4},
- {"tccontext", 2, 5},
- {"tcschedule", 2, 6},
- {"tcschefback", 2, 7},
- {"entrylo1", 3, 0},
- {"globalnumber", 3, 1},
- {"tcopt", 3, 7},
- {"context", 4, 0},
- {"contextconfig", 4, 1},
- {"userlocal", 4, 2},
- {"xcontextconfig", 4, 3},
- {"debugcontextid", 4, 4},
- {"memorymapid", 4, 5},
- {"pagemask", 5, 0},
- {"pagegrain", 5, 1},
- {"segctl0", 5, 2},
- {"segctl1", 5, 3},
- {"segctl2", 5, 4},
- {"pwbase", 5, 5},
- {"pwfield", 5, 6},
- {"pwsize", 5, 7},
- {"wired", 6, 0},
- {"srsconf0", 6, 1},
- {"srsconf1", 6, 2},
- {"srsconf2", 6, 3},
- {"srsconf3", 6, 4},
- {"srsconf4", 6, 5},
- {"pwctl", 6, 6},
- {"hwrena", 7, 0},
- {"badvaddr", 8, 0},
- {"badinst", 8, 1},
- {"badinstrp", 8, 2},
- {"badinstrx", 8, 3},
- {"count", 9, 0},
- {"entryhi", 10, 0},
- {"guestctl1", 10, 4},
- {"guestctl2", 10, 5},
- {"guestctl3", 10, 6},
- {"compare", 11, 0},
- {"guestctl0ext", 11, 4},
- {"status", 12, 0},
- {"intctl", 12, 1},
- {"srsctl", 12, 2},
- {"srsmap", 12, 3},
- {"view_ipl", 12, 4},
- {"srsmap2", 12, 5},
- {"guestctl0", 12, 6},
- {"gtoffset", 12, 7},
- {"cause", 13, 0},
- {"view_ripl", 13, 4},
- {"nestedexc", 13, 5},
- {"epc", 14, 0},
- {"nestedepc", 14, 2},
- {"prid", 15, 0},
- {"ebase", 15, 1},
- {"cdmmbase", 15, 2},
- {"cmgcrbase", 15, 3},
- {"bevva", 15, 4},
- {"config", 16, 0},
- {"config1", 16, 1},
- {"config2", 16, 2},
- {"config3", 16, 3},
- {"config4", 16, 4},
- {"config5", 16, 5},
- {"lladdr", 17, 0},
- {"maar", 17, 1},
- {"maari", 17, 2},
- {"watchlo0", 18, 0},
- {"watchlo1", 18, 1},
- {"watchlo2", 18, 2},
- {"watchlo3", 18, 3},
- {"watchlo4", 18, 4},
- {"watchlo5", 18, 5},
- {"watchlo6", 18, 6},
- {"watchlo7", 18, 7},
- {"watchlo8", 18, 8},
- {"watchlo9", 18, 9},
- {"watchlo10", 18, 10},
- {"watchlo11", 18, 11},
- {"watchlo12", 18, 12},
- {"watchlo13", 18, 13},
- {"watchlo14", 18, 14},
- {"watchlo15", 18, 15},
- {"watchhi0", 19, 0},
- {"watchhi1", 19, 1},
- {"watchhi2", 19, 2},
- {"watchhi3", 19, 3},
- {"watchhi4", 19, 4},
- {"watchhi5", 19, 5},
- {"watchhi6", 19, 6},
- {"watchhi7", 19, 7},
- {"watchhi8", 19, 8},
- {"watchhi9", 19, 9},
- {"watchhi10", 19, 10},
- {"watchhi11", 19, 11},
- {"watchhi12", 19, 12},
- {"watchhi13", 19, 13},
- {"watchhi14", 19, 14},
- {"watchhi15", 19, 15},
- {"xcontext", 20, 0},
- {"debug", 23, 0},
- {"tracecontrol", 23, 1},
- {"tracecontrol2", 23, 2},
- {"usertracedata1", 23, 3},
- {"traceibpc", 23, 4},
- {"tracedbpc", 23, 5},
- {"debug2", 23, 6},
- {"depc", 24, 0},
- {"tracecontrol3", 24, 2},
- {"usertracedata2", 24, 3},
- {"perfctl0", 25, 0},
- {"perfcnt0", 25, 1},
- {"perfctl1", 25, 2},
- {"perfcnt1", 25, 3},
- {"perfctl2", 25, 4},
- {"perfcnt2", 25, 5},
- {"perfctl3", 25, 6},
- {"perfcnt3", 25, 7},
- {"perfctl4", 25, 8},
- {"perfcnt4", 25, 9},
- {"perfctl5", 25, 10},
- {"perfcnt5", 25, 11},
- {"perfctl6", 25, 12},
- {"perfcnt6", 25, 13},
- {"perfctl7", 25, 14},
- {"perfcnt7", 25, 15},
- {"errctl", 26, 0},
- {"cacheerr", 27, 0},
- {"itaglo", 28, 0},
- {"idatalo", 28, 1},
- {"dtaglo", 28, 2},
- {"ddatalo", 28, 3},
- {"itaghi", 29, 0},
- {"idatahi", 29, 1},
- {"dtaghi", 29, 2},
- {"ddatahi", 29, 3},
- {"errorepc", 30, 0},
- {"desave", 31, 0},
- {"kscratch1", 31, 2},
- {"kscratch2", 31, 3},
- {"kscratch3", 31, 4},
- {"kscratch4", 31, 5},
- {"kscratch5", 31, 6},
- {"kscratch6", 31, 7}};
- int Index = 0;
- for (auto Reg : Regs) {
- NameIndexMap[Reg.Name] = Index;
- unsigned RegEnc = (Reg.RegNum << 5) | Reg.Select;
- EncIndexMap[RegEnc] = Index++;
- }
- }
-};
-
-} // namespace llvm
-
-#endif // LLVM_LIB_TARGET_MIPS_MIPSCP0REGMAP_H
>From bd28a5b7ab3fd55c532b4ffb8278650e4d4715ae Mon Sep 17 00:00:00 2001
From: Nemanja Rakovic <ot_nemanja.rakovic at mediatek.com>
Date: Mon, 5 Oct 2026 13:22:34 +0200
Subject: [PATCH 10/15] fixup! [nanoMIPS 4/7] Add register definitions
---
llvm/lib/Target/Mips/MipsRegisterInfo.td | 92 ++++++++++++------------
1 file changed, 45 insertions(+), 47 deletions(-)
diff --git a/llvm/lib/Target/Mips/MipsRegisterInfo.td b/llvm/lib/Target/Mips/MipsRegisterInfo.td
index 51f9ce394cfbc..6c67793e6738d 100644
--- a/llvm/lib/Target/Mips/MipsRegisterInfo.td
+++ b/llvm/lib/Target/Mips/MipsRegisterInfo.td
@@ -567,53 +567,6 @@ class GPRNM32Class<list<ValueType> regTypes> :
def GPRNM32 : GPRNM32Class<[i32]>;
-class COP0SelRegClassNM<list<ValueType> regTypes> :
- RegisterClass<"Mips", regTypes, 32, (add
- COP0Sel_INDEX, COP0Sel_MVPCONTROL, COP0Sel_MVPCONF0, COP0Sel_MVPCONF1,
- COP0Sel_VPCONTROL, COP0Sel_RANDOM, COP0Sel_VPECONTROL, COP0Sel_VPECONF0,
- COP0Sel_VPECONF1, COP0Sel_YQMASK, COP0Sel_VPESCHEDULE, COP0Sel_VPESCHEFBACK,
- COP0Sel_VPEOPT, COP0Sel_ENTRYLO0, COP0Sel_TCSTATUS, COP0Sel_TCBIND,
- COP0Sel_TCRESTART, COP0Sel_TCHALT, COP0Sel_TCCONTEXT, COP0Sel_TCSCHEDULE,
- COP0Sel_TCSCHEFBACK, COP0Sel_ENTRYLO1, COP0Sel_GLOBALNUMBER, COP0Sel_TCOPT,
- COP0Sel_CONTEXT, COP0Sel_CONTEXTCONFIG, COP0Sel_USERLOCAL,
- COP0Sel_XCONTEXTCONFIG, COP0Sel_DEBUGCONTEXTID, COP0Sel_MEMORYMAPID,
- COP0Sel_PAGEMASK, COP0Sel_PAGEGRAIN, COP0Sel_SEGCTL0, COP0Sel_SEGCTL1,
- COP0Sel_SEGCTL2, COP0Sel_PWBASE, COP0Sel_PWFIELD, COP0Sel_PWSIZE,
- COP0Sel_WIRED, COP0Sel_SRSCONF0, COP0Sel_SRSCONF1, COP0Sel_SRSCONF2,
- COP0Sel_SRSCONF3, COP0Sel_SRSCONF4, COP0Sel_PWCTL, COP0Sel_HWRENA,
- COP0Sel_BADVADDR, COP0Sel_BADINST, COP0Sel_BADINSTRP, COP0Sel_BADINSTRX,
- COP0Sel_COUNT, COP0Sel_ENTRYHI, COP0Sel_GUESTCTL1, COP0Sel_GUESTCTL2,
- COP0Sel_GUESTCTL3, COP0Sel_COMPARE, COP0Sel_GUESTCTL0EXT, COP0Sel_STATUS,
- COP0Sel_INTCTL, COP0Sel_SRSCTL, COP0Sel_SRSMAP, COP0Sel_VIEW_IPL,
- COP0Sel_SRSMAP2, COP0Sel_GUESTCTL0, COP0Sel_GTOFFSET, COP0Sel_CAUSE,
- COP0Sel_VIEW_RIPL, COP0Sel_NESTEDEXC, COP0Sel_EPC, COP0Sel_NESTEDEPC,
- COP0Sel_PRID, COP0Sel_EBASE, COP0Sel_CDMMBASE, COP0Sel_CMGCRBASE,
- COP0Sel_BEVVA, COP0Sel_CONFIG, COP0Sel_CONFIG1, COP0Sel_CONFIG2,
- COP0Sel_CONFIG3, COP0Sel_CONFIG4, COP0Sel_CONFIG5, COP0Sel_LLADDR,
- COP0Sel_MAAR, COP0Sel_MAARI, COP0Sel_WATCHLO0, COP0Sel_WATCHLO1,
- COP0Sel_WATCHLO2, COP0Sel_WATCHLO3, COP0Sel_WATCHLO4, COP0Sel_WATCHLO5,
- COP0Sel_WATCHLO6, COP0Sel_WATCHLO7, COP0Sel_WATCHLO8, COP0Sel_WATCHLO9,
- COP0Sel_WATCHLO10, COP0Sel_WATCHLO11, COP0Sel_WATCHLO12, COP0Sel_WATCHLO13,
- COP0Sel_WATCHLO14, COP0Sel_WATCHLO15, COP0Sel_WATCHHI0, COP0Sel_WATCHHI1,
- COP0Sel_WATCHHI2, COP0Sel_WATCHHI3, COP0Sel_WATCHHI4, COP0Sel_WATCHHI5,
- COP0Sel_WATCHHI6, COP0Sel_WATCHHI7, COP0Sel_WATCHHI8, COP0Sel_WATCHHI9,
- COP0Sel_WATCHHI10, COP0Sel_WATCHHI11, COP0Sel_WATCHHI12, COP0Sel_WATCHHI13,
- COP0Sel_WATCHHI14, COP0Sel_WATCHHI15, COP0Sel_XCONTEXT, COP0Sel_DEBUG,
- COP0Sel_TRACECONTROL, COP0Sel_TRACECONTROL2, COP0Sel_USERTRACEDATA1,
- COP0Sel_TRACEIBPC, COP0Sel_TRACEDBPC, COP0Sel_DEBUG2, COP0Sel_DEPC,
- COP0Sel_TRACECONTROL3, COP0Sel_USERTRACEDATA2, COP0Sel_PERFCTL0,
- COP0Sel_PERFCNT0, COP0Sel_PERFCTL1, COP0Sel_PERFCNT1, COP0Sel_PERFCTL2,
- COP0Sel_PERFCNT2, COP0Sel_PERFCTL3, COP0Sel_PERFCNT3, COP0Sel_PERFCTL4,
- COP0Sel_PERFCNT4, COP0Sel_PERFCTL5, COP0Sel_PERFCNT5, COP0Sel_PERFCTL6,
- COP0Sel_PERFCNT6, COP0Sel_PERFCTL7, COP0Sel_PERFCNT7, COP0Sel_ERRCTL,
- COP0Sel_CACHEERR, COP0Sel_ITAGLO, COP0Sel_IDATALO, COP0Sel_DTAGLO,
- COP0Sel_DDATALO, COP0Sel_ITAGHI, COP0Sel_IDATAHI, COP0Sel_DTAGHI,
- COP0Sel_DDATAHI, COP0Sel_ERROREPC, COP0Sel_DESAVE, COP0Sel_KSCRATCH1,
- COP0Sel_KSCRATCH2, COP0Sel_KSCRATCH3, COP0Sel_KSCRATCH4, COP0Sel_KSCRATCH5,
- COP0Sel_KSCRATCH6)>;
-
-def COP0Sel : COP0SelRegClassNM<[i32]>, Unallocatable;
-
def GPRNM32_TAIL : RegisterClass<"Mips", [i32], 32, (add
// Not preserved across procedure calls
T4_NM, T5_NM,
@@ -823,6 +776,51 @@ def DSPCC : RegisterClass<"Mips", [v4i8, v2i16], 32, (add DSPCCond)>;
def COP0 : RegisterClass<"Mips", [i32], 32, (sequence "COP0%u", 0, 31)>,
Unallocatable;
+// Coprocessor 0 registers with a fixed select.
+def COP0Sel : RegisterClass<"Mips", [i32], 32, (add
+ COP0Sel_INDEX, COP0Sel_MVPCONTROL, COP0Sel_MVPCONF0, COP0Sel_MVPCONF1,
+ COP0Sel_VPCONTROL, COP0Sel_RANDOM, COP0Sel_VPECONTROL, COP0Sel_VPECONF0,
+ COP0Sel_VPECONF1, COP0Sel_YQMASK, COP0Sel_VPESCHEDULE, COP0Sel_VPESCHEFBACK,
+ COP0Sel_VPEOPT, COP0Sel_ENTRYLO0, COP0Sel_TCSTATUS, COP0Sel_TCBIND,
+ COP0Sel_TCRESTART, COP0Sel_TCHALT, COP0Sel_TCCONTEXT, COP0Sel_TCSCHEDULE,
+ COP0Sel_TCSCHEFBACK, COP0Sel_ENTRYLO1, COP0Sel_GLOBALNUMBER, COP0Sel_TCOPT,
+ COP0Sel_CONTEXT, COP0Sel_CONTEXTCONFIG, COP0Sel_USERLOCAL,
+ COP0Sel_XCONTEXTCONFIG, COP0Sel_DEBUGCONTEXTID, COP0Sel_MEMORYMAPID,
+ COP0Sel_PAGEMASK, COP0Sel_PAGEGRAIN, COP0Sel_SEGCTL0, COP0Sel_SEGCTL1,
+ COP0Sel_SEGCTL2, COP0Sel_PWBASE, COP0Sel_PWFIELD, COP0Sel_PWSIZE,
+ COP0Sel_WIRED, COP0Sel_SRSCONF0, COP0Sel_SRSCONF1, COP0Sel_SRSCONF2,
+ COP0Sel_SRSCONF3, COP0Sel_SRSCONF4, COP0Sel_PWCTL, COP0Sel_HWRENA,
+ COP0Sel_BADVADDR, COP0Sel_BADINST, COP0Sel_BADINSTRP, COP0Sel_BADINSTRX,
+ COP0Sel_COUNT, COP0Sel_ENTRYHI, COP0Sel_GUESTCTL1, COP0Sel_GUESTCTL2,
+ COP0Sel_GUESTCTL3, COP0Sel_COMPARE, COP0Sel_GUESTCTL0EXT, COP0Sel_STATUS,
+ COP0Sel_INTCTL, COP0Sel_SRSCTL, COP0Sel_SRSMAP, COP0Sel_VIEW_IPL,
+ COP0Sel_SRSMAP2, COP0Sel_GUESTCTL0, COP0Sel_GTOFFSET, COP0Sel_CAUSE,
+ COP0Sel_VIEW_RIPL, COP0Sel_NESTEDEXC, COP0Sel_EPC, COP0Sel_NESTEDEPC,
+ COP0Sel_PRID, COP0Sel_EBASE, COP0Sel_CDMMBASE, COP0Sel_CMGCRBASE,
+ COP0Sel_BEVVA, COP0Sel_CONFIG, COP0Sel_CONFIG1, COP0Sel_CONFIG2,
+ COP0Sel_CONFIG3, COP0Sel_CONFIG4, COP0Sel_CONFIG5, COP0Sel_LLADDR,
+ COP0Sel_MAAR, COP0Sel_MAARI, COP0Sel_WATCHLO0, COP0Sel_WATCHLO1,
+ COP0Sel_WATCHLO2, COP0Sel_WATCHLO3, COP0Sel_WATCHLO4, COP0Sel_WATCHLO5,
+ COP0Sel_WATCHLO6, COP0Sel_WATCHLO7, COP0Sel_WATCHLO8, COP0Sel_WATCHLO9,
+ COP0Sel_WATCHLO10, COP0Sel_WATCHLO11, COP0Sel_WATCHLO12, COP0Sel_WATCHLO13,
+ COP0Sel_WATCHLO14, COP0Sel_WATCHLO15, COP0Sel_WATCHHI0, COP0Sel_WATCHHI1,
+ COP0Sel_WATCHHI2, COP0Sel_WATCHHI3, COP0Sel_WATCHHI4, COP0Sel_WATCHHI5,
+ COP0Sel_WATCHHI6, COP0Sel_WATCHHI7, COP0Sel_WATCHHI8, COP0Sel_WATCHHI9,
+ COP0Sel_WATCHHI10, COP0Sel_WATCHHI11, COP0Sel_WATCHHI12, COP0Sel_WATCHHI13,
+ COP0Sel_WATCHHI14, COP0Sel_WATCHHI15, COP0Sel_XCONTEXT, COP0Sel_DEBUG,
+ COP0Sel_TRACECONTROL, COP0Sel_TRACECONTROL2, COP0Sel_USERTRACEDATA1,
+ COP0Sel_TRACEIBPC, COP0Sel_TRACEDBPC, COP0Sel_DEBUG2, COP0Sel_DEPC,
+ COP0Sel_TRACECONTROL3, COP0Sel_USERTRACEDATA2, COP0Sel_PERFCTL0,
+ COP0Sel_PERFCNT0, COP0Sel_PERFCTL1, COP0Sel_PERFCNT1, COP0Sel_PERFCTL2,
+ COP0Sel_PERFCNT2, COP0Sel_PERFCTL3, COP0Sel_PERFCNT3, COP0Sel_PERFCTL4,
+ COP0Sel_PERFCNT4, COP0Sel_PERFCTL5, COP0Sel_PERFCNT5, COP0Sel_PERFCTL6,
+ COP0Sel_PERFCNT6, COP0Sel_PERFCTL7, COP0Sel_PERFCNT7, COP0Sel_ERRCTL,
+ COP0Sel_CACHEERR, COP0Sel_ITAGLO, COP0Sel_IDATALO, COP0Sel_DTAGLO,
+ COP0Sel_DDATALO, COP0Sel_ITAGHI, COP0Sel_IDATAHI, COP0Sel_DTAGHI,
+ COP0Sel_DDATAHI, COP0Sel_ERROREPC, COP0Sel_DESAVE, COP0Sel_KSCRATCH1,
+ COP0Sel_KSCRATCH2, COP0Sel_KSCRATCH3, COP0Sel_KSCRATCH4, COP0Sel_KSCRATCH5,
+ COP0Sel_KSCRATCH6)>, Unallocatable;
+
// Coprocessor 2 registers.
def COP2 : RegisterClass<"Mips", [i32], 32, (sequence "COP2%u", 0, 31)>,
Unallocatable;
>From 1dd46bb0a7f9bbb9bf2f58fc962249c212509631 Mon Sep 17 00:00:00 2001
From: Nemanja Rakovic <ot_nemanja.rakovic at mediatek.com>
Date: Mon, 5 Oct 2026 14:40:22 +0200
Subject: [PATCH 11/15] fixup! [nanoMIPS 2/7] Add ELF and relocation support
---
llvm/lib/Object/ELF.cpp | 3 ++-
llvm/unittests/Object/ELFTest.cpp | 2 ++
2 files changed, 4 insertions(+), 1 deletion(-)
diff --git a/llvm/lib/Object/ELF.cpp b/llvm/lib/Object/ELF.cpp
index 3e020820be4f4..3fd08d392a26e 100644
--- a/llvm/lib/Object/ELF.cpp
+++ b/llvm/lib/Object/ELF.cpp
@@ -219,7 +219,6 @@ uint32_t llvm::object::getELFRelativeRelocationType(uint32_t Machine) {
case ELF::EM_IAMCU:
return ELF::R_386_RELATIVE;
case ELF::EM_MIPS:
- case ELF::EM_NANOMIPS:
break;
case ELF::EM_AARCH64:
return ELF::R_AARCH64_RELATIVE;
@@ -256,6 +255,8 @@ uint32_t llvm::object::getELFRelativeRelocationType(uint32_t Machine) {
break;
case ELF::EM_LOONGARCH:
return ELF::R_LARCH_RELATIVE;
+ case ELF::EM_NANOMIPS:
+ return ELF::R_NANOMIPS_RELATIVE;
default:
break;
}
diff --git a/llvm/unittests/Object/ELFTest.cpp b/llvm/unittests/Object/ELFTest.cpp
index 6d659774848ee..d523877880313 100644
--- a/llvm/unittests/Object/ELFTest.cpp
+++ b/llvm/unittests/Object/ELFTest.cpp
@@ -309,6 +309,8 @@ TEST(ELFTest, getRISCVVendorRelocationTypeName) {
TEST(ELFTest, getELFRelativeRelocationType) {
EXPECT_EQ(ELF::R_VE_RELATIVE, getELFRelativeRelocationType(EM_VE));
EXPECT_EQ(ELF::R_LARCH_RELATIVE, getELFRelativeRelocationType(EM_LOONGARCH));
+ EXPECT_EQ(ELF::R_NANOMIPS_RELATIVE,
+ getELFRelativeRelocationType(EM_NANOMIPS));
}
// This is a test for the DataRegion helper struct, defined in ELF.h header.
>From 35a5c9efe8767cfb8f02504dc78ae11bfb0abcf5 Mon Sep 17 00:00:00 2001
From: Nemanja Rakovic <ot_nemanja.rakovic at mediatek.com>
Date: Mon, 5 Oct 2026 20:09:11 +0200
Subject: [PATCH 12/15] fixup! [nanoMIPS 6/7] Add instructions
---
llvm/lib/Target/Mips/NanoMipsInstrInfo.td | 20 ++++++++++----------
1 file changed, 10 insertions(+), 10 deletions(-)
diff --git a/llvm/lib/Target/Mips/NanoMipsInstrInfo.td b/llvm/lib/Target/Mips/NanoMipsInstrInfo.td
index 16fb42c84898d..12883705d464a 100644
--- a/llvm/lib/Target/Mips/NanoMipsInstrInfo.td
+++ b/llvm/lib/Target/Mips/NanoMipsInstrInfo.td
@@ -138,17 +138,17 @@ class AddImmediate_Desc<string opstr, Operand Od,
class CondLogicI32_Desc<string opstr, Operand Od, RegisterOperand RO>
: ArithLogicINM_Desc<opstr, Od, RO>;
-let isMoveReg = 1 in {
- class MoveBase_Desc
- : InstNM<(outs GPRNM32NZOpnd:$rt), (ins GPRNM32Opnd:$rs),
- "move\t$rt, $rs">;
-
- class MovePBase_Desc<RegisterOperand SR1O, RegisterOperand SR2O,
- RegisterOperand DR1O, RegisterOperand DR2O>
- : InstNM<(outs DR1O:$dst1, DR2O:$dst2), (ins SR1O:$src1, SR2O:$src2),
- "movep\t$dst1, $dst2, $src1, $src2">;
+class MoveBase_Desc
+ : InstNM<(outs GPRNM32NZOpnd:$rt), (ins GPRNM32Opnd:$rs),
+ "move\t$rt, $rs"> {
+ let isMoveReg = 1;
}
+class MovePBase_Desc<RegisterOperand SR1O, RegisterOperand SR2O,
+ RegisterOperand DR1O, RegisterOperand DR2O>
+ : InstNM<(outs DR1O:$dst1, DR2O:$dst2), (ins SR1O:$src1, SR2O:$src2),
+ "movep\t$dst1, $dst2, $src1, $src2">;
+
class Call_Desc<string opstr, DAGOperand calltarget>
: InstNM<(outs), (ins calltarget:$addr), !strconcat(opstr, "\t$addr")> {
let isCall = 1;
@@ -833,7 +833,7 @@ class CondMove_Desc<string opstr>
: InstNM<(outs GPRNM32Opnd:$rd),
(ins GPRNM32Opnd:$rs, GPRNM32Opnd:$rt, GPRNM32Opnd:$F),
!strconcat(opstr, "\t$rd, $rs, $rt")>,
- RegConstraint<"$F = $rd">, IsCommutable;
+ RegConstraint<"$F = $rd">;
def MOVZ_NM : CondMove_Desc<"movz">, CondMove_Enc<0b0>;
def MOVN_NM : CondMove_Desc<"movn">, CondMove_Enc<0b1>;
>From cbd38d784b4414ce3fd4244866fe27e7ad2375ce Mon Sep 17 00:00:00 2001
From: Nemanja Rakovic <ot_nemanja.rakovic at mediatek.com>
Date: Mon, 5 Oct 2026 20:19:15 +0200
Subject: [PATCH 13/15] fixup! [nanoMIPS 6/7] Add instructions
---
llvm/lib/Target/Mips/NanoMipsInstrFormats.td | 1 -
llvm/lib/Target/Mips/NanoMipsInstrInfo.td | 6 +++---
2 files changed, 3 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/Target/Mips/NanoMipsInstrFormats.td b/llvm/lib/Target/Mips/NanoMipsInstrFormats.td
index 022c0efb0a886..bfe028f06c62f 100644
--- a/llvm/lib/Target/Mips/NanoMipsInstrFormats.td
+++ b/llvm/lib/Target/Mips/NanoMipsInstrFormats.td
@@ -269,7 +269,6 @@ class _Pool_PP_SR<bits<2> isel> : _Pool_P_U12<0b0011> {
class Arith4x4_Enc<bits<2> isel> : _Pool_P16_4X4<isel> {
bits<5> dst;
bits<5> rs;
- bits<5> rt;
let Inst{9} = dst{4};
let Inst{7-5} = dst{2-0};
diff --git a/llvm/lib/Target/Mips/NanoMipsInstrInfo.td b/llvm/lib/Target/Mips/NanoMipsInstrInfo.td
index 12883705d464a..baf8aa79c3f4c 100644
--- a/llvm/lib/Target/Mips/NanoMipsInstrInfo.td
+++ b/llvm/lib/Target/Mips/NanoMipsInstrInfo.td
@@ -88,7 +88,7 @@ def sym32_nm : Operand<pAny>;
// P16_4X4
class Arith4x4_Desc<string opstr, RegisterOperand RO>
: InstNM<(outs RO:$dst), (ins RO:$rt, RO:$rs),
- !strconcat(opstr, "\t$dst, $rt, $rs")>;
+ !strconcat(opstr, "\t$dst, $rt, $rs")>, RegConstraint<"$rt = $dst">;
// 32-bit arithmetic and logical instructions with 3 register operands.
class ArithLogicR32_Desc<string opstr, RegisterOperand RO>
@@ -99,7 +99,7 @@ class ArithLogicR32_Desc<string opstr, RegisterOperand RO>
// POOL16C_0
class ArithLogicR16_Desc<string opstr, RegisterOperand RO>
: InstNM<(outs RO:$rd), (ins RO:$rs, RO:$rt),
- !strconcat(opstr, "\t$rd, $rs, $rt")>;
+ !strconcat(opstr, "\t$rd, $rs, $rt")>, RegConstraint<"$rt = $rd">;
class ArithLogicR16U_Desc<string opstr, RegisterOperand RO>
: InstNM<(outs RO:$rd), (ins RO:$rs),
@@ -187,7 +187,7 @@ class LoadAddressAbs_Desc<string opstr, RegisterOperand RO, DAGOperand MO>
// 16-bit register operations
def NOT16_NM : ArithLogicR16U_Desc<"not", GPRNM16R3Opnd>,
ArithLogicR16_Enc<0b00>;
-let isCommutable = 1, TwoOperandAliasConstraint = "$rt = $rd" in {
+let isCommutable = 1 in {
def XOR16_NM : ArithLogicR16_Desc<"xor", GPRNM16R3Opnd>,
ArithLogicR16_Enc<0b01>;
def AND16_NM : ArithLogicR16_Desc<"and", GPRNM16R3Opnd>,
>From 5fd3f32ec5f9d5207bf011d34a1766f3d142bd78 Mon Sep 17 00:00:00 2001
From: Nemanja Rakovic <ot_nemanja.rakovic at mediatek.com>
Date: Mon, 5 Oct 2026 20:20:52 +0200
Subject: [PATCH 14/15] fixup! [nanoMIPS 7/7][test] Add instruction encoding
and mnemonic tests
---
llvm/test/CodeGen/Mips/nanomips/16bit.mir | 12 ++++++------
1 file changed, 6 insertions(+), 6 deletions(-)
diff --git a/llvm/test/CodeGen/Mips/nanomips/16bit.mir b/llvm/test/CodeGen/Mips/nanomips/16bit.mir
index bbbc8c457f26d..c3c25a56f8300 100644
--- a/llvm/test/CodeGen/Mips/nanomips/16bit.mir
+++ b/llvm/test/CodeGen/Mips/nanomips/16bit.mir
@@ -29,11 +29,11 @@ body: |
...
---
# CHECK-LABEL: and16:
-# CHECK: and $a0, $a0, $a1 # encoding: [0x48,0x52]
+# CHECK: and $a0, $a1, $a0 # encoding: [0x58,0x52]
name: and16
body: |
bb.0:
- $a0_nm = AND16_NM $a0_nm, $a1_nm
+ $a0_nm = AND16_NM $a1_nm, $a0_nm
...
---
# CHECK-LABEL: andi16:
@@ -77,11 +77,11 @@ body: |
...
---
# CHECK-LABEL: or16:
-# CHECK: or $a0, $a0, $a1 # encoding: [0x4c,0x52]
+# CHECK: or $a0, $a1, $a0 # encoding: [0x5c,0x52]
name: or16
body: |
bb.0:
- $a0_nm = OR16_NM $a0_nm, $a1_nm
+ $a0_nm = OR16_NM $a1_nm, $a0_nm
...
---
# CHECK-LABEL: sdbbp16:
@@ -117,11 +117,11 @@ body: |
...
---
# CHECK-LABEL: xor16:
-# CHECK: xor $a0, $a0, $a1 # encoding: [0x44,0x52]
+# CHECK: xor $a0, $a1, $a0 # encoding: [0x54,0x52]
name: xor16
body: |
bb.0:
- $a0_nm = XOR16_NM $a0_nm, $a1_nm
+ $a0_nm = XOR16_NM $a1_nm, $a0_nm
...
# --- arithmetic ---
>From a9e7195e6964303e8134a811bd77440d518807f3 Mon Sep 17 00:00:00 2001
From: Nemanja Rakovic <ot_nemanja.rakovic at mediatek.com>
Date: Mon, 5 Oct 2026 21:34:53 +0200
Subject: [PATCH 15/15] fixup! [nanoMIPS 6/7] Add instructions
---
llvm/lib/Target/Mips/NanoMipsInstrInfo.td | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/llvm/lib/Target/Mips/NanoMipsInstrInfo.td b/llvm/lib/Target/Mips/NanoMipsInstrInfo.td
index baf8aa79c3f4c..0fdf57d44f15a 100644
--- a/llvm/lib/Target/Mips/NanoMipsInstrInfo.td
+++ b/llvm/lib/Target/Mips/NanoMipsInstrInfo.td
@@ -400,7 +400,7 @@ let isReMaterializable = 1 in {
}
class LoadAddressGPRel_Desc<string opstr, RegisterOperand RO, DAGOperand MO>
- : InstNM<(outs RO:$rt), (ins RO:$rs, MO:$addr),
+ : InstNM<(outs RO:$rt), (ins GPRNMGPOpnd:$rs, MO:$addr),
!strconcat(opstr, "\t$rt, $rs, $addr")>;
def ADDIUGP48_NM : LoadAddressGPRel_Desc<"addiu.b32", GPRNM48Opnd,
More information about the llvm-commits
mailing list