-
Notifications
You must be signed in to change notification settings - Fork 13.5k
[KeyInstr][Clang] Switch stmt atom #134643
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
base: main
Are you sure you want to change the base?
Conversation
@llvm/pr-subscribers-clang Author: Orlando Cazalet-Hyams (OCHyams) ChangesThis patch is part of a stack that teaches Clang to generate Key Instructions The Key Instructions project is introduced, including a "quick summary" section The feature is only functional in LLVM if LLVM is built with CMake flag The Clang-side work is demoed here: Full diff: https://github.com/llvm/llvm-project/pull/134643.diff 2 Files Affected:
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 3562b4ea22a24..7dd82d73d6b6a 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -2276,6 +2276,8 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
// failure.
llvm::BasicBlock *DefaultBlock = createBasicBlock("sw.default");
SwitchInsn = Builder.CreateSwitch(CondV, DefaultBlock);
+ addInstToNewSourceAtom(SwitchInsn, CondV);
+
if (HLSLControlFlowAttr != HLSLControlFlowHintAttr::SpellingNotCalculated) {
llvm::MDBuilder MDHelper(CGM.getLLVMContext());
llvm::ConstantInt *BranchHintConstant =
diff --git a/clang/test/KeyInstructions/switch.c b/clang/test/KeyInstructions/switch.c
new file mode 100644
index 0000000000000..cff6b834106e9
--- /dev/null
+++ b/clang/test/KeyInstructions/switch.c
@@ -0,0 +1,51 @@
+// RUN: %clang -gkey-instructions -x c++ -std=c++17 %s -gmlt -S -emit-llvm -o - \
+// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank --check-prefixes=CHECK,CHECK-CXX
+
+// RUN: %clang -gkey-instructions -x c %s -gmlt -S -emit-llvm -o - \
+// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank
+
+int g;
+void a(int A, int B) {
+// CHECK: entry:
+// The load gets associated with the branch rather than the store.
+// FIXME: Is that the best thing to do?
+// CHECK: %0 = load i32, ptr %A.addr{{.*}}, !dbg [[G2R2:!.*]]
+// CHECK: store i32 %0, ptr @g{{.*}}, !dbg [[G1R1:!.*]]
+// CHECK: switch i32 %0, label %{{.*}} [
+// CHECK: i32 0, label %sw.bb
+// CHECK: i32 1, label %sw.bb1
+// CHECK: ], !dbg [[G2R1:!.*]]
+ switch ((g = A)) {
+ case 0: break;
+ case 1: {
+// CHECK: sw.bb1:
+// CHECK: %1 = load i32, ptr %B.addr{{.*}}, !dbg [[G3R2:!.*]]
+// CHECK: switch i32 %1, label %{{.*}} [
+// CHECK: i32 0, label %sw.bb2
+// CHECK: ], !dbg [[G3R1:!.*]]
+ switch ((B)) {
+ case 0: {
+// Test that assignments in constant-folded switches don't go missing.
+// CHECK-CXX: sw.bb2:
+// CHECK-CXX: store i32 1, ptr %C{{.*}}, !dbg [[G4R1:!.*]]
+#ifdef __cplusplus
+ switch (const int C = 1; C) {
+ case 0: break;
+ case 1: break;
+ default: break;
+ }
+#endif
+ } break;
+ default: break;
+ }
+ } break;
+ default: break;
+ }
+}
+
+// CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2)
+// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
+// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
+// CHECK: [[G3R2]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 2)
+// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
+// CHECK-CXX: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)
|
@llvm/pr-subscribers-clang-codegen Author: Orlando Cazalet-Hyams (OCHyams) ChangesThis patch is part of a stack that teaches Clang to generate Key Instructions The Key Instructions project is introduced, including a "quick summary" section The feature is only functional in LLVM if LLVM is built with CMake flag The Clang-side work is demoed here: Full diff: https://github.com/llvm/llvm-project/pull/134643.diff 2 Files Affected:
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 3562b4ea22a24..7dd82d73d6b6a 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -2276,6 +2276,8 @@ void CodeGenFunction::EmitSwitchStmt(const SwitchStmt &S) {
// failure.
llvm::BasicBlock *DefaultBlock = createBasicBlock("sw.default");
SwitchInsn = Builder.CreateSwitch(CondV, DefaultBlock);
+ addInstToNewSourceAtom(SwitchInsn, CondV);
+
if (HLSLControlFlowAttr != HLSLControlFlowHintAttr::SpellingNotCalculated) {
llvm::MDBuilder MDHelper(CGM.getLLVMContext());
llvm::ConstantInt *BranchHintConstant =
diff --git a/clang/test/KeyInstructions/switch.c b/clang/test/KeyInstructions/switch.c
new file mode 100644
index 0000000000000..cff6b834106e9
--- /dev/null
+++ b/clang/test/KeyInstructions/switch.c
@@ -0,0 +1,51 @@
+// RUN: %clang -gkey-instructions -x c++ -std=c++17 %s -gmlt -S -emit-llvm -o - \
+// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank --check-prefixes=CHECK,CHECK-CXX
+
+// RUN: %clang -gkey-instructions -x c %s -gmlt -S -emit-llvm -o - \
+// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank
+
+int g;
+void a(int A, int B) {
+// CHECK: entry:
+// The load gets associated with the branch rather than the store.
+// FIXME: Is that the best thing to do?
+// CHECK: %0 = load i32, ptr %A.addr{{.*}}, !dbg [[G2R2:!.*]]
+// CHECK: store i32 %0, ptr @g{{.*}}, !dbg [[G1R1:!.*]]
+// CHECK: switch i32 %0, label %{{.*}} [
+// CHECK: i32 0, label %sw.bb
+// CHECK: i32 1, label %sw.bb1
+// CHECK: ], !dbg [[G2R1:!.*]]
+ switch ((g = A)) {
+ case 0: break;
+ case 1: {
+// CHECK: sw.bb1:
+// CHECK: %1 = load i32, ptr %B.addr{{.*}}, !dbg [[G3R2:!.*]]
+// CHECK: switch i32 %1, label %{{.*}} [
+// CHECK: i32 0, label %sw.bb2
+// CHECK: ], !dbg [[G3R1:!.*]]
+ switch ((B)) {
+ case 0: {
+// Test that assignments in constant-folded switches don't go missing.
+// CHECK-CXX: sw.bb2:
+// CHECK-CXX: store i32 1, ptr %C{{.*}}, !dbg [[G4R1:!.*]]
+#ifdef __cplusplus
+ switch (const int C = 1; C) {
+ case 0: break;
+ case 1: break;
+ default: break;
+ }
+#endif
+ } break;
+ default: break;
+ }
+ } break;
+ default: break;
+ }
+}
+
+// CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2)
+// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
+// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
+// CHECK: [[G3R2]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 2)
+// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
+// CHECK-CXX: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)
|
98ea64f
to
2fb58a6
Compare
eeee08d
to
97617b6
Compare
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 with some test nits, please do disagree with those
void a(int A, int B) { | ||
// CHECK: entry: | ||
// The load gets associated with the branch rather than the store. | ||
// FIXME: Is that the best thing to do? |
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.
Interesting -- I wonder what happens when various bits get optimised away:
- The switch probably can't be constant-propagated or otherwise affected without also messing with the load?
- The store could be DSE'd quite easily
I feel the least desirable outcome is one where the switch disappears and the load gets is_stmt, thus leading to the load and store being steps, on the same line. And that seems unlikely to occur given that if the switch can be optimised, then the load has already been optimised.
A long way of saying, this is probably alright.
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.
Consider also that we could have:
switch
((g = A))
{
If the store gets DSE'd and switch stays put, and we have the current setup (load in switch's atom group), then we don't step on ((g = A))
. The store and load are line y
and switch is line x
. So non-key-instructions behaviour in that case is step y, x
whereas with this patch it would be just x
. If we associated the load with the store instead of the switch it'd be y, x
(step on the load then the switch/br).
That's a long way of saying... maybe we should switch it round? I can't remember how tricky it would be. I think at worst it involves adding another param to addInstToNewSourceAtom
to avoid overriding existing groups (atm it won't override an existing group if the new rank designation is lower priority.
We could make that <=
instead too... that would impact the other dual-membership setups which we need to check all make sense after the change.
So - any objection to me adding this to the TODO list instead, to submit it as another patch after the initial stack lands?
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.
SGTM as a TODO
// CHECK-CXX: sw.bb2: | ||
// CHECK-CXX: store i32 1, ptr %C{{.*}}, !dbg [[G4R1:!.*]] |
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.
Shouldn't this be testing for the switch getting a distinct group number too? For completeness if nothing else.
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.
There's no switch emitted as it gets constant folded: https://godbolt.org/z/3vv4qxTMr
This patch is part of a stack that teaches Clang to generate Key Instructions metadata for C and C++. The Key Instructions project is introduced, including a "quick summary" section at the top which adds context for this PR, here: https://discourse.llvm.org/t/rfc-improving-is-stmt-placement-for-better-interactive-debugging/82668 The feature is only functional in LLVM if LLVM is built with CMake flag LLVM_EXPERIMENTAL_KEY_INSTRUCTIONs. Eventually that flag will be removed. The Clang-side work is demoed here: #130943
97617b6
to
2e3a53b
Compare
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
void a(int A, int B) { | ||
// CHECK: entry: | ||
// The load gets associated with the branch rather than the store. | ||
// FIXME: Is that the best thing to do? |
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.
SGTM as a TODO
This patch is part of a stack that teaches Clang to generate Key Instructions
metadata for C and C++.
The Key Instructions project is introduced, including a "quick summary" section
at the top which adds context for this PR, here:
https://discourse.llvm.org/t/rfc-improving-is-stmt-placement-for-better-interactive-debugging/82668
The feature is only functional in LLVM if LLVM is built with CMake flag
LLVM_EXPERIMENTAL_KEY_INSTRUCTIONs. Eventually that flag will be removed.
The Clang-side work is demoed here:
#130943