StephenFan created this revision. StephenFan added reviewers: MaskRay, vitalybuka, rsmith. Herald added a project: All. StephenFan requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
Fix https://github.com/llvm/llvm-project/issues/56356 For following test case: extern int bar(char *A, int n); void goto_bypass(void) { { char x; l1: bar(&x, 1); } goto l1; } And using `clang -cc1 -O2 -S -emit-llvm` to compile it. In the past, due to the existence of bypassed label, the lifetime intrinsic would not be generated. This was also the cause of pr56356. In this patch, if the variable is bypassed, we do variable allocation, emit lifetime-start intrinsic and record the lifetime-start intrinsic in LexicalScope. Then When emitting the bypass label, we emit the lifetime instrinsic again to make sure the lifetime of the bypassed variable is start again. Address sanitizer will capture these lifetime intrinsics and instrument poison and unpoison code. Finally pr56356 can be resolved. Here is the new llvm-ir of the test case above. define dso_local void @goto_bypass() local_unnamed_addr #0 { entry: %x = alloca i8, align 1 call void @llvm.lifetime.start.p0(i64 1, ptr nonnull %x) #3 br label %l1 l1: ; preds = %l1, %entry call void @llvm.lifetime.start.p0(i64 1, ptr nonnull %x) #3 %call = call i32 @bar(ptr noundef nonnull %x, i32 noundef 1) #3 call void @llvm.lifetime.end.p0(i64 1, ptr nonnull %x) #3 br label %l1 } Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D129448 Files: clang/lib/CodeGen/CGDecl.cpp clang/lib/CodeGen/CGStmt.cpp clang/lib/CodeGen/CodeGenFunction.h clang/test/CodeGen/lifetime2.c
Index: clang/test/CodeGen/lifetime2.c =================================================================== --- clang/test/CodeGen/lifetime2.c +++ clang/test/CodeGen/lifetime2.c @@ -35,11 +35,12 @@ // CHECK-LABEL: @goto_bypass void goto_bypass(void) { { - // O2-NOT: @llvm.lifetime.start.p0i8(i64 1 - // O2-NOT: @llvm.lifetime.end.p0i8(i64 1 + // O2: @llvm.lifetime.start.p0i8(i64 1 char x; l1: + // O2: @llvm.lifetime.start.p0i8(i64 1 bar(&x, 1); + // O2: @llvm.lifetime.end.p0i8(i64 1 } goto l1; } @@ -69,8 +70,8 @@ switch (n) { case 1: n = n; - // O2-NOT: @llvm.lifetime.start.p0i8(i64 1 - // O2-NOT: @llvm.lifetime.end.p0i8(i64 1 + // O2: @llvm.lifetime.start.p0i8(i64 1 + // O2: @llvm.lifetime.end.p0i8(i64 1 char x; bar(&x, 1); break; @@ -83,7 +84,7 @@ // CHECK-LABEL: @indirect_jump void indirect_jump(int n) { char x; - // O2-NOT: @llvm.lifetime + // O2: @llvm.lifetime void *T[] = {&&L}; goto *T[n]; L: Index: clang/lib/CodeGen/CodeGenFunction.h =================================================================== --- clang/lib/CodeGen/CodeGenFunction.h +++ clang/lib/CodeGen/CodeGenFunction.h @@ -38,6 +38,7 @@ #include "llvm/ADT/MapVector.h" #include "llvm/ADT/SmallVector.h" #include "llvm/Frontend/OpenMP/OMPIRBuilder.h" +#include "llvm/IR/IntrinsicInst.h" #include "llvm/IR/ValueHandle.h" #include "llvm/Support/Debug.h" #include "llvm/Transforms/Utils/SanitizerStats.h" @@ -931,6 +932,7 @@ class LexicalScope : public RunCleanupsScope { SourceRange Range; SmallVector<const LabelDecl*, 4> Labels; + SmallVector<const llvm::CallInst *, 4> LifetimeStartMarkers; LexicalScope *ParentScope; LexicalScope(const LexicalScope &) = delete; @@ -950,6 +952,19 @@ Labels.push_back(label); } + void addLifetimeStartMarker(const llvm::CallInst *LifetimeStartMarker) { + assert(isa<llvm::IntrinsicInst>(LifetimeStartMarker) && + cast<llvm::IntrinsicInst>(LifetimeStartMarker)->getIntrinsicID() == + llvm::Intrinsic::lifetime_start && + "LifetimeStartMarker Is not a lifetime start intrinsic"); + LifetimeStartMarkers.push_back(LifetimeStartMarker); + } + + const SmallVector<const llvm::CallInst *, 4> & + getLifetimeStartMarkers() const { + return LifetimeStartMarkers; + } + /// Exit this cleanup scope, emitting any accumulated /// cleanups. ~LexicalScope() { @@ -2922,7 +2937,8 @@ void EmitSehTryScopeBegin(); void EmitSehTryScopeEnd(); - llvm::Value *EmitLifetimeStart(llvm::TypeSize Size, llvm::Value *Addr); + llvm::Value *EmitLifetimeStart(llvm::TypeSize Size, llvm::Value *Addr, + bool isBypassed = false); void EmitLifetimeEnd(llvm::Value *Size, llvm::Value *Addr); llvm::Value *EmitCXXNewExpr(const CXXNewExpr *E); Index: clang/lib/CodeGen/CGStmt.cpp =================================================================== --- clang/lib/CodeGen/CGStmt.cpp +++ clang/lib/CodeGen/CGStmt.cpp @@ -647,6 +647,12 @@ EmitBlock(Dest.getBlock()); + if (CurLexicalScope) + llvm::for_each(CurLexicalScope->getLifetimeStartMarkers(), + [this](const llvm::CallInst *LifetimeStartMarker) { + Builder.Insert(LifetimeStartMarker->clone()); + }); + // Emit debug info for labels. if (CGDebugInfo *DI = getDebugInfo()) { if (CGM.getCodeGenOpts().hasReducedDebugInfo()) { Index: clang/lib/CodeGen/CGDecl.cpp =================================================================== --- clang/lib/CodeGen/CGDecl.cpp +++ clang/lib/CodeGen/CGDecl.cpp @@ -1330,7 +1330,8 @@ /// \return a pointer to the temporary size Value if a marker was emitted, null /// otherwise llvm::Value *CodeGenFunction::EmitLifetimeStart(llvm::TypeSize Size, - llvm::Value *Addr) { + llvm::Value *Addr, + bool isBypassed) { if (!ShouldEmitLifetimeMarkers) return nullptr; @@ -1342,6 +1343,8 @@ Addr = Builder.CreateBitCast(Addr, AllocaInt8PtrTy); llvm::CallInst *C = Builder.CreateCall(CGM.getLLVMLifetimeStartFn(), {SizeV, Addr}); + if (isBypassed && CurLexicalScope) + CurLexicalScope->addLifetimeStartMarker(C); C->setDoesNotThrow(); return SizeV; } @@ -1551,24 +1554,10 @@ // Emit a lifetime intrinsic if meaningful. There's no point in doing this // if we don't have a valid insertion point (?). if (HaveInsertPoint() && !IsMSCatchParam) { - // If there's a jump into the lifetime of this variable, its lifetime - // gets broken up into several regions in IR, which requires more work - // to handle correctly. For now, just omit the intrinsics; this is a - // rare case, and it's better to just be conservatively correct. - // PR28267. - // - // We have to do this in all language modes if there's a jump past the - // declaration. We also have to do it in C if there's a jump to an - // earlier point in the current block because non-VLA lifetimes begin as - // soon as the containing block is entered, not when its variables - // actually come into scope; suppressing the lifetime annotations - // completely in this case is unnecessarily pessimistic, but again, this - // is rare. - if (!Bypasses.IsBypassed(&D) && - !(!getLangOpts().CPlusPlus && hasLabelBeenSeenInCurrentScope())) { + if (!(!getLangOpts().CPlusPlus && hasLabelBeenSeenInCurrentScope())) { llvm::TypeSize Size = CGM.getDataLayout().getTypeAllocSize(allocaTy); - emission.SizeForLifetimeMarkers = - EmitLifetimeStart(Size, AllocaAddr.getPointer()); + emission.SizeForLifetimeMarkers = EmitLifetimeStart( + Size, AllocaAddr.getPointer(), Bypasses.IsBypassed(&D)); } } else { assert(!emission.useLifetimeMarkers());
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits