summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/Target/Target.td15
-rw-r--r--llvm/test/MC/AArch64/arm64-diags.s8
-rw-r--r--llvm/test/MC/AArch64/basic-a64-diagnostics.s20
-rw-r--r--llvm/utils/TableGen/AsmMatcherEmitter.cpp77
4 files changed, 97 insertions, 23 deletions
diff --git a/llvm/include/llvm/Target/Target.td b/llvm/include/llvm/Target/Target.td
index 62072dba807..955da7bd5c8 100644
--- a/llvm/include/llvm/Target/Target.td
+++ b/llvm/include/llvm/Target/Target.td
@@ -269,6 +269,21 @@ class RegisterClass<string namespace, list<ValueType> regTypes, int alignment,
// useful as it is sometimes beneficial to assign registers to highly
// constrained classes first. The value has to be in the range [0,63].
int AllocationPriority = 0;
+
+ // The diagnostic type to present when referencing this operand in a match
+ // failure error message. If this is empty, the default Match_InvalidOperand
+ // diagnostic type will be used. If this is "<name>", a Match_<name> enum
+ // value will be generated and used for this operand type. The target
+ // assembly parser is responsible for converting this into a user-facing
+ // diagnostic message.
+ string DiagnosticType = "";
+
+ // A diagnostic message to emit when an invalid value is provided for this
+ // register class when it is being used an an assembly operand. If this is
+ // non-empty, an anonymous diagnostic type enum value will be generated, and
+ // the assembly matcher will provide a function to map from diagnostic types
+ // to message strings.
+ string DiagnosticString = "";
}
// The memberList in a RegisterClass is a dag of set operations. TableGen
diff --git a/llvm/test/MC/AArch64/arm64-diags.s b/llvm/test/MC/AArch64/arm64-diags.s
index 3510193a71f..bdf0f10d394 100644
--- a/llvm/test/MC/AArch64/arm64-diags.s
+++ b/llvm/test/MC/AArch64/arm64-diags.s
@@ -9,7 +9,7 @@ foo:
ldr x3, [foo + 4]
; CHECK: ldr x3, foo+4 ; encoding: [0bAAA00011,A,A,0x58]
; CHECK: ; fixup A - offset: 0, value: foo+4, kind: fixup_aarch64_ldr_pcrel_imm19
-; CHECK-ERRORS: error: invalid operand for instruction
+; CHECK-ERRORS: error: expected label or encodable integer pc offset
; The last argument should be flagged as an error. rdar://9576009
ld4.8b {v0, v1, v2, v3}, [x0], #33
@@ -42,13 +42,13 @@ foo:
; CHECK-ERRORS: error: index must be an integer in range [-256, 255].
; CHECK-ERRORS: ldr x0, [x0, #804]!
; CHECK-ERRORS: ^
-; CHECK-ERRORS: error: invalid operand for instruction
+; CHECK-ERRORS: error: expected label or encodable integer pc offset
; CHECK-ERRORS: ldr w0, [w0, #301]!
; CHECK-ERRORS: ^
; CHECK-ERRORS: error: index must be an integer in range [-256, 255].
; CHECK-ERRORS: ldr x0, [x0], #804
; CHECK-ERRORS: ^
-; CHECK-ERRORS: error: invalid operand for instruction
+; CHECK-ERRORS: error: expected label or encodable integer pc offset
; CHECK-ERRORS: ldr w0, [w0], #301
; CHECK-ERRORS: ^
; CHECK-ERRORS: error: index must be a multiple of 4 in range [-256, 252].
@@ -477,7 +477,7 @@ tlbi vale3
; CHECK-ERRORS: error: too few operands for instruction
; CHECK-ERRORS: b.ne
; CHECK-ERRORS: ^
-; CHECK-ERRORS: error: invalid operand for instruction
+; CHECK-ERRORS: error: expected label or encodable integer pc offset
; CHECK-ERRORS: b.eq 0, 0
; CHECK-ERRORS: ^
diff --git a/llvm/test/MC/AArch64/basic-a64-diagnostics.s b/llvm/test/MC/AArch64/basic-a64-diagnostics.s
index ab3e50e374e..6f2f9d44782 100644
--- a/llvm/test/MC/AArch64/basic-a64-diagnostics.s
+++ b/llvm/test/MC/AArch64/basic-a64-diagnostics.s
@@ -1814,7 +1814,7 @@
;; Not possible to fmov ZR to a whole vector
fmov v0.4s, #0.0
-// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: expected compatible register or floating-point constant
// CHECK-ERROR-NEXT: fmov v0.4s, #0.0
// CHECK-ERROR-NEXT: ^
@@ -1963,10 +1963,10 @@
ldr x3, [x4, #25], #0
ldr x4, [x9, #0], #4
// CHECK-ERROR-AARCH64: error: {{expected symbolic reference or integer|index must be a multiple of 8}} in range [0, 32760]
-// CHECK-ERROR-ARM64: error: invalid operand for instruction
+// CHECK-ERROR-ARM64: error: expected label or encodable integer pc offset
// CHECK-ERROR-NEXT: ldr x3, [x4, #25], #0
// CHECK-ERROR-NEXT: ^
-// CHECK-ERROR-AARCH64-NEXT: error: invalid operand for instruction
+// CHECK-ERROR-AARCH64-NEXT: error: expected label or encodable integer pc offset
// CHECK-ERROR-AARCH64-NEXT: ldr x4, [x9, #0], #4
// CHECK-ERROR-AARCH64-NEXT: ^
@@ -2196,7 +2196,7 @@
// CHECK-ERROR-NEXT: error: {{expected|index must be an}} integer in range [-256, 255]
// CHECK-ERROR-NEXT: ldrh w9, [sp, #-257]!
// CHECK-ERROR-NEXT: ^
-// CHECK-ERROR-NEXT: error: invalid operand for instruction
+// CHECK-ERROR-NEXT: error: expected label or encodable integer pc offset
// CHECK-ERROR-NEXT: ldr w1, [x19, #256]!
// CHECK-ERROR-NEXT: ^
// CHECK-ERROR-NEXT: error: {{expected|index must be an}} integer in range [-256, 255]
@@ -2221,7 +2221,7 @@
// CHECK-ERROR-NEXT: error: {{expected|index must be an}} integer in range [-256, 255]
// CHECK-ERROR-NEXT: ldrsh x22, [x13, #-257]!
// CHECK-ERROR-NEXT: ^
-// CHECK-ERROR-NEXT: error: invalid operand for instruction
+// CHECK-ERROR-NEXT: error: expected label or encodable integer pc offset
// CHECK-ERROR-NEXT: ldrsw x2, [x3, #256]!
// CHECK-ERROR-NEXT: ^
// CHECK-ERROR-NEXT: error: {{expected|index must be an}} integer in range [-256, 255]
@@ -2298,13 +2298,13 @@
// CHECK-ERROR-NEXT: error: {{expected|index must be an}} integer in range [-256, 255]
// CHECK-ERROR-NEXT: ldr h3, [x13, #-257]!
// CHECK-ERROR-NEXT: ^
-// CHECK-ERROR-NEXT: error: invalid operand for instruction
+// CHECK-ERROR-NEXT: error: expected label or encodable integer pc offset
// CHECK-ERROR-NEXT: ldr s3, [x3, #256]!
// CHECK-ERROR-NEXT: ^
// CHECK-ERROR-NEXT: error: {{expected|index must be an}} integer in range [-256, 255]
// CHECK-ERROR-NEXT: ldr s3, [x13, #-257]!
// CHECK-ERROR-NEXT: ^
-// CHECK-ERROR-NEXT: error: invalid operand for instruction
+// CHECK-ERROR-NEXT: error: expected label or encodable integer pc offset
// CHECK-ERROR-NEXT: ldr d3, [x3, #256]!
// CHECK-ERROR-NEXT: ^
// CHECK-ERROR-NEXT: error: {{expected|index must be an}} integer in range [-256, 255]
@@ -2397,7 +2397,7 @@
//// 32-bit addresses
ldr w0, [w20]
ldrsh x3, [wsp]
-// CHECK-ERROR: error: invalid operand for instruction
+// CHECK-ERROR: error: expected label or encodable integer pc offset
// CHECK-ERROR-NEXT: ldr w0, [w20]
// CHECK-ERROR-NEXT: ^
// CHECK-ERROR-NEXT: error: invalid operand for instruction
@@ -2435,7 +2435,7 @@
// CHECK-ERROR-ARM64-NEXT: error: prefetch operand out of range, [0,31] expected
// CHECK-ERROR-NEXT: prfm #32, [sp, #8]
// CHECK-ERROR-NEXT: ^
-// CHECK-ERROR-NEXT: error: invalid operand for instruction
+// CHECK-ERROR-NEXT: error: expected label or encodable integer pc offset
// CHECK-ERROR-NEXT: prfm pldl1strm, [w3, #8]
// CHECK-ERROR-NEXT: ^
// CHECK-ERROR-AARCH64-NEXT: error: operand specifier not recognised
@@ -2453,7 +2453,7 @@
ldr w10, [x6, x9, sxtw #2]
ldr w11, [x7, w2, lsl #2]
ldr w12, [x8, w1, sxtx]
-// CHECK-ERROR-NEXT: error: invalid operand for instruction
+// CHECK-ERROR-NEXT: error: expected label or encodable integer pc offset
// CHECK-ERROR-NEXT: ldr w3, [xzr, x3]
// CHECK-ERROR-NEXT: ^
// CHECK-ERROR-NEXT: error: expected #imm after shift specifier
diff --git a/llvm/utils/TableGen/AsmMatcherEmitter.cpp b/llvm/utils/TableGen/AsmMatcherEmitter.cpp
index 191dbdea098..60ec8c3eef2 100644
--- a/llvm/utils/TableGen/AsmMatcherEmitter.cpp
+++ b/llvm/utils/TableGen/AsmMatcherEmitter.cpp
@@ -704,13 +704,13 @@ public:
/// Map of AsmOperandClass records to their class information.
std::map<Record*, ClassInfo*> AsmOperandClasses;
+ /// Map of RegisterClass records to their class information.
+ std::map<Record*, ClassInfo*> RegisterClassClasses;
+
private:
/// Map of token to class information which has already been constructed.
std::map<std::string, ClassInfo*> TokenClasses;
- /// Map of RegisterClass records to their class information.
- std::map<Record*, ClassInfo*> RegisterClassClasses;
-
private:
/// getTokenClass - Lookup or create the class for the given token.
ClassInfo *getTokenClass(StringRef Token);
@@ -1282,6 +1282,19 @@ buildRegisterClasses(SmallPtrSetImpl<Record*> &SingletonRegisters) {
} else
CI->ValueName = CI->ValueName + "," + RC.getName();
+ Init *DiagnosticType = Def->getValueInit("DiagnosticType");
+ if (StringInit *SI = dyn_cast<StringInit>(DiagnosticType))
+ CI->DiagnosticType = SI->getValue();
+
+ Init *DiagnosticString = Def->getValueInit("DiagnosticString");
+ if (StringInit *SI = dyn_cast<StringInit>(DiagnosticString))
+ CI->DiagnosticString = SI->getValue();
+
+ // If we have a diagnostic string but the diagnostic type is not specified
+ // explicitly, create an anonymous diagnostic type.
+ if (!CI->DiagnosticString.empty() && CI->DiagnosticType.empty())
+ CI->DiagnosticType = RC.getName();
+
RegisterClassClasses.insert(std::make_pair(Def, CI));
}
@@ -2178,7 +2191,18 @@ static void emitMatchClassEnumeration(CodeGenTarget &Target,
OS << "enum MatchClassKind {\n";
OS << " InvalidMatchClass = 0,\n";
OS << " OptionalMatchClass = 1,\n";
+ ClassInfo::ClassInfoKind LastKind = ClassInfo::Token;
+ StringRef LastName = "OptionalMatchClass";
for (const auto &CI : Infos) {
+ if (LastKind == ClassInfo::Token && CI.Kind != ClassInfo::Token) {
+ OS << " MCK_LAST_TOKEN = " << LastName << ",\n";
+ } else if (LastKind < ClassInfo::UserClass0 &&
+ CI.Kind >= ClassInfo::UserClass0) {
+ OS << " MCK_LAST_REGISTER = " << LastName << ",\n";
+ }
+ LastKind = (ClassInfo::ClassInfoKind)CI.Kind;
+ LastName = CI.Name;
+
OS << " " << CI.Name << ", // ";
if (CI.Kind == ClassInfo::Token) {
OS << "'" << CI.ValueName << "'\n";
@@ -2229,6 +2253,26 @@ static void emitOperandMatchErrorDiagStrings(AsmMatcherInfo &Info, raw_ostream &
OS << "}\n\n";
}
+static void emitRegisterMatchErrorFunc(AsmMatcherInfo &Info, raw_ostream &OS) {
+ OS << "static unsigned getDiagKindFromRegisterClass(MatchClassKind "
+ "RegisterClass) {\n";
+ OS << " switch (RegisterClass) {\n";
+
+ for (const auto &CI: Info.Classes) {
+ if (CI.isRegisterClass() && !CI.DiagnosticType.empty()) {
+ OS << " case " << CI.Name << ":\n";
+ OS << " return " << Info.Target.getName() << "AsmParser::Match_"
+ << CI.DiagnosticType << ";\n";
+ }
+ }
+
+ OS << " default:\n";
+ OS << " return MCTargetAsmParser::Match_InvalidOperand;\n";
+
+ OS << " }\n";
+ OS << "}\n\n";
+}
+
/// emitValidateOperandClass - Emit the function to validate an operand class.
static void emitValidateOperandClass(AsmMatcherInfo &Info,
raw_ostream &OS) {
@@ -2243,7 +2287,7 @@ static void emitValidateOperandClass(AsmMatcherInfo &Info,
// Check for Token operands first.
// FIXME: Use a more specific diagnostic type.
- OS << " if (Operand.isToken())\n";
+ OS << " if (Operand.isToken() && Kind <= MCK_LAST_TOKEN)\n";
OS << " return isSubclass(matchTokenString(Operand.getToken()), Kind) ?\n"
<< " MCTargetAsmParser::Match_Success :\n"
<< " MCTargetAsmParser::Match_InvalidOperand;\n\n";
@@ -2279,8 +2323,12 @@ static void emitValidateOperandClass(AsmMatcherInfo &Info,
<< "; break;\n";
OS << " }\n";
OS << " return isSubclass(OpKind, Kind) ? "
- << "MCTargetAsmParser::Match_Success :\n "
- << " MCTargetAsmParser::Match_InvalidOperand;\n }\n\n";
+ << "(unsigned)MCTargetAsmParser::Match_Success :\n "
+ << " getDiagKindFromRegisterClass(Kind);\n }\n\n";
+
+ // Expected operand is a register, but actual is not.
+ OS << " if (Kind > MCK_LAST_TOKEN && Kind <= MCK_LAST_REGISTER)\n";
+ OS << " return getDiagKindFromRegisterClass(Kind);\n\n";
// Generic fallthrough match failure case for operands that don't have
// specialized diagnostic types.
@@ -2429,6 +2477,10 @@ static void emitOperandDiagnosticTypes(AsmMatcherInfo &Info, raw_ostream &OS) {
if (!OpClassEntry.second->DiagnosticType.empty())
Types.insert(OpClassEntry.second->DiagnosticType);
}
+ for (const auto &OpClassEntry : Info.RegisterClassClasses) {
+ if (!OpClassEntry.second->DiagnosticType.empty())
+ Types.insert(OpClassEntry.second->DiagnosticType);
+ }
if (Types.empty()) return;
@@ -2959,6 +3011,9 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
// match failure in diagnostics.
emitOperandMatchErrorDiagStrings(Info, OS);
+ // Emit a function to map register classes to operand match failure codes.
+ emitRegisterMatchErrorFunc(Info, OS);
+
// Emit the routine to match token strings to their match class.
emitMatchTokenString(Target, Info.Classes, OS);
@@ -3226,12 +3281,16 @@ void AsmMatcherEmitter::run(raw_ostream &OS) {
OS << " }\n";
OS << " // If the generic handler indicates an invalid operand\n";
OS << " // failure, check for a special case.\n";
- OS << " if (Diag == Match_InvalidOperand) {\n";
- OS << " Diag = validateTargetOperandClass(Actual, Formal);\n";
- OS << " if (Diag == Match_Success) {\n";
+ OS << " if (Diag != Match_Success) {\n";
+ OS << " unsigned TargetDiag = validateTargetOperandClass(Actual, Formal);\n";
+ OS << " if (TargetDiag == Match_Success) {\n";
OS << " ++ActualIdx;\n";
OS << " continue;\n";
OS << " }\n";
+ OS << " // If the target matcher returned a specific error code use\n";
+ OS << " // that, else use the one from the generic matcher.\n";
+ OS << " if (TargetDiag != Match_InvalidOperand)\n";
+ OS << " Diag = TargetDiag;\n";
OS << " }\n";
OS << " // If current formal operand wasn't matched and it is optional\n"
<< " // then try to match next formal operand\n";
OpenPOWER on IntegriCloud