Reland D80966 [codeview] Put !heapallocsite on calls to operator new

With a change to use `CGM.getCodeGenOpts().getDebugInfo() != codegenoptions::NoDebugInfo`
instead of `getDebugInfo()`,
to fix `Profile-<arch> :: instrprof-gcov-multithread_fork.test`

See CodeGenModule::CodeGenModule, `EmitGcovArcs || EmitGcovNotes` can
set `clang::CodeGen::CodeGenModule::DebugInfo`.

---

Clang marks calls to operator new as heap allocation sites, but the
operator declared at global scope returns a void pointer. There is no
explicit cast in the code, so the compiler has to write down the
allocated type itself.

Also generalize a cast to use CallBase, so that we mark heap alloc sites
when exceptions are enabled.

Differential Revision: https://reviews.llvm.org/D80966
This commit is contained in:
Fangrui Song 2020-06-07 13:35:01 -07:00
parent ce677ef532
commit b6e143aa54
7 changed files with 61 additions and 16 deletions

View File

@ -4951,7 +4951,7 @@ RValue CodeGenFunction::EmitCall(const CGFunctionInfo &CallInfo,
// Add metadata for calls to MSAllocator functions
if (getDebugInfo() && TargetDecl &&
TargetDecl->hasAttr<MSAllocatorAttr>())
getDebugInfo()->addHeapAllocSiteMetadata(CI, RetTy, Loc);
getDebugInfo()->addHeapAllocSiteMetadata(CI, RetTy->getPointeeType(), Loc);
// 4. Finish the call.

View File

@ -2146,16 +2146,14 @@ llvm::DIType *CGDebugInfo::getOrCreateStandaloneType(QualType D,
return T;
}
void CGDebugInfo::addHeapAllocSiteMetadata(llvm::Instruction *CI,
QualType D,
void CGDebugInfo::addHeapAllocSiteMetadata(llvm::CallBase *CI,
QualType AllocatedTy,
SourceLocation Loc) {
llvm::MDNode *node;
if (D.getTypePtr()->isVoidPointerType()) {
if (AllocatedTy->isVoidType())
node = llvm::MDNode::get(CGM.getLLVMContext(), None);
} else {
QualType PointeeTy = D.getTypePtr()->getPointeeType();
node = getOrCreateType(PointeeTy, getOrCreateFile(Loc));
}
else
node = getOrCreateType(AllocatedTy, getOrCreateFile(Loc));
CI->setMetadata("heapallocsite", node);
}

View File

@ -509,7 +509,7 @@ public:
llvm::DIType *getOrCreateStandaloneType(QualType Ty, SourceLocation Loc);
/// Add heapallocsite metadata for MSAllocator calls.
void addHeapAllocSiteMetadata(llvm::Instruction *CallSite, QualType Ty,
void addHeapAllocSiteMetadata(llvm::CallBase *CallSite, QualType AllocatedTy,
SourceLocation Loc);
void completeType(const EnumDecl *ED);

View File

@ -1638,6 +1638,12 @@ llvm::Value *CodeGenFunction::EmitCXXNewExpr(const CXXNewExpr *E) {
RValue RV =
EmitNewDeleteCall(*this, allocator, allocatorType, allocatorArgs);
// Set !heapallocsite metadata on the call to operator new.
if (CGM.getCodeGenOpts().getDebugInfo() != codegenoptions::NoDebugInfo)
if (auto *newCall = dyn_cast<llvm::CallBase>(RV.getScalarVal()))
getDebugInfo()->addHeapAllocSiteMetadata(newCall, allocType,
E->getExprLoc());
// If this was a call to a global replaceable allocation function that does
// not take an alignment argument, the allocator is known to produce
// storage that's suitably aligned for any object that fits, up to a known

View File

@ -2081,11 +2081,15 @@ Value *ScalarExprEmitter::VisitCastExpr(CastExpr *CE) {
}
}
// Update heapallocsite metadata when there is an explicit cast.
if (llvm::CallInst *CI = dyn_cast<llvm::CallInst>(Src))
if (CI->getMetadata("heapallocsite") && isa<ExplicitCastExpr>(CE))
CGF.getDebugInfo()->
addHeapAllocSiteMetadata(CI, CE->getType(), CE->getExprLoc());
// Update heapallocsite metadata when there is an explicit pointer cast.
if (auto *CI = dyn_cast<llvm::CallBase>(Src)) {
if (CI->getMetadata("heapallocsite") && isa<ExplicitCastExpr>(CE)) {
QualType PointeeType = DestTy->getPointeeType();
if (!PointeeType.isNull())
CGF.getDebugInfo()->addHeapAllocSiteMetadata(CI, PointeeType,
CE->getExprLoc());
}
}
return Builder.CreateBitCast(Src, DstTy);
}

View File

@ -1,19 +1,22 @@
// RUN: %clang_cc1 -triple x86_64-windows-msvc -debug-info-kind=limited -gcodeview -fdeclspec -S -emit-llvm < %s | FileCheck %s
// RUN: %clang_cc1 -triple x86_64-windows-msvc -debug-info-kind=limited -gcodeview -fdeclspec -S -emit-llvm %s -o - | FileCheck %s
struct Foo;
struct Bar;
__declspec(allocator) void *alloc_void();
__declspec(allocator) struct Foo *alloc_foo();
void call_alloc() {
struct Foo *p = alloc_void();
struct Foo *w = alloc_foo();
struct Foo *q = (struct Foo*)alloc_void();
struct Foo *r = (struct Foo*)(struct Bar*)alloc_void();
}
// CHECK-LABEL: define {{.*}}void @call_alloc
// CHECK: call i8* {{.*}}@alloc_void{{.*}} !heapallocsite [[DBG1:!.*]]
// CHECK: call i8* {{.*}}@alloc_void{{.*}} !heapallocsite [[DBG2:!.*]]
// CHECK: call %struct.Foo* {{.*}}@alloc_foo{{.*}} !heapallocsite [[DBG2:!.*]]
// CHECK: call i8* {{.*}}@alloc_void{{.*}} !heapallocsite [[DBG2]]
// CHECK: call i8* {{.*}}@alloc_void{{.*}} !heapallocsite [[DBG3:!.*]]
// CHECK: [[DBG1]] = !{}

View File

@ -0,0 +1,34 @@
// RUN: %clang_cc1 -fexceptions -triple x86_64-windows-msvc -debug-info-kind=limited -gcodeview -fdeclspec -S -emit-llvm %s -o - | FileCheck %s
struct Foo {
int x;
};
struct Bar {
int y;
};
extern Foo *gv_foo;
extern Bar *gv_bar;
extern "C" void doit() {
gv_foo = new Foo();
gv_bar = new Bar();
}
// CHECK-LABEL: define {{.*}}void @doit
// CHECK: call {{.*}} i8* {{.*}}@"??2@YAPEAX_K@Z"(i64 4) {{.*}} !heapallocsite [[DBG_FOO:!.*]]
// CHECK: call {{.*}} i8* {{.*}}@"??2@YAPEAX_K@Z"(i64 4) {{.*}} !heapallocsite [[DBG_BAR:!.*]]
extern "C" void useinvoke() {
struct HasDtor {
~HasDtor() { delete gv_foo; }
} o;
gv_foo = new Foo();
}
// CHECK-LABEL: define {{.*}}void @useinvoke
// CHECK: invoke {{.*}} i8* {{.*}}@"??2@YAPEAX_K@Z"(i64 4)
// CHECK-NEXT: to label {{.*}} unwind label {{.*}} !heapallocsite [[DBG_FOO]]
// CHECK: [[DBG_FOO]] = distinct !DICompositeType(tag: DW_TAG_structure_type,
// CHECK-SAME: name: "Foo"
// CHECK: [[DBG_BAR]] = distinct !DICompositeType(tag: DW_TAG_structure_type,
// CHECK-SAME: name: "Bar"