[LoongArch] Report error in AsmParser when rd == rk or rd == rj for AM* instructions
authorWeining Lu <luweining@loongson.cn>
Fri, 21 Oct 2022 01:56:27 +0000 (09:56 +0800)
committerWeining Lu <luweining@loongson.cn>
Fri, 21 Oct 2022 01:56:45 +0000 (09:56 +0800)
Do this check because the ISA manual says (edited from the original translation):

> If the AM* instruction has its rd == rj, an Instruction Non-defined Exception will be triggered when the instruction is executed.
>
> If the AM* instruction has its rd == rk, the execution result is unpredictable. It is software's responsibility to avoid this situation.

Note that binutils does the same check except when rd == r0 but this
is undocumented.

Differential Revision: https://reviews.llvm.org/D136076

llvm/lib/Target/LoongArch/AsmParser/LoongArchAsmParser.cpp
llvm/test/MC/LoongArch/Basic/Integer/invalid64.s

index 10b4660..77f431b 100644 (file)
@@ -74,6 +74,7 @@ public:
     Match_Dummy = FIRST_TARGET_MATCH_RESULT_TY,
     Match_RequiresMsbNotLessThanLsb,
     Match_RequiresOpnd2NotR0R1,
+    Match_RequiresAMORdDifferRkRj,
 #define GET_OPERAND_DIAGNOSTIC_TYPES
 #include "LoongArchGenAsmMatcher.inc"
 #undef GET_OPERAND_DIAGNOSTIC_TYPES
@@ -667,8 +668,16 @@ bool LoongArchAsmParser::processInstruction(MCInst &Inst, SMLoc IDLoc,
 }
 
 unsigned LoongArchAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
-  switch (Inst.getOpcode()) {
+  unsigned Opc = Inst.getOpcode();
+  switch (Opc) {
   default:
+    if (Opc >= LoongArch::AMADD_D && Opc <= LoongArch::AMXOR_W) {
+      unsigned Rd = Inst.getOperand(0).getReg();
+      unsigned Rk = Inst.getOperand(1).getReg();
+      unsigned Rj = Inst.getOperand(2).getReg();
+      if (Rd == Rk || Rd == Rj)
+        return Match_RequiresAMORdDifferRkRj;
+    }
     break;
   case LoongArch::CSRXCHG: {
     unsigned Rj = Inst.getOperand(2).getReg();
@@ -791,6 +800,9 @@ bool LoongArchAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode,
   }
   case Match_RequiresOpnd2NotR0R1:
     return Error(Operands[2]->getStartLoc(), "must not be $r0 or $r1");
+  case Match_RequiresAMORdDifferRkRj:
+    return Error(Operands[1]->getStartLoc(),
+                 "$rd must be different from both $rk and $rj");
   case Match_InvalidUImm2:
     return generateImmOutOfRangeError(Operands, ErrorInfo, /*Lower=*/0,
                                       /*Upper=*/(1 << 2) - 1);
index 5ee9659..7e67a19 100644 (file)
@@ -79,3 +79,17 @@ bstrins.d $a0, $a0, 1, 2
 # CHECK: :[[#@LINE+1]]:22: error: msb is less than lsb
 bstrpick.d $a0, $a0, 32, 63
 # CHECK:             ^~~~~~
+
+# CHECK: :[[#@LINE+1]]:10: error: $rd must be different from both $rk and $rj
+amadd.d $zero, $zero, $zero
+# CHECK: :[[#@LINE+1]]:10: error: $rd must be different from both $rk and $rj
+ammin.w $zero, $zero, $a0
+# CHECK: :[[#@LINE+1]]:10: error: $rd must be different from both $rk and $rj
+amxor.w $zero, $a0, $zero
+
+# CHECK: :[[#@LINE+1]]:10: error: $rd must be different from both $rk and $rj
+amadd.d $a0, $a0, $a0
+# CHECK: :[[#@LINE+1]]:10: error: $rd must be different from both $rk and $rj
+ammin.w $a0, $a0, $a1
+# CHECK: :[[#@LINE+1]]:10: error: $rd must be different from both $rk and $rj
+amxor.w $a0, $a1, $a0