[clang] [Clang] Add fake use emission to Clang with -fextend-lifetimes (PR #110102)

via cfe-commits cfe-commits at lists.llvm.org
Thu Sep 26 03:32:29 PDT 2024


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Stephen Tozer (SLTozer)

<details>
<summary>Changes</summary>

Following the [previous patch](https://github.com/llvm/llvm-project/pull/110000) which adds the "extend lifetimes" flag without (almost) any functionality, this patch adds the real feature by allowing Clang to emit fake uses. These are emitted as a new form of cleanup, set for variable addresses, which just emits a fake use intrinsic when the variable falls out of scope. The code for achieving this is simple, with most of the logic centered on determining whether to emit a fake use for a given address, and on ensuring that fake uses are ignored in a few cases.

All code originally written by @<!-- -->wolfy1961, while I'll be handling the review.

---

Patch is 26.63 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/110102.diff


21 Files Affected:

- (modified) clang/lib/CodeGen/CGCall.cpp (+20-10) 
- (modified) clang/lib/CodeGen/CGCleanup.cpp (+5-2) 
- (modified) clang/lib/CodeGen/CGCleanup.h (+8) 
- (modified) clang/lib/CodeGen/CGDecl.cpp (+69) 
- (modified) clang/lib/CodeGen/CodeGenFunction.cpp (+3-3) 
- (modified) clang/lib/CodeGen/CodeGenFunction.h (+16) 
- (modified) clang/lib/CodeGen/CodeGenModule.h (+4) 
- (modified) clang/lib/CodeGen/EHScopeStack.h (+7-2) 
- (added) clang/test/CodeGen/extend-liveness1.c (+29) 
- (added) clang/test/CodeGen/extend-liveness2.cpp (+34) 
- (added) clang/test/CodeGen/fake-use-determinism.c (+18) 
- (added) clang/test/CodeGen/fake-use-lambda.cpp (+43) 
- (added) clang/test/CodeGen/fake-use-landingpad.c (+16) 
- (added) clang/test/CodeGen/fake-use-noreturn.cpp (+27) 
- (added) clang/test/CodeGen/fake-use-return-line.c (+15) 
- (added) clang/test/CodeGen/fake-use-sanitizer.cpp (+37) 
- (added) clang/test/CodeGen/fake-use-scalar.c (+22) 
- (added) clang/test/CodeGen/fake-use-small-aggs.c (+24) 
- (added) clang/test/CodeGen/fake-use-while.c (+18) 
- (added) clang/test/CodeGen/fake-use.cpp (+44) 
- (added) clang/test/CodeGen/no-fake-use-O0.cpp (+50) 


``````````diff
diff --git a/clang/lib/CodeGen/CGCall.cpp b/clang/lib/CodeGen/CGCall.cpp
index 4ae981e4013e9c..13c556a4e20a13 100644
--- a/clang/lib/CodeGen/CGCall.cpp
+++ b/clang/lib/CodeGen/CGCall.cpp
@@ -3566,16 +3566,26 @@ static llvm::StoreInst *findDominatingStoreToReturnValue(CodeGenFunction &CGF) {
     llvm::BasicBlock *IP = CGF.Builder.GetInsertBlock();
     if (IP->empty()) return nullptr;
 
-    // Look at directly preceding instruction, skipping bitcasts and lifetime
-    // markers.
-    for (llvm::Instruction &I : make_range(IP->rbegin(), IP->rend())) {
-      if (isa<llvm::BitCastInst>(&I))
-        continue;
-      if (auto *II = dyn_cast<llvm::IntrinsicInst>(&I))
-        if (II->getIntrinsicID() == llvm::Intrinsic::lifetime_end)
-          continue;
-
-      return GetStoreIfValid(&I);
+   // Look at directly preceding instruction, skipping bitcasts, lifetime
+   // markers, and fake uses and their operands.
+   const llvm::Instruction *LoadIntoFakeUse = nullptr;
+   for (llvm::Instruction &I : make_range(IP->rbegin(), IP->rend())) {
+     // Ignore instructions that are just loads for fake uses; the load should
+     // immediately precede the fake use, so we only need to remember the
+     // operand for the last fake use seen.
+     if (LoadIntoFakeUse == &I)
+       continue;
+     if (isa<llvm::BitCastInst>(&I))
+       continue;
+     if (auto *II = dyn_cast<llvm::IntrinsicInst>(&I)) {
+       if (II->getIntrinsicID() == llvm::Intrinsic::lifetime_end)
+         continue;
+
+       if (II->getIntrinsicID() == llvm::Intrinsic::fake_use) {
+         LoadIntoFakeUse = dyn_cast<llvm::Instruction>(II->getArgOperand(0));
+         continue;
+       }
+     }      return GetStoreIfValid(&I);
     }
     return nullptr;
   }
diff --git a/clang/lib/CodeGen/CGCleanup.cpp b/clang/lib/CodeGen/CGCleanup.cpp
index 5d253c92a38a81..82532e182bebbd 100644
--- a/clang/lib/CodeGen/CGCleanup.cpp
+++ b/clang/lib/CodeGen/CGCleanup.cpp
@@ -112,11 +112,11 @@ void EHScopeStack::deallocate(size_t Size) {
   StartOfData += llvm::alignTo(Size, ScopeStackAlignment);
 }
 
-bool EHScopeStack::containsOnlyLifetimeMarkers(
+bool EHScopeStack::containsOnlyNoopCleanups(
     EHScopeStack::stable_iterator Old) const {
   for (EHScopeStack::iterator it = begin(); stabilize(it) != Old; it++) {
     EHCleanupScope *cleanup = dyn_cast<EHCleanupScope>(&*it);
-    if (!cleanup || !cleanup->isLifetimeMarker())
+    if (!cleanup || !(cleanup->isLifetimeMarker() || cleanup->isFakeUse()))
       return false;
   }
 
@@ -154,6 +154,7 @@ void *EHScopeStack::pushCleanup(CleanupKind Kind, size_t Size) {
   bool IsNormalCleanup = Kind & NormalCleanup;
   bool IsEHCleanup = Kind & EHCleanup;
   bool IsLifetimeMarker = Kind & LifetimeMarker;
+  bool IsFakeUse = Kind & FakeUse;
 
   // Per C++ [except.terminate], it is implementation-defined whether none,
   // some, or all cleanups are called before std::terminate. Thus, when
@@ -176,6 +177,8 @@ void *EHScopeStack::pushCleanup(CleanupKind Kind, size_t Size) {
     InnermostEHScope = stable_begin();
   if (IsLifetimeMarker)
     Scope->setLifetimeMarker();
+  if (IsFakeUse)
+    Scope->setFakeUse();
 
   // With Windows -EHa, Invoke llvm.seh.scope.begin() for EHCleanup
   // If exceptions are disabled/ignored and SEH is not in use, then there is no
diff --git a/clang/lib/CodeGen/CGCleanup.h b/clang/lib/CodeGen/CGCleanup.h
index c73c97146abc4d..ba78e5478ac373 100644
--- a/clang/lib/CodeGen/CGCleanup.h
+++ b/clang/lib/CodeGen/CGCleanup.h
@@ -87,6 +87,10 @@ class EHScope {
     LLVM_PREFERRED_TYPE(bool)
     unsigned IsLifetimeMarker : 1;
 
+    /// Whether this cleanup is a fake use
+    LLVM_PREFERRED_TYPE(bool)
+    unsigned IsFakeUse : 1;
+
     /// Whether the normal cleanup should test the activation flag.
     LLVM_PREFERRED_TYPE(bool)
     unsigned TestFlagInNormalCleanup : 1;
@@ -352,6 +356,7 @@ class alignas(8) EHCleanupScope : public EHScope {
     CleanupBits.IsEHCleanup = isEH;
     CleanupBits.IsActive = true;
     CleanupBits.IsLifetimeMarker = false;
+    CleanupBits.IsFakeUse = false;
     CleanupBits.TestFlagInNormalCleanup = false;
     CleanupBits.TestFlagInEHCleanup = false;
     CleanupBits.CleanupSize = cleanupSize;
@@ -384,6 +389,9 @@ class alignas(8) EHCleanupScope : public EHScope {
   bool isLifetimeMarker() const { return CleanupBits.IsLifetimeMarker; }
   void setLifetimeMarker() { CleanupBits.IsLifetimeMarker = true; }
 
+  bool isFakeUse() const { return CleanupBits.IsFakeUse; }
+  void setFakeUse() { CleanupBits.IsFakeUse = true; }
+
   bool hasActiveFlag() const { return ActiveFlag.isValid(); }
   Address getActiveFlag() const {
     return ActiveFlag;
diff --git a/clang/lib/CodeGen/CGDecl.cpp b/clang/lib/CodeGen/CGDecl.cpp
index 563f728e29d781..7fdf18f3ca2e7b 100644
--- a/clang/lib/CodeGen/CGDecl.cpp
+++ b/clang/lib/CodeGen/CGDecl.cpp
@@ -1353,6 +1353,14 @@ void CodeGenFunction::EmitLifetimeEnd(llvm::Value *Size, llvm::Value *Addr) {
   C->setDoesNotThrow();
 }
 
+void CodeGenFunction::EmitFakeUse(Address Addr) {
+  auto NL = ApplyDebugLocation::CreateEmpty(*this);
+  llvm::Value *V = Builder.CreateLoad(Addr, "fake.use");
+  llvm::CallInst *C = Builder.CreateCall(CGM.getLLVMFakeUseFn(), {V});
+  C->setDoesNotThrow();
+  C->setTailCallKind(llvm::CallInst::TCK_NoTail);
+}
+
 void CodeGenFunction::EmitAndRegisterVariableArrayDimensions(
     CGDebugInfo *DI, const VarDecl &D, bool EmitDebugInfo) {
   // For each dimension stores its QualType and corresponding
@@ -1412,6 +1420,39 @@ void CodeGenFunction::EmitAndRegisterVariableArrayDimensions(
   }
 }
 
+/// Return the maximum size of an aggregate for which we generate a fake use
+/// intrinsic when -fextend-lifetimes is in effect.
+static uint64_t maxFakeUseAggregateSize(const ASTContext &C) {
+  return 4 * C.getTypeSize(C.UnsignedIntTy);
+}
+
+// Helper function to determine whether a variable's or parameter's lifetime
+// should be extended.
+static bool extendLifetime(const ASTContext &Context, const Decl *FuncDecl,
+                           const VarDecl &D,
+                           ImplicitParamDecl *CXXABIThisDecl) {
+  // When we're not inside a valid function it is unlikely that any
+  // lifetime extension is useful.
+  if (!FuncDecl)
+    return false;
+  if (FuncDecl->isImplicit())
+    return false;
+  // Do not extend compiler-created variables except for the this pointer.
+  if (D.isImplicit() && &D != CXXABIThisDecl)
+    return false;
+  QualType Ty = D.getType();
+  // No need to extend volatiles, they have a memory location.
+  if (Ty.isVolatileQualified())
+    return false;
+  // Don't extend variables that exceed a certain size.
+  if (Context.getTypeSize(Ty) > maxFakeUseAggregateSize(Context))
+    return false;
+  // Do not extend variables in nodebug functions.
+  if (FuncDecl->hasAttr<NoDebugAttr>())
+    return false;
+  return true;
+}
+
 /// EmitAutoVarAlloca - Emit the alloca and debug information for a
 /// local variable.  Does not emit initialization or destruction.
 CodeGenFunction::AutoVarEmission
@@ -1664,6 +1705,17 @@ CodeGenFunction::EmitAutoVarAlloca(const VarDecl &D) {
                                          emission.getOriginalAllocatedAddress(),
                                          emission.getSizeForLifetimeMarkers());
 
+  // Analogous to lifetime markers, we use a 'cleanup' to emit fake.use
+  // calls for local variables. We are exempting volatile variables and
+  // non-scalars larger than 4 times the size of an unsigned int (32 bytes).
+  // Larger non-scalars are often allocated in memory and may create unnecessary
+  // overhead.
+  if (CGM.getCodeGenOpts().ExtendLifetimes) {
+    if (extendLifetime(getContext(), CurCodeDecl, D, CXXABIThisDecl))
+      EHStack.pushCleanup<FakeUse>(NormalFakeUse,
+                                   emission.getAllocatedAddress());
+  }
+
   return emission;
 }
 
@@ -2523,6 +2575,14 @@ llvm::Function *CodeGenModule::getLLVMLifetimeEndFn() {
   return LifetimeEndFn;
 }
 
+/// Lazily declare the @llvm.fake.use intrinsic.
+llvm::Function *CodeGenModule::getLLVMFakeUseFn() {
+  if (!FakeUseFn)
+    FakeUseFn = llvm::Intrinsic::getDeclaration(&getModule(),
+                                                llvm::Intrinsic::fake_use);
+  return FakeUseFn;
+}
+
 namespace {
   /// A cleanup to perform a release of an object at the end of a
   /// function.  This is used to balance out the incoming +1 of a
@@ -2716,6 +2776,15 @@ void CodeGenFunction::EmitParmDecl(const VarDecl &D, ParamValue Arg,
 
   setAddrOfLocalVar(&D, DeclPtr);
 
+  // Push a FakeUse 'cleanup' object onto the EHStack for the parameter,
+  // which may be the 'this' pointer. This causes the emission of a fake.use
+  // call with the parameter as argument at the end of the function.
+  if (CGM.getCodeGenOpts().ExtendLifetimes ||
+      (CGM.getCodeGenOpts().ExtendThisPtr && &D == CXXABIThisDecl)) {
+    if (extendLifetime(getContext(), CurCodeDecl, D, CXXABIThisDecl))
+      EHStack.pushCleanup<FakeUse>(NormalFakeUse, DeclPtr);
+  }
+
   // Emit debug info for param declarations in non-thunk functions.
   if (CGDebugInfo *DI = getDebugInfo()) {
     if (CGM.getCodeGenOpts().hasReducedDebugInfo() && !CurFuncIsThunk &&
diff --git a/clang/lib/CodeGen/CodeGenFunction.cpp b/clang/lib/CodeGen/CodeGenFunction.cpp
index eda96f3e352ce3..630a9c8db95fe5 100644
--- a/clang/lib/CodeGen/CodeGenFunction.cpp
+++ b/clang/lib/CodeGen/CodeGenFunction.cpp
@@ -403,9 +403,9 @@ void CodeGenFunction::FinishFunction(SourceLocation EndLoc) {
   // important to do this before we enter the return block or return
   // edges will be *really* confused.
   bool HasCleanups = EHStack.stable_begin() != PrologueCleanupDepth;
-  bool HasOnlyLifetimeMarkers =
-      HasCleanups && EHStack.containsOnlyLifetimeMarkers(PrologueCleanupDepth);
-  bool EmitRetDbgLoc = !HasCleanups || HasOnlyLifetimeMarkers;
+  bool HasOnlyNoopCleanups =
+      HasCleanups && EHStack.containsOnlyNoopCleanups(PrologueCleanupDepth);
+  bool EmitRetDbgLoc = !HasCleanups || HasOnlyNoopCleanups;
 
   std::optional<ApplyDebugLocation> OAL;
   if (HasCleanups) {
diff --git a/clang/lib/CodeGen/CodeGenFunction.h b/clang/lib/CodeGen/CodeGenFunction.h
index 3e2abbd9bc1094..1525eb0f09b6e5 100644
--- a/clang/lib/CodeGen/CodeGenFunction.h
+++ b/clang/lib/CodeGen/CodeGenFunction.h
@@ -718,6 +718,20 @@ class CodeGenFunction : public CodeGenTypeCache {
     }
   };
 
+  // We are using objects of this 'cleanup' class to emit fake.use calls
+  // for -fextend-lifetimes and -fextend-this-ptr. They are placed at the end of
+  // a variable's scope analogous to lifetime markers.
+  class FakeUse final : public EHScopeStack::Cleanup {
+    Address Addr;
+
+  public:
+    FakeUse(Address addr) : Addr(addr) {}
+
+    void Emit(CodeGenFunction &CGF, Flags flags) override {
+      CGF.EmitFakeUse(Addr);
+    }
+  };
+
   /// Header for data within LifetimeExtendedCleanupStack.
   struct LifetimeExtendedCleanupHeader {
     /// The size of the following cleanup object.
@@ -4975,6 +4989,8 @@ class CodeGenFunction : public CodeGenTypeCache {
 
   RValue EmitAtomicExpr(AtomicExpr *E);
 
+  void EmitFakeUse(Address Addr);
+
   //===--------------------------------------------------------------------===//
   //                         Annotations Emission
   //===--------------------------------------------------------------------===//
diff --git a/clang/lib/CodeGen/CodeGenModule.h b/clang/lib/CodeGen/CodeGenModule.h
index c58bb88035ca8a..71198134f17413 100644
--- a/clang/lib/CodeGen/CodeGenModule.h
+++ b/clang/lib/CodeGen/CodeGenModule.h
@@ -601,6 +601,9 @@ class CodeGenModule : public CodeGenTypeCache {
   /// void @llvm.lifetime.end(i64 %size, i8* nocapture <ptr>)
   llvm::Function *LifetimeEndFn = nullptr;
 
+  /// void @llvm.fake.use(...)
+  llvm::Function *FakeUseFn = nullptr;
+
   std::unique_ptr<SanitizerMetadata> SanitizerMD;
 
   llvm::MapVector<const Decl *, bool> DeferredEmptyCoverageMappingDecls;
@@ -1268,6 +1271,7 @@ class CodeGenModule : public CodeGenTypeCache {
 
   llvm::Function *getLLVMLifetimeStartFn();
   llvm::Function *getLLVMLifetimeEndFn();
+  llvm::Function *getLLVMFakeUseFn();
 
   // Make sure that this type is translated.
   void UpdateCompletedType(const TagDecl *TD);
diff --git a/clang/lib/CodeGen/EHScopeStack.h b/clang/lib/CodeGen/EHScopeStack.h
index 0c667e80bb6d8c..ed11dc2bb05d73 100644
--- a/clang/lib/CodeGen/EHScopeStack.h
+++ b/clang/lib/CodeGen/EHScopeStack.h
@@ -87,6 +87,11 @@ enum CleanupKind : unsigned {
 
   LifetimeMarker = 0x8,
   NormalEHLifetimeMarker = LifetimeMarker | NormalAndEHCleanup,
+
+  // FakeUse needs to be recognized as a special cleanup similar to lifetime
+  // markers chiefly to be ignored in most contexts.
+  FakeUse = 0x10,
+  NormalFakeUse = FakeUse | NormalCleanup,
 };
 
 /// A stack of scopes which respond to exceptions, including cleanups
@@ -352,8 +357,8 @@ class EHScopeStack {
   void popTerminate();
 
   // Returns true iff the current scope is either empty or contains only
-  // lifetime markers, i.e. no real cleanup code
-  bool containsOnlyLifetimeMarkers(stable_iterator Old) const;
+  // noop cleanups, i.e. lifetime markers and fake uses.
+  bool containsOnlyNoopCleanups(stable_iterator Old) const;
 
   /// Determines whether the exception-scopes stack is empty.
   bool empty() const { return StartOfData == EndOfBuffer; }
diff --git a/clang/test/CodeGen/extend-liveness1.c b/clang/test/CodeGen/extend-liveness1.c
new file mode 100644
index 00000000000000..ef2d00eb6be312
--- /dev/null
+++ b/clang/test/CodeGen/extend-liveness1.c
@@ -0,0 +1,29 @@
+// RUN: %clang_cc1 %s -O2 -emit-llvm -fextend-lifetimes -o - | FileCheck %s
+// Check that fake use calls are emitted at the correct locations, i.e.
+// at the end of lexical blocks and at the end of the function.
+
+extern int use(int);
+int glob1;
+int glob2;
+float globf;
+
+int foo(int i) {
+  // CHECK: define{{.*}}foo
+  if (i < 4) {
+    int j = i * 3;
+    if (glob1 > 3) {
+      float f = globf;
+      // CHECK: [[SSAVAL:%[a-z0-9]*]] = load float{{.*}}globf
+      j = f;
+      glob2 = j;
+      // CHECK: store{{.*}}glob2
+      // CHECK-NEXT: call void (...) @llvm.fake.use(float [[SSAVAL]])
+    }
+    glob1 = j;
+    // CHECK: store{{.*}}glob1
+    // CHECK-NEXT: call void (...) @llvm.fake.use(i32 %j.
+  }
+  // CHECK: call void (...) @llvm.fake.use(i32 %i)
+  // CHECK-NEXT: ret
+  return 4;
+}
diff --git a/clang/test/CodeGen/extend-liveness2.cpp b/clang/test/CodeGen/extend-liveness2.cpp
new file mode 100644
index 00000000000000..119c783c634806
--- /dev/null
+++ b/clang/test/CodeGen/extend-liveness2.cpp
@@ -0,0 +1,34 @@
+// RUN: %clang_cc1 %s -O2 -emit-llvm -fextend-lifetimes -fcxx-exceptions -fexceptions -o - | FileCheck %s
+// REQUIRES: x86-registered-target
+// This test checks that the fake_use concept works with exception handling and that we
+// can handle the __int128 data type.
+
+class A {
+public:
+  A(int i) : m_i(i) {}
+  void func(__int128 i128);
+
+  int m_i;
+};
+
+extern int bar();
+extern void foo();
+int glob;
+
+void A::func(__int128 i128) {
+  int j = 4;
+  try {
+    int k = bar();
+    foo();
+    // CHECK: [[SSAVAL:%[a-z0-9]*]] = invoke{{.*}}bar
+    glob = 0;
+    // CHECK: store{{.*}}glob
+    // CHECK-NEXT: call void (...) @llvm.fake.use(i32 [[SSAVAL]])
+  } catch (...) {
+    foo();
+  }
+  // CHECK-LABEL: try.cont:
+  // CHECK-DAG: call void (...) @llvm.fake.use({{.*%this}})
+  // CHECK-DAG: call void (...) @llvm.fake.use(i128 %i128.sroa.0.0.insert.insert)
+  // CHECK: ret void
+}
diff --git a/clang/test/CodeGen/fake-use-determinism.c b/clang/test/CodeGen/fake-use-determinism.c
new file mode 100644
index 00000000000000..d62efbb4efe7ee
--- /dev/null
+++ b/clang/test/CodeGen/fake-use-determinism.c
@@ -0,0 +1,18 @@
+// RUN: %clang -S -O2 -emit-llvm -fextend-lifetimes %s -o - | FileCheck %s
+// REQUIRES: asserts
+//
+// We are checking that the fake.use calls for i, j and k appear
+// in a particular order. It is not the order itself that is important
+// but that it remains the same between different test runs.
+
+// CHECK:       call {{.*}}void (...) @llvm.fake.use(i32 %k)
+// CHECK-NEXT:  call {{.*}}void (...) @llvm.fake.use(i32 %j)
+// CHECK-NEXT:  call {{.*}}void (...) @llvm.fake.use(i32 %i)
+
+extern void bar();
+void foo(int i, int j, int k)
+{
+   for (int l = 0; l < i; l++) {
+      bar();
+   }
+}
diff --git a/clang/test/CodeGen/fake-use-lambda.cpp b/clang/test/CodeGen/fake-use-lambda.cpp
new file mode 100644
index 00000000000000..fd4881b9bcd531
--- /dev/null
+++ b/clang/test/CodeGen/fake-use-lambda.cpp
@@ -0,0 +1,43 @@
+// RUN: %clang_cc1 %s -triple=%itanium_abi_triple -O1 -emit-llvm -fextend-lifetimes -o - | FileCheck %s
+// Make sure we don't crash compiling a lambda that is not nested in a function.
+// We also check that fake uses are properly issued in lambdas.
+
+int glob;
+
+extern int foo();
+
+struct S {
+  static const int a;
+};
+
+const int S::a = [](int b) __attribute__((noinline)) {
+  return b * foo();
+}
+(glob);
+
+int func(int param) {
+  return ([=](int lambdaparm) __attribute__((noinline))->int {
+    int lambdalocal = lambdaparm * 2;
+    return lambdalocal;
+  }(glob));
+}
+
+// We are looking for the first lambda's call operator, which should contain
+// 2 fake uses, one for 'b' and one for its 'this' pointer (in that order).
+// The mangled function name contains a $_0, followed by 'cl'.
+// This lambda is an orphaned lambda, i.e. one without lexical parent.
+//
+// CHECK:     define internal {{.+\"_Z.+\$_0.*cl.*\"}}
+// CHECK-NOT: ret
+// CHECK:     fake.use(i32
+// CHECK-NOT: ret
+// CHECK:     fake.use(ptr
+
+// The second lambda. We are looking for 3 fake uses.
+// CHECK:     define internal {{.+\"_Z.+\$_0.*cl.*\"}}
+// CHECK-NOT: ret
+// CHECK:     fake.use(i32
+// CHECK-NOT: ret
+// CHECK:     fake.use(i32
+// CHECK-NOT: ret
+// CHECK:     fake.use(ptr
diff --git a/clang/test/CodeGen/fake-use-landingpad.c b/clang/test/CodeGen/fake-use-landingpad.c
new file mode 100644
index 00000000000000..91526f29936146
--- /dev/null
+++ b/clang/test/CodeGen/fake-use-landingpad.c
@@ -0,0 +1,16 @@
+// RUN: %clang_cc1 %s -O3 -emit-llvm -fextend-lifetimes -fexceptions -o - | FileCheck %s
+
+// Check that fake uses do not mistakenly cause a landing pad to be generated when
+// exceptions are enabled.
+
+extern void bar(int);
+void foo(int p) {
+  int a = 17;
+  bar(a);
+}
+
+// CHECK:      define {{.*}} @foo
+// CHECK-NOT:  personality
+// CHECK:      entry:
+// CHECK:      llvm.fake.use
+// CHECK-NOT:  landingpad
diff --git a/clang/test/CodeGen/fake-use-noreturn.cpp b/clang/test/CodeGen/fake-use-noreturn.cpp
new file mode 100644
index 00000000000000..acfcb0ce90b5e4
--- /dev/null
+++ b/clang/test/CodeGen/fake-use-noreturn.cpp
@@ -0,0 +1,27 @@
+// RUN: %clang %s -S -emit-llvm -fextend-lifetimes -O2 -o - -fno-discard-value-names | FileCheck %s
+//
+// Check we can correctly produce fake uses for function-level variables even
+// when we have a return in a nested conditional and there is no code at the end
+// of the function.
+
+// CHECK-LABEL: define{{.*}}@_Z3fooi
+// CHECK:         call{{.*}}llvm.fake.use(i32 %i)
+// CHECK-LABEL: define{{.*}}@_ZN1C3barEi
+// CHECK-DAG:     call{{.*}}llvm.fake.use(i32 %i)
+// CHECK-DAG:     call{{.*}}llvm.fake.use({{.*}}%this)
+
+void foo(int i) {
+   while (0)
+     if (1)
+       return;
+}
+
+class C {
+  void bar(int i);
+};
+
+void C::bar(int i) {
+  while (0)
+    if (1)
+      return;
+}
diff --git a/clang/test/CodeGen/fake-use-return-line.c b/clang/test/CodeGen/fake-use-return-line.c
new file mode 100644
index 00000000000000..0c4377058d6628
--- /dev/null
+++ b/clang/test/CodeGen/fake-use-return-line.c
@@ -0,0 +1,15 @@
+// RUN: %clang_cc1 -emit-llvm -O2 -debug-info-kind=limited -fextend-lifetimes -o - %s | FileCheck %s
+
+// Clang adjusts the line numbers of returns based on the line numbers of
+// dominating stores to %retval; we test that fake use intrinsics do not affect
+// this, and the return is given the correct line.
+
+// CHECK: define{{.*}}@main
+// CHECK: ret i32{{.*}}!dbg ![[MDINDEX:[0-9]*]]
+// CHECK: ![[MDINDEX]] = !DILocation(line: [[# @LINE + 5]]
+int main()
+{
+  volatile int a = 1;
+  int b = a + 2;
+  return b;
+}
diff --git a/clang/test/CodeGen/fake-use-sanitizer.cpp b/clang/test/CodeGen/fake-use-sanitizer.cpp
new file mode 100644
index 00000000000000..915924a2b31025
--- /dev/null
+++ b/clang/test/CodeGen/fake-use-san...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/110102


More information about the cfe-commits mailing list