-
Notifications
You must be signed in to change notification settings - Fork 15.3k
[ExtendLifetimes] Add extend lifetimes to emit fake uses from clang #106724
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
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -2543,6 +2543,10 @@ void CodeGenModule::ConstructAttributeList(StringRef Name, | |||||
| if (shouldDisableTailCalls()) | ||||||
| FuncAttrs.addAttribute("disable-tail-calls", "true"); | ||||||
|
|
||||||
| // Suppress the machine instruction scheduler when -fextend-lifetimes is on. | ||||||
| if (CodeGenOpts.ExtendLifetimes) | ||||||
| FuncAttrs.addAttribute(llvm::Attribute::OptimizeForDebugging); | ||||||
|
|
||||||
| // CPU/feature overrides. addDefaultFunctionDefinitionAttributes | ||||||
| // handles these separately to set them based on the global defaults. | ||||||
| GetCPUAndFeaturesAttributes(CalleeInfo.getCalleeDecl(), FuncAttrs); | ||||||
|
|
@@ -3558,15 +3562,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. | ||||||
| // 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 are just loads for fake uses; the load should | ||||||
|
||||||
| // Ignore instructions are just loads for fake uses; the load should | |
| // Ignore instructions that are just loads for fake uses; the load should |
?
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -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); | ||||||||||||||||||||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This limit should be documented in the associated release note.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Good call - the release note also ought to be part of this patch imo. |
||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| // 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,15 @@ llvm::Function *CodeGenModule::getLLVMLifetimeEndFn() { | |||||||||||||||||||
| return LifetimeEndFn; | ||||||||||||||||||||
| } | ||||||||||||||||||||
|
|
||||||||||||||||||||
| /// Lazily declare the @llvm.fake.use intrinsic. | ||||||||||||||||||||
| llvm::Function *CodeGenModule::getLLVMFakeUseFn() { | ||||||||||||||||||||
| if (FakeUseFn) | ||||||||||||||||||||
| return FakeUseFn; | ||||||||||||||||||||
| FakeUseFn = | ||||||||||||||||||||
| llvm::Intrinsic::getDeclaration(&getModule(), llvm::Intrinsic::fake_use); | ||||||||||||||||||||
| return FakeUseFn; | ||||||||||||||||||||
|
||||||||||||||||||||
| if (FakeUseFn) | |
| return FakeUseFn; | |
| FakeUseFn = | |
| llvm::Intrinsic::getDeclaration(&getModule(), llvm::Intrinsic::fake_use); | |
| return FakeUseFn; | |
| if (!FakeUseFn) | |
| FakeUseFn = | |
| llvm::Intrinsic::getDeclaration(&getModule(), llvm::Intrinsic::fake_use); | |
| return FakeUseFn; |
This seems a bit simpler to read, but I'm not insisting.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,8 @@ | ||
| // RUN: %clang_cc1 %s -emit-llvm -O2 -fextend-lifetimes -o - | FileCheck %s | ||
|
|
||
| // Emit the function attribute disable-post-ra when | ||
| // -fextend-lifetimes is on. | ||
|
|
||
| // CHECK: attributes #0 = {{{.*}}optdebug | ||
|
|
||
| void foo() {} |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -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; | ||
| } |
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.
Also -fextend-this-ptr?