ARM: improved assembler diagnostics for missing CPU features.

When an instruction match is found, but the subtarget features it
requires are not available (missing floating point unit, or thumb vs arm
mode, for example), issue a diagnostic that identifies what the feature
mismatch is.

rdar://11257547

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@155499 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Jim Grosbach 2012-04-24 22:40:08 +00:00
parent 86b7e2acc9
commit 14ce6fac24
5 changed files with 83 additions and 35 deletions

View File

@ -438,6 +438,10 @@ class Predicate<string cond> {
/// 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<string cond> {
class AssemblerPredicate<string cond, string name = ""> {
bit AssemblerMatcherPredicate = 1;
string AssemblerCondString = cond;
string PredicateName = name;
}
/// TokenAlias - This class allows targets to define assembler token

View File

@ -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()">;

View File

@ -7277,6 +7277,7 @@ unsigned ARMAsmParser::checkTargetMatchPredicate(MCInst &Inst) {
return Match_Success;
}
static const char *getSubtargetFeatureName(unsigned Val);
bool ARMAsmParser::
MatchAndEmitInstruction(SMLoc IDLoc,
SmallVectorImpl<MCParsedAsmOperand*> &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) {

View File

@ -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: ^

View File

@ -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<Record*, SubtargetFeatureInfo*>::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<MCParsedAsmOperand*>"
<< " &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";