diff options
Diffstat (limited to 'llvm/lib/Target/ARM')
| -rw-r--r-- | llvm/lib/Target/ARM/ARM.td | 5 | ||||
| -rw-r--r-- | llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp | 417 |
2 files changed, 289 insertions, 133 deletions
diff --git a/llvm/lib/Target/ARM/ARM.td b/llvm/lib/Target/ARM/ARM.td index 25b9802f541..c1a3f639461 100644 --- a/llvm/lib/Target/ARM/ARM.td +++ b/llvm/lib/Target/ARM/ARM.td @@ -1022,6 +1022,10 @@ def ARMAsmWriter : AsmWriter { bit isMCAsmWriter = 1; } +def ARMAsmParser : AsmParser { + bit ReportMultipleNearMisses = 1; +} + def ARMAsmParserVariant : AsmParserVariant { int Variant = 0; string Name = "ARM"; @@ -1032,5 +1036,6 @@ def ARM : Target { // Pull in Instruction Info. let InstructionSet = ARMInstrInfo; let AssemblyWriters = [ARMAsmWriter]; + let AssemblyParsers = [ARMAsmParser]; let AssemblyParserVariants = [ARMAsmParserVariant]; } diff --git a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index b84a4e8b8e5..f2925f176a1 100644 --- a/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/llvm/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -17,6 +17,7 @@ #include "llvm/ADT/APInt.h" #include "llvm/ADT/None.h" #include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/SmallSet.h" #include "llvm/ADT/SmallVector.h" #include "llvm/ADT/StringMap.h" #include "llvm/ADT/StringRef.h" @@ -84,6 +85,11 @@ static cl::opt<ImplicitItModeTy> ImplicitItMode( static cl::opt<bool> AddBuildAttributes("arm-add-build-attributes", cl::init(false)); +cl::opt<bool> +DevDiags("arm-asm-parser-dev-diags", cl::init(false), + cl::desc("Use extended diagnostics, which include implementation " + "details useful for development")); + enum VectorLaneTy { NoLanes, AllLanes, IndexedLane }; class UnwindContext { @@ -608,8 +614,22 @@ public: uint64_t &ErrorInfo, bool MatchingInlineAsm) override; unsigned MatchInstruction(OperandVector &Operands, MCInst &Inst, - uint64_t &ErrorInfo, bool MatchingInlineAsm, - bool &EmitInITBlock, MCStreamer &Out); + SmallVectorImpl<NearMissInfo> &NearMisses, + bool MatchingInlineAsm, bool &EmitInITBlock, + MCStreamer &Out); + + struct NearMissMessage { + SMLoc Loc; + SmallString<128> Message; + }; + + const char *getOperandMatchFailDiag(ARMMatchResultTy Error); + void FilterNearMisses(SmallVectorImpl<NearMissInfo> &NearMissesIn, + SmallVectorImpl<NearMissMessage> &NearMissesOut, + SMLoc IDLoc, OperandVector &Operands); + void ReportNearMisses(SmallVectorImpl<NearMissInfo> &NearMisses, SMLoc IDLoc, + OperandVector &Operands); + void onLabelParsed(MCSymbol *Symbol) override; }; @@ -8909,19 +8929,19 @@ bool ARMAsmParser::isITBlockTerminator(MCInst &Inst) const { } unsigned ARMAsmParser::MatchInstruction(OperandVector &Operands, MCInst &Inst, - uint64_t &ErrorInfo, + SmallVectorImpl<NearMissInfo> &NearMisses, bool MatchingInlineAsm, bool &EmitInITBlock, MCStreamer &Out) { // If we can't use an implicit IT block here, just match as normal. if (inExplicitITBlock() || !isThumbTwo() || !useImplicitITThumb()) - return MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm); + return MatchInstructionImpl(Operands, Inst, &NearMisses, MatchingInlineAsm); // Try to match the instruction in an extension of the current IT block (if // there is one). if (inImplicitITBlock()) { extendImplicitITBlock(ITState.Cond); - if (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm) == + if (MatchInstructionImpl(Operands, Inst, nullptr, MatchingInlineAsm) == Match_Success) { // The match succeded, but we still have to check that the instruction is // valid in this implicit IT block. @@ -8947,7 +8967,7 @@ unsigned ARMAsmParser::MatchInstruction(OperandVector &Operands, MCInst &Inst, // Finish the current IT block, and try to match outside any IT block. flushPendingInstructions(Out); unsigned PlainMatchResult = - MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm); + MatchInstructionImpl(Operands, Inst, &NearMisses, MatchingInlineAsm); if (PlainMatchResult == Match_Success) { const MCInstrDesc &MCID = MII.get(Inst.getOpcode()); if (MCID.isPredicable()) { @@ -8974,7 +8994,7 @@ unsigned ARMAsmParser::MatchInstruction(OperandVector &Operands, MCInst &Inst, // condition, so we create an IT block with a dummy condition, and fix it up // once we know the actual condition. startImplicitITBlock(); - if (MatchInstructionImpl(Operands, Inst, ErrorInfo, MatchingInlineAsm) == + if (MatchInstructionImpl(Operands, Inst, nullptr, MatchingInlineAsm) == Match_Success) { const MCInstrDesc &MCID = MII.get(Inst.getOpcode()); if (MCID.isPredicable()) { @@ -9004,7 +9024,8 @@ bool ARMAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, unsigned MatchResult; bool PendConditionalInstruction = false; - MatchResult = MatchInstruction(Operands, Inst, ErrorInfo, MatchingInlineAsm, + SmallVector<NearMissInfo, 4> NearMisses; + MatchResult = MatchInstruction(Operands, Inst, NearMisses, MatchingInlineAsm, PendConditionalInstruction, Out); SMLoc ErrorLoc; @@ -9061,33 +9082,9 @@ bool ARMAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, Out.EmitInstruction(Inst, getSTI()); } return false; - case Match_MissingFeature: { - assert(ErrorInfo && "Unknown missing feature!"); - // Special case the error message for the very common case where only - // a single subtarget feature is missing (Thumb vs. ARM, e.g.). - std::string Msg = "instruction requires:"; - uint64_t Mask = 1; - for (unsigned i = 0; i < (sizeof(ErrorInfo)*8-1); ++i) { - if (ErrorInfo & Mask) { - Msg += " "; - Msg += getSubtargetFeatureName(ErrorInfo & Mask); - } - Mask <<= 1; - } - return Error(IDLoc, Msg); - } - case Match_InvalidOperand: { - SMLoc ErrorLoc = IDLoc; - if (ErrorInfo != ~0ULL) { - if (ErrorInfo >= Operands.size()) - return Error(IDLoc, "too few operands for instruction"); - - ErrorLoc = ((ARMOperand &)*Operands[ErrorInfo]).getStartLoc(); - if (ErrorLoc == SMLoc()) ErrorLoc = IDLoc; - } - - return Error(ErrorLoc, "invalid operand for instruction"); - } + case Match_NearMisses: + ReportNearMisses(NearMisses, IDLoc, Operands); + return true; case Match_MnemonicFail: { uint64_t FBS = ComputeAvailableFeatures(getSTI().getFeatureBits()); std::string Suggestion = ARMMnemonicSpellCheck( @@ -9095,104 +9092,6 @@ bool ARMAsmParser::MatchAndEmitInstruction(SMLoc IDLoc, unsigned &Opcode, return Error(IDLoc, "invalid instruction" + Suggestion, ((ARMOperand &)*Operands[0]).getLocRange()); } - case Match_RequiresNotITBlock: - return Error(IDLoc, "flag setting instruction only valid outside IT block"); - case Match_RequiresITBlock: - return Error(IDLoc, "instruction only valid inside IT block"); - case Match_RequiresV6: - return Error(IDLoc, "instruction variant requires ARMv6 or later"); - case Match_RequiresThumb2: - return Error(IDLoc, "instruction variant requires Thumb2"); - case Match_RequiresV8: - return Error(IDLoc, "instruction variant requires ARMv8 or later"); - case Match_RequiresFlagSetting: - return Error(IDLoc, "no flag-preserving variant of this instruction available"); - case Match_ImmRange0_1: - return Error(ErrorLoc, "immediate operand must be in the range [0,1]"); - case Match_ImmRange0_3: - return Error(ErrorLoc, "immediate operand must be in the range [0,3]"); - case Match_ImmRange0_7: - return Error(ErrorLoc, "immediate operand must be in the range [0,7]"); - case Match_ImmRange0_15: - return Error(ErrorLoc, "immediate operand must be in the range [0,15]"); - case Match_ImmRange0_31: - return Error(ErrorLoc, "immediate operand must be in the range [0,31]"); - case Match_ImmRange0_32: - return Error(ErrorLoc, "immediate operand must be in the range [0,32]"); - case Match_ImmRange0_63: - return Error(ErrorLoc, "immediate operand must be in the range [0,63]"); - case Match_ImmRange0_239: - return Error(ErrorLoc, "immediate operand must be in the range [0,239]"); - case Match_ImmRange0_255: - return Error(ErrorLoc, "immediate operand must be in the range [0,255]"); - case Match_ImmRange0_4095: - return Error(ErrorLoc, "immediate operand must be in the range [0,4095]"); - case Match_ImmRange0_65535: - return Error(ErrorLoc, "immediate operand must be in the range [0,65535]"); - case Match_ImmRange1_7: - return Error(ErrorLoc, "immediate operand must be in the range [1,7]"); - case Match_ImmRange1_8: - return Error(ErrorLoc, "immediate operand must be in the range [1,8]"); - case Match_ImmRange1_15: - return Error(ErrorLoc, "immediate operand must be in the range [1,15]"); - case Match_ImmRange1_16: - return Error(ErrorLoc, "immediate operand must be in the range [1,16]"); - case Match_ImmRange1_31: - return Error(ErrorLoc, "immediate operand must be in the range [1,31]"); - case Match_ImmRange1_32: - return Error(ErrorLoc, "immediate operand must be in the range [1,32]"); - case Match_ImmRange1_64: - return Error(ErrorLoc, "immediate operand must be in the range [1,64]"); - case Match_ImmRange8_8: - return Error(ErrorLoc, "immediate operand must be 8."); - case Match_ImmRange16_16: - return Error(ErrorLoc, "immediate operand must be 16."); - case Match_ImmRange32_32: - return Error(ErrorLoc, "immediate operand must be 32."); - case Match_ImmRange256_65535: - return Error(ErrorLoc, "immediate operand must be in the range [255,65535]"); - case Match_ImmRange0_16777215: - return Error(ErrorLoc, "immediate operand must be in the range [0,0xffffff]"); - case Match_AlignedMemoryRequiresNone: - case Match_DupAlignedMemoryRequiresNone: - case Match_AlignedMemoryRequires16: - case Match_DupAlignedMemoryRequires16: - case Match_AlignedMemoryRequires32: - case Match_DupAlignedMemoryRequires32: - case Match_AlignedMemoryRequires64: - case Match_DupAlignedMemoryRequires64: - case Match_AlignedMemoryRequires64or128: - case Match_DupAlignedMemoryRequires64or128: - case Match_AlignedMemoryRequires64or128or256: - { - SMLoc ErrorLoc = ((ARMOperand &)*Operands[ErrorInfo]).getAlignmentLoc(); - if (ErrorLoc == SMLoc()) ErrorLoc = IDLoc; - switch (MatchResult) { - default: - llvm_unreachable("Missing Match_Aligned type"); - case Match_AlignedMemoryRequiresNone: - case Match_DupAlignedMemoryRequiresNone: - return Error(ErrorLoc, "alignment must be omitted"); - case Match_AlignedMemoryRequires16: - case Match_DupAlignedMemoryRequires16: - return Error(ErrorLoc, "alignment must be 16 or omitted"); - case Match_AlignedMemoryRequires32: - case Match_DupAlignedMemoryRequires32: - return Error(ErrorLoc, "alignment must be 32 or omitted"); - case Match_AlignedMemoryRequires64: - case Match_DupAlignedMemoryRequires64: - return Error(ErrorLoc, "alignment must be 64 or omitted"); - case Match_AlignedMemoryRequires64or128: - case Match_DupAlignedMemoryRequires64or128: - return Error(ErrorLoc, "alignment must be 64, 128 or omitted"); - case Match_AlignedMemoryRequires64or128or256: - return Error(ErrorLoc, "alignment must be 64, 128, 256 or omitted"); - } - } - case Match_InvalidComplexRotationEven: - return Error(IDLoc, "complex rotation must be 0, 90, 180 or 270"); - case Match_InvalidComplexRotationOdd: - return Error(IDLoc, "complex rotation must be 90 or 270"); } llvm_unreachable("Implement any new match types added!"); @@ -10203,6 +10102,258 @@ extern "C" void LLVMInitializeARMAsmParser() { #define GET_MATCHER_IMPLEMENTATION #include "ARMGenAsmMatcher.inc" +const char *ARMAsmParser::getOperandMatchFailDiag(ARMMatchResultTy Error) { + switch (Error) { + case Match_AlignedMemoryRequiresNone: + case Match_DupAlignedMemoryRequiresNone: + return "alignment must be omitted"; + case Match_AlignedMemoryRequires16: + case Match_DupAlignedMemoryRequires16: + return "alignment must be 16 or omitted"; + case Match_AlignedMemoryRequires32: + case Match_DupAlignedMemoryRequires32: + return "alignment must be 32 or omitted"; + case Match_AlignedMemoryRequires64: + case Match_DupAlignedMemoryRequires64: + return "alignment must be 64 or omitted"; + case Match_AlignedMemoryRequires64or128: + case Match_DupAlignedMemoryRequires64or128: + return "alignment must be 64, 128 or omitted"; + case Match_AlignedMemoryRequires64or128or256: + return "alignment must be 64, 128, 256 or omitted"; + case Match_ImmRange0_1: + return "immediate operand must be in the range [0,1]"; + case Match_ImmRange0_3: + return "immediate operand must be in the range [0,3]"; + case Match_ImmRange0_7: + return "immediate operand must be in the range [0,7]"; + case Match_ImmRange0_15: + return "immediate operand must be in the range [0,15]"; + case Match_ImmRange0_31: + return "immediate operand must be in the range [0,31]"; + case Match_ImmRange0_32: + return "immediate operand must be in the range [0,32]"; + case Match_ImmRange0_63: + return "immediate operand must be in the range [0,63]"; + case Match_ImmRange0_239: + return "immediate operand must be in the range [0,239]"; + case Match_ImmRange0_255: + return "immediate operand must be in the range [0,255]"; + case Match_ImmRange0_4095: + return "immediate operand must be in the range [0,4095]"; + case Match_ImmRange0_65535: + return "immediate operand must be in the range [0,65535]"; + case Match_ImmRange1_7: + return "immediate operand must be in the range [1,7]"; + case Match_ImmRange1_8: + return "immediate operand must be in the range [1,8]"; + case Match_ImmRange1_15: + return "immediate operand must be in the range [1,15]"; + case Match_ImmRange1_16: + return "immediate operand must be in the range [1,16]"; + case Match_ImmRange1_31: + return "immediate operand must be in the range [1,31]"; + case Match_ImmRange1_32: + return "immediate operand must be in the range [1,32]"; + case Match_ImmRange1_64: + return "immediate operand must be in the range [1,64]"; + case Match_ImmRange8_8: + return "immediate operand must be 8."; + case Match_ImmRange16_16: + return "immediate operand must be 16."; + case Match_ImmRange32_32: + return "immediate operand must be 32."; + case Match_ImmRange256_65535: + return "immediate operand must be in the range [255,65535]"; + case Match_ImmRange0_16777215: + return "immediate operand must be in the range [0,0xffffff]"; + case Match_InvalidComplexRotationEven: + return "complex rotation must be 0, 90, 180 or 270"; + case Match_InvalidComplexRotationOdd: + return "complex rotation must be 90 or 270"; + default: + return nullptr; + } +} + +// Process the list of near-misses, throwing away ones we don't want to report +// to the user, and converting the rest to a source location and string that +// should be reported. +void +ARMAsmParser::FilterNearMisses(SmallVectorImpl<NearMissInfo> &NearMissesIn, + SmallVectorImpl<NearMissMessage> &NearMissesOut, + SMLoc IDLoc, OperandVector &Operands) { + // TODO: If operand didn't match, sub in a dummy one and run target + // predicate, so that we can avoid reporting near-misses that are invalid? + // TODO: Many operand types dont have SuperClasses set, so we report + // redundant ones. + // TODO: Some operands are superclasses of registers (e.g. + // MCK_RegShiftedImm), we don't have any way to represent that currently. + // TODO: This is not all ARM-specific, can some of it be factored out? + + // Record some information about near-misses that we have already seen, so + // that we can avoid reporting redundant ones. For example, if there are + // variants of an instruction that take 8- and 16-bit immediates, we want + // to only report the widest one. + std::multimap<unsigned, unsigned> OperandMissesSeen; + SmallSet<uint64_t, 4> FeatureMissesSeen; + + // Process the near-misses in reverse order, so that we see more general ones + // first, and so can avoid emitting more specific ones. + for (NearMissInfo &I : reverse(NearMissesIn)) { + switch (I.getKind()) { + case NearMissInfo::NearMissOperand: { + SMLoc OperandLoc = + ((ARMOperand &)*Operands[I.getOperandIndex()]).getStartLoc(); + const char *OperandDiag = + getOperandMatchFailDiag((ARMMatchResultTy)I.getOperandError()); + + // If we have already emitted a message for a superclass, don't also report + // the sub-class. We consider all operand classes that we don't have a + // specialised diagnostic for to be equal for the propose of this check, + // so that we don't report the generic error multiple times on the same + // operand. + unsigned DupCheckMatchClass = OperandDiag ? I.getOperandClass() : ~0U; + auto PrevReports = OperandMissesSeen.equal_range(I.getOperandIndex()); + if (std::any_of(PrevReports.first, PrevReports.second, + [DupCheckMatchClass]( + const std::pair<unsigned, unsigned> Pair) { + if (DupCheckMatchClass == ~0U) + return Pair.second == ~0U; + else + return isSubclass((MatchClassKind)DupCheckMatchClass, + (MatchClassKind)Pair.second); + })) + break; + OperandMissesSeen.insert( + std::make_pair(I.getOperandIndex(), DupCheckMatchClass)); + + NearMissMessage Message; + Message.Loc = OperandLoc; + raw_svector_ostream OS(Message.Message); + if (OperandDiag) { + OS << OperandDiag; + } else if (I.getOperandClass() == InvalidMatchClass) { + OS << "too many operands for instruction"; + } else { + OS << "invalid operand for instruction"; + if (DevDiags) { + OS << " class" << I.getOperandClass() << ", error " + << I.getOperandError() << ", opcode " + << MII.getName(I.getOpcode()); + } + } + NearMissesOut.emplace_back(Message); + break; + } + case NearMissInfo::NearMissFeature: { + uint64_t MissingFeatures = I.getFeatures(); + // Don't report the same set of features twice. + if (FeatureMissesSeen.count(MissingFeatures)) + break; + FeatureMissesSeen.insert(MissingFeatures); + + // Special case: don't report a feature set which includes arm-mode for + // targets that don't have ARM mode. + if ((MissingFeatures & Feature_IsARM) && !hasARM()) + break; + // Don't report any near-misses that both require switching instruction + // set, and adding other subtarget features. + if (isThumb() && (MissingFeatures & Feature_IsARM) && + (MissingFeatures & ~Feature_IsARM)) + break; + if (!isThumb() && (MissingFeatures & Feature_IsThumb) && + (MissingFeatures & ~Feature_IsThumb)) + break; + if (!isThumb() && (MissingFeatures & Feature_IsThumb2) && + (MissingFeatures & ~(Feature_IsThumb2 | Feature_IsThumb))) + break; + + NearMissMessage Message; + Message.Loc = IDLoc; + raw_svector_ostream OS(Message.Message); + + OS << "instruction requires:"; + uint64_t Mask = 1; + for (unsigned MaskPos = 0; MaskPos < (sizeof(MissingFeatures) * 8 - 1); + ++MaskPos) { + if (MissingFeatures & Mask) { + OS << " " << getSubtargetFeatureName(MissingFeatures & Mask); + } + Mask <<= 1; + } + NearMissesOut.emplace_back(Message); + + break; + } + case NearMissInfo::NearMissPredicate: { + NearMissMessage Message; + Message.Loc = IDLoc; + switch (I.getPredicateError()) { + case Match_RequiresNotITBlock: + Message.Message = "flag setting instruction only valid outside IT block"; + break; + case Match_RequiresITBlock: + Message.Message = "instruction only valid inside IT block"; + break; + case Match_RequiresV6: + Message.Message = "instruction variant requires ARMv6 or later"; + break; + case Match_RequiresThumb2: + Message.Message = "instruction variant requires Thumb2"; + break; + case Match_RequiresV8: + Message.Message = "instruction variant requires ARMv8 or later"; + break; + case Match_RequiresFlagSetting: + Message.Message = "no flag-preserving variant of this instruction available"; + break; + case Match_InvalidOperand: + Message.Message = "invalid operand for instruction"; + break; + default: + llvm_unreachable("Unhandled target predicate error"); + break; + } + NearMissesOut.emplace_back(Message); + break; + } + case NearMissInfo::NearMissTooFewOperands: { + SMLoc EndLoc = ((ARMOperand &)*Operands.back()).getEndLoc(); + NearMissesOut.emplace_back( + NearMissMessage{ EndLoc, StringRef("too few operands for instruction") }); + break; + } + case NearMissInfo::NoNearMiss: + // This should never leave the matcher. + llvm_unreachable("not a near-miss"); + break; + } + } +} + +void ARMAsmParser::ReportNearMisses(SmallVectorImpl<NearMissInfo> &NearMisses, + SMLoc IDLoc, OperandVector &Operands) { + SmallVector<NearMissMessage, 4> Messages; + FilterNearMisses(NearMisses, Messages, IDLoc, Operands); + + if (Messages.size() == 0) { + // No near-misses were found, so the best we can do is "invalid + // instruction". + Error(IDLoc, "invalid instruction"); + } else if (Messages.size() == 1) { + // One near miss was found, report it as the sole error. + Error(Messages[0].Loc, Messages[0].Message); + } else { + // More than one near miss, so report a generic "invalid instruction" + // error, followed by notes for each of the near-misses. + Error(IDLoc, "invalid instruction, any one of the following would fix this:"); + for (auto &M : Messages) { + Note(M.Loc, M.Message); + } + } +} + // FIXME: This structure should be moved inside ARMTargetParser // when we start to table-generate them, and we can use the ARM // flags below, that were generated by table-gen. |

