Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td +++ include/clang/Driver/Options.td @@ -1758,11 +1758,16 @@ Flags<[CC1Option]>, HelpText<"Place each data in its own section (ELF Only)">; def fno_data_sections : Flag <["-"], "fno-data-sections">, Group, Flags<[CC1Option]>; +def fextend_this_ptr : Flag <["-"], "fextend-this-ptr">, Group, + HelpText<"Extend the lifetime of the 'this' pointer to improve visibility " + "in optimized debugging">, Flags<[CC1Option]>; +def fextend_lifetimes : Flag <["-"], "fextend-lifetimes">, Group, + HelpText<"Extend the lifetimes of local variables and parameters to improve " + "visibility in optimized debugging">, Flags<[CC1Option]>; def fstack_size_section : Flag<["-"], "fstack-size-section">, Group, Flags<[CC1Option]>, HelpText<"Emit section containing metadata on function stack sizes">; def fno_stack_size_section : Flag<["-"], "fno-stack-size-section">, Group, Flags<[CC1Option]>, HelpText<"Don't emit section containing metadata on function stack sizes">; - def funique_section_names : Flag <["-"], "funique-section-names">, Group, Flags<[CC1Option]>, HelpText<"Use unique names for text and data sections (ELF Only)">; Index: include/clang/Frontend/CodeGenOptions.def =================================================================== --- include/clang/Frontend/CodeGenOptions.def +++ include/clang/Frontend/CodeGenOptions.def @@ -309,6 +309,12 @@ /// The default TLS model to use. ENUM_CODEGENOPT(DefaultTLSModel, TLSModel, 2, GeneralDynamicTLSModel) +/// Whether to extend the live range of the this ptr. +CODEGENOPT(ExtendThisPtr, 1, 0) + +/// Whether to extend the live range of all local variables. +CODEGENOPT(ExtendLifetimes, 1, 0) + /// Number of path components to strip when emitting checks. (0 == full /// filename) VALUE_CODEGENOPT(EmitCheckPathComponentsToStrip, 32, 0) Index: lib/CodeGen/CGCall.cpp =================================================================== --- lib/CodeGen/CGCall.cpp +++ lib/CodeGen/CGCall.cpp @@ -2757,6 +2757,14 @@ II != IE; ++II) { if (llvm::IntrinsicInst *Intrinsic = dyn_cast(&*II)) { + // Ignore fake uses and the instructions that load their + // operands. + if (Intrinsic->getIntrinsicID() == llvm::Intrinsic::fake_use) { + const llvm::Value *FakeUseArg = Intrinsic->getArgOperand(0); + if (++II == IE || &*II != FakeUseArg) + break; + continue; + } if (Intrinsic->getIntrinsicID() == llvm::Intrinsic::lifetime_end) { const llvm::Value *CastAddr = Intrinsic->getArgOperand(1); ++II; Index: lib/CodeGen/CGCleanup.h =================================================================== --- lib/CodeGen/CGCleanup.h +++ lib/CodeGen/CGCleanup.h @@ -77,6 +77,9 @@ /// Whether this cleanup is a lifetime marker unsigned IsLifetimeMarker : 1; + /// Whether this cleanup is a fake use + unsigned IsFakeUse : 1; + /// Whether the normal cleanup should test the activation flag. unsigned TestFlagInNormalCleanup : 1; @@ -321,6 +324,9 @@ 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 != nullptr; } Address getActiveFlag() const { return Address(ActiveFlag, CharUnits::One()); Index: lib/CodeGen/CGCleanup.cpp =================================================================== --- lib/CodeGen/CGCleanup.cpp +++ lib/CodeGen/CGCleanup.cpp @@ -149,7 +149,8 @@ EHScopeStack::stable_iterator Old) const { for (EHScopeStack::iterator it = begin(); stabilize(it) != Old; it++) { EHCleanupScope *cleanup = dyn_cast(&*it); - if (!cleanup || !cleanup->isLifetimeMarker()) + // Augment this test to also ignore fake use "cleanups". + if (!cleanup || !(cleanup->isLifetimeMarker() || cleanup->isFakeUse())) return false; } @@ -188,6 +189,7 @@ bool IsEHCleanup = Kind & EHCleanup; bool IsActive = !(Kind & InactiveCleanup); bool IsLifetimeMarker = Kind & LifetimeMarker; + bool IsFakeUse = Kind & FakeUse; EHCleanupScope *Scope = new (Buffer) EHCleanupScope(IsNormalCleanup, IsEHCleanup, @@ -202,6 +204,8 @@ InnermostEHScope = stable_begin(); if (IsLifetimeMarker) Scope->setLifetimeMarker(); + if (IsFakeUse) + Scope->setFakeUse(); return Scope->getCleanupBuffer(); } Index: lib/CodeGen/CGDecl.cpp =================================================================== --- lib/CodeGen/CGDecl.cpp +++ lib/CodeGen/CGDecl.cpp @@ -1089,6 +1089,15 @@ 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 @@ -1350,6 +1359,12 @@ EHStack.pushCleanup(NormalEHLifetimeMarker, emission.getOriginalAllocatedAddress(), emission.getSizeForLifetimeMarkers()); + // Analogous to lifetime markers, we use a 'cleanup' to emit fake.use + // calls for local variables. + if (CGM.getCodeGenOpts().ExtendLifetimes && + hasScalarEvaluationKind(D.getType())) { + EHStack.pushCleanup(NormalFakeUse, emission.getAllocatedAddress()); + } return emission; } @@ -1979,6 +1994,15 @@ return LifetimeEndFn; } +/// Lazily declare the @llvm.fake.use intrinsic. +llvm::Constant *CodeGenModule::getLLVMFakeUseFn() { + if (FakeUseFn) + return 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 @@ -2152,6 +2176,21 @@ 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 (CurFuncDecl && !CurFuncDecl->isImplicit() && + (&D == CXXABIThisDecl || !D.isImplicit())) { + if (CGM.getCodeGenOpts().ExtendLifetimes) { + if (IsScalar) + EHStack.pushCleanup(NormalFakeUse, DeclPtr); + } else if (CGM.getCodeGenOpts().ExtendThisPtr) { + // Enter only the 'this' pointer for -fextend-this-ptr. + if (&D == CXXABIThisDecl) + EHStack.pushCleanup(NormalFakeUse, DeclPtr); + } + } + // Emit debug info for param declaration. if (CGDebugInfo *DI = getDebugInfo()) { if (CGM.getCodeGenOpts().getDebugInfo() >= Index: lib/CodeGen/CodeGenFunction.h =================================================================== --- lib/CodeGen/CodeGenFunction.h +++ lib/CodeGen/CodeGenFunction.h @@ -505,6 +505,21 @@ } }; + // We are using objects of this 'cleanup' class to emit fake.use calls + // for -fextend-lifetimes. 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. @@ -3966,6 +3981,8 @@ RValue EmitAtomicExpr(AtomicExpr *E); + void EmitFakeUse(Address Addr); + //===--------------------------------------------------------------------===// // Annotations Emission //===--------------------------------------------------------------------===// Index: lib/CodeGen/CodeGenModule.h =================================================================== --- lib/CodeGen/CodeGenModule.h +++ lib/CodeGen/CodeGenModule.h @@ -495,6 +495,9 @@ /// void @llvm.lifetime.end(i64 %size, i8* nocapture ) llvm::Constant *LifetimeEndFn = nullptr; + /// void @llvm.fake.use(i8* nocapture ) + llvm::Constant *FakeUseFn = nullptr; + GlobalDecl initializedGlobalDecl; std::unique_ptr SanitizerMD; @@ -1007,6 +1010,7 @@ llvm::Constant *getLLVMLifetimeStartFn(); llvm::Constant *getLLVMLifetimeEndFn(); + llvm::Constant *getLLVMFakeUseFn(); // Make sure that this type is translated. void UpdateCompletedType(const TagDecl *TD); Index: lib/CodeGen/EHScopeStack.h =================================================================== --- lib/CodeGen/EHScopeStack.h +++ lib/CodeGen/EHScopeStack.h @@ -93,6 +93,11 @@ 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 Index: lib/Driver/ToolChains/Clang.cpp =================================================================== --- lib/Driver/ToolChains/Clang.cpp +++ lib/Driver/ToolChains/Clang.cpp @@ -4970,6 +4970,11 @@ if (Args.hasArg(options::OPT_fretain_comments_from_system_headers)) CmdArgs.push_back("-fretain-comments-from-system-headers"); + if (Args.hasArg(options::OPT_fextend_this_ptr)) + CmdArgs.push_back("-fextend-this-ptr"); + if (Args.hasArg(options::OPT_fextend_lifetimes)) + CmdArgs.push_back("-fextend-lifetimes"); + // Forward -fcomment-block-commands to -cc1. Args.AddAllArgs(CmdArgs, options::OPT_fcomment_block_commands); // Forward -fparse-all-comments to -cc1. Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp +++ lib/Frontend/CompilerInvocation.cpp @@ -1152,6 +1152,11 @@ Opts.CudaGpuBinaryFileName = Args.getLastArgValue(OPT_fcuda_include_gpubinary); + Opts.ExtendThisPtr = Opts.OptimizationLevel > 0 && + Args.hasArg(OPT_fextend_this_ptr); + Opts.ExtendLifetimes = Opts.OptimizationLevel > 0 && + Args.hasArg(OPT_fextend_lifetimes); + Opts.Backchain = Args.hasArg(OPT_mbackchain); Opts.EmitCheckPathComponentsToStrip = getLastArgIntValue( Index: test/CodeGen/fake-use-determinism.c =================================================================== --- /dev/null +++ test/CodeGen/fake-use-determinism.c @@ -0,0 +1,26 @@ +// RUN: %clang -S -O2 -emit-llvm -fextend-lifetimes %s -o - | FileCheck %s +// REQUIRES: asserts +// +// Non-deterministic order of fake.use instructions. +// +// 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. +// +// Different targets may have different forms. For example, on X86, we get a +// line like: +// tail call void (...) @llvm.fake.use(i32 %i) +// but on ARM, we get a line like: +// tail call arm_aapcs_vfpcc void (...) @llvm.fake.use(i32 %i) + +// 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(); + } +} Index: test/CodeGen/fake-use-landingpad.c =================================================================== --- /dev/null +++ test/CodeGen/fake-use-landingpad.c @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 %s -O3 -emit-llvm -fextend-lifetimes -fexceptions -o - | FileCheck %s +// REQUIRES: asserts + +// 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-NOT: landingpad Index: test/CodeGen/fake-use-noreturn.c =================================================================== --- /dev/null +++ test/CodeGen/fake-use-noreturn.c @@ -0,0 +1,13 @@ +// RUN: %clang_cc1 %s -S -emit-llvm -fextend-lifetimes -o %t.ll +// +// Check we don't assert when we have a return in a nested conditional and +// there is no code at the end of the function. + +// CHECK: define{{.*}}main +// CHECK: call{{.*}}llvm.fake.use + +void foo(int i) { + while (0) + if (1) + return; +} Index: test/CodeGen/fake-use-return-line.c =================================================================== --- /dev/null +++ test/CodeGen/fake-use-return-line.c @@ -0,0 +1,10 @@ +// RUN: %clang_cc1 -S -emit-llvm -O2 -debug-info-kind=limited -fextend-lifetimes -o - %s | FileCheck %s +int main() +{ + volatile int a = 1; + int b = a + 2; + return b; +} +// CHECK: define{{.*}}@main +// CHECK: ret i32{{.*}}!dbg ![[MDINDEX:[0-9]*]] +// CHECK: ![[MDINDEX]] = !DILocation(line: 6 Index: test/CodeGen/fake-use-sanitizer.cpp =================================================================== --- /dev/null +++ test/CodeGen/fake-use-sanitizer.cpp @@ -0,0 +1,38 @@ +// RUN: %clang_cc1 %s -O1 -emit-llvm -fextend-lifetimes -fsanitize=null -fsanitize-trap=null -o - | FileCheck --check-prefix TRAP %s +// RUN: %clang_cc1 %s -O1 -emit-llvm -fextend-lifetimes -o - | FileCheck --check-prefix FAKEUSE %s +// REQUIRES: asserts + +// With -fextend-lifetimes the compiler generated a fake.use of a +// reference variable at the end of the function, in the cleanup block. This prompted the +// address sanitizer to verify that the variable has been allocated properly, even when +// the functions returns early. +// We check that sanitizers are disabled for code generated for the benefit of fake.use +// intrinsics, as well as that the fake.use is no longer generated in the cleanup block. +// It should be generated in the block preceding the cleanup block instead. + +struct A { short s1, s2; }; +extern A& getA(); + +void foo() +{ + auto& va = getA(); + short s = va.s1 & ~va.s2; + if (s == 0) + return; + + auto& vb = getA(); +} + +// TRAP: define{{.*}}foo +// TRAP: [[COMPARE:%[^\s]*]] = icmp eq +// TRAP-NOT: br i1 [[COMPARE]]{{.*}}trap +// TRAP: br i1 [[COMPARE]]{{.*}}%if.end +// TRAP-NOT: trap: +// TRAP: if.end: +// TRAP-NOT: call{{.*}}llvm.trap + +// FAKEUSE: if.end: +// FAKEUSE-NEXT: [[CALL:%[^\s]*]] = {{.*}}call{{.*}}getA +// FAKEUSE-NOT: br{{.*}}cleanup +// FAKEUSE: call{{.*}}fake.use({{.*}}[[CALL]]) +// FAKEUSE: cleanup: Index: test/CodeGen/fake-use-scalar.c =================================================================== --- /dev/null +++ test/CodeGen/fake-use-scalar.c @@ -0,0 +1,20 @@ +// RUN: %clang_cc1 %s -O2 -emit-llvm -fextend-lifetimes -o - | FileCheck %s +// Make sure we don't generate fake.use for non-scalar +// variables. + +struct A { + unsigned long t; + char c[1024]; + unsigned char r[32]; +}; + + +int foo() +{ + struct A s; + struct A v[128]; + char c[32]; + return 0; +} + +// CHECK-NOT: fake.use Index: test/CodeGen/fake-use-while.c =================================================================== --- /dev/null +++ test/CodeGen/fake-use-while.c @@ -0,0 +1,18 @@ +// RUN: %clang_cc1 %s -S -emit-llvm -fextend-lifetimes -o %t.ll +// +// Check we don't assert when there is no more code after a while statement +// and the body of the while statement ends in a return, i.e. no insertion point +// is available. + +// CHECK: define{{.*}}main +// CHECK: call{{.*}}llvm.fake.use + +void foo() { + { + while (1) { + int ret; + if (1) + return; + } + } +} Index: test/CodeGen/fake-use.cpp =================================================================== --- /dev/null +++ test/CodeGen/fake-use.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 %s -O2 -emit-llvm -fextend-this-ptr -o - | FileCheck %s +// Check that we generate a fake_use call with the 'this' pointer as argument. +// The call should appear after the call to bar(). + +extern void bar(); + +class v +{ +public: + int x; + int y; + int z; + int w; + + v(int a, int b, int c, int d) : x(a), y(b), z(c), w(d) {} +}; + +class w +{ +public: + v test(int, int, int, int, int, int, int, int, int, int); + w(int in): a(in), b(1234) {} + +private: + int a; + int b; +}; + +v w::test(int q, int w, int e, int r, int t, int y, int u, int i, int o, int p) +{ +// CHECK: define{{.*}}test + int res = q*w + e - r*t + y*u*i*o*p; + int res2 = (w + e + r + t + y + o)*(p*q); + int res3 = res + res2; + int res4 = q*e + t*y*i + p*e*w * 6 * 4 * 3; + + v V(res, res2, res3, res4); + + bar(); +// CHECK: call{{.*}}bar +// CHECK: call void (...) @llvm.fake.use(%class.w* %this) + return V; +// CHECK: ret +} Index: test/CodeGen/no-fake-use-O0.cpp =================================================================== --- /dev/null +++ test/CodeGen/no-fake-use-O0.cpp @@ -0,0 +1,49 @@ +// RUN: %clang_cc1 %s -O0 -emit-llvm -fextend-this-ptr -o - | FileCheck %s +// RUN: %clang_cc1 %s -O0 -emit-llvm -fextend-lifetimes -o - | FileCheck %s +// RUN: %clang_cc1 %s -O1 -emit-llvm -fextend-this-ptr -o - | FileCheck -check-prefix=OPT %s +// RUN: %clang_cc1 %s -O1 -emit-llvm -fextend-lifetimes -o - | FileCheck -check-prefix=OPT %s +// RUN: %clang_cc1 %s -Os -emit-llvm -fextend-this-ptr -o - | FileCheck -check-prefix=OPT %s +// RUN: %clang_cc1 %s -Os -emit-llvm -fextend-lifetimes -o - | FileCheck -check-prefix=OPT %s +// RUN: %clang_cc1 %s -Oz -emit-llvm -fextend-this-ptr -o - | FileCheck -check-prefix=OPT %s +// RUN: %clang_cc1 %s -Oz -emit-llvm -fextend-lifetimes -o - | FileCheck -check-prefix=OPT %s +// Check that we do not generate a fake_use call when we are not optimizing. + +extern void bar(); + +class v +{ +public: + int x; + int y; + int z; + int w; + + v(int a, int b, int c, int d) : x(a), y(b), z(c), w(d) {} +}; + +class w +{ +public: + v test(int, int, int, int, int, int, int, int, int, int); + w(int in): a(in), b(1234) {} + +private: + int a; + int b; +}; + +v w::test(int q, int w, int e, int r, int t, int y, int u, int i, int o, int p) +{ +// CHECK: define{{.*}}test + int res = q*w + e - r*t + y*u*i*o*p; + int res2 = (w + e + r + t + y + o)*(p*q); + int res3 = res + res2; + int res4 = q*e + t*y*i + p*e*w * 6 * 4 * 3; + + v V(res, res2, res3, res4); + + bar(); +// CHECK-NOT: call void (...) @llvm.fake.use +// OPT: call void (...) @llvm.fake.use + return V; +}