summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoranbbna <117081688+anbbna@users.noreply.github.com>2024-03-13 07:27:18 +0800
committerGitHub <noreply@github.com>2024-03-13 07:27:18 +0800
commit65f07b804c2c05cf49bd043f2a6e9a0020198165 (patch)
tree87178eb6394ce5192cb8877afa93ba612511cfe7
parent418f0066ebfcde8cd72d33cc103fc1c3e36a1205 (diff)
[MIPS] Introduce NAL instruction support for Mipsr6 and prer6 (#84429)
NAL is an assembly idiom on Pre-R6 instruction sets (which is implemented in binutils), or an actual instruction on Release 6 instruction set, and is used to read the PC, due to the nature of the MIPS architecture. Since we can't read the PC directly, on pre-R6 we use a always-not-taken Branch and Link operation to the address of the next instruction, which effectively writes the address to $31, thus PC is read with offset +8. MIPS Release 6 removed the conventional Branch and Link instructions, but kept NAL as an actual instruction for compatibility on the assembly level. The instruction has the same encoding of the pre-R6 ones, and with the same behavior: PC + 8 -> $31.
-rw-r--r--llvm/lib/Target/Mips/Mips32r6InstrFormats.td11
-rw-r--r--llvm/lib/Target/Mips/Mips32r6InstrInfo.td16
-rw-r--r--llvm/lib/Target/Mips/MipsInstrInfo.td3
-rw-r--r--llvm/lib/Target/Mips/MipsScheduleGeneric.td2
-rw-r--r--llvm/test/MC/Mips/mips32/nal.s14
-rw-r--r--llvm/test/MC/Mips/mips32r6/nal.s21
6 files changed, 65 insertions, 2 deletions
diff --git a/llvm/lib/Target/Mips/Mips32r6InstrFormats.td b/llvm/lib/Target/Mips/Mips32r6InstrFormats.td
index ccb6d1df777a..8536c52028c3 100644
--- a/llvm/lib/Target/Mips/Mips32r6InstrFormats.td
+++ b/llvm/lib/Target/Mips/Mips32r6InstrFormats.td
@@ -86,6 +86,7 @@ def OPCODE5_BC1NEZ : OPCODE5<0b01101>;
def OPCODE5_BC2EQZ : OPCODE5<0b01001>;
def OPCODE5_BC2NEZ : OPCODE5<0b01101>;
def OPCODE5_BGEZAL : OPCODE5<0b10001>;
+def OPCODE5_NAL : OPCODE5<0b10000>;
def OPCODE5_SIGRIE : OPCODE5<0b10111>;
// The next four constants are unnamed in the spec. These names are taken from
// the OPGROUP names they are used with.
@@ -201,6 +202,16 @@ class BAL_FM : MipsR6Inst {
let Inst{15-0} = offset;
}
+// NAL for Release 6
+class NAL_FM : MipsR6Inst {
+ bits<32> Inst;
+
+ let Inst{31-26} = OPGROUP_REGIMM.Value;
+ let Inst{25-21} = 0b00000;
+ let Inst{20-16} = OPCODE5_NAL.Value;
+ let Inst{15-0} = 0x00;
+}
+
class COP0_EVP_DVP_FM<bits<1> sc> : MipsR6Inst {
bits<5> rt;
diff --git a/llvm/lib/Target/Mips/Mips32r6InstrInfo.td b/llvm/lib/Target/Mips/Mips32r6InstrInfo.td
index 854563ab32bd..9c29acbd0d8a 100644
--- a/llvm/lib/Target/Mips/Mips32r6InstrInfo.td
+++ b/llvm/lib/Target/Mips/Mips32r6InstrInfo.td
@@ -73,6 +73,7 @@ class AUI_ENC : AUI_FM;
class AUIPC_ENC : PCREL16_FM<OPCODE5_AUIPC>;
class BAL_ENC : BAL_FM;
+class NAL_ENC : NAL_FM;
class BALC_ENC : BRANCH_OFF26_FM<0b111010>;
class BC_ENC : BRANCH_OFF26_FM<0b110010>;
class BEQC_ENC : CMP_BRANCH_2R_OFF16_FM<OPGROUP_ADDI>,
@@ -381,6 +382,12 @@ class BC_DESC_BASE<string instr_asm, DAGOperand opnd> : BRANCH_DESC_BASE,
bit isCTI = 1;
}
+class NAL_DESC_BASE<string instr_asm> : BRANCH_DESC_BASE,
+ MipsR6Arch<instr_asm> {
+ string AsmString = instr_asm;
+ bit isCTI = 1;
+}
+
class CMP_BC_DESC_BASE<string instr_asm, DAGOperand opnd,
RegisterOperand GPROpnd> : BRANCH_DESC_BASE,
MipsR6Arch<instr_asm> {
@@ -424,6 +431,12 @@ class BAL_DESC : BC_DESC_BASE<"bal", brtarget> {
bit isCTI = 1;
}
+class NAL_DESC : NAL_DESC_BASE<"nal"> {
+ bit hasDelaySlot = 1;
+ list<Register> Defs = [RA];
+ bit isCTI = 1;
+}
+
class BALC_DESC : BC_DESC_BASE<"balc", brtarget26> {
bit isCall = 1;
list<Register> Defs = [RA];
@@ -868,6 +881,8 @@ def AUI : R6MMR6Rel, AUI_ENC, AUI_DESC, ISA_MIPS32R6;
def AUIPC : R6MMR6Rel, AUIPC_ENC, AUIPC_DESC, ISA_MIPS32R6;
def BAL : BAL_ENC, BAL_DESC, ISA_MIPS32R6;
def BALC : R6MMR6Rel, BALC_ENC, BALC_DESC, ISA_MIPS32R6;
+def NAL : NAL_ENC, NAL_DESC, ISA_MIPS32R6;
+
let AdditionalPredicates = [NotInMicroMips] in {
def BC1EQZ : BC1EQZ_ENC, BC1EQZ_DESC, ISA_MIPS32R6, HARDFLOAT;
def BC1NEZ : BC1NEZ_ENC, BC1NEZ_DESC, ISA_MIPS32R6, HARDFLOAT;
@@ -948,7 +963,6 @@ let AdditionalPredicates = [NotInMicroMips] in {
def MUL_R6 : R6MMR6Rel, MUL_R6_ENC, MUL_R6_DESC, ISA_MIPS32R6;
def MULU : R6MMR6Rel, MULU_ENC, MULU_DESC, ISA_MIPS32R6;
}
-def NAL; // BAL with rd=0
let AdditionalPredicates = [NotInMicroMips] in {
def PREF_R6 : R6MMR6Rel, PREF_ENC, PREF_DESC, ISA_MIPS32R6;
def RINT_D : RINT_D_ENC, RINT_D_DESC, ISA_MIPS32R6, HARDFLOAT;
diff --git a/llvm/lib/Target/Mips/MipsInstrInfo.td b/llvm/lib/Target/Mips/MipsInstrInfo.td
index 4b6f4b22e71b..23e04c442bf6 100644
--- a/llvm/lib/Target/Mips/MipsInstrInfo.td
+++ b/llvm/lib/Target/Mips/MipsInstrInfo.td
@@ -3049,6 +3049,9 @@ def : MipsInstAlias<"divu $rd, $imm", (UDivIMacro GPR32Opnd:$rd, GPR32Opnd:$rd,
simm32:$imm), 0>,
ISA_MIPS1_NOT_32R6_64R6;
+
+def : MipsInstAlias<"nal", (BLTZAL ZERO, 0), 1>, ISA_MIPS1_NOT_32R6_64R6;
+
def SRemMacro : MipsAsmPseudoInst<(outs GPR32Opnd:$rd),
(ins GPR32Opnd:$rs, GPR32Opnd:$rt),
"rem\t$rd, $rs, $rt">,
diff --git a/llvm/lib/Target/Mips/MipsScheduleGeneric.td b/llvm/lib/Target/Mips/MipsScheduleGeneric.td
index a3df88a93cfb..6771a897eea7 100644
--- a/llvm/lib/Target/Mips/MipsScheduleGeneric.td
+++ b/llvm/lib/Target/Mips/MipsScheduleGeneric.td
@@ -285,7 +285,7 @@ def GenericWriteJumpAndLink : SchedWriteRes<[GenericIssueCTISTD]> {
// jalr, jr.hb, jr, jalr.hb, jarlc, jialc
def : InstRW<[GenericWriteJump], (instrs B, BAL, BAL_BR, BEQ, BNE, BGTZ, BGEZ,
BLEZ, BLTZ, BLTZAL, J, JALX, JR, JR_HB, ERET,
- ERet, ERETNC, DERET)>;
+ ERet, ERETNC, DERET, NAL)>;
def : InstRW<[GenericWriteJump], (instrs BEQL, BNEL, BGEZL, BGTZL, BLEZL,
BLTZL)>;
diff --git a/llvm/test/MC/Mips/mips32/nal.s b/llvm/test/MC/Mips/mips32/nal.s
new file mode 100644
index 000000000000..72c723108586
--- /dev/null
+++ b/llvm/test/MC/Mips/mips32/nal.s
@@ -0,0 +1,14 @@
+# RUN: llvm-mc %s -triple=mipsel-linux-gnu -filetype=obj -o - | \
+# RUN: llvm-objdump --no-print-imm-hex -d - | FileCheck %s --check-prefix=MIPS32-EL
+# RUN: llvm-mc %s -triple=mips-linux-gnu -filetype=obj -o - | \
+# RUN: llvm-objdump --no-print-imm-hex -d - | FileCheck %s --check-prefix=MIPS32-EB
+
+# Whether it is a macro or an actual instruction, it always has a delay slot.
+# Ensure the delay slot is filled correctly.
+# MIPS32-EL: 00 00 10 04 bltzal $zero, 0x4
+# MIPS32-EL-NEXT: 00 00 00 00 nop
+# MIPS32-EB: 04 10 00 00 bltzal $zero, 0x4
+# MIPS32-EB-NEXT: 00 00 00 00 nop
+
+nal_test:
+ nal
diff --git a/llvm/test/MC/Mips/mips32r6/nal.s b/llvm/test/MC/Mips/mips32r6/nal.s
new file mode 100644
index 000000000000..94c1a774f47e
--- /dev/null
+++ b/llvm/test/MC/Mips/mips32r6/nal.s
@@ -0,0 +1,21 @@
+# RUN: llvm-mc %s -triple=mipsisa32r6el-linux-gnu -filetype=obj -o - | \
+# RUN: llvm-objdump --no-print-imm-hex -d - | FileCheck %s --check-prefix=MIPS32R6-EL
+# RUN: llvm-mc %s -triple=mipsisa32r6-linux-gnu -filetype=obj -o - | \
+# RUN: llvm-objdump --no-print-imm-hex -d - | FileCheck %s --check-prefix=MIPS32R6-EB
+
+# Whether it is a macro or an actual instruction, it always has a delay slot.
+# Ensure the delay slot is filled correctly.
+# Also ensure that NAL does not reside in a forbidden slot.
+# MIPS32R6-EL: 00 00 80 f8 bnezc $4, 0x4
+# MIPS32R6-EL-NEXT: 00 00 00 00 nop
+# MIPS32R6-EL: 00 00 10 04 nal
+# MIPS32R6-EL-NEXT: 00 00 00 00 nop
+# MIPS32R6-EB: f8 80 00 00 bnezc $4, 0x4
+# MIPS32R6-EB-NEXT: 00 00 00 00 nop
+# MIPS32R6-EB: 04 10 00 00 nal
+# MIPS32R6-EB-NEXT: 00 00 00 00 nop
+
+nal_test:
+ # We generate a fobidden solt just for testing.
+ bnezc $a0, 0
+ nal