-
Notifications
You must be signed in to change notification settings - Fork 15.4k
[clang][TableGen] Fix Duplicate Entries in TableGen #140828
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
|
@llvm/pr-subscribers-backend-risc-v Author: Vincent (Mr-Anyone) ChangesFixed TableGen duplicate issues that causes the wrong interrupt attribute from being selected. resolves #140701 Full diff: https://github.com/llvm/llvm-project/pull/140828.diff 2 Files Affected:
diff --git a/clang/test/AST/ast-dump-riscv-attributes.cpp b/clang/test/AST/ast-dump-riscv-attributes.cpp
new file mode 100644
index 0000000000000..7efe626072311
--- /dev/null
+++ b/clang/test/AST/ast-dump-riscv-attributes.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple riscv64 -ast-dump -ast-dump-filter c23 -std=c23 -x c %s | FileCheck --strict-whitespace %s
+
+// CHECK: FunctionDecl{{.*}}pre_c23
+// CHECK-NEXT: |-CompoundStmt
+// CHECK-NEXT: `-RISCVInterruptAttr{{.*}}supervisor
+__attribute__((interrupt("supervisor"))) void pre_c23(){}
+
+// CHECK: FunctionDecl{{.*}}in_c23
+// CHECK-NEXT: |-CompoundStmt
+// CHECK-NEXT: `-RISCVInterruptAttr{{.*}}supervisor
+// CHECK-NOT: `-RISCVInterruptAttr{{.*}}machine
+[[gnu::interrupt("supervisor")]] void in_c23(){}
diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp
index 9684ec9520e5a..effef13c8d276 100644
--- a/clang/utils/TableGen/ClangAttrEmitter.cpp
+++ b/clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -20,6 +20,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
@@ -3667,6 +3668,9 @@ static bool GenerateTargetSpecificAttrChecks(const Record *R,
static void GenerateHasAttrSpellingStringSwitch(
ArrayRef<std::pair<const Record *, FlattenedSpelling>> Attrs,
raw_ostream &OS, StringRef Variety, StringRef Scope = "") {
+
+ llvm::StringMap<std::string> TargetSpecificMap;
+
for (const auto &[Attr, Spelling] : Attrs) {
// C++11-style attributes have specific version information associated with
// them. If the attribute has no scope, the version information must not
@@ -3727,12 +3731,24 @@ static void GenerateHasAttrSpellingStringSwitch(
}
}
- std::string TestStr = !Test.empty()
- ? Test + " ? " + itostr(Version) + " : 0"
- : itostr(Version);
- if (Scope.empty() || Scope == Spelling.nameSpace())
- OS << " .Case(\"" << Spelling.name() << "\", " << TestStr << ")\n";
+ std::string TestStr =
+ !Test.empty() ? '(' + Test + " ? " + itostr(Version) + " : 0" + ')'
+ : '(' + itostr(Version) + ')';
+
+ if (Scope.empty() || Scope == Spelling.nameSpace()) {
+ if (TargetSpecificMap.contains(Spelling.name())) {
+ TargetSpecificMap[Spelling.name()] += " || " + TestStr;
+ } else {
+ TargetSpecificMap[Spelling.name()] = TestStr;
+ }
+ }
+ }
+
+ for (auto &entry : TargetSpecificMap) {
+ OS << " .Case(\"" << entry.getKey() << "\", " << entry.getValue()
+ << ")\n";
}
+
OS << " .Default(0);\n";
}
|
|
@llvm/pr-subscribers-clang Author: Vincent (Mr-Anyone) ChangesFixed TableGen duplicate issues that causes the wrong interrupt attribute from being selected. resolves #140701 Full diff: https://github.com/llvm/llvm-project/pull/140828.diff 2 Files Affected:
diff --git a/clang/test/AST/ast-dump-riscv-attributes.cpp b/clang/test/AST/ast-dump-riscv-attributes.cpp
new file mode 100644
index 0000000000000..7efe626072311
--- /dev/null
+++ b/clang/test/AST/ast-dump-riscv-attributes.cpp
@@ -0,0 +1,12 @@
+// RUN: %clang_cc1 -triple riscv64 -ast-dump -ast-dump-filter c23 -std=c23 -x c %s | FileCheck --strict-whitespace %s
+
+// CHECK: FunctionDecl{{.*}}pre_c23
+// CHECK-NEXT: |-CompoundStmt
+// CHECK-NEXT: `-RISCVInterruptAttr{{.*}}supervisor
+__attribute__((interrupt("supervisor"))) void pre_c23(){}
+
+// CHECK: FunctionDecl{{.*}}in_c23
+// CHECK-NEXT: |-CompoundStmt
+// CHECK-NEXT: `-RISCVInterruptAttr{{.*}}supervisor
+// CHECK-NOT: `-RISCVInterruptAttr{{.*}}machine
+[[gnu::interrupt("supervisor")]] void in_c23(){}
diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp
index 9684ec9520e5a..effef13c8d276 100644
--- a/clang/utils/TableGen/ClangAttrEmitter.cpp
+++ b/clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -20,6 +20,7 @@
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/StringSwitch.h"
#include "llvm/Support/ErrorHandling.h"
@@ -3667,6 +3668,9 @@ static bool GenerateTargetSpecificAttrChecks(const Record *R,
static void GenerateHasAttrSpellingStringSwitch(
ArrayRef<std::pair<const Record *, FlattenedSpelling>> Attrs,
raw_ostream &OS, StringRef Variety, StringRef Scope = "") {
+
+ llvm::StringMap<std::string> TargetSpecificMap;
+
for (const auto &[Attr, Spelling] : Attrs) {
// C++11-style attributes have specific version information associated with
// them. If the attribute has no scope, the version information must not
@@ -3727,12 +3731,24 @@ static void GenerateHasAttrSpellingStringSwitch(
}
}
- std::string TestStr = !Test.empty()
- ? Test + " ? " + itostr(Version) + " : 0"
- : itostr(Version);
- if (Scope.empty() || Scope == Spelling.nameSpace())
- OS << " .Case(\"" << Spelling.name() << "\", " << TestStr << ")\n";
+ std::string TestStr =
+ !Test.empty() ? '(' + Test + " ? " + itostr(Version) + " : 0" + ')'
+ : '(' + itostr(Version) + ')';
+
+ if (Scope.empty() || Scope == Spelling.nameSpace()) {
+ if (TargetSpecificMap.contains(Spelling.name())) {
+ TargetSpecificMap[Spelling.name()] += " || " + TestStr;
+ } else {
+ TargetSpecificMap[Spelling.name()] = TestStr;
+ }
+ }
+ }
+
+ for (auto &entry : TargetSpecificMap) {
+ OS << " .Case(\"" << entry.getKey() << "\", " << entry.getValue()
+ << ")\n";
}
+
OS << " .Default(0);\n";
}
|
Fixed TableGen duplicate issues that causes the wrong interrupt attribute from being selected. resolves llvm#140701
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
AaronBallman
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for working on this! In general, this looks good to me, just nits about our coding style.
| } | ||
|
|
||
| // Create the actual string switch statement after all the attributes have | ||
| // been parsed |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| // been parsed | |
| // been parsed. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
| for (auto &entry : TestStringMap) { | ||
| OS << " .Case(\"" << entry.getKey() << "\", " << entry.getValue() | ||
| << ")\n"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| for (auto &entry : TestStringMap) { | |
| OS << " .Case(\"" << entry.getKey() << "\", " << entry.getValue() | |
| << ")\n"; | |
| for (auto &Entry : TestStringMap) { | |
| OS << " .Case(\"" << Entry.getKey() << "\", " << Entry.getValue() | |
| << ")\n"; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done.
| if (TestStringMap.contains(Spelling.name())) { | ||
| TestStringMap[Spelling.name()] += " || " + TestStr; | ||
| } else { | ||
| TestStringMap[Spelling.name()] = TestStr; | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
| if (TestStringMap.contains(Spelling.name())) { | |
| TestStringMap[Spelling.name()] += " || " + TestStr; | |
| } else { | |
| TestStringMap[Spelling.name()] = TestStr; | |
| } | |
| if (TestStringMap.contains(Spelling.name())) | |
| TestStringMap[Spelling.name()] += " || " + TestStr; | |
| else | |
| TestStringMap[Spelling.name()] = TestStr; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
done, thanks.
| // CHECK: FunctionDecl{{.*}}in_c23 | ||
| // CHECK-NEXT: |-CompoundStmt | ||
| // CHECK-NEXT: `-RISCVInterruptAttr{{.*}}supervisor | ||
| // CHECK-NOT: `-RISCVInterruptAttr{{.*}}machine |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't get this test. Why does this choose the RISCV interrupt instead of the GNU one? And where would 'machine' come from?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
"-triple riscv64" is why you get the RISCVInterruptAttr, which is expected.
"machine" is on a CHECK-NOT line, which is what the bug was about.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess the question is 'how'? Is the "supervisor" not coming from the string?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Before this patch, our "has attribute" check was looking through a StringSwitch that had multiple cases with the same string argument but different resulting values (that would check for target triples and arches). So we'd hit the first case, say "this matches", and the test for the attribute would only pass if the target triple matched. Because the first triple was never the RISCV attribute, we'd always say "we don't have this attribute". In turn, this would mean parsing would say "well, we don't know about this attribute, so eat all the arguments". But because Sema could figure out which handleInterruptAttr function to call, we'd actually go ahead and make the correct attribute, just with the incorrect argument. The default if no argument is specified for RISCV is machine. So we'd ignore supervisor and just substitute in machine quietly for the user.
| : itostr(Version); | ||
| if (Scope.empty() || Scope == Spelling.nameSpace()) | ||
| OS << " .Case(\"" << Spelling.name() << "\", " << TestStr << ")\n"; | ||
| std::string TestStr = |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you share a before/after generated file so that I can take a look? I'm having a hard time visualizing what this does.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Before: https://pastebin.com/iwkWd3Bf
After: https://pastebin.com/eikjMpQt
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Take the interrupt attribute as an example:
This is the original string: true && (T.getArch() == llvm::Triple::riscv32 || T.getArch() == llvm::Triple::riscv64) ? 1 : 0.
The problem is that there are multiple of them for a single attribute, such as true && (T.getArch() == llvm::Triple::arm || T.getArch() == llvm::Triple::thumb || T.getArch() == llvm::Triple::armeb || T.getArch() == llvm::Triple::thumbeb) ? 1 : 0 for arm.
Meaning that, we used to get:
.Case("interrupt",true && (T.getArch() == llvm::Triple::riscv32 || T.getArch() == llvm::Triple::riscv64) ? 1 : 0 )
.Case("interrupt",true && (T.getArch() == llvm::Triple::arm || T.getArch() == llvm::Triple::thumb || T.getArch() == llvm::Triple::armeb || T.getArch() == llvm::Triple::thumbeb) ? 1 : 0
...
This is the new one TestStr: (true && (T.getArch() == llvm::Triple::avr) ? 1 : 0), with the only difference being the added parentheses. We can join test strings together with ||, meaning we generate something like this:
(true && (T.getArch() == llvm::Triple::riscv32 || T.getArch() == llvm::Triple::riscv64) ? 1 : 0) ||
(true && (T.getArch() == llvm::Triple::arm || T.getArch() == llvm::Triple::thumb || T.getArch() == llvm::Triple::armeb || T.getArch() == llvm::Triple::thumbeb) ? 1 : 0) ...
So now we have a single case statement instead,
.Case("interrupt",(true && (T.getArch() == llvm::Triple::riscv32 || T.getArch() == llvm::Triple::riscv64) ? 1 : 0) ||
(true && (T.getArch() == llvm::Triple::arm || T.getArch() == llvm::Triple::thumb || T.getArch() == llvm::Triple::armeb || T.getArch() == llvm::Triple::thumbeb) ? 1 : 0) ... )
...
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Got it, thank you for that!
AaronBallman
left a comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
Fixed TableGen duplicate issues that causes the wrong interrupt attribute from being selected.
resolves #140701