Index: include/llvm/MC/MCParser/MCTargetAsmParser.h =================================================================== --- include/llvm/MC/MCParser/MCTargetAsmParser.h +++ include/llvm/MC/MCParser/MCTargetAsmParser.h @@ -100,6 +100,7 @@ enum NearMissKind { NoNearMiss, NearMissOperand, + NearMissMultipleOperands, NearMissFeature, NearMissPredicate, NearMissTooFewOperands, @@ -146,6 +147,13 @@ return Result; } + static NearMissInfo getMissedMultipleOperands(unsigned Opcode) { + NearMissInfo Result; + Result.Kind = NearMissMultipleOperands; + Result.MissedOperand.Opcode = Opcode; + return Result; + } + // The instruction encoding is not valid because it expects more operands // than were parsed. OperandClass is the class of the expected operand that // was not provided. Opcode is the instruction encoding. @@ -181,7 +189,8 @@ } // Opcode of the encoding we were trying to match. unsigned getOpcode() const { - assert(Kind == NearMissOperand || Kind == NearMissTooFewOperands); + assert(Kind == NearMissOperand || Kind == NearMissTooFewOperands || + Kind == NearMissMultipleOperands); return MissedOperand.Opcode; } // Error code returned when validating the operand. Index: lib/Target/ARM/AsmParser/ARMAsmParser.cpp =================================================================== --- lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -10075,6 +10075,7 @@ std::multimap OperandMissesSeen; SmallSet FeatureMissesSeen; bool ReportedTooFewOperands = false; + bool HaveMultipleBadOperands = false; // Process the near-misses in reverse order, so that we see more general ones // first, and so can avoid emitting more specific ones. @@ -10196,6 +10197,12 @@ NearMissesOut.emplace_back(Message); break; } + case NearMissInfo::NearMissMultipleOperands: { + // Just record the fact that we have seen this, we will use it as a + // fall-back if we don't find a better operand error to report. + HaveMultipleBadOperands = true; + break; + } case NearMissInfo::NearMissTooFewOperands: { if (!ReportedTooFewOperands) { SMLoc EndLoc = ((ARMOperand &)*Operands.back()).getEndLoc(); @@ -10211,6 +10218,16 @@ break; } } + + // If there is an encoding that missed on multiple operands (but matched the + // target features and early predicate), but we haven't been able to emit a + // more specific error for any operands, emit a generic error. This lets the + // user know that the mnemonic exists, and that some combination of operands + // would work for teh current target. + if (HaveMultipleBadOperands && NearMissesOut.empty()) { + NearMissesOut.emplace_back(NearMissMessage{ + IDLoc, StringRef("invalid operands for instruction")}); + } } void ARMAsmParser::ReportNearMisses(SmallVectorImpl &NearMisses, Index: test/MC/ARM/diagnostics.s =================================================================== --- test/MC/ARM/diagnostics.s +++ test/MC/ARM/diagnostics.s @@ -1,4 +1,4 @@ -@ RUN: not llvm-mc -triple=armv7-apple-darwin < %s 2> %t + RUN: not llvm-mc -triple=armv7-apple-darwin < %s 2> %t @ RUN: FileCheck --check-prefix=CHECK-ERRORS --check-prefix=CHECK-ERRORS-V7 < %t %s @ RUN: not llvm-mc -triple=armv8 < %s 2> %t @ RUN: FileCheck --check-prefix=CHECK-ERRORS --check-prefix=CHECK-ERRORS-V8 < %t %s @@ -161,7 +161,7 @@ @ CHECK-ERRORS: operand must be an immediate in the range [0,7] @ CHECK-ERRORS-V7: operand must be an immediate in the range [0,7] @ CHECK-ERRORS-V7: operand must be an immediate in the range [0,7] -@ CHECK-ERRORS-V8: invalid instruction +@ CHECK-ERRORS-V8: error: invalid operands for instruction @ CHECK-ERRORS-V8: too many operands for instruction @ CHECK-ERRORS: operand must be an immediate in the range [0,15] @ CHECK-ERRORS-V7: operand must be an immediate in the range [0,15] @@ -205,7 +205,7 @@ @ CHECK-ERRORS: operand must be an immediate in the range [0,7] @ CHECK-ERRORS: operand must be an immediate in the range [0,7] @ CHECK-ERRORS-V7: operand must be an immediate in the range [0,7] -@ CHECK-ERRORS-V8: invalid instruction +@ CHECK-ERRORS-V8: error: invalid operands for instruction @ CHECK-ERRORS-V7: operand must be an immediate in the range [0,7] @ CHECK-ERRORS-V8: too many operands for instruction @ CHECK-ERRORS: operand must be an immediate in the range [0,15] Index: test/MC/ARM/invalid-fp-armv8.s =================================================================== --- test/MC/ARM/invalid-fp-armv8.s +++ test/MC/ARM/invalid-fp-armv8.s @@ -35,38 +35,38 @@ @ V8: error: invalid instruction vseleq.f32 s0, d2, d1 -@ V8: error: invalid instruction +@ V8: error: invalid operands for instruction vselgt.f64 s3, s2, s1 @ V8: error: invalid operand for instruction vselgt.f32 s0, q3, q1 -@ V8: error: invalid instruction +@ V8: error: invalid operands for instruction vselgt.f64 q0, s3, q1 -@ V8: error: invalid instruction +@ V8: error: invalid operands for instruction vmaxnm.f32 s0, d2, d1 -@ V8: error: invalid instruction +@ V8: error: invalid operands for instruction vminnm.f64 s3, s2, s1 @ V8: error: invalid operand for instruction vmaxnm.f32 s0, q3, q1 -@ V8: error: invalid instruction +@ V8: error: invalid operands for instruction vmaxnm.f64 q0, s3, q1 -@ V8: error: invalid instruction +@ V8: error: invalid operands for instruction vmaxnmgt.f64 q0, s3, q1 @ CHECK: error: instruction 'vmaxnm' is not predicable, but condition code specified vcvta.s32.f64 d3, s2 -@ V8: error: invalid instruction +@ V8: error: invalid operands for instruction vcvtp.s32.f32 d3, s2 @ V8: error: operand must be a register in range [s0, s31] vcvtn.u32.f64 d3, s2 -@ V8: error: invalid instruction +@ V8: error: invalid operands for instruction vcvtm.u32.f32 d3, s2 @ V8: error: operand must be a register in range [s0, s31] vcvtnge.u32.f64 d3, s2 @ V8: error: instruction 'vcvtn' is not predicable, but condition code specified vcvtbgt.f64.f16 q0, d3 -@ V8: error: invalid instruction +@ V8: error: invalid operands for instruction vcvttlt.f64.f16 s0, s3 @ V8: error: invalid instruction, any one of the following would fix this: @ V8: note: operand must be a register in range [d0, d31] @@ -79,12 +79,12 @@ @ V8: error: operand must be a register in range [s0, s31] vrintrlo.f32.f32 d3, q0 -@ V8: error: invalid instruction +@ V8: error: invalid operands for instruction vrintxcs.f32.f32 d3, d0 @ V8: error: instruction requires: NEON vrinta.f64.f64 s3, q0 -@ V8: error: invalid instruction +@ V8: error: invalid operands for instruction vrintn.f32.f32 d3, d0 @ V8: error: instruction requires: NEON vrintp.f32 q3, q0 Index: test/MC/ARM/invalid-neon-v8.s =================================================================== --- test/MC/ARM/invalid-neon-v8.s +++ test/MC/ARM/invalid-neon-v8.s @@ -1,9 +1,9 @@ @ RUN: not llvm-mc -triple armv8 -mattr=-fp-armv8 -show-encoding < %s 2>&1 | FileCheck %s vmaxnm.f32 s4, d5, q1 -@ CHECK: error: invalid instruction +@ CHECK: error: invalid operands for instruction vmaxnm.f64.f64 s4, d5, q1 -@ CHECK: error: invalid instruction +@ CHECK: error: invalid operands for instruction vmaxnmge.f64.f64 s4, d5, q1 @ CHECK: error: instruction 'vmaxnm' is not predicable, but condition code specified @@ -12,12 +12,12 @@ vcvtp.u32.f32 s1, d2 @ CHECK: error: operand must be a register in range [d0, d31] vcvtp.f32.u32 d1, q2 -@ CHECK: error: invalid instruction +@ CHECK: error: invalid operands for instruction vcvtplo.f32.u32 s1, s2 @ CHECK: error: instruction 'vcvtp' is not predicable, but condition code specified vrinta.f64.f64 s3, d12 -@ CHECK: error: invalid instruction +@ CHECK: error: invalid operands for instruction vrintn.f32 d3, q12 @ CHECK: error: invalid instruction, any one of the following would fix this: @ CHECK: note: operand must be a register in range [d0, d31] @@ -50,7 +50,7 @@ @ CHECK: error: instruction 'sha1h' is not predicable, but condition code specified sha1c.32 s0, d1, q2 -@ CHECK: error: invalid instruction +@ CHECK: error: invalid operands for instruction sha1m.32 q0, s1, q2 @ CHECK: error: operand must be a register in range [q0, q15] sha1p.32 s0, q1, q2 @@ -62,12 +62,12 @@ sha256h2.32 q0, q1, s2 @ CHECK: error: operand must be a register in range [q0, q15] sha256su1.32 s0, d1, q2 -@ CHECK: error: invalid instruction +@ CHECK: error: invalid operands for instruction sha256su1lt.32 q0, d1, q2 @ CHECK: error: instruction 'sha256su1' is not predicable, but condition code specified vmull.p64 q0, s1, s3 -@ CHECK: error: invalid instruction +@ CHECK: error: invalid operands for instruction vmull.p64 s1, d2, d3 @ CHECK: error: operand must be a register in range [q0, q15] vmullge.p64 q0, d16, d17 Index: test/MC/ARM/ldrd-strd-gnu-arm-bad-regs.s =================================================================== --- test/MC/ARM/ldrd-strd-gnu-arm-bad-regs.s +++ test/MC/ARM/ldrd-strd-gnu-arm-bad-regs.s @@ -2,18 +2,18 @@ .text .arm -@ CHECK: error: invalid instruction +@ CHECK: error: invalid operands for instruction @ CHECK: ldrd r12, [r0, #512] ldrd r12, [r0, #512] -@ CHECK: error: invalid instruction +@ CHECK: error: invalid operands for instruction @ CHECK: strd r12, [r0, #512] strd r12, [r0, #512] -@ CHECK: error: invalid instruction +@ CHECK: error: invalid operands for instruction @ CHECK: ldrd r1, [r0, #512] ldrd r1, [r0, #512] -@ CHECK: error: invalid instruction +@ CHECK: error: invalid operands for instruction @ CHECK: strd r1, [r0, #512] strd r1, [r0, #512] Index: test/MC/ARM/ldrd-strd-gnu-bad-inst.s =================================================================== --- test/MC/ARM/ldrd-strd-gnu-bad-inst.s +++ test/MC/ARM/ldrd-strd-gnu-bad-inst.s @@ -10,9 +10,9 @@ strd r0 @ CHECK: error: too few operands for instruction ldrd r0 -@ CHECK: error: invalid instruction +@ CHECK: error: invalid operands for instruction strd s0, [r0] -@ CHECK: error: invalid instruction +@ CHECK: error: invalid operands for instruction ldrd s0, [r0] .arm @ CHECK: error: too few operands for instruction @@ -23,7 +23,7 @@ strd r0 @ CHECK: error: too few operands for instruction ldrd r0 -@ CHECK: error: invalid instruction +@ CHECK: error: invalid operands for instruction strd s0, [r0] -@ CHECK: error: invalid instruction +@ CHECK: error: invalid operands for instruction ldrd s0, [r0] Index: test/MC/ARM/ldrd-strd-gnu-sp.s =================================================================== --- test/MC/ARM/ldrd-strd-gnu-sp.s +++ test/MC/ARM/ldrd-strd-gnu-sp.s @@ -8,20 +8,20 @@ .arm -// V7: error: invalid instruction +// V7: error: invalid operands for instruction // V8: ldrd r12, sp, [r0, #32] @ encoding: [0xd0,0xc2,0xc0,0xe1] ldrd r12, [r0, #32] -// V7: error: invalid instruction +// V7: error: invalid operands for instruction // V8: strd r12, sp, [r0, #32] @ encoding: [0xf0,0xc2,0xc0,0xe1] strd r12, [r0, #32] .thumb -// V7: error: invalid instruction +// V7: error: invalid operands for instruction // V8: ldrd r12, sp, [r0, #32] @ encoding: [0xd0,0xe9,0x08,0xcd] ldrd r12, [r0, #32] -// V7: error: invalid instruction +// V7: error: invalid operands for instruction // V8: strd r12, sp, [r0, #32] @ encoding: [0xc0,0xe9,0x08,0xcd] strd r12, [r0, #32] Index: test/MC/ARM/ldrd-strd-gnu-thumb-bad-regs.s =================================================================== --- test/MC/ARM/ldrd-strd-gnu-thumb-bad-regs.s +++ test/MC/ARM/ldrd-strd-gnu-thumb-bad-regs.s @@ -2,10 +2,10 @@ .text .thumb -@ CHECK: error: invalid instruction +@ CHECK: error: invalid operands for instruction @ CHECK: ldrd r12, [r0, #512] ldrd r12, [r0, #512] -@ CHECK: error: invalid instruction +@ CHECK: error: invalid operands for instruction @ CHECK: strd r12, [r0, #512] strd r12, [r0, #512] Index: test/MC/ARM/thumb-mov.s =================================================================== --- test/MC/ARM/thumb-mov.s +++ test/MC/ARM/thumb-mov.s @@ -19,7 +19,7 @@ // CHECK-NEXT: movs r0, pc // CHECK: note: invalid operand for instruction // CHECK-NEXT: movs r0, pc -// CHECK: error: invalid instruction +// CHECK: error: invalid operands for instruction // CHECK-NEXT: movs pc, pc // mov.w selects t2MOVr @@ -32,7 +32,7 @@ // CHECK-NEXT: mov.w r0, pc // CHECK: note: invalid operand for instruction // CHECK-NEXT: mov.w r0, pc -// CHECK: error: invalid instruction +// CHECK: error: invalid operands for instruction // CHECK-NEXT: mov.w pc, pc // movs.w selects t2MOVr @@ -45,7 +45,7 @@ // CHECK-NEXT: movs.w r0, pc // CHECK: note: invalid operand for instruction // CHECK-NEXT: movs.w r0, pc -// CHECK: error: invalid instruction +// CHECK: error: invalid operands for instruction // CHECK-NEXT: movs.w pc, pc Index: test/MC/ARM/thumb2-diagnostics.s =================================================================== --- test/MC/ARM/thumb2-diagnostics.s +++ test/MC/ARM/thumb2-diagnostics.s @@ -43,7 +43,7 @@ @ CHECK-ERRORS: operand must be an immediate in the range [0,7] @ CHECK-ERRORS-V7: operand must be an immediate in the range [0,7] @ CHECK-ERRORS-V7: operand must be an immediate in the range [0,7] -@ CHECK-ERRORS-V8: invalid instruction +@ CHECK-ERRORS-V8: error: invalid operands for instruction @ CHECK-ERRORS-V8: too many operands for instruction @ CHECK-ERRORS: operand must be an immediate in the range [0,15] @ CHECK-ERRORS-V7: operand must be an immediate in the range [0,15] @@ -91,8 +91,11 @@ and sp, r1, #80008000 and pc, r1, #80008000 -@ CHECK-ERRORS: error: invalid instruction -@ CHECK-ERRORS: error: invalid instruction +@ CHECK-ERRORS-V7: error: invalid operands for instruction +@ CHECK-ERRORS-V8: invalid instruction, any one of the following would fix this: +@ CHECK-ERRORS-V8: note: invalid operand for instruction +@ CHECK-ERRORS-V8: note: operand must be a register in range [r0, r14] +@ CHECK-ERRORS: error: invalid operands for instruction ssat r0, #1, r0, asr #32 usat r0, #1, r0, asr #32 @@ -129,7 +132,7 @@ @ CHECK-ERRORS: error: invalid instruction, any one of the following would fix this: @ CHECK-ERRORS: note: instruction requires: arm-mode @ CHECK-ERRORS: note: invalid operand for instruction -@ CHECK-ERRORS: error: invalid instruction +@ CHECK-ERRORS: error: invalid operands for instruction @ CHECK-ERRORS: error: invalid instruction, any one of the following would fix this: @ CHECK-ERRORS: note: invalid operand for instruction @ CHECK-ERRORS: note: instruction requires: arm-mode Index: test/MC/ARM/vfp4.s =================================================================== --- test/MC/ARM/vfp4.s +++ test/MC/ARM/vfp4.s @@ -6,7 +6,7 @@ @ ARM: vfma.f64 d16, d18, d17 @ encoding: [0xa1,0x0b,0xe2,0xee] @ THUMB: vfma.f64 d16, d18, d17 @ encoding: [0xe2,0xee,0xa1,0x0b] -@ THUMB_V7EM-ERRORS: error: invalid instruction +@ THUMB_V7EM-ERRORS: error: invalid operands for instruction @ THUMB_V7EM-ERRORS-NEXT: vfma.f64 d16, d18, d17 vfma.f64 d16, d18, d17 @@ -17,7 +17,7 @@ @ ARM: vfma.f32 d16, d18, d17 @ encoding: [0xb1,0x0c,0x42,0xf2] @ THUMB: vfma.f32 d16, d18, d17 @ encoding: [0x42,0xef,0xb1,0x0c] -@ THUMB_V7EM-ERRORS: error: invalid instruction +@ THUMB_V7EM-ERRORS: error: invalid operands for instruction @ THUMB_V7EM-ERRORS-NEXT: vfma.f32 d16, d18, d17 vfma.f32 d16, d18, d17 @@ -29,7 +29,7 @@ @ ARM: vfnma.f64 d16, d18, d17 @ encoding: [0xe1,0x0b,0xd2,0xee] @ THUMB: vfnma.f64 d16, d18, d17 @ encoding: [0xd2,0xee,0xe1,0x0b] -@ THUMB_V7EM-ERRORS: error: invalid instruction +@ THUMB_V7EM-ERRORS: error: invalid operands for instruction @ THUMB_V7EM-ERRORS-NEXT: vfnma.f64 d16, d18, d17 vfnma.f64 d16, d18, d17 @@ -40,7 +40,7 @@ @ ARM: vfms.f64 d16, d18, d17 @ encoding: [0xe1,0x0b,0xe2,0xee] @ THUMB: vfms.f64 d16, d18, d17 @ encoding: [0xe2,0xee,0xe1,0x0b] -@ THUMB_V7EM-ERRORS: error: invalid instruction +@ THUMB_V7EM-ERRORS: error: invalid operands for instruction @ THUMB_V7EM-ERRORS-NEXT: vfms.f64 d16, d18, d17 vfms.f64 d16, d18, d17 @@ -51,7 +51,7 @@ @ ARM: vfms.f32 d16, d18, d17 @ encoding: [0xb1,0x0c,0x62,0xf2] @ THUMB: vfms.f32 d16, d18, d17 @ encoding: [0x62,0xef,0xb1,0x0c] -@ THUMB_V7EM-ERRORS: error: invalid instruction +@ THUMB_V7EM-ERRORS: error: invalid operands for instruction @ THUMB_V7EM-ERRORS-NEXT: vfms.f32 d16, d18, d17 vfms.f32 d16, d18, d17 @@ -63,7 +63,7 @@ @ ARM: vfnms.f64 d16, d18, d17 @ encoding: [0xa1,0x0b,0xd2,0xee] @ THUMB: vfnms.f64 d16, d18, d17 @ encoding: [0xd2,0xee,0xa1,0x0b] -@ THUMB_V7EM-ERRORS: error: invalid instruction +@ THUMB_V7EM-ERRORS: error: invalid operands for instruction @ THUMB_V7EM-ERRORS-NEXT: vfnms.f64 d16, d18, d17 vfnms.f64 d16, d18, d17 Index: utils/TableGen/AsmMatcherEmitter.cpp =================================================================== --- utils/TableGen/AsmMatcherEmitter.cpp +++ utils/TableGen/AsmMatcherEmitter.cpp @@ -3258,7 +3258,6 @@ OS << " NearMissInfo FeaturesNearMiss = NearMissInfo::getSuccess();\n"; OS << " NearMissInfo EarlyPredicateNearMiss = NearMissInfo::getSuccess();\n"; OS << " NearMissInfo LatePredicateNearMiss = NearMissInfo::getSuccess();\n"; - OS << " bool MultipleInvalidOperands = false;\n"; } if (HasMnemonicFirst) { @@ -3297,11 +3296,12 @@ OS << " OperandNearMiss =\n"; OS << " NearMissInfo::getTooFewOperands(Formal, it->Opcode);\n"; OS << " } else if (OperandNearMiss.getKind() != NearMissInfo::NearMissTooFewOperands) {\n"; - OS << " // If more than one operand is invalid, give up on this match entry.\n"; + OS << " // An invalid operand plus a missing one at the end are reported the\n"; + OS << " // same way as multiple invalid operands.\n"; OS << " DEBUG_WITH_TYPE(\n"; OS << " \"asm-matcher\",\n"; OS << " dbgs() << \"second invalid operand, giving up on this opcode\\n\");\n"; - OS << " MultipleInvalidOperands = true;\n"; + OS << " OperandNearMiss = NearMissInfo::getMissedMultipleOperands(it->Opcode);\n"; OS << " break;\n"; OS << " }\n"; OS << " } else {\n"; @@ -3370,7 +3370,7 @@ OS << " DEBUG_WITH_TYPE(\n"; OS << " \"asm-matcher\",\n"; OS << " dbgs() << \"second operand mismatch, skipping this opcode\\n\");\n"; - OS << " MultipleInvalidOperands = true;\n"; + OS << " OperandNearMiss = NearMissInfo::getMissedMultipleOperands(it->Opcode);\n"; OS << " break;\n"; OS << " }\n"; OS << " }\n\n"; @@ -3392,15 +3392,14 @@ OS << " }\n\n"; } - if (ReportMultipleNearMisses) - OS << " if (MultipleInvalidOperands) {\n"; - else + if (!ReportMultipleNearMisses) { OS << " if (!OperandsValid) {\n"; - OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"Opcode result: multiple \"\n"; - OS << " \"operand mismatches, ignoring \"\n"; - OS << " \"this opcode\\n\");\n"; - OS << " continue;\n"; - OS << " }\n"; + OS << " DEBUG_WITH_TYPE(\"asm-matcher\", dbgs() << \"Opcode result: multiple \"\n"; + OS << " \"operand mismatches, ignoring \"\n"; + OS << " \"this opcode\\n\");\n"; + OS << " continue;\n"; + OS << " }\n"; + } // Emit check that the required features are available. OS << " if ((AvailableFeatures & it->RequiredFeatures) "