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 @@ -43,6 +43,8 @@ uint64_t &ErrorInfo, bool MatchingInlineAsm) override; + unsigned checkTargetMatchPredicate(MCInst &Inst) override; + unsigned validateTargetOperandClass(MCParsedAsmOperand &Op, unsigned Kind) override; @@ -66,6 +68,7 @@ public: enum LoongArchMatchResultTy { Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY, + Match_RequiresMsbNotLessThanLsb, #define GET_OPERAND_DIAGNOSTIC_TYPES #include "LoongArchGenAsmMatcher.inc" #undef GET_OPERAND_DIAGNOSTIC_TYPES @@ -369,6 +372,32 @@ return false; } +unsigned LoongArchAsmParser::checkTargetMatchPredicate(MCInst &Inst) { + switch (Inst.getOpcode()) { + default: + break; + case LoongArch::BSTRINS_W: + case LoongArch::BSTRINS_D: + case LoongArch::BSTRPICK_W: + case LoongArch::BSTRPICK_D: { + unsigned Opc = Inst.getOpcode(); + const signed Msb = + (Opc == LoongArch::BSTRINS_W || Opc == LoongArch::BSTRINS_D) + ? Inst.getOperand(3).getImm() + : Inst.getOperand(2).getImm(); + const signed Lsb = + (Opc == LoongArch::BSTRINS_W || Opc == LoongArch::BSTRINS_D) + ? Inst.getOperand(4).getImm() + : Inst.getOperand(3).getImm(); + if (Msb < Lsb) + return Match_RequiresMsbNotLessThanLsb; + return Match_Success; + } + } + + return Match_Success; +} + unsigned LoongArchAsmParser::validateTargetOperandClass(MCParsedAsmOperand &AsmOp, unsigned Kind) { @@ -455,6 +484,11 @@ switch (Result) { default: break; + case Match_RequiresMsbNotLessThanLsb: { + SMLoc ErrorStart = Operands[3]->getStartLoc(); + return Error(ErrorStart, "msb is less than lsb", + SMRange(ErrorStart, Operands[4]->getEndLoc())); + } case Match_InvalidUImm2: return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0, /*Upper=*/(1 << 2) - 1); diff --git a/llvm/test/MC/LoongArch/Basic/Integer/invalid.s b/llvm/test/MC/LoongArch/Basic/Integer/invalid.s --- a/llvm/test/MC/LoongArch/Basic/Integer/invalid.s +++ b/llvm/test/MC/LoongArch/Basic/Integer/invalid.s @@ -180,3 +180,12 @@ ## Using floating point registers when integer registers are expected sll.w $a0, $a0, $fa0 # CHECK: :[[#@LINE-1]]:18: error: invalid operand for instruction + +## msbw < lsbw +# CHECK: :[[#@LINE+1]]:21: error: msb is less than lsb +bstrins.w $a0, $a0, 1, 2 +# CHECK: ^~~~ + +# CHECK: :[[#@LINE+1]]:22: error: msb is less than lsb +bstrpick.w $a0, $a0, 30, 31 +# CHECK: ^~~~~~ diff --git a/llvm/test/MC/LoongArch/Basic/Integer/invalid64.s b/llvm/test/MC/LoongArch/Basic/Integer/invalid64.s --- a/llvm/test/MC/LoongArch/Basic/Integer/invalid64.s +++ b/llvm/test/MC/LoongArch/Basic/Integer/invalid64.s @@ -64,3 +64,12 @@ # CHECK: :[[#@LINE-1]]:14: error: immediate must be an integer in the range [-524288, 524287] pcaddu18i $a0, 0x80000 # CHECK: :[[#@LINE-1]]:16: error: immediate must be an integer in the range [-524288, 524287] + +## msbd < lsbd +# CHECK: :[[#@LINE+1]]:21: error: msb is less than lsb +bstrins.d $a0, $a0, 1, 2 +# CHECK: ^~~~ + +# CHECK: :[[#@LINE+1]]:22: error: msb is less than lsb +bstrpick.d $a0, $a0, 32, 63 +# CHECK: ^~~~~~