diff --git a/include/llvm/Target/Target.td b/include/llvm/Target/Target.td index e3f4c6465d3..cf87fb157cf 100644 --- a/include/llvm/Target/Target.td +++ b/include/llvm/Target/Target.td @@ -438,6 +438,10 @@ class Predicate { /// e.g. "ModeThumb,FeatureThumb2" is translated to /// "(Bits & ModeThumb) != 0 && (Bits & FeatureThumb2) != 0". string AssemblerCondString = ""; + + /// PredicateName - User-level name to use for the predicate. Mainly for use + /// in diagnostics such as missing feature errors in the asm matcher. + string PredicateName = ""; } /// NoHonorSignDependentRounding - This predicate is true if support for @@ -761,9 +765,10 @@ def DefaultAsmParserVariant : AsmParserVariant; /// AssemblerPredicate - This is a Predicate that can be used when the assembler /// matches instructions and aliases. -class AssemblerPredicate { +class AssemblerPredicate { bit AssemblerMatcherPredicate = 1; string AssemblerCondString = cond; + string PredicateName = name; } /// TokenAlias - This class allows targets to define assembler token diff --git a/lib/Target/ARM/ARMInstrInfo.td b/lib/Target/ARM/ARMInstrInfo.td index 6b874b2cfcc..633b53fefc9 100644 --- a/lib/Target/ARM/ARMInstrInfo.td +++ b/lib/Target/ARM/ARMInstrInfo.td @@ -161,53 +161,59 @@ def ARMbfi : SDNode<"ARMISD::BFI", SDT_ARMBFI>; // ARM Instruction Predicate Definitions. // def HasV4T : Predicate<"Subtarget->hasV4TOps()">, - AssemblerPredicate<"HasV4TOps">; + AssemblerPredicate<"HasV4TOps", "armv4t">; def NoV4T : Predicate<"!Subtarget->hasV4TOps()">; def HasV5T : Predicate<"Subtarget->hasV5TOps()">; def HasV5TE : Predicate<"Subtarget->hasV5TEOps()">, - AssemblerPredicate<"HasV5TEOps">; + AssemblerPredicate<"HasV5TEOps", "armv5te">; def HasV6 : Predicate<"Subtarget->hasV6Ops()">, - AssemblerPredicate<"HasV6Ops">; + AssemblerPredicate<"HasV6Ops", "armv6">; def NoV6 : Predicate<"!Subtarget->hasV6Ops()">; def HasV6T2 : Predicate<"Subtarget->hasV6T2Ops()">, - AssemblerPredicate<"HasV6T2Ops">; + AssemblerPredicate<"HasV6T2Ops", "armv6t2">; def NoV6T2 : Predicate<"!Subtarget->hasV6T2Ops()">; def HasV7 : Predicate<"Subtarget->hasV7Ops()">, - AssemblerPredicate<"HasV7Ops">; + AssemblerPredicate<"HasV7Ops", "armv7">; def NoVFP : Predicate<"!Subtarget->hasVFP2()">; def HasVFP2 : Predicate<"Subtarget->hasVFP2()">, - AssemblerPredicate<"FeatureVFP2">; + AssemblerPredicate<"FeatureVFP2", "VFP2">; def HasVFP3 : Predicate<"Subtarget->hasVFP3()">, - AssemblerPredicate<"FeatureVFP3">; + AssemblerPredicate<"FeatureVFP3", "VFP3">; def HasVFP4 : Predicate<"Subtarget->hasVFP4()">, - AssemblerPredicate<"FeatureVFP4">; + AssemblerPredicate<"FeatureVFP4", "VFP4">; def HasNEON : Predicate<"Subtarget->hasNEON()">, - AssemblerPredicate<"FeatureNEON">; + AssemblerPredicate<"FeatureNEON", "NEON">; def HasFP16 : Predicate<"Subtarget->hasFP16()">, - AssemblerPredicate<"FeatureFP16">; + AssemblerPredicate<"FeatureFP16","half-float">; def HasDivide : Predicate<"Subtarget->hasDivide()">, - AssemblerPredicate<"FeatureHWDiv">; + AssemblerPredicate<"FeatureHWDiv", "divide">; def HasT2ExtractPack : Predicate<"Subtarget->hasT2ExtractPack()">, - AssemblerPredicate<"FeatureT2XtPk">; + AssemblerPredicate<"FeatureT2XtPk", + "pack/extract">; def HasThumb2DSP : Predicate<"Subtarget->hasThumb2DSP()">, - AssemblerPredicate<"FeatureDSPThumb2">; + AssemblerPredicate<"FeatureDSPThumb2", + "thumb2-dsp">; def HasDB : Predicate<"Subtarget->hasDataBarrier()">, - AssemblerPredicate<"FeatureDB">; + AssemblerPredicate<"FeatureDB", + "data-barriers">; def HasMP : Predicate<"Subtarget->hasMPExtension()">, - AssemblerPredicate<"FeatureMP">; + AssemblerPredicate<"FeatureMP", + "mp-extensions">; def UseNEONForFP : Predicate<"Subtarget->useNEONForSinglePrecisionFP()">; def DontUseNEONForFP : Predicate<"!Subtarget->useNEONForSinglePrecisionFP()">; def IsThumb : Predicate<"Subtarget->isThumb()">, - AssemblerPredicate<"ModeThumb">; + AssemblerPredicate<"ModeThumb", "thumb">; def IsThumb1Only : Predicate<"Subtarget->isThumb1Only()">; def IsThumb2 : Predicate<"Subtarget->isThumb2()">, - AssemblerPredicate<"ModeThumb,FeatureThumb2">; + AssemblerPredicate<"ModeThumb,FeatureThumb2", + "thumb2">; def IsMClass : Predicate<"Subtarget->isMClass()">, - AssemblerPredicate<"FeatureMClass">; + AssemblerPredicate<"FeatureMClass", "armv7m">; def IsARClass : Predicate<"!Subtarget->isMClass()">, - AssemblerPredicate<"!FeatureMClass">; + AssemblerPredicate<"!FeatureMClass", + "armv7a/r">; def IsARM : Predicate<"!Subtarget->isThumb()">, - AssemblerPredicate<"!ModeThumb">; + AssemblerPredicate<"!ModeThumb", "arm-mode">; def IsIOS : Predicate<"Subtarget->isTargetIOS()">; def IsNotIOS : Predicate<"!Subtarget->isTargetIOS()">; def IsNaCl : Predicate<"Subtarget->isTargetNaCl()">; diff --git a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp index 2c53e3f8f8c..cbd9bdb77ca 100644 --- a/lib/Target/ARM/AsmParser/ARMAsmParser.cpp +++ b/lib/Target/ARM/AsmParser/ARMAsmParser.cpp @@ -7277,6 +7277,7 @@ unsigned ARMAsmParser::checkTargetMatchPredicate(MCInst &Inst) { return Match_Success; } +static const char *getSubtargetFeatureName(unsigned Val); bool ARMAsmParser:: MatchAndEmitInstruction(SMLoc IDLoc, SmallVectorImpl &Operands, @@ -7317,9 +7318,21 @@ MatchAndEmitInstruction(SMLoc IDLoc, Inst.setLoc(IDLoc); Out.EmitInstruction(Inst); return false; - case Match_MissingFeature: - Error(IDLoc, "instruction requires a CPU feature not currently enabled"); - return true; + 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:"; + unsigned 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 != ~0U) { diff --git a/test/MC/ARM/thumb-diagnostics.s b/test/MC/ARM/thumb-diagnostics.s index 99d7e38c7ed..4d09af32ef3 100644 --- a/test/MC/ARM/thumb-diagnostics.s +++ b/test/MC/ARM/thumb-diagnostics.s @@ -67,7 +67,7 @@ error: invalid operand for instruction @ Invalid writeback and register lists for STM stm r1, {r2, r6} stm r1!, {r2, r9} -@ CHECK-ERRORS: error: instruction requires a CPU feature not currently enabled +@ CHECK-ERRORS: error: instruction requires: thumb2 @ CHECK-ERRORS: stm r1, {r2, r6} @ CHECK-ERRORS: ^ @ CHECK-ERRORS: error: registers must be in range r0-r7 @@ -95,13 +95,13 @@ error: invalid operand for instruction str r2, [r7, #-1] str r5, [r1, #3] str r3, [r7, #128] -@ CHECK-ERRORS: error: instruction requires a CPU feature not currently enabled +@ CHECK-ERRORS: error: instruction requires: thumb2 @ CHECK-ERRORS: str r2, [r7, #-1] @ CHECK-ERRORS: ^ -@ CHECK-ERRORS: error: instruction requires a CPU feature not currently enabled +@ CHECK-ERRORS: error: instruction requires: thumb2 @ CHECK-ERRORS: str r5, [r1, #3] @ CHECK-ERRORS: ^ -@ CHECK-ERRORS: error: instruction requires a CPU feature not currently enabled +@ CHECK-ERRORS: error: instruction requires: thumb2 @ CHECK-ERRORS: str r3, [r7, #128] @ CHECK-ERRORS: ^ @@ -111,7 +111,7 @@ error: invalid operand for instruction @ CHECK-ERRORS: error: invalid operand for instruction @ CHECK-ERRORS: svc #-1 @ CHECK-ERRORS: ^ -@ CHECK-ERRORS: error: instruction requires a CPU feature not currently enabled +@ CHECK-ERRORS: error: instruction requires: arm-mode @ CHECK-ERRORS: svc #256 @ CHECK-ERRORS: ^ @@ -121,15 +121,15 @@ error: invalid operand for instruction add sp, #3 add sp, sp, #512 add r2, sp, #1024 -@ CHECK-ERRORS: error: instruction requires a CPU feature not currently enabled +@ CHECK-ERRORS: error: instruction requires: thumb2 @ CHECK-ERRORS: add sp, #-1 @ CHECK-ERRORS: ^ -@ CHECK-ERRORS: error: instruction requires a CPU feature not currently enabled +@ CHECK-ERRORS: error: instruction requires: thumb2 @ CHECK-ERRORS: add sp, #3 @ CHECK-ERRORS: ^ -@ CHECK-ERRORS: error: instruction requires a CPU feature not currently enabled +@ CHECK-ERRORS: error: instruction requires: thumb2 @ CHECK-ERRORS: add sp, sp, #512 @ CHECK-ERRORS: ^ -@ CHECK-ERRORS: error: instruction requires a CPU feature not currently enabled +@ CHECK-ERRORS: error: instruction requires: arm-mode @ CHECK-ERRORS: add r2, sp, #1024 @ CHECK-ERRORS: ^ diff --git a/utils/TableGen/AsmMatcherEmitter.cpp b/utils/TableGen/AsmMatcherEmitter.cpp index a44fbe6256f..03807b10926 100644 --- a/utils/TableGen/AsmMatcherEmitter.cpp +++ b/utils/TableGen/AsmMatcherEmitter.cpp @@ -1951,6 +1951,25 @@ static void emitSubtargetFeatureFlagEnumeration(AsmMatcherInfo &Info, OS << "};\n\n"; } +/// emitGetSubtargetFeatureName - Emit the helper function to get the +/// user-level name for a subtarget feature. +static void emitGetSubtargetFeatureName(AsmMatcherInfo &Info, raw_ostream &OS) { + OS << "// User-level names for subtarget features that participate in\n" + << "// instruction matching.\n" + << "static const char *getSubtargetFeatureName(unsigned Val) {\n" + << " switch(Val) {\n"; + for (std::map::const_iterator + it = Info.SubtargetFeatures.begin(), + ie = Info.SubtargetFeatures.end(); it != ie; ++it) { + SubtargetFeatureInfo &SFI = *it->second; + // FIXME: Totally just a placeholder name to get the algorithm working. + OS << " case " << SFI.getEnumName() << ": return \"" + << SFI.TheDef->getValueAsString("PredicateName") << "\";\n"; + } + OS << " default: return \"(unknown)\";\n"; + OS << " }\n}\n\n"; +} + /// emitComputeAvailableFeatures - Emit the function to compute the list of /// available features given a subtarget. static void emitComputeAvailableFeatures(AsmMatcherInfo &Info, @@ -2380,6 +2399,9 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << "\n#ifdef GET_MATCHER_IMPLEMENTATION\n"; OS << "#undef GET_MATCHER_IMPLEMENTATION\n\n"; + // Generate the helper function to get the names for subtarget features. + emitGetSubtargetFeatureName(Info, OS); + // Generate the function that remaps for mnemonic aliases. bool HasMnemonicAliases = emitMnemonicAliases(OS, Info); @@ -2510,8 +2532,8 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { << Target.getName() << ClassName << "::\n" << "MatchInstructionImpl(const SmallVectorImpl" << " &Operands,\n"; - OS << " MCInst &Inst, unsigned &ErrorInfo,\n"; - OS << " unsigned VariantID) {\n"; + OS << " MCInst &Inst, unsigned &ErrorInfo, "; + OS << "unsigned VariantID) {\n"; // Emit code to get the available features. OS << " // Get the current feature set.\n"; @@ -2586,6 +2608,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " if ((AvailableFeatures & it->RequiredFeatures) " << "!= it->RequiredFeatures) {\n"; OS << " HadMatchOtherThanFeatures = true;\n"; + OS << " ErrorInfo = it->RequiredFeatures & ~AvailableFeatures;\n"; OS << " continue;\n"; OS << " }\n"; OS << "\n"; @@ -2620,6 +2643,7 @@ void AsmMatcherEmitter::run(raw_ostream &OS) { OS << " // Okay, we had no match. Try to return a useful error code.\n"; OS << " if (HadMatchOtherThanPredicate || !HadMatchOtherThanFeatures)"; OS << " return RetCode;\n"; + OS << " assert(ErrorInfo && \"missing feature(s) but what?!\");"; OS << " return Match_MissingFeature;\n"; OS << "}\n\n";