diff --git a/clang/lib/CodeGen/CGClass.cpp b/clang/lib/CodeGen/CGClass.cpp index 13792c1042046..4a465e6526da0 100644 --- a/clang/lib/CodeGen/CGClass.cpp +++ b/clang/lib/CodeGen/CGClass.cpp @@ -627,6 +627,7 @@ static void EmitMemberInitializer(CodeGenFunction &CGF, CXXCtorInitializer *MemberInit, const CXXConstructorDecl *Constructor, FunctionArgList &Args) { + ApplyAtomGroup Grp(CGF.getDebugInfo()); ApplyDebugLocation Loc(CGF, MemberInit->getSourceLocation()); assert(MemberInit->isAnyMemberInitializer() && "Must have member initializer!"); @@ -1000,7 +1001,8 @@ namespace { void emitMemcpyIR(Address DestPtr, Address SrcPtr, CharUnits Size) { DestPtr = DestPtr.withElementType(CGF.Int8Ty); SrcPtr = SrcPtr.withElementType(CGF.Int8Ty); - CGF.Builder.CreateMemCpy(DestPtr, SrcPtr, Size.getQuantity()); + auto *I = CGF.Builder.CreateMemCpy(DestPtr, SrcPtr, Size.getQuantity()); + CGF.addInstToCurrentSourceAtom(I, nullptr); } void addInitialField(FieldDecl *F) { @@ -1113,6 +1115,7 @@ namespace { } pushEHDestructors(); + ApplyAtomGroup Grp(CGF.getDebugInfo()); emitMemcpy(); AggregatedInits.clear(); } @@ -1248,6 +1251,7 @@ namespace { reset(); } + ApplyAtomGroup Grp(CGF.getDebugInfo()); emitMemcpy(); AggregatedStmts.clear(); } @@ -1338,9 +1342,9 @@ void CodeGenFunction::EmitCtorPrologue(const CXXConstructorDecl *CD, assert(!Member->isBaseInitializer()); assert(Member->isAnyMemberInitializer() && "Delegating initializer on non-delegating constructor"); - ApplyAtomGroup Grp(getDebugInfo()); CM.addMemberInitializer(Member); } + CM.finish(); } @@ -1563,6 +1567,7 @@ void CodeGenFunction::emitImplicitAssignmentOperatorBody(FunctionArgList &Args) AssignmentMemcpyizer AM(*this, AssignOp, Args); for (auto *I : RootCS->body()) AM.emitAssignment(I); + AM.finish(); } diff --git a/clang/test/DebugInfo/KeyInstructions/init-member-memcopyable-2.cpp b/clang/test/DebugInfo/KeyInstructions/init-member-memcopyable-2.cpp new file mode 100644 index 0000000000000..c94fc588bf13b --- /dev/null +++ b/clang/test/DebugInfo/KeyInstructions/init-member-memcopyable-2.cpp @@ -0,0 +1,59 @@ +// RUN: %clang_cc1 -triple x86_64-linux-gnu -gkey-instructions %s -gno-column-info -debug-info-kind=line-tables-only -emit-llvm -o - \ +// RUN: | FileCheck %s + +// g::h and i can be memcpy'd, check the assignment gets Key Instructions metadata. + +struct e { + e(e &); + e& operator=(const e&); +}; + +struct g { + e f; + int h; + int i; +}; + +// Copy assignment operator. +// CHECK: define{{.*}}ptr @_ZN1gaSERKS_ +// CHECK-NEXT: entry: +// CHECK-NEXT: %this.addr = alloca ptr, align 8 +// CHECK-NEXT: %.addr = alloca ptr, align 8 +// CHECK-NEXT: store ptr %this, ptr %this.addr, align 8 +// CHECK-NEXT: store ptr %0, ptr %.addr, align 8 +// CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 8 +// CHECK-NEXT: %1 = load ptr, ptr %.addr, align 8 +// CHECK-NEXT: %call = call {{.*}}ptr @_ZN1eaSERKS_(ptr {{.*}}%this1, ptr {{.*}}%1) +// CHECK-NEXT: %h = getelementptr inbounds nuw %struct.g, ptr %this1, i32 0, i32 1 +// CHECK-NEXT: %2 = load ptr, ptr %.addr, align 8 +// CHECK-NEXT: %h2 = getelementptr inbounds nuw %struct.g, ptr %2, i32 0, i32 1 +// CHECK-NEXT: call void @llvm.memcpy{{.*}}(ptr align 4 %h, ptr align 4 %h2, i64 8, i1 false), !dbg [[S1_G1R1:!.*]] +// CHECK-NEXT: ret ptr %this1, !dbg + +// Copy ctor. +// CHECK: define{{.*}}void @_ZN1gC2ERS_ +// CHECK-NEXT: entry: +// CHECK-NEXT: %this.addr = alloca ptr, align 8 +// CHECK-NEXT: %.addr = alloca ptr, align 8 +// CHECK-NEXT: store ptr %this, ptr %this.addr, align 8 +// CHECK-NEXT: store ptr %0, ptr %.addr, align 8 +// CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 8 +// CHECK-NEXT: %1 = load ptr, ptr %.addr, align 8 +// CHECK-NEXT: call void @_ZN1eC1ERS_ +// CHECK-NEXT: %h = getelementptr inbounds nuw %struct.g, ptr %this1, i32 0, i32 1 +// CHECK-NEXT: %2 = load ptr, ptr %.addr, align 8 +// CHECK-NEXT: %h2 = getelementptr inbounds nuw %struct.g, ptr %2, i32 0, i32 1 +// CHECK-NEXT: call void @llvm.memcpy{{.*}}(ptr align 4 %h, ptr align 4 %h2, i64 8, i1 false), !dbg [[S2_G1R1:!.*]] +// CHECK-NEXT: ret void, !dbg + +// CHECK: [[S1:!.*]] = distinct !DISubprogram(name: "operator=", +// CHECK: [[S1_G1R1]] = !DILocation(line: 11, scope: [[S1]], atomGroup: 1, atomRank: 1) + +// CHECK: [[S2:!.*]] = distinct !DISubprogram(name: "g", +// CHECK: [[S2_G1R1]] = !DILocation(line: 11, scope: [[S2]], atomGroup: 1, atomRank: 1) + +[[gnu::nodebug]] +void fun(g *x) { + g y = g(*x); + y = *x; +} diff --git a/clang/test/DebugInfo/KeyInstructions/init-member-memcopyable.cpp b/clang/test/DebugInfo/KeyInstructions/init-member-memcopyable.cpp new file mode 100644 index 0000000000000..cd3807735fa32 --- /dev/null +++ b/clang/test/DebugInfo/KeyInstructions/init-member-memcopyable.cpp @@ -0,0 +1,62 @@ +// RUN: %clang_cc1 -triple x86_64-linux-gnu -gkey-instructions %s -gno-column-info -debug-info-kind=line-tables-only -emit-llvm -o - \ +// RUN: | FileCheck %s + +// g::h can be memcpy'd (in this case emitted as load/stored), check the +// assignment gets Key Instructions metadata. + +struct e { + e(e&); + e& operator=(const e&); +}; + +struct g { + e f; + int h; +}; + +// Copy assignment operator. +// CHECK: define{{.*}}ptr @_ZN1gaSERKS_ +// CHECK-NEXT: entry: +// CHECK-NEXT: %this.addr = alloca ptr, align 8 +// CHECK-NEXT: %.addr = alloca ptr, align 8 +// CHECK-NEXT: store ptr %this, ptr %this.addr, align 8 +// CHECK-NEXT: store ptr %0, ptr %.addr, align 8 +// CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 8 +// CHECK-NEXT: %1 = load ptr, ptr %.addr, align 8 +// CHECK-NEXT: %call = call {{.*}}ptr @_ZN1eaSERKS_(ptr {{.*}}%this1, ptr {{.*}}%1) +// CHECK-NEXT: %2 = load ptr, ptr %.addr, align 8 +// CHECK-NEXT: %h = getelementptr inbounds nuw %struct.g, ptr %2, i32 0, i32 1 +// CHECK-NEXT: %3 = load i32, ptr %h, align 4, !dbg [[S1_G1R2:!.*]] +// CHECK-NEXT: %h2 = getelementptr inbounds nuw %struct.g, ptr %this1, i32 0, i32 1 +// CHECK-NEXT: store i32 %3, ptr %h2, align 4, !dbg [[S1_G1R1:!.*]] +// CHECK-NEXT: ret ptr %this1, !dbg + +// Copy ctor. +// CHECK: define{{.*}}void @_ZN1gC2ERS_ +// CHECK-NEXT: entry: +// CHECK-NEXT: %this.addr = alloca ptr, align 8 +// CHECK-NEXT: %.addr = alloca ptr, align 8 +// CHECK-NEXT: store ptr %this, ptr %this.addr, align 8 +// CHECK-NEXT: store ptr %0, ptr %.addr, align 8 +// CHECK-NEXT: %this1 = load ptr, ptr %this.addr, align 8 +// CHECK-NEXT: %1 = load ptr, ptr %.addr, align 8 +// CHECK-NEXT: call void @_ZN1eC1ERS_ +// CHECK-NEXT: %h = getelementptr inbounds nuw %struct.g, ptr %this1, i32 0, i32 1 +// CHECK-NEXT: %2 = load ptr, ptr %.addr, align 8 +// CHECK-NEXT: %h2 = getelementptr inbounds nuw %struct.g, ptr %2, i32 0, i32 1 +// CHECK-NEXT: %3 = load i32, ptr %h2, align 4, !dbg [[S2_G1R2:!.*]] +// CHECK-NEXT: store i32 %3, ptr %h, align 4, !dbg [[S2_G1R1:!.*]] +// CHECK-NEXT: ret void, !dbg + +// CHECK: [[S1:!.*]] = distinct !DISubprogram(name: "operator=", +// CHECK: [[S1_G1R2]] = !DILocation(line: 12, scope: [[S1]], atomGroup: 1, atomRank: 2) +// CHECK: [[S1_G1R1]] = !DILocation(line: 12, scope: [[S1]], atomGroup: 1, atomRank: 1) + +// CHECK: [[S2:!.*]] = distinct !DISubprogram(name: "g", +// CHECK: [[S2_G1R2]] = !DILocation(line: 12, scope: [[S2]], atomGroup: 1, atomRank: 2) +// CHECK: [[S2_G1R1]] = !DILocation(line: 12, scope: [[S2]], atomGroup: 1, atomRank: 1) + +void fun(g *x) { + g y = g(*x); + y = *x; +}