diff --git a/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp b/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp --- a/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp +++ b/llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp @@ -69,6 +69,7 @@ enum LoongArchMatchResultTy { Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY, Match_RequiresMsbNotLessThanLsb, + Match_RequiresOpnd2NotR0R1, #define GET_OPERAND_DIAGNOSTIC_TYPES #include "LoongArchGenAsmMatcher.inc" #undef GET_OPERAND_DIAGNOSTIC_TYPES @@ -151,7 +152,9 @@ bool isUImm3() const { return isUImm<3>(); } bool isUImm5() const { return isUImm<5>(); } bool isUImm6() const { return isUImm<6>(); } + bool isUImm8() const { return isUImm<8>(); } bool isUImm12() const { return isUImm<12>(); } + bool isUImm14() const { return isUImm<14>(); } bool isUImm15() const { return isUImm<15>(); } bool isSImm12() const { return isSImm<12>(); } bool isSImm14lsl2() const { return isSImm<14, 2>(); } @@ -376,6 +379,12 @@ switch (Inst.getOpcode()) { default: break; + case LoongArch::CSRXCHG: { + unsigned Rj = Inst.getOperand(2).getReg(); + if (Rj == LoongArch::R0 || Rj == LoongArch::R1) + return Match_RequiresOpnd2NotR0R1; + return Match_Success; + } case LoongArch::BSTRINS_W: case LoongArch::BSTRINS_D: case LoongArch::BSTRPICK_W: @@ -489,6 +498,8 @@ return Error(ErrorStart, "msb is less than lsb", SMRange(ErrorStart, Operands[4]->getEndLoc())); } + case Match_RequiresOpnd2NotR0R1: + return Error(Operands[2]->getStartLoc(), "must not be $r0 or $r1"); case Match_InvalidUImm2: return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, /*Upper=*/(1 << 2) - 1); diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrFormats.td b/llvm/lib/Target/LoongArch/LoongArchInstrFormats.td --- a/llvm/lib/Target/LoongArch/LoongArchInstrFormats.td +++ b/llvm/lib/Target/LoongArch/LoongArchInstrFormats.td @@ -322,3 +322,83 @@ let Inst{9-5} = rj; let Inst{4-0} = imm5; } + +// FmtCSR +// +class FmtCSR op, dag outs, dag ins, string opcstr, string opnstr, + list pattern = []> + : LAInst { + bits<14> csr_num; + bits<5> rd; + + let Inst{31-24} = op{12-5}; + let Inst{23-10} = csr_num; + let Inst{9-5} = op{4-0}; + let Inst{4-0} = rd; +} + +// FmtCSRXCHG +// +class FmtCSRXCHG op, dag outs, dag ins, string opcstr, string opnstr, + list pattern = []> + : LAInst { + bits<14> csr_num; + bits<5> rj; + bits<5> rd; + + let Inst{31-24} = op; + let Inst{23-10} = csr_num; + let Inst{9-5} = rj; + let Inst{4-0} = rd; +} + +// FmtCACOP +// <0b0000011000 | I12 | rj | I5> +class FmtCACOP pattern = []> + : LAInst { + bits<12> imm12; + bits<5> rj; + bits<5> op; + + let Inst{31-22} = 0b0000011000; + let Inst{21-10} = imm12; + let Inst{9-5} = rj; + let Inst{4-0} = op; +} + +// FmtIMM32 +// +class FmtI32 op, string opstr, list pattern = []> + : LAInst<(outs), (ins), opstr, "", pattern> { + let Inst{31-0} = op; +} + +// FmtINVTLB +// <0b00000110010010011 | rk | rj | I5> +class FmtINVTLB pattern = []> + : LAInst { + bits<5> rk; + bits<5> rj; + bits<5> op; + + let Inst{31-15} = 0b00000110010010011; + let Inst{14-10} = rk; + let Inst{9-5} = rj; + let Inst{4-0} = op; +} + +// FmtLDPTE +// <0b00000110010001 | seq | rj | 00000> +class FmtLDPTE pattern = []> + : LAInst { + bits<8> seq; + bits<5> rj; + + let Inst{31-18} = 0b00000110010001; + let Inst{17-10} = seq; + let Inst{9-5} = rj; + let Inst{4-0} = 0b00000; +} diff --git a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td --- a/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td +++ b/llvm/lib/Target/LoongArch/LoongArchInstrInfo.td @@ -60,10 +60,18 @@ let ParserMatchClass = UImmAsmOperand<6>; } +def uimm8 : Operand { + let ParserMatchClass = UImmAsmOperand<8>; +} + def uimm12 : Operand { let ParserMatchClass = UImmAsmOperand<12>; } +def uimm14 : Operand { + let ParserMatchClass = UImmAsmOperand<14>; +} + def uimm15 : Operand { let ParserMatchClass = UImmAsmOperand<15>; } @@ -205,6 +213,12 @@ : Fmt2RI14; +class IOCSRRD op, string opstr> + : Fmt2R; + +class IOCSRWR op, string opstr> + : Fmt2R; + //===----------------------------------------------------------------------===// // Basic Integer Instructions //===----------------------------------------------------------------------===// @@ -536,3 +550,55 @@ include "LoongArchFloat32InstrInfo.td" include "LoongArchFloat64InstrInfo.td" + +//===----------------------------------------------------------------------===// +// Privilege Instructions +//===----------------------------------------------------------------------===// + +// CSR Access Instructions +def CSRRD : FmtCSR<0b0000010000000, (outs GPR:$rd), (ins uimm14:$csr_num), + "csrrd", "$rd, $csr_num">; +let Constraints = "$rd = $dst" in { +def CSRWR : FmtCSR<0b0000010000001, (outs GPR:$dst), + (ins GPR:$rd, uimm14:$csr_num), "csrwr", "$rd, $csr_num">; +def CSRXCHG : FmtCSRXCHG<0b00000100, (outs GPR:$dst), + (ins GPR:$rd, GPR:$rj, uimm14:$csr_num), + "csrxchg", "$rd, $rj, $csr_num">; +} // Constraints = "$rd = $dst" + +// IOCSR Access Instructions +def IOCSRRD_B : IOCSRRD<0b0000011001001000000000, "iocsrrd.b">; +def IOCSRRD_H : IOCSRRD<0b0000011001001000000001, "iocsrrd.h">; +def IOCSRRD_W : IOCSRRD<0b0000011001001000000010, "iocsrrd.w">; +def IOCSRWR_B : IOCSRWR<0b0000011001001000000100, "iocsrwr.b">; +def IOCSRWR_H : IOCSRWR<0b0000011001001000000101, "iocsrwr.h">; +def IOCSRWR_W : IOCSRWR<0b0000011001001000000110, "iocsrwr.w">; +let Predicates = [IsLA64] in { +def IOCSRRD_D : IOCSRRD<0b0000011001001000000011, "iocsrrd.d">; +def IOCSRWR_D : IOCSRWR<0b0000011001001000000111, "iocsrwr.d">; +} // Predicates = [IsLA64] + +// Cache Maintenance Instructions +def CACOP : FmtCACOP<(outs), (ins uimm5:$op, GPR:$rj, simm12:$imm12), "cacop", + "$op, $rj, $imm12">; + +// TLB Maintenance Instructions +def TLBSRCH : FmtI32<0b00000110010010000010100000000000, "tlbsrch">; +def TLBRD : FmtI32<0b00000110010010000010110000000000, "tlbrd">; +def TLBWR : FmtI32<0b00000110010010000011000000000000, "tlbwr">; +def TLBFILL : FmtI32<0b00000110010010000011010000000000, "tlbfill">; +def TLBCLR : FmtI32<0b00000110010010000010000000000000, "tlbclr">; +def TLBFLUSH : FmtI32<0b00000110010010000010010000000000, "tlbflush">; +def INVTLB : FmtINVTLB<(outs), (ins GPR:$rk, GPR:$rj, uimm5:$op), "invtlb", + "$op, $rj, $rk">; + +// Software Page Walking Instructions +def LDDIR : Fmt2RI8<0b00000110010000, (outs GPR:$rd), + (ins GPR:$rj, uimm8:$imm8), "lddir", "$rd, $rj, $imm8">; +def LDPTE : FmtLDPTE<(outs), (ins GPR:$rj, uimm8:$seq), "ldpte", "$rj, $seq">; + + +// Other Miscellaneous Instructions +def ERTN : FmtI32<0b00000110010010000011100000000000, "ertn">; +def DBCL : MISC_I15<0b00000000001010101, "dbcl">; +def IDLE : MISC_I15<0b00000110010010001, "idle">; diff --git a/llvm/test/MC/LoongArch/Basic/Privilege/invalid.s b/llvm/test/MC/LoongArch/Basic/Privilege/invalid.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/LoongArch/Basic/Privilege/invalid.s @@ -0,0 +1,14 @@ +# RUN: not llvm-mc --triple=loongarch32 %s 2>&1 | FileCheck %s --check-prefixes=ERR,ERR32 +# RUN: not llvm-mc --triple=loongarch64 %s 2>&1 | FileCheck %s --check-prefix=ERR + +## csrxchg: rj != 0,1 +csrxchg $a0, $zero, 0 +# ERR: :[[#@LINE-1]]:15: error: must not be $r0 or $r1 +csrxchg $a0, $ra, 0 +# ERR: :[[#@LINE-1]]:15: error: must not be $r0 or $r1 + +## LoongArch64 mnemonics +iocsrrd.d $a0, $a1 +# ERR32: :[[#@LINE-1]]:1: error: instruction requires the following: LA64 Basic Integer and Privilege Instruction Set +iocsrwr.d $a0, $a1 +# ERR32: :[[#@LINE-1]]:1: error: instruction requires the following: LA64 Basic Integer and Privilege Instruction Set diff --git a/llvm/test/MC/LoongArch/Basic/Privilege/valid.s b/llvm/test/MC/LoongArch/Basic/Privilege/valid.s new file mode 100644 --- /dev/null +++ b/llvm/test/MC/LoongArch/Basic/Privilege/valid.s @@ -0,0 +1,118 @@ +## Test valid privilege instructions + +# RUN: llvm-mc %s --triple=loongarch32 --show-encoding \ +# RUN: | FileCheck --check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ %s +# RUN: llvm-mc %s --triple=loongarch64 --show-encoding --defsym=LA64=1 \ +# RUN: | FileCheck --check-prefixes=CHECK-ASM,CHECK-ASM-AND-OBJ,CHECK64-ASM,CHECK64-ASM-AND-OBJ %s +# RUN: llvm-mc %s --triple=loongarch32 --filetype=obj | llvm-objdump -d - \ +# RUN: | FileCheck --check-prefix=CHECK-ASM-AND-OBJ %s +# RUN: llvm-mc %s --triple=loongarch64 --filetype=obj --defsym=LA64=1 | llvm-objdump -d - \ +# RUN: | FileCheck --check-prefixes=CHECK-ASM-AND-OBJ,CHECK64-ASM-AND-OBJ %s + +############################################################# +## Instructions for both loongarch32 and loongarch64 +############################################################# + +# CHECK-ASM-AND-OBJ: csrrd $s3, 30 +# CHECK-ASM: encoding: [0x1a,0x78,0x00,0x04] +csrrd $s3, 30 + +# CHECK-ASM-AND-OBJ: csrwr $s1, 194 +# CHECK-ASM: encoding: [0x38,0x08,0x03,0x04] +csrwr $s1, 194 + +# CHECK-ASM-AND-OBJ: csrxchg $a2, $s4, 214 +# CHECK-ASM: encoding: [0x66,0x5b,0x03,0x04] +csrxchg $a2, $s4, 214 + +# CHECK-ASM-AND-OBJ: iocsrrd.b $s3, $s1 +# CHECK-ASM: encoding: [0x1a,0x03,0x48,0x06] +iocsrrd.b $s3, $s1 + +# CHECK-ASM-AND-OBJ: iocsrrd.h $a1, $s4 +# CHECK-ASM: encoding: [0x65,0x07,0x48,0x06] +iocsrrd.h $a1, $s4 + +# CHECK-ASM-AND-OBJ: iocsrrd.w $a6, $t8 +# CHECK-ASM: encoding: [0x8a,0x0a,0x48,0x06] +iocsrrd.w $a6, $t8 + +# CHECK-ASM-AND-OBJ: iocsrwr.b $a0, $s0 +# CHECK-ASM: encoding: [0xe4,0x12,0x48,0x06] +iocsrwr.b $a0, $s0 + +# CHECK-ASM-AND-OBJ: iocsrwr.h $a7, $zero +# CHECK-ASM: encoding: [0x0b,0x14,0x48,0x06] +iocsrwr.h $a7, $zero + +# CHECK-ASM-AND-OBJ: iocsrwr.w $t8, $s3 +# CHECK-ASM: encoding: [0x54,0x1b,0x48,0x06] +iocsrwr.w $t8, $s3 + +# CHECK-ASM-AND-OBJ: cacop 0, $a6, 27 +# CHECK-ASM: encoding: [0x40,0x6d,0x00,0x06] +cacop 0, $a6, 27 + +# CHECK-ASM-AND-OBJ: tlbclr +# CHECK-ASM: encoding: [0x00,0x20,0x48,0x06] +tlbclr + +# CHECK-ASM-AND-OBJ: tlbflush +# CHECK-ASM: encoding: [0x00,0x24,0x48,0x06] +tlbflush + +# CHECK-ASM-AND-OBJ: tlbsrch +# CHECK-ASM: encoding: [0x00,0x28,0x48,0x06] +tlbsrch + +# CHECK-ASM-AND-OBJ: tlbrd +# CHECK-ASM: encoding: [0x00,0x2c,0x48,0x06] +tlbrd + +# CHECK-ASM-AND-OBJ: tlbwr +# CHECK-ASM: encoding: [0x00,0x30,0x48,0x06] +tlbwr + +# CHECK-ASM-AND-OBJ: tlbfill +# CHECK-ASM: encoding: [0x00,0x34,0x48,0x06] +tlbfill + +# CHECK-ASM-AND-OBJ: invtlb 16, $s6, $s2 +# CHECK-ASM: encoding: [0xb0,0xe7,0x49,0x06] +invtlb 16, $s6, $s2 + +# CHECK-ASM-AND-OBJ: lddir $t0, $s7, 92 +# CHECK-ASM: encoding: [0xcc,0x73,0x41,0x06] +lddir $t0, $s7, 92 + +# CHECK-ASM-AND-OBJ: ldpte $t6, 200 +# CHECK-ASM: encoding: [0x40,0x22,0x47,0x06] +ldpte $t6, 200 + +# CHECK-ASM-AND-OBJ: ertn +# CHECK-ASM: encoding: [0x00,0x38,0x48,0x06] +ertn + +# CHECK-ASM-AND-OBJ: dbcl 201 +# CHECK-ASM: encoding: [0xc9,0x80,0x2a,0x00] +dbcl 201 + +# CHECK-ASM-AND-OBJ: idle 204 +# CHECK-ASM: encoding: [0xcc,0x80,0x48,0x06] +idle 204 + +############################################################# +## Instructions only for loongarch64 +############################################################# + +.ifdef LA64 + +# CHECK64-ASM-AND-OBJ: iocsrrd.d $t5, $s2 +# CHECK64-ASM: encoding: [0x31,0x0f,0x48,0x06] +iocsrrd.d $t5, $s2 + +# CHECK64-ASM-AND-OBJ: iocsrwr.d $t8, $a3 +# CHECK64-ASM: encoding: [0xf4,0x1c,0x48,0x06] +iocsrwr.d $t8, $a3 + +.endif