Skip to content

Commit

Permalink
[MIPS] Introduce NAL instruction support for Mipsr6 and prer6 (#84429)
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
anbbna committed Mar 12, 2024
1 parent 418f006 commit 65f07b8
Show file tree
Hide file tree
Showing 6 changed files with 65 additions and 2 deletions.
11 changes: 11 additions & 0 deletions llvm/lib/Target/Mips/Mips32r6InstrFormats.td
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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;

Expand Down
16 changes: 15 additions & 1 deletion llvm/lib/Target/Mips/Mips32r6InstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
Expand Down Expand Up @@ -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> {
Expand Down Expand Up @@ -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];
Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/Mips/MipsInstrInfo.td
Original file line number Diff line number Diff line change
Expand Up @@ -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">,
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/Target/Mips/MipsScheduleGeneric.td
Original file line number Diff line number Diff line change
Expand Up @@ -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)>;
Expand Down
14 changes: 14 additions & 0 deletions llvm/test/MC/Mips/mips32/nal.s
Original file line number Diff line number Diff line change
@@ -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
21 changes: 21 additions & 0 deletions llvm/test/MC/Mips/mips32r6/nal.s
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 65f07b8

Please sign in to comment.