diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index c320bf723c88b..8c96cce7a5cf5 100644 --- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -7629,6 +7629,39 @@ bool ARMAsmParser::validateInstruction(MCInst &Inst, } return false; } + case ARM::t2STREXB: + case ARM::t2STREXH: + case ARM::t2STREX: + case ARM::STREXB: + case ARM::STREXH: + case ARM::STREX: + case ARM::STREXD: { + unsigned Rd = MRI->getEncodingValue(Inst.getOperand(0).getReg()); + unsigned Rm = MRI->getEncodingValue(Inst.getOperand(1).getReg()); + unsigned Rn = MRI->getEncodingValue(Inst.getOperand(2).getReg()); + + if (Rd == 15 || Rm == 15 || Rn == 15) + return Error(Operands[3]->getStartLoc(), "operand can't be R15"); + + if (Rd == Rm || Rd == Rn || (Opcode == ARM::STREXD && Rd == Rm + 1)) + return Error(Operands[3]->getStartLoc(), + "destination operand can't be identical to source operand"); + return false; + } + case ARM::t2STREXD: { + unsigned Rd = MRI->getEncodingValue(Inst.getOperand(0).getReg()); + unsigned Rm1 = MRI->getEncodingValue(Inst.getOperand(1).getReg()); + unsigned Rm2 = MRI->getEncodingValue(Inst.getOperand(2).getReg()); + unsigned Rn = MRI->getEncodingValue(Inst.getOperand(3).getReg()); + + if (Rd == 15 || Rn == 15) + return Error(Operands[4]->getStartLoc(), "operand can't be R15"); + + if (Rd == Rm1 || Rd == Rm2 || Rd == Rn) + return Error(Operands[4]->getStartLoc(), + "destination operand can't be identical to source operand"); + return false; + } case ARM::t2IT: { // Encoding is unpredictable if it ever results in a notional 'NV' // predicate. Since we don't parse 'NV' directly this means an 'AL' diff --git a/llvm/test/MC/ARM/diagnostics.s b/llvm/test/MC/ARM/diagnostics.s index e6d80ea7a6280..f29be4e3bafcc 100644 --- a/llvm/test/MC/ARM/diagnostics.s +++ b/llvm/test/MC/ARM/diagnostics.s @@ -336,6 +336,58 @@ @ CHECK-ERRORS: strexd r6, r5, r3, [r8] @ CHECK-ERRORS: ^ + @ Invalid Rm/Rn operands for strex + strex r1, r2, [r1] + strex r1, r1, [r2] + +@ CHECK-ERRORS: error: destination operand can't be identical to source operand +@ CHECK-ERRORS: strex r1, r2, [r1] +@ CHECK-ERRORS: ^ +@ CHECK-ERRORS: error: destination operand can't be identical to source operand +@ CHECK-ERRORS: strex r1, r1, [r2] +@ CHECK-ERRORS: ^ + + @ Can not use R15 as operand for strex + strex r15, r2, [r1] + strex r1, r15, [r2] + strex r1, r2, [r15] + +@ CHECK-ERRORS: error: operand can't be R15 +@ CHECK-ERRORS: strex r15, r2, [r1] +@ CHECK-ERRORS: ^ +@ CHECK-ERRORS: error: operand can't be R15 +@ CHECK-ERRORS: strex r1, r15, [r2] +@ CHECK-ERRORS: ^ +@ CHECK-ERRORS: error: operand can't be R15 +@ CHECK-ERRORS: strex r1, r2, [r15] +@ CHECK-ERRORS: ^ + + @ Can not use R15 as operand for strexd + strexd r15, r0, r1, [r6] + strexd r2, r0, r1, [r15] + +@ CHECK-ERRORS: error: operand can't be R15 +@ CHECK-ERRORS: strexd r15, r0, r1, [r6] +@ CHECK-ERRORS: ^ +@ CHECK-ERRORS: error: operand can't be R15 +@ CHECK-ERRORS: strexd r2, r0, r1, [r15] +@ CHECK-ERRORS: ^ + + @ Invalid Rm/Rn operands for strexd + strexd r1, r0, r1, [r6] + strexd r2, r2, r3, [r6] + strexd r4, r0, r1, [r4] + +@ CHECK-ERRORS: error: destination operand can't be identical to source operand +@ CHECK-ERRORS: strexd r1, r0, r1, [r6] +@ CHECK-ERRORS: ^ +@ CHECK-ERRORS: error: destination operand can't be identical to source operand +@ CHECK-ERRORS: strexd r2, r2, r3, [r6] +@ CHECK-ERRORS: ^ +@ CHECK-ERRORS: error: destination operand can't be identical to source operand +@ CHECK-ERRORS: strexd r4, r0, r1, [r4] +@ CHECK-ERRORS: ^ + @ Illegal rotate operators for extend instructions sxtb r8, r3, #8 sxtb r8, r3, ror 24