-
Notifications
You must be signed in to change notification settings - Fork 13.3k
[KeyInstr][Clang] Ret atom #134652
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: users/OCHyams/ki-clang-builtins
Are you sure you want to change the base?
[KeyInstr][Clang] Ret atom #134652
Conversation
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
@llvm/pr-subscribers-clang-codegen Author: Orlando Cazalet-Hyams (OCHyams) Changes[KeyInstr][Clang] Ret atom This 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: [KeyInstr][Clang] Update tests with ret atoms Patch is 21.44 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/134652.diff 21 Files Affected:
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 7aa77e55dbfcc..dba3fadba4f60 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -3883,7 +3883,8 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
// Functions with no result always return void.
if (!ReturnValue.isValid()) {
- Builder.CreateRetVoid();
+ auto *I = Builder.CreateRetVoid();
+ addRetToOverrideOrNewSourceAtom(I, nullptr);
return;
}
@@ -4065,6 +4066,9 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
if (RetDbgLoc)
Ret->setDebugLoc(std::move(RetDbgLoc));
+
+ llvm::Value *Backup = RV ? Ret->getOperand(0) : nullptr;
+ addRetToOverrideOrNewSourceAtom(cast<llvm::ReturnInst>(Ret), Backup);
}
void CodeGenFunction::EmitReturnValueCheck(llvm::Value *RV) {
diff --git a/clang/lib/CodeGen/CGCleanup.cpp b/clang/lib/CodeGen/CGCleanup.cpp
index 7e1c5b7da9552..7292dcd47172c 100644
--- a/clang/lib/CodeGen/CGCleanup.cpp
+++ b/clang/lib/CodeGen/CGCleanup.cpp
@@ -1118,6 +1118,8 @@ void CodeGenFunction::EmitBranchThroughCleanup(JumpDest Dest) {
// Create the branch.
llvm::BranchInst *BI = Builder.CreateBr(Dest.getBlock());
+ // This is the primary instruction for this atom, acting in place of a ret.
+ addInstToCurrentSourceAtom(BI, nullptr);
// Calculate the innermost active normal cleanup.
EHScopeStack::stable_iterator
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 9292be24fc12e..21c2dd14799dd 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -1594,6 +1594,7 @@ static bool isSwiftAsyncCallee(const CallExpr *CE) {
/// if the function returns void, or may be missing one if the function returns
/// non-void. Fun stuff :).
void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
+ ApplyAtomGroup Grp(getDebugInfo());
if (requiresReturnValueCheck()) {
llvm::Constant *SLoc = EmitCheckSourceLocation(S.getBeginLoc());
auto *SLocPtr =
@@ -1603,6 +1604,7 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
CGM.getSanitizerMetadata()->disableSanitizerForGlobal(SLocPtr);
assert(ReturnLocation.isValid() && "No valid return location");
Builder.CreateStore(SLocPtr, ReturnLocation);
+ //*OCH?*//
}
// Returning from an outlined SEH helper is UB, and we already warn on it.
@@ -1669,16 +1671,19 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
// If this function returns a reference, take the address of the expression
// rather than the value.
RValue Result = EmitReferenceBindingToExpr(RV);
- Builder.CreateStore(Result.getScalarVal(), ReturnValue);
+ auto *I = Builder.CreateStore(Result.getScalarVal(), ReturnValue);
+ addInstToCurrentSourceAtom(I, I->getValueOperand());
} else {
switch (getEvaluationKind(RV->getType())) {
case TEK_Scalar: {
llvm::Value *Ret = EmitScalarExpr(RV);
- if (CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect)
+ if (CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect) {
EmitStoreOfScalar(Ret, MakeAddrLValue(ReturnValue, RV->getType()),
/*isInit*/ true);
- else
- Builder.CreateStore(Ret, ReturnValue);
+ } else {
+ auto *I = Builder.CreateStore(Ret, ReturnValue);
+ addInstToCurrentSourceAtom(I, I->getValueOperand());
+ }
break;
}
case TEK_Complex:
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index b176227657f24..a4d2a48d77a17 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -36,6 +36,7 @@
#include "clang/CodeGen/CGFunctionInfo.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/ScopeExit.h"
#include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Dominators.h"
@@ -339,6 +340,15 @@ llvm::DebugLoc CodeGenFunction::EmitReturnBlock() {
// later by the actual 'ret' instruction.
llvm::DebugLoc Loc = BI->getDebugLoc();
Builder.SetInsertPoint(BI->getParent());
+
+ // Key Instructions: If there's only one `ret` then we want to put the
+ // instruction in the same source atom group as the store to the ret-value
+ // alloca and unconditional `br` to the return block that we're about to
+ // delete. It all comes from the same source (`return (value)`).
+ if (auto *DI = getDebugInfo(); DI && BI->getDebugLoc())
+ DI->setRetInstSourceAtomOverride(
+ BI->getDebugLoc().get()->getAtomGroup());
+
BI->eraseFromParent();
delete ReturnBlock.getBlock();
ReturnBlock = JumpDest();
@@ -1543,6 +1553,12 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
Bypasses.Init(CGM, Body);
}
+ // Finalize function debug info on exit.
+ auto Cleanup = llvm::make_scope_exit([this] {
+ if (CGDebugInfo *DI = getDebugInfo())
+ DI->completeFunction();
+ });
+
// Emit the standard function prologue.
StartFunction(GD, ResTy, Fn, FnInfo, Args, Loc, BodyRange.getBegin());
diff --git a/clang/test/KeyInstructions/agg.c b/clang/test/KeyInstructions/agg.c
index 6caf84e89537f..5772922787fd5 100644
--- a/clang/test/KeyInstructions/agg.c
+++ b/clang/test/KeyInstructions/agg.c
@@ -24,6 +24,8 @@ void fun(Struct a) {
// CHECK: %matins = insertelement <25 x float> %3, float 0.000000e+00, i64 0, !dbg [[G4R2:!.*]]
// CHECK: store <25 x float> %matins, ptr @m{{.*}}, !dbg [[G4R1:!.*]]
m[0][0] = 0;
+
+// CHECK: ret{{.*}}, !dbg [[RET:!.*]]
}
// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
@@ -32,3 +34,4 @@ void fun(Struct a) {
// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
// CHECK: [[G4R2]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 2)
// CHECK: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)
+// CHECK: [[RET:!.*]] = !DILocation({{.*}}, atomGroup: [[#]], atomRank: [[#]])
diff --git a/clang/test/KeyInstructions/assign-scalar.c b/clang/test/KeyInstructions/assign-scalar.c
index 1f1fe8fda39e6..801f3c1391e02 100644
--- a/clang/test/KeyInstructions/assign-scalar.c
+++ b/clang/test/KeyInstructions/assign-scalar.c
@@ -34,6 +34,8 @@ void fun() {
// CHECK: %dec = add i64 %3, -1, !dbg [[G6R2:!.*]]
// CHECK: store i64 %dec, ptr @g{{.*}}, !dbg [[G6R1:!.*]]
g--;
+
+// CHECK: ret{{.*}}, !dbg [[RET:!.*]]
}
// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
@@ -46,3 +48,4 @@ void fun() {
// CHECK: [[G5R1]] = !DILocation({{.*}}, atomGroup: 5, atomRank: 1)
// CHECK: [[G6R2]] = !DILocation({{.*}}, atomGroup: 6, atomRank: 2)
// CHECK: [[G6R1]] = !DILocation({{.*}}, atomGroup: 6, atomRank: 1)
+// CHECK: [[RET:!.*]] = !DILocation({{.*}}, atomGroup: [[#]], atomRank: [[#]])
diff --git a/clang/test/KeyInstructions/bitfield.cpp b/clang/test/KeyInstructions/bitfield.cpp
index 0586050ba8397..be470dd7ca029 100644
--- a/clang/test/KeyInstructions/bitfield.cpp
+++ b/clang/test/KeyInstructions/bitfield.cpp
@@ -7,7 +7,10 @@ void foo(int x, S s) {
// CHECK: %bf.set = or i8 %bf.clear, %bf.value, !dbg [[G1R2:!.*]]
// CHECK: store i8 %bf.set, ptr %s, align 4, !dbg [[G1R1:!.*]]
s.a = x;
+
+// CHECK: ret{{.*}}, !dbg [[RET:!.*]]
}
// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2)
// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
+// CHECK: [[RET:!.*]] = !DILocation({{.*}}, atomGroup: [[#]], atomRank: [[#]])
diff --git a/clang/test/KeyInstructions/builtin.c b/clang/test/KeyInstructions/builtin.c
index 5129a4ac2c482..dbf4e287d58f2 100644
--- a/clang/test/KeyInstructions/builtin.c
+++ b/clang/test/KeyInstructions/builtin.c
@@ -57,6 +57,8 @@ void fun() {
// CHECK: call void @llvm.memset{{.*}}, !dbg [[G14R1:!.*]]
__builtin___memset_chk(f4, 0, sizeof(float), -1);
+
+// CHECK: ret{{.*}}, !dbg [[RET:!.*]]
}
// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2)
@@ -75,3 +77,4 @@ void fun() {
// CHECK: [[G12R1]] = !DILocation({{.*}}, atomGroup: 12, atomRank: 1)
// CHECK: [[G13R1]] = !DILocation({{.*}}, atomGroup: 13, atomRank: 1)
// CHECK: [[G14R1]] = !DILocation({{.*}}, atomGroup: 14, atomRank: 1)
+// CHECK: [[RET:!.*]] = !DILocation({{.*}}, atomGroup: [[#]], atomRank: [[#]])
diff --git a/clang/test/KeyInstructions/complex.c b/clang/test/KeyInstructions/complex.c
index b97314e815bdc..86dd098ed93fc 100644
--- a/clang/test/KeyInstructions/complex.c
+++ b/clang/test/KeyInstructions/complex.c
@@ -28,6 +28,8 @@ void test() {
// CHECK: %add = fadd float %0, %1, !dbg [[G4R2:!.*]]
// CHECK: store float %add, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G4R1:!.*]]
__imag ci = __imag ci + __imag ci;
+
+// CHECK: ret{{.*}}, !dbg [[RET:!.*]]
}
// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2)
@@ -38,3 +40,4 @@ void test() {
// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
// CHECK: [[G4R2]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 2)
// CHECK: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)
+// CHECK: [[RET:!.*]] = !DILocation({{.*}}, atomGroup: [[#]], atomRank: [[#]])
diff --git a/clang/test/KeyInstructions/do.c b/clang/test/KeyInstructions/do.c
index 4b7a38cb35985..9778394c5d005 100644
--- a/clang/test/KeyInstructions/do.c
+++ b/clang/test/KeyInstructions/do.c
@@ -25,9 +25,12 @@ void a(int A) {
// CHECK: %tobool = icmp ne i32 %dec, 0, !dbg [[G2R1:!.*]]
// CHECK: br i1 %tobool, label %do.body, label %do.end, !dbg [[G3R1:!.*]], !llvm.loop
do { } while (--A);
+
+// CHECK: ret{{.*}}, !dbg [[RET:!.*]]
}
// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2)
// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
+// CHECK: [[RET:!.*]] = !DILocation({{.*}}, atomGroup: [[#]], atomRank: [[#]])
diff --git a/clang/test/KeyInstructions/for.c b/clang/test/KeyInstructions/for.c
index 3221ece69a717..1336a461eae2b 100644
--- a/clang/test/KeyInstructions/for.c
+++ b/clang/test/KeyInstructions/for.c
@@ -27,6 +27,8 @@ void a(int A) {
// CHECK: %inc = add{{.*}}, !dbg [[G4R2:!.*]]
// CHECK: store i32 %inc, ptr %i{{.*}}, !dbg [[G4R1:!.*]]
for (int i = 0; i < A; ++i) { }
+
+// CHECK: ret{{.*}}, !dbg [[RET:!.*]]
}
// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
@@ -35,3 +37,4 @@ void a(int A) {
// CHECK: [[G5R1]] = !DILocation({{.*}}, atomGroup: 5, atomRank: 1)
// CHECK: [[G4R2]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 2)
// CHECK: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)
+// CHECK: [[RET:!.*]] = !DILocation({{.*}}, atomGroup: [[#]], atomRank: [[#]])
diff --git a/clang/test/KeyInstructions/if.c b/clang/test/KeyInstructions/if.c
index ccc7eb9253198..6fff140db9d01 100644
--- a/clang/test/KeyInstructions/if.c
+++ b/clang/test/KeyInstructions/if.c
@@ -31,7 +31,9 @@ void a(int A) {
// CHECK-CXX: br i1 %tobool4, label %if.then5, label %if.end6{{.*}}, !dbg [[G5R1:!.*]]
if (int B = A; B)
;
-#endif
+#endif
+
+// CHECK: ret{{.*}}, !dbg [[RET:!.*]]
}
// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2)
@@ -44,3 +46,4 @@ void a(int A) {
// CHECK-CXX: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)
// CHECK-CXX: [[G5R2]] = !DILocation({{.*}}, atomGroup: 5, atomRank: 2)
// CHECK-CXX: [[G5R1]] = !DILocation({{.*}}, atomGroup: 5, atomRank: 1)
+// CHECK: [[RET:!.*]] = !DILocation({{.*}}, atomGroup: [[#]], atomRank: [[#]])
diff --git a/clang/test/KeyInstructions/init-agg.c b/clang/test/KeyInstructions/init-agg.c
index dc3ccaedc57b5..1fd0b4909f6ad 100644
--- a/clang/test/KeyInstructions/init-agg.c
+++ b/clang/test/KeyInstructions/init-agg.c
@@ -33,6 +33,8 @@ void a() {
// CHECK: store i8 -86, ptr %uninit{{.*}}, !dbg [[G5R1:!.*]], !annotation
char uninit; // -ftrivial-auto-var-init=pattern
+
+// CHECK: ret{{.*}}, !dbg [[RET:!.*]]
}
// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
@@ -41,3 +43,4 @@ void a() {
// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
// CHECK: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)
// CHECK: [[G5R1]] = !DILocation({{.*}}, atomGroup: 5, atomRank: 1)
+// CHECK: [[RET:!.*]] = !DILocation({{.*}}, atomGroup: [[#]], atomRank: [[#]])
diff --git a/clang/test/KeyInstructions/init-member.cpp b/clang/test/KeyInstructions/init-member.cpp
index 60949bd8a604a..a830fd06acb35 100644
--- a/clang/test/KeyInstructions/init-member.cpp
+++ b/clang/test/KeyInstructions/init-member.cpp
@@ -17,6 +17,8 @@ void fun() {
// CHECK: store i32 1, ptr %x{{.*}}, !dbg [[G1R1:!.*]]
// CHECK: store float 5.000000e+00, ptr %y{{.*}}, !dbg [[G2R1:!.*]]
+// CHECK: ret{{.*}}, !dbg [[RET:!.*]]
// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
+// CHECK: [[RET:!.*]] = !DILocation({{.*}}, atomGroup: [[#]], atomRank: [[#]])
diff --git a/clang/test/KeyInstructions/init-scalar.c b/clang/test/KeyInstructions/init-scalar.c
index c212c2a4fd623..439283b80e3da 100644
--- a/clang/test/KeyInstructions/init-scalar.c
+++ b/clang/test/KeyInstructions/init-scalar.c
@@ -10,10 +10,10 @@ void a() {
// CHECK: %add = add {{.*}}, !dbg [[G2R2:!.*]]
// CHECK: store i32 %add, ptr %B, align 4, !dbg [[G2R1:!.*]]
int B = 2 * A + 1;
-// CHECK-TODO: ret{{.*}}, !dbg [[G3R1:!.*]]
+// CHECK: ret{{.*}}, !dbg [[G3R1:!.*]]
}
// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
// CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2)
// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
-// CHECK-TODO: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
+// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
diff --git a/clang/test/KeyInstructions/init-static.cpp b/clang/test/KeyInstructions/init-static.cpp
index 82e14b59df5e5..5f5ea75662038 100644
--- a/clang/test/KeyInstructions/init-static.cpp
+++ b/clang/test/KeyInstructions/init-static.cpp
@@ -5,8 +5,9 @@ void g(int *a) {
// CHECK: %2 = load ptr, ptr %a.addr{{.*}}, !dbg [[G1R2:!.*]]
// CHECK: store ptr %2, ptr @_ZZ1gPiE1b{{.*}}, !dbg [[G1R1:!.*]]
static int &b = *a;
+// CHECK: ret{{.*}}, !dbg [[RET:!.*]]
}
// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2)
// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
-
+// CHECK: [[RET:!.*]] = !DILocation({{.*}}, atomGroup: [[#]], atomRank: [[#]])
diff --git a/clang/test/KeyInstructions/return-va-arg.c b/clang/test/KeyInstructions/return-va-arg.c
new file mode 100644
index 0000000000000..2864489afd738
--- /dev/null
+++ b/clang/test/KeyInstructions/return-va-arg.c
@@ -0,0 +1,25 @@
+// RUN: %clang -gkey-instructions -gno-column-info -x c++ %s -gmlt -S -emit-llvm -o - \
+// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank
+
+// RUN: %clang -gkey-instructions -gno-column-info -x c %s -gmlt -S -emit-llvm -o - \
+// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank
+
+typedef struct {
+ struct{} a;
+ double b;
+} s1;
+
+s1 f(int z, ...) {
+ __builtin_va_list list;
+ __builtin_va_start(list, z);
+// CHECK: vaarg.end:
+// CHECK-NEXT: %vaarg.addr = phi ptr
+// CHECK-NEXT: call void @llvm.memcpy{{.*}}, !dbg [[G1R1:!.*]]
+// CHECK-NEXT: {{.*}} = getelementptr{{.*}}
+// CHECK-NEXT: [[LOAD:%.*]] = load double{{.*}}, !dbg [[G1R2:!.*]]
+// CHECK-NEXT: ret double [[LOAD]], !dbg [[G1R1]]
+ return __builtin_va_arg(list, s1);
+}
+
+// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
+// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2)
diff --git a/clang/test/KeyInstructions/return.c b/clang/test/KeyInstructions/return.c
new file mode 100644
index 0000000000000..24c58450d37ed
--- /dev/null
+++ b/clang/test/KeyInstructions/return.c
@@ -0,0 +1,90 @@
+// RUN: %clang -gkey-instructions -gno-column-info -x c++ %s -gmlt -S -emit-llvm -o - \
+// RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-CXX
+
+// RUN: %clang -gkey-instructions -gno-column-info -x c %s -gmlt -S -emit-llvm -o - \
+// RUN: | FileCheck %s
+
+// Check the stores to `retval` allocas and branches to `return` block are in
+// the same atom group. They are both rank 1, which could in theory introduce
+// an extra step in some optimized code. This low risk currently feels an
+// acceptable for keeping the code a bit simpler (as opposed to adding
+// scaffolding to make the store rank 2).
+
+// Also check that in the case of a single return (no control flow) the
+// return instruction inherits the atom group of the branch to the return
+// block when the blocks get folded togather.
+
+#ifdef __cplusplus
+#define nomangle extern "C"
+#else
+#define nomangle
+#endif
+
+int g;
+nomangle float a() {
+// CHECK: float @a()
+ if (g)
+// CHECK: if.then:
+// CHECK-NEXT: %1 = load i32, ptr @g{{.*}}, !dbg [[G2R3:!.*]]
+// CHECK-NEXT: %conv = sitofp i32 %1 to float{{.*}}, !dbg [[G2R2:!.*]]
+// CHECK-NEXT: store float %conv, ptr %retval{{.*}}, !dbg [[G2R1:!.*]]
+// CHECK-NEXT: br label %return{{.*}}, !dbg [[G2R1]]
+ return g;
+// CHECK: if.end:
+// CHECK-NEXT: store float 1.000000e+00, ptr %retval{{.*}}, !dbg [[G3R1:!.*]]
+// CHECK-NEXT: br label %return, !dbg [[G3R1]]
+
+// CHECK: return:
+// CHECK-NEXT: %2 = load float, ptr %retval{{.*}}, !dbg [[G4R2:!.*]]
+// CHECK-NEXT: ret float %2{{.*}}, !dbg [[G4R1:!.*]]
+ return 1;
+}
+
+// CHECK: void @b()
+// CHECK: ret void{{.*}}, !dbg [[B_G1R1:!.*]]
+nomangle void b() { return; }
+
+// CHECK: i32 @c()
+// CHECK: %add = add{{.*}}, !dbg [[C_G1R2:!.*]]
+// CHECK: ret i32 %add{{.*}}, !dbg [[C_G1R1:!.*]]
+nomangle int c() { return g + 1; }
+
+// NOTE: (return) (g = 1) are two separate atoms.
+// CHECK: i32 @d()
+// CHECK: store{{.*}}, !dbg [[D_G2R1:!.*]]
+// CHECK: ret i32 1{{.*}}, !dbg [[D_G1R1:!.*]]
+nomangle int d() { return g = 1; }
+
+// The implicit return here get the line number of the closing brace; make it
+// key to match existing behaviour.
+// CHECK: ret void, !dbg [[E_G1R1:!.*]]
+nomangle void e() {}
+
+#ifdef __cplusplus
+// CHECK-CXX: ptr @_Z1fRi
+int &f(int &r) {
+// Include ctrl-flow to stop ret value store being elided.
+ if (r)
+// CHECK-CXX: if.then:
+// CHECK-CXX-NEXT: %2 = load ptr, ptr %r.addr{{.*}}, !dbg [[F_G2R2:!.*]]
+// CHECK-CXX-NEXT: store ptr %2, ptr %retval{{.*}}, !dbg [[F_G2R1:!.*]]
+// CHECK-CXX-NEXT: br label %return, !dbg [[F_G2R1:!.*]]
+ return r;
+ return g;
+}
+#endif
+
+// CHECK: [[G2R3]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 3)
+// CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2)
+// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
+// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
+// CHECK: [[G4R2]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 2)
+// CHECK: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)
+// CHECK: [[B_G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
+// CHECK: [[C_G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2)
+// CHECK: [[C_G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
+// CHECK: [[D_G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
+// CHECK: [[D_G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
+// CHECK: [[E_G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
+// CHECK-CXX: [[F_G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2)
+// CHECK-CXX: [[F_G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
diff --git a/clang/test/KeyInstructions/switch.c b/clang/test/KeyInstructions/switch.c
index cff6b834106e9..32485156a8be1 100644
--- a/clang/test/KeyInstructions/switch.c
+++ b/clang/test/KeyInstructions/switch.c
@@ -41,6 +41,8 @@ void a(int A, int B) {
} break;
default: break;
}
+
+// CHECK: ret{{.*}}, !dbg [[RET:!.*]]
}
// CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2)
@@ -49,3 +51,4 @@ void a(int A, int B) {
// CHECK: [[G3R2]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 2)
// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
// CHECK-CXX: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)
+// CHECK: [[RET:!.*]] = !DILocation({{.*}}, atomGroup: [[#]]...
[truncated]
|
@llvm/pr-subscribers-clang Author: Orlando Cazalet-Hyams (OCHyams) Changes[KeyInstr][Clang] Ret atom This 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: [KeyInstr][Clang] Update tests with ret atoms Patch is 21.44 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/134652.diff 21 Files Affected:
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 7aa77e55dbfcc..dba3fadba4f60 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -3883,7 +3883,8 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
// Functions with no result always return void.
if (!ReturnValue.isValid()) {
- Builder.CreateRetVoid();
+ auto *I = Builder.CreateRetVoid();
+ addRetToOverrideOrNewSourceAtom(I, nullptr);
return;
}
@@ -4065,6 +4066,9 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI,
if (RetDbgLoc)
Ret->setDebugLoc(std::move(RetDbgLoc));
+
+ llvm::Value *Backup = RV ? Ret->getOperand(0) : nullptr;
+ addRetToOverrideOrNewSourceAtom(cast<llvm::ReturnInst>(Ret), Backup);
}
void CodeGenFunction::EmitReturnValueCheck(llvm::Value *RV) {
diff --git a/clang/lib/CodeGen/CGCleanup.cpp b/clang/lib/CodeGen/CGCleanup.cpp
index 7e1c5b7da9552..7292dcd47172c 100644
--- a/clang/lib/CodeGen/CGCleanup.cpp
+++ b/clang/lib/CodeGen/CGCleanup.cpp
@@ -1118,6 +1118,8 @@ void CodeGenFunction::EmitBranchThroughCleanup(JumpDest Dest) {
// Create the branch.
llvm::BranchInst *BI = Builder.CreateBr(Dest.getBlock());
+ // This is the primary instruction for this atom, acting in place of a ret.
+ addInstToCurrentSourceAtom(BI, nullptr);
// Calculate the innermost active normal cleanup.
EHScopeStack::stable_iterator
diff --git a/clang/lib/CodeGen/CGStmt.cpp b/clang/lib/CodeGen/CGStmt.cpp
index 9292be24fc12e..21c2dd14799dd 100644
--- a/clang/lib/CodeGen/CGStmt.cpp
+++ b/clang/lib/CodeGen/CGStmt.cpp
@@ -1594,6 +1594,7 @@ static bool isSwiftAsyncCallee(const CallExpr *CE) {
/// if the function returns void, or may be missing one if the function returns
/// non-void. Fun stuff :).
void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
+ ApplyAtomGroup Grp(getDebugInfo());
if (requiresReturnValueCheck()) {
llvm::Constant *SLoc = EmitCheckSourceLocation(S.getBeginLoc());
auto *SLocPtr =
@@ -1603,6 +1604,7 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
CGM.getSanitizerMetadata()->disableSanitizerForGlobal(SLocPtr);
assert(ReturnLocation.isValid() && "No valid return location");
Builder.CreateStore(SLocPtr, ReturnLocation);
+ //*OCH?*//
}
// Returning from an outlined SEH helper is UB, and we already warn on it.
@@ -1669,16 +1671,19 @@ void CodeGenFunction::EmitReturnStmt(const ReturnStmt &S) {
// If this function returns a reference, take the address of the expression
// rather than the value.
RValue Result = EmitReferenceBindingToExpr(RV);
- Builder.CreateStore(Result.getScalarVal(), ReturnValue);
+ auto *I = Builder.CreateStore(Result.getScalarVal(), ReturnValue);
+ addInstToCurrentSourceAtom(I, I->getValueOperand());
} else {
switch (getEvaluationKind(RV->getType())) {
case TEK_Scalar: {
llvm::Value *Ret = EmitScalarExpr(RV);
- if (CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect)
+ if (CurFnInfo->getReturnInfo().getKind() == ABIArgInfo::Indirect) {
EmitStoreOfScalar(Ret, MakeAddrLValue(ReturnValue, RV->getType()),
/*isInit*/ true);
- else
- Builder.CreateStore(Ret, ReturnValue);
+ } else {
+ auto *I = Builder.CreateStore(Ret, ReturnValue);
+ addInstToCurrentSourceAtom(I, I->getValueOperand());
+ }
break;
}
case TEK_Complex:
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index b176227657f24..a4d2a48d77a17 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -36,6 +36,7 @@
#include "clang/CodeGen/CGFunctionInfo.h"
#include "clang/Frontend/FrontendDiagnostic.h"
#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/ScopeExit.h"
#include "llvm/Frontend/OpenMP/OMPIRBuilder.h"
#include "llvm/IR/DataLayout.h"
#include "llvm/IR/Dominators.h"
@@ -339,6 +340,15 @@ llvm::DebugLoc CodeGenFunction::EmitReturnBlock() {
// later by the actual 'ret' instruction.
llvm::DebugLoc Loc = BI->getDebugLoc();
Builder.SetInsertPoint(BI->getParent());
+
+ // Key Instructions: If there's only one `ret` then we want to put the
+ // instruction in the same source atom group as the store to the ret-value
+ // alloca and unconditional `br` to the return block that we're about to
+ // delete. It all comes from the same source (`return (value)`).
+ if (auto *DI = getDebugInfo(); DI && BI->getDebugLoc())
+ DI->setRetInstSourceAtomOverride(
+ BI->getDebugLoc().get()->getAtomGroup());
+
BI->eraseFromParent();
delete ReturnBlock.getBlock();
ReturnBlock = JumpDest();
@@ -1543,6 +1553,12 @@ void CodeGenFunction::GenerateCode(GlobalDecl GD, llvm::Function *Fn,
Bypasses.Init(CGM, Body);
}
+ // Finalize function debug info on exit.
+ auto Cleanup = llvm::make_scope_exit([this] {
+ if (CGDebugInfo *DI = getDebugInfo())
+ DI->completeFunction();
+ });
+
// Emit the standard function prologue.
StartFunction(GD, ResTy, Fn, FnInfo, Args, Loc, BodyRange.getBegin());
diff --git a/clang/test/KeyInstructions/agg.c b/clang/test/KeyInstructions/agg.c
index 6caf84e89537f..5772922787fd5 100644
--- a/clang/test/KeyInstructions/agg.c
+++ b/clang/test/KeyInstructions/agg.c
@@ -24,6 +24,8 @@ void fun(Struct a) {
// CHECK: %matins = insertelement <25 x float> %3, float 0.000000e+00, i64 0, !dbg [[G4R2:!.*]]
// CHECK: store <25 x float> %matins, ptr @m{{.*}}, !dbg [[G4R1:!.*]]
m[0][0] = 0;
+
+// CHECK: ret{{.*}}, !dbg [[RET:!.*]]
}
// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
@@ -32,3 +34,4 @@ void fun(Struct a) {
// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
// CHECK: [[G4R2]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 2)
// CHECK: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)
+// CHECK: [[RET:!.*]] = !DILocation({{.*}}, atomGroup: [[#]], atomRank: [[#]])
diff --git a/clang/test/KeyInstructions/assign-scalar.c b/clang/test/KeyInstructions/assign-scalar.c
index 1f1fe8fda39e6..801f3c1391e02 100644
--- a/clang/test/KeyInstructions/assign-scalar.c
+++ b/clang/test/KeyInstructions/assign-scalar.c
@@ -34,6 +34,8 @@ void fun() {
// CHECK: %dec = add i64 %3, -1, !dbg [[G6R2:!.*]]
// CHECK: store i64 %dec, ptr @g{{.*}}, !dbg [[G6R1:!.*]]
g--;
+
+// CHECK: ret{{.*}}, !dbg [[RET:!.*]]
}
// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
@@ -46,3 +48,4 @@ void fun() {
// CHECK: [[G5R1]] = !DILocation({{.*}}, atomGroup: 5, atomRank: 1)
// CHECK: [[G6R2]] = !DILocation({{.*}}, atomGroup: 6, atomRank: 2)
// CHECK: [[G6R1]] = !DILocation({{.*}}, atomGroup: 6, atomRank: 1)
+// CHECK: [[RET:!.*]] = !DILocation({{.*}}, atomGroup: [[#]], atomRank: [[#]])
diff --git a/clang/test/KeyInstructions/bitfield.cpp b/clang/test/KeyInstructions/bitfield.cpp
index 0586050ba8397..be470dd7ca029 100644
--- a/clang/test/KeyInstructions/bitfield.cpp
+++ b/clang/test/KeyInstructions/bitfield.cpp
@@ -7,7 +7,10 @@ void foo(int x, S s) {
// CHECK: %bf.set = or i8 %bf.clear, %bf.value, !dbg [[G1R2:!.*]]
// CHECK: store i8 %bf.set, ptr %s, align 4, !dbg [[G1R1:!.*]]
s.a = x;
+
+// CHECK: ret{{.*}}, !dbg [[RET:!.*]]
}
// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2)
// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
+// CHECK: [[RET:!.*]] = !DILocation({{.*}}, atomGroup: [[#]], atomRank: [[#]])
diff --git a/clang/test/KeyInstructions/builtin.c b/clang/test/KeyInstructions/builtin.c
index 5129a4ac2c482..dbf4e287d58f2 100644
--- a/clang/test/KeyInstructions/builtin.c
+++ b/clang/test/KeyInstructions/builtin.c
@@ -57,6 +57,8 @@ void fun() {
// CHECK: call void @llvm.memset{{.*}}, !dbg [[G14R1:!.*]]
__builtin___memset_chk(f4, 0, sizeof(float), -1);
+
+// CHECK: ret{{.*}}, !dbg [[RET:!.*]]
}
// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2)
@@ -75,3 +77,4 @@ void fun() {
// CHECK: [[G12R1]] = !DILocation({{.*}}, atomGroup: 12, atomRank: 1)
// CHECK: [[G13R1]] = !DILocation({{.*}}, atomGroup: 13, atomRank: 1)
// CHECK: [[G14R1]] = !DILocation({{.*}}, atomGroup: 14, atomRank: 1)
+// CHECK: [[RET:!.*]] = !DILocation({{.*}}, atomGroup: [[#]], atomRank: [[#]])
diff --git a/clang/test/KeyInstructions/complex.c b/clang/test/KeyInstructions/complex.c
index b97314e815bdc..86dd098ed93fc 100644
--- a/clang/test/KeyInstructions/complex.c
+++ b/clang/test/KeyInstructions/complex.c
@@ -28,6 +28,8 @@ void test() {
// CHECK: %add = fadd float %0, %1, !dbg [[G4R2:!.*]]
// CHECK: store float %add, ptr getelementptr inbounds nuw ({ float, float }, ptr @ci, i32 0, i32 1){{.*}}, !dbg [[G4R1:!.*]]
__imag ci = __imag ci + __imag ci;
+
+// CHECK: ret{{.*}}, !dbg [[RET:!.*]]
}
// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2)
@@ -38,3 +40,4 @@ void test() {
// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
// CHECK: [[G4R2]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 2)
// CHECK: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)
+// CHECK: [[RET:!.*]] = !DILocation({{.*}}, atomGroup: [[#]], atomRank: [[#]])
diff --git a/clang/test/KeyInstructions/do.c b/clang/test/KeyInstructions/do.c
index 4b7a38cb35985..9778394c5d005 100644
--- a/clang/test/KeyInstructions/do.c
+++ b/clang/test/KeyInstructions/do.c
@@ -25,9 +25,12 @@ void a(int A) {
// CHECK: %tobool = icmp ne i32 %dec, 0, !dbg [[G2R1:!.*]]
// CHECK: br i1 %tobool, label %do.body, label %do.end, !dbg [[G3R1:!.*]], !llvm.loop
do { } while (--A);
+
+// CHECK: ret{{.*}}, !dbg [[RET:!.*]]
}
// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2)
// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
+// CHECK: [[RET:!.*]] = !DILocation({{.*}}, atomGroup: [[#]], atomRank: [[#]])
diff --git a/clang/test/KeyInstructions/for.c b/clang/test/KeyInstructions/for.c
index 3221ece69a717..1336a461eae2b 100644
--- a/clang/test/KeyInstructions/for.c
+++ b/clang/test/KeyInstructions/for.c
@@ -27,6 +27,8 @@ void a(int A) {
// CHECK: %inc = add{{.*}}, !dbg [[G4R2:!.*]]
// CHECK: store i32 %inc, ptr %i{{.*}}, !dbg [[G4R1:!.*]]
for (int i = 0; i < A; ++i) { }
+
+// CHECK: ret{{.*}}, !dbg [[RET:!.*]]
}
// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
@@ -35,3 +37,4 @@ void a(int A) {
// CHECK: [[G5R1]] = !DILocation({{.*}}, atomGroup: 5, atomRank: 1)
// CHECK: [[G4R2]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 2)
// CHECK: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)
+// CHECK: [[RET:!.*]] = !DILocation({{.*}}, atomGroup: [[#]], atomRank: [[#]])
diff --git a/clang/test/KeyInstructions/if.c b/clang/test/KeyInstructions/if.c
index ccc7eb9253198..6fff140db9d01 100644
--- a/clang/test/KeyInstructions/if.c
+++ b/clang/test/KeyInstructions/if.c
@@ -31,7 +31,9 @@ void a(int A) {
// CHECK-CXX: br i1 %tobool4, label %if.then5, label %if.end6{{.*}}, !dbg [[G5R1:!.*]]
if (int B = A; B)
;
-#endif
+#endif
+
+// CHECK: ret{{.*}}, !dbg [[RET:!.*]]
}
// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2)
@@ -44,3 +46,4 @@ void a(int A) {
// CHECK-CXX: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)
// CHECK-CXX: [[G5R2]] = !DILocation({{.*}}, atomGroup: 5, atomRank: 2)
// CHECK-CXX: [[G5R1]] = !DILocation({{.*}}, atomGroup: 5, atomRank: 1)
+// CHECK: [[RET:!.*]] = !DILocation({{.*}}, atomGroup: [[#]], atomRank: [[#]])
diff --git a/clang/test/KeyInstructions/init-agg.c b/clang/test/KeyInstructions/init-agg.c
index dc3ccaedc57b5..1fd0b4909f6ad 100644
--- a/clang/test/KeyInstructions/init-agg.c
+++ b/clang/test/KeyInstructions/init-agg.c
@@ -33,6 +33,8 @@ void a() {
// CHECK: store i8 -86, ptr %uninit{{.*}}, !dbg [[G5R1:!.*]], !annotation
char uninit; // -ftrivial-auto-var-init=pattern
+
+// CHECK: ret{{.*}}, !dbg [[RET:!.*]]
}
// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
@@ -41,3 +43,4 @@ void a() {
// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
// CHECK: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)
// CHECK: [[G5R1]] = !DILocation({{.*}}, atomGroup: 5, atomRank: 1)
+// CHECK: [[RET:!.*]] = !DILocation({{.*}}, atomGroup: [[#]], atomRank: [[#]])
diff --git a/clang/test/KeyInstructions/init-member.cpp b/clang/test/KeyInstructions/init-member.cpp
index 60949bd8a604a..a830fd06acb35 100644
--- a/clang/test/KeyInstructions/init-member.cpp
+++ b/clang/test/KeyInstructions/init-member.cpp
@@ -17,6 +17,8 @@ void fun() {
// CHECK: store i32 1, ptr %x{{.*}}, !dbg [[G1R1:!.*]]
// CHECK: store float 5.000000e+00, ptr %y{{.*}}, !dbg [[G2R1:!.*]]
+// CHECK: ret{{.*}}, !dbg [[RET:!.*]]
// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
+// CHECK: [[RET:!.*]] = !DILocation({{.*}}, atomGroup: [[#]], atomRank: [[#]])
diff --git a/clang/test/KeyInstructions/init-scalar.c b/clang/test/KeyInstructions/init-scalar.c
index c212c2a4fd623..439283b80e3da 100644
--- a/clang/test/KeyInstructions/init-scalar.c
+++ b/clang/test/KeyInstructions/init-scalar.c
@@ -10,10 +10,10 @@ void a() {
// CHECK: %add = add {{.*}}, !dbg [[G2R2:!.*]]
// CHECK: store i32 %add, ptr %B, align 4, !dbg [[G2R1:!.*]]
int B = 2 * A + 1;
-// CHECK-TODO: ret{{.*}}, !dbg [[G3R1:!.*]]
+// CHECK: ret{{.*}}, !dbg [[G3R1:!.*]]
}
// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
// CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2)
// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
-// CHECK-TODO: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
+// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
diff --git a/clang/test/KeyInstructions/init-static.cpp b/clang/test/KeyInstructions/init-static.cpp
index 82e14b59df5e5..5f5ea75662038 100644
--- a/clang/test/KeyInstructions/init-static.cpp
+++ b/clang/test/KeyInstructions/init-static.cpp
@@ -5,8 +5,9 @@ void g(int *a) {
// CHECK: %2 = load ptr, ptr %a.addr{{.*}}, !dbg [[G1R2:!.*]]
// CHECK: store ptr %2, ptr @_ZZ1gPiE1b{{.*}}, !dbg [[G1R1:!.*]]
static int &b = *a;
+// CHECK: ret{{.*}}, !dbg [[RET:!.*]]
}
// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2)
// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
-
+// CHECK: [[RET:!.*]] = !DILocation({{.*}}, atomGroup: [[#]], atomRank: [[#]])
diff --git a/clang/test/KeyInstructions/return-va-arg.c b/clang/test/KeyInstructions/return-va-arg.c
new file mode 100644
index 0000000000000..2864489afd738
--- /dev/null
+++ b/clang/test/KeyInstructions/return-va-arg.c
@@ -0,0 +1,25 @@
+// RUN: %clang -gkey-instructions -gno-column-info -x c++ %s -gmlt -S -emit-llvm -o - \
+// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank
+
+// RUN: %clang -gkey-instructions -gno-column-info -x c %s -gmlt -S -emit-llvm -o - \
+// RUN: | FileCheck %s --implicit-check-not atomGroup --implicit-check-not atomRank
+
+typedef struct {
+ struct{} a;
+ double b;
+} s1;
+
+s1 f(int z, ...) {
+ __builtin_va_list list;
+ __builtin_va_start(list, z);
+// CHECK: vaarg.end:
+// CHECK-NEXT: %vaarg.addr = phi ptr
+// CHECK-NEXT: call void @llvm.memcpy{{.*}}, !dbg [[G1R1:!.*]]
+// CHECK-NEXT: {{.*}} = getelementptr{{.*}}
+// CHECK-NEXT: [[LOAD:%.*]] = load double{{.*}}, !dbg [[G1R2:!.*]]
+// CHECK-NEXT: ret double [[LOAD]], !dbg [[G1R1]]
+ return __builtin_va_arg(list, s1);
+}
+
+// CHECK: [[G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
+// CHECK: [[G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2)
diff --git a/clang/test/KeyInstructions/return.c b/clang/test/KeyInstructions/return.c
new file mode 100644
index 0000000000000..24c58450d37ed
--- /dev/null
+++ b/clang/test/KeyInstructions/return.c
@@ -0,0 +1,90 @@
+// RUN: %clang -gkey-instructions -gno-column-info -x c++ %s -gmlt -S -emit-llvm -o - \
+// RUN: | FileCheck %s --check-prefixes=CHECK,CHECK-CXX
+
+// RUN: %clang -gkey-instructions -gno-column-info -x c %s -gmlt -S -emit-llvm -o - \
+// RUN: | FileCheck %s
+
+// Check the stores to `retval` allocas and branches to `return` block are in
+// the same atom group. They are both rank 1, which could in theory introduce
+// an extra step in some optimized code. This low risk currently feels an
+// acceptable for keeping the code a bit simpler (as opposed to adding
+// scaffolding to make the store rank 2).
+
+// Also check that in the case of a single return (no control flow) the
+// return instruction inherits the atom group of the branch to the return
+// block when the blocks get folded togather.
+
+#ifdef __cplusplus
+#define nomangle extern "C"
+#else
+#define nomangle
+#endif
+
+int g;
+nomangle float a() {
+// CHECK: float @a()
+ if (g)
+// CHECK: if.then:
+// CHECK-NEXT: %1 = load i32, ptr @g{{.*}}, !dbg [[G2R3:!.*]]
+// CHECK-NEXT: %conv = sitofp i32 %1 to float{{.*}}, !dbg [[G2R2:!.*]]
+// CHECK-NEXT: store float %conv, ptr %retval{{.*}}, !dbg [[G2R1:!.*]]
+// CHECK-NEXT: br label %return{{.*}}, !dbg [[G2R1]]
+ return g;
+// CHECK: if.end:
+// CHECK-NEXT: store float 1.000000e+00, ptr %retval{{.*}}, !dbg [[G3R1:!.*]]
+// CHECK-NEXT: br label %return, !dbg [[G3R1]]
+
+// CHECK: return:
+// CHECK-NEXT: %2 = load float, ptr %retval{{.*}}, !dbg [[G4R2:!.*]]
+// CHECK-NEXT: ret float %2{{.*}}, !dbg [[G4R1:!.*]]
+ return 1;
+}
+
+// CHECK: void @b()
+// CHECK: ret void{{.*}}, !dbg [[B_G1R1:!.*]]
+nomangle void b() { return; }
+
+// CHECK: i32 @c()
+// CHECK: %add = add{{.*}}, !dbg [[C_G1R2:!.*]]
+// CHECK: ret i32 %add{{.*}}, !dbg [[C_G1R1:!.*]]
+nomangle int c() { return g + 1; }
+
+// NOTE: (return) (g = 1) are two separate atoms.
+// CHECK: i32 @d()
+// CHECK: store{{.*}}, !dbg [[D_G2R1:!.*]]
+// CHECK: ret i32 1{{.*}}, !dbg [[D_G1R1:!.*]]
+nomangle int d() { return g = 1; }
+
+// The implicit return here get the line number of the closing brace; make it
+// key to match existing behaviour.
+// CHECK: ret void, !dbg [[E_G1R1:!.*]]
+nomangle void e() {}
+
+#ifdef __cplusplus
+// CHECK-CXX: ptr @_Z1fRi
+int &f(int &r) {
+// Include ctrl-flow to stop ret value store being elided.
+ if (r)
+// CHECK-CXX: if.then:
+// CHECK-CXX-NEXT: %2 = load ptr, ptr %r.addr{{.*}}, !dbg [[F_G2R2:!.*]]
+// CHECK-CXX-NEXT: store ptr %2, ptr %retval{{.*}}, !dbg [[F_G2R1:!.*]]
+// CHECK-CXX-NEXT: br label %return, !dbg [[F_G2R1:!.*]]
+ return r;
+ return g;
+}
+#endif
+
+// CHECK: [[G2R3]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 3)
+// CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2)
+// CHECK: [[G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
+// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
+// CHECK: [[G4R2]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 2)
+// CHECK: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)
+// CHECK: [[B_G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
+// CHECK: [[C_G1R2]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 2)
+// CHECK: [[C_G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
+// CHECK: [[D_G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
+// CHECK: [[D_G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
+// CHECK: [[E_G1R1]] = !DILocation({{.*}}, atomGroup: 1, atomRank: 1)
+// CHECK-CXX: [[F_G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2)
+// CHECK-CXX: [[F_G2R1]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 1)
diff --git a/clang/test/KeyInstructions/switch.c b/clang/test/KeyInstructions/switch.c
index cff6b834106e9..32485156a8be1 100644
--- a/clang/test/KeyInstructions/switch.c
+++ b/clang/test/KeyInstructions/switch.c
@@ -41,6 +41,8 @@ void a(int A, int B) {
} break;
default: break;
}
+
+// CHECK: ret{{.*}}, !dbg [[RET:!.*]]
}
// CHECK: [[G2R2]] = !DILocation({{.*}}, atomGroup: 2, atomRank: 2)
@@ -49,3 +51,4 @@ void a(int A, int B) {
// CHECK: [[G3R2]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 2)
// CHECK: [[G3R1]] = !DILocation({{.*}}, atomGroup: 3, atomRank: 1)
// CHECK-CXX: [[G4R1]] = !DILocation({{.*}}, atomGroup: 4, atomRank: 1)
+// CHECK: [[RET:!.*]] = !DILocation({{.*}}, atomGroup: [[#]]...
[truncated]
|
[KeyInstr][Clang] Ret atom
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
[KeyInstr][Clang] Update tests with ret atoms