Skip to content

Commit e86bfab

Browse files
authored
Merge pull request swiftlang#9811 from fhahn/pick-pointer-tbaa
Pick Pointer TBAA Improvements
2 parents 0da2269 + 0f3de86 commit e86bfab

File tree

16 files changed

+804
-125
lines changed

16 files changed

+804
-125
lines changed

clang/lib/CodeGen/CodeGenTBAA.cpp

Lines changed: 69 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,9 @@ CodeGenTBAA::CodeGenTBAA(ASTContext &Ctx, CodeGenTypes &CGTypes,
3939
llvm::Module &M, const CodeGenOptions &CGO,
4040
const LangOptions &Features)
4141
: Context(Ctx), CGTypes(CGTypes), Module(M), CodeGenOpts(CGO),
42-
Features(Features), MDHelper(M.getContext()), Root(nullptr),
43-
Char(nullptr) {}
42+
Features(Features),
43+
MangleCtx(ItaniumMangleContext::create(Ctx, Ctx.getDiagnostics())),
44+
MDHelper(M.getContext()), Root(nullptr), Char(nullptr) {}
4445

4546
CodeGenTBAA::~CodeGenTBAA() {
4647
}
@@ -202,40 +203,87 @@ llvm::MDNode *CodeGenTBAA::getTypeInfoHelper(const Type *Ty) {
202203
// Other qualifiers could theoretically be distinguished, especially if
203204
// they involve a significant representation difference. We don't
204205
// currently do so, however.
205-
//
206-
// Computing the pointee type string recursively is implicitly more
207-
// forgiving than the standards require. Effectively, we are turning
208-
// the question "are these types compatible/similar" into "are
209-
// accesses to these types allowed to alias". In both C and C++,
210-
// the latter question has special carve-outs for signedness
211-
// mismatches that only apply at the top level. As a result, we are
212-
// allowing e.g. `int *` l-values to access `unsigned *` objects.
213206
if (Ty->isPointerType() || Ty->isReferenceType()) {
214207
llvm::MDNode *AnyPtr = createScalarTypeNode("any pointer", getChar(), Size);
215208
if (!CodeGenOpts.PointerTBAA)
216209
return AnyPtr;
217-
// Compute the depth of the pointer and generate a tag of the form "p<depth>
218-
// <base type tag>".
210+
// C++ [basic.lval]p11 permits objects to accessed through an l-value of
211+
// similar type. Two types are similar under C++ [conv.qual]p2 if the
212+
// decomposition of the types into pointers, member pointers, and arrays has
213+
// the same structure when ignoring cv-qualifiers at each level of the
214+
// decomposition. Meanwhile, C makes T(*)[] and T(*)[N] compatible, which
215+
// would really complicate any attempt to distinguish pointers to arrays by
216+
// their bounds. It's simpler, and much easier to explain to users, to
217+
// simply treat all pointers to arrays as pointers to their element type for
218+
// aliasing purposes. So when creating a TBAA tag for a pointer type, we
219+
// recursively ignore both qualifiers and array types when decomposing the
220+
// pointee type. The only meaningful remaining structure is the number of
221+
// pointer types we encountered along the way, so we just produce the tag
222+
// "p<depth> <base type tag>". If we do find a member pointer type, for now
223+
// we just conservatively bail out with AnyPtr (below) rather than trying to
224+
// create a tag that honors the similar-type rules while still
225+
// distinguishing different kinds of member pointer.
219226
unsigned PtrDepth = 0;
220227
do {
221228
PtrDepth++;
222-
Ty = Ty->getPointeeType().getTypePtr();
229+
Ty = Ty->getPointeeType()->getBaseElementTypeUnsafe();
223230
} while (Ty->isPointerType());
224-
// TODO: Implement C++'s type "similarity" and consider dis-"similar"
225-
// pointers distinct for non-builtin types.
231+
232+
// While there are no special rules in the standards regarding void pointers
233+
// and strict aliasing, emitting distinct tags for void pointers break some
234+
// common idioms and there is no good alternative to re-write the code
235+
// without strict-aliasing violations.
236+
if (Ty->isVoidType())
237+
return AnyPtr;
238+
239+
assert(!isa<VariableArrayType>(Ty));
240+
// When the underlying type is a builtin type, we compute the pointee type
241+
// string recursively, which is implicitly more forgiving than the standards
242+
// require. Effectively, we are turning the question "are these types
243+
// compatible/similar" into "are accesses to these types allowed to alias".
244+
// In both C and C++, the latter question has special carve-outs for
245+
// signedness mismatches that only apply at the top level. As a result, we
246+
// are allowing e.g. `int *` l-values to access `unsigned *` objects.
247+
SmallString<256> TyName;
226248
if (isa<BuiltinType>(Ty)) {
227249
llvm::MDNode *ScalarMD = getTypeInfoHelper(Ty);
228250
StringRef Name =
229251
cast<llvm::MDString>(
230252
ScalarMD->getOperand(CodeGenOpts.NewStructPathTBAA ? 2 : 0))
231253
->getString();
232-
SmallString<256> OutName("p");
233-
OutName += std::to_string(PtrDepth);
234-
OutName += " ";
235-
OutName += Name;
236-
return createScalarTypeNode(OutName, AnyPtr, Size);
254+
TyName = Name;
255+
} else {
256+
// Be conservative if the type isn't a RecordType. We are specifically
257+
// required to do this for member pointers until we implement the
258+
// similar-types rule.
259+
const auto *RT = Ty->getAs<RecordType>();
260+
if (!RT)
261+
return AnyPtr;
262+
263+
// For unnamed structs or unions C's compatible types rule applies. Two
264+
// compatible types in different compilation units can have different
265+
// mangled names, meaning the metadata emitted below would incorrectly
266+
// mark them as no-alias. Use AnyPtr for such types in both C and C++, as
267+
// C and C++ types may be visible when doing LTO.
268+
//
269+
// Note that using AnyPtr is overly conservative. We could summarize the
270+
// members of the type, as per the C compatibility rule in the future.
271+
// This also covers anonymous structs and unions, which have a different
272+
// compatibility rule, but it doesn't matter because you can never have a
273+
// pointer to an anonymous struct or union.
274+
if (!RT->getDecl()->getDeclName())
275+
return AnyPtr;
276+
277+
// For non-builtin types use the mangled name of the canonical type.
278+
llvm::raw_svector_ostream TyOut(TyName);
279+
MangleCtx->mangleCanonicalTypeName(QualType(Ty, 0), TyOut);
237280
}
238-
return AnyPtr;
281+
282+
SmallString<256> OutName("p");
283+
OutName += std::to_string(PtrDepth);
284+
OutName += " ";
285+
OutName += TyName;
286+
return createScalarTypeNode(OutName, AnyPtr, Size);
239287
}
240288

241289
// Accesses to arrays are accesses to objects of their element types.

clang/lib/CodeGen/CodeGenTBAA.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ namespace clang {
2424
class ASTContext;
2525
class CodeGenOptions;
2626
class LangOptions;
27+
class MangleContext;
2728
class QualType;
2829
class Type;
2930

@@ -119,6 +120,7 @@ class CodeGenTBAA {
119120
llvm::Module &Module;
120121
const CodeGenOptions &CodeGenOpts;
121122
const LangOptions &Features;
123+
std::unique_ptr<MangleContext> MangleCtx;
122124

123125
// MDHelper - Helper for creating metadata.
124126
llvm::MDBuilder MDHelper;

clang/test/CXX/drs/cwg158.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
1-
// RUN: %clang_cc1 -triple x86_64-linux -std=c++98 %s -O3 -disable-llvm-passes -pedantic-errors -emit-llvm -o - | FileCheck %s
2-
// RUN: %clang_cc1 -triple x86_64-linux -std=c++11 %s -O3 -disable-llvm-passes -pedantic-errors -emit-llvm -o - | FileCheck %s
3-
// RUN: %clang_cc1 -triple x86_64-linux -std=c++14 %s -O3 -disable-llvm-passes -pedantic-errors -emit-llvm -o - | FileCheck %s
4-
// RUN: %clang_cc1 -triple x86_64-linux -std=c++1z %s -O3 -disable-llvm-passes -pedantic-errors -emit-llvm -o - | FileCheck %s
1+
// RUN: %clang_cc1 -triple x86_64-linux -std=c++98 %s -O3 -disable-llvm-passes -pedantic-errors -emit-llvm -o - | FileCheck --check-prefixes=CHECK %s
2+
// RUN: %clang_cc1 -triple x86_64-linux -std=c++11 %s -O3 -disable-llvm-passes -pedantic-errors -emit-llvm -o - | FileCheck --check-prefixes=CHECK %s
3+
// RUN: %clang_cc1 -triple x86_64-linux -std=c++14 %s -O3 -disable-llvm-passes -pedantic-errors -emit-llvm -o - | FileCheck --check-prefixes=CHECK %s
4+
// RUN: %clang_cc1 -triple x86_64-linux -std=c++1z %s -O3 -disable-llvm-passes -pedantic-errors -emit-llvm -o - | FileCheck --check-prefixes=CHECK %s
5+
// RUN: %clang_cc1 -triple x86_64-linux -std=c++1z %s -O3 -pointer-tbaa -disable-llvm-passes -pedantic-errors -emit-llvm -o - | FileCheck --check-prefixes=CHECK,POINTER-TBAA %s
56

67
// cwg158: yes
78

89
// CHECK-LABEL: define {{.*}} @_Z1f
910
const int *f(const int * const *p, int **q) {
11+
// CHECK: load ptr, ptr %p.addr
1012
// CHECK: load ptr, {{.*}}, !tbaa ![[INTPTR_TBAA:[^,]*]]
1113
const int *x = *p;
1214
// CHECK: store ptr null, {{.*}}, !tbaa ![[INTPTR_TBAA]]
@@ -18,10 +20,24 @@ struct A {};
1820

1921
// CHECK-LABEL: define {{.*}} @_Z1g
2022
const int *(A::*const *g(const int *(A::* const **p)[3], int *(A::***q)[3]))[3] {
23+
// CHECK: load ptr, ptr %p.addr
2124
// CHECK: load ptr, {{.*}}, !tbaa ![[MEMPTR_TBAA:[^,]*]]
2225
const int *(A::*const *x)[3] = *p;
2326
// CHECK: store ptr null, {{.*}}, !tbaa ![[MEMPTR_TBAA]]
2427
*q = 0;
2528
return x;
2629
}
2730

31+
// CHECK-LABEL: define {{.*}} @_Z1h
32+
const int * h(const int * (*p)[10], int *(*q)[9]) {
33+
// CHECK: load ptr, ptr %p.addr, align 8, !tbaa [[PTRARRAY_TBAA:!.+]]
34+
const int * x = *p[0];
35+
36+
// CHECK: load ptr, ptr %q.addr, align 8, !tbaa [[PTRARRAY_TBAA]]
37+
*q[0] = 0;
38+
return x;
39+
}
40+
41+
// POINTER-TBAA: [[PTRARRAY_TBAA]] = !{[[PTRARRAY_TY:!.+]], [[PTRARRAY_TY]], i64 0}
42+
// POINTER-TBAA: [[PTRARRAY_TY]] = !{!"p2 int", [[ANYPTR:!.+]], i64 0}
43+
// POINTER-TBAA: [[ANYPTR]] = !{!"any pointer"

clang/test/CodeGen/tbaa-pointers.c

Lines changed: 99 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -116,17 +116,96 @@ void p2struct(struct S1 **ptr) {
116116
// COMMON-LABEL: define void @p2struct(
117117
// COMMON-SAME: ptr noundef [[PTR:%.+]])
118118
// COMMON: [[PTR_ADDR:%.+]] = alloca ptr, align 8
119-
// ENABLED-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[P2S1_0:!.+]]
120-
// ENABLED-NEXT: [[BASE:%.+]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[P2S1_0]]
121-
// ENABLED-NEXT: store ptr null, ptr [[BASE]], align 8, !tbaa [[P1S1_:!.+]]
122-
// DEFAULT-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]]
123-
// DEFAULT-NEXT: [[BASE:%.+]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]]
124-
// DEFAULT-NEXT: store ptr null, ptr [[BASE]], align 8, !tbaa [[ANYPTR]]
119+
// ENABLED-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[P2S1_TAG:!.+]]
120+
// DEFAULT-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]]
121+
// ENABLED-NEXT: [[BASE:%.+]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[P2S1_TAG]]
122+
// DEFAULT-NEXT: [[BASE:%.+]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]]
123+
// ENABLED-NEXT: store ptr null, ptr [[BASE]], align 8, !tbaa [[P1S1_TAG:!.+]]
124+
// DEFAULT-NEXT: store ptr null, ptr [[BASE]], align 8, !tbaa [[ANYPTR]]
125+
// COMMON-NEXT: ret void
126+
//
127+
*ptr = 0;
128+
}
129+
130+
void p2struct_const(struct S1 const **ptr) {
131+
// COMMON-LABEL: define void @p2struct_const(
132+
// COMMON-SAME: ptr noundef [[PTR:%.+]])
133+
// COMMON: [[PTR_ADDR:%.+]] = alloca ptr, align 8
134+
// COMMON-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR:!.+]]
135+
// COMMON-NEXT: [[BASE:%.+]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]]
136+
// ENABLED-NEXT: store ptr null, ptr [[BASE]], align 8, !tbaa [[P1S1_TAG]]
137+
// DEFAULT-NEXT: store ptr null, ptr [[BASE]], align 8, !tbaa [[ANYPTR]]
125138
// COMMON-NEXT: ret void
126139
//
127140
*ptr = 0;
128141
}
129142

143+
struct S2 {
144+
struct S1 *s;
145+
};
146+
147+
void p2struct2(struct S2 *ptr) {
148+
// COMMON-LABEL: define void @p2struct2(
149+
// COMMON-SAME: ptr noundef [[PTR:%.+]])
150+
// COMMON: [[PTR_ADDR:%.+]] = alloca ptr, align 8
151+
// ENABLED-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[P1S2_TAG:!.+]]
152+
// ENABLED-NEXT: [[BASE:%.+]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[P1S2_TAG]]
153+
// ENABLED-NEXT: [[S:%.+]] = getelementptr inbounds %struct.S2, ptr [[BASE]], i32 0, i32 0
154+
// ENABLED-NEXT: store ptr null, ptr [[S]], align 8, !tbaa [[S2_S_TAG:!.+]]
155+
// DEFAULT-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]]
156+
// DEFAULT-NEXT: [[BASE:%.+]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]]
157+
// DEFAULT-NEXT: [[S:%.+]] = getelementptr inbounds %struct.S2, ptr [[BASE]], i32 0, i32 0
158+
// DEFAULT-NEXT: store ptr null, ptr [[S]], align 8, !tbaa [[S2_S_TAG:!.+]]
159+
// COMMON-NEXT: ret void
160+
ptr->s = 0;
161+
}
162+
163+
164+
void vla1(int n, int ptr[][n], int idx) {
165+
// COMMON-LABEL: define void @vla1(
166+
// COMMON-SAME: i32 noundef [[N:%.+]], ptr noundef [[PTR:%.+]], i32 noundef [[IDX:%.+]])
167+
// COMMON: [[N_ADDR:%.+]] = alloca i32, align 4
168+
// COMMON-NEXT: [[PTR_ADDR:%.+]] = alloca ptr, align 8
169+
// COMMON-NEXT: [[IDX_ADDR:%.+]] = alloca i32, align 4
170+
// COMMON-NEXT: store i32 [[N]], ptr [[N_ADDR]], align 4, !tbaa [[INT_TY:!.+]]
171+
// ENABLED-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[P1INT0:!.+]]
172+
// DEFAULT-NEXT: store ptr [[PTR]], ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]]
173+
// COMMON-NEXT: store i32 [[IDX]], ptr [[IDX_ADDR]], align 4, !tbaa [[INT_TY]]
174+
// COMMON-NEXT: [[L:%.+]] = load i32, ptr [[N_ADDR]], align 4, !tbaa [[INT_TY]]
175+
// COMMON-NEXT: [[L_EXT:%.+]] = zext i32 [[L]] to i64
176+
// ENABLED-NEXT: [[L_PTR:%.+]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[P1INT0]]
177+
// DEFAULT-NEXT: [[L_PTR:%.+]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]]
178+
// COMMON-NEXT: [[L_IDX:%.+]] = load i32, ptr [[IDX_ADDR]], align 4, !tbaa [[INT_TY]]
179+
// COMMON-NEXT: [[IDX_EXT:%.+]] = sext i32 [[L_IDX]] to i64
180+
// COMMON-NEXT: [[MUL:%.+]] = mul nsw i64 [[IDX_EXT]], [[L_EXT]]
181+
// COMMON-NEXT: [[GEP1:%.+]] = getelementptr inbounds i32, ptr [[L_PTR]], i64 [[MUL]]
182+
// COMMON-NEXT: [[GEP2:%.+]] = getelementptr inbounds i32, ptr [[GEP1]], i64 0
183+
// COMMON-NEXT: store i32 0, ptr [[GEP2]], align 4, !tbaa [[INT_TAG:!.+]]
184+
// ENABLED-NEXT: ret void
185+
186+
ptr[idx][0] = 0;
187+
}
188+
189+
typedef struct {
190+
int i1;
191+
} TypedefS;
192+
193+
void unamed_struct_typedef(TypedefS *ptr) {
194+
// COMMON-LABEL: define void @unamed_struct_typedef(
195+
// COMMON-SAME: ptr noundef %ptr)
196+
// COMMON-NEXT: entry:
197+
// COMMON-NEXT: [[PTR_ADDR:%.+]] = alloca ptr, align 8
198+
// DEFAULT-NEXT: store ptr %ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]]
199+
// DEFAULT-NEXT: [[L0:%.+]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[ANYPTR]]
200+
// ENABLED-NEXT: store ptr %ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[P1TYPEDEF:!.+]]
201+
// ENABLED-NEXT: [[L0:%.+]] = load ptr, ptr [[PTR_ADDR]], align 8, !tbaa [[P1TYPEDEF]]
202+
// COMMON-NEXT: [[GEP:%.+]] = getelementptr inbounds %struct.TypedefS, ptr [[L0]], i32 0, i32 0
203+
// COMMON-NEXT: store i32 0, ptr [[GEP]], align 4
204+
// COMMON-NEXT: ret void
205+
206+
ptr->i1 = 0;
207+
}
208+
130209
// ENABLED: [[P2INT_0]] = !{[[P2INT:!.+]], [[P2INT]], i64 0}
131210
// ENABLED: [[P2INT]] = !{!"p2 int", [[ANY_POINTER:!.+]], i64 0}
132211
// DEFAULT: [[ANYPTR]] = !{[[ANY_POINTER:!.+]], [[ANY_POINTER]], i64 0}
@@ -145,3 +224,17 @@ void p2struct(struct S1 **ptr) {
145224
// ENABLED: [[P2CHAR]] = !{!"p2 omnipotent char", [[ANY_POINTER]], i64 0}
146225
// ENABLED: [[P1CHAR_0]] = !{[[P1CHAR:!.+]], [[P1CHAR]], i64 0}
147226
// ENABLED: [[P1CHAR]] = !{!"p1 omnipotent char", [[ANY_POINTER]], i64 0}
227+
// ENABLED: [[P2S1_TAG]] = !{[[P2S1:!.+]], [[P2S1]], i64 0}
228+
// ENABLED: [[P2S1]] = !{!"p2 _ZTS2S1", [[ANY_POINTER]], i64 0}
229+
// ENABLED: [[P1S1_TAG:!.+]] = !{[[P1S1:!.+]], [[P1S1]], i64 0}
230+
// ENABLED: [[P1S1]] = !{!"p1 _ZTS2S1", [[ANY_POINTER]], i64 0}
231+
// ENABLED: [[P1S2_TAG]] = !{[[P1S2:!.+]], [[P1S2]], i64 0}
232+
// ENABLED: [[P1S2]] = !{!"p1 _ZTS2S2", [[ANY_POINTER]], i64 0}
233+
234+
// ENABLED: [[S2_S_TAG]] = !{[[S2_TY:!.+]], [[P1S1]], i64 0}
235+
// ENABLED: [[S2_TY]] = !{!"S2", [[P1S1]], i64 0}
236+
// DEFAULT: [[S2_S_TAG]] = !{[[S2_TY:!.+]], [[ANY_POINTER]], i64 0}
237+
// DEFAULT: [[S2_TY]] = !{!"S2", [[ANY_POINTER]], i64 0}
238+
// COMMON: [[INT_TAG]] = !{[[INT_TY:!.+]], [[INT_TY]], i64 0}
239+
// COMMON: [[INT_TY]] = !{!"int", [[CHAR]], i64 0}
240+
// ENABLED: [[P1TYPEDEF]] = !{[[ANY_POINTER]], [[ANY_POINTER]], i64 0}

clang/test/CodeGen/tbaa-reference.cpp

Lines changed: 23 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
// RUN: %clang_cc1 -triple x86_64-linux -O1 -disable-llvm-passes %s -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK,OLD-PATH
2+
// RUN: %clang_cc1 -triple x86_64-linux -O1 -disable-llvm-passes -pointer-tbaa %s -emit-llvm -o - | FileCheck %s -check-prefixes=CHECK,OLD-PATH-POINTER
23
// RUN: %clang_cc1 -triple x86_64-linux -O1 -disable-llvm-passes %s -emit-llvm -new-struct-path-tbaa -o - | FileCheck %s -check-prefixes=CHECK,NEW-PATH
4+
// RUN: %clang_cc1 -triple x86_64-linux -O1 -disable-llvm-passes %s -pointer-tbaa -emit-llvm -new-struct-path-tbaa -o - | FileCheck %s -check-prefixes=CHECK,NEW-PATH-POINTER
35
//
46
// Check that we generate correct TBAA information for reference accesses.
57

@@ -14,13 +16,13 @@ struct B {
1416
B::B(S &s) : s(s) {
1517
// CHECK-LABEL: _ZN1BC2ER1S
1618
// Check initialization of the reference parameter.
17-
// CHECK: store ptr {{.*}}, ptr {{.*}}, !tbaa [[TAG_pointer:!.*]]
19+
// CHECK: store ptr {{.*}}, ptr %s.addr, align 8, !tbaa [[TAG_S_PTR:!.*]]
1820

1921
// Check loading of the reference parameter.
20-
// CHECK: load ptr, ptr {{.*}}, !tbaa [[TAG_pointer]]
22+
// CHECK: load ptr, ptr {{.*}}, !tbaa [[TAG_S_PTR:!.*]]
2123

2224
// Check initialization of the reference member.
23-
// CHECK: store ptr {{.*}}, ptr {{.*}}, !tbaa [[TAG_pointer]]
25+
// CHECK: store ptr {{.*}}, ptr {{.*}}, !tbaa [[TAG_S_PTR]]
2426
}
2527

2628
S &B::get() {
@@ -30,16 +32,32 @@ S &B::get() {
3032
return s;
3133
}
3234

33-
// OLD-PATH-DAG: [[TAG_pointer]] = !{[[TYPE_pointer:!.*]], [[TYPE_pointer]], i64 0}
35+
// OLD-PATH-DAG: [[TAG_S_PTR]] = !{[[TYPE_pointer:!.*]], [[TYPE_pointer]], i64 0}
3436
// OLD-PATH-DAG: [[TAG_B_s]] = !{[[TYPE_B:!.*]], [[TYPE_pointer]], i64 0}
3537
//
3638
// OLD-PATH-DAG: [[TYPE_B]] = !{!"_ZTS1B", [[TYPE_pointer]], i64 0}
3739
// OLD-PATH-DAG: [[TYPE_pointer]] = !{!"any pointer", [[TYPE_char:!.*]], i64 0}
3840
// OLD-PATH-DAG: [[TYPE_char]] = !{!"omnipotent char", {{!.*}}, i64 0}
3941

40-
// NEW-PATH-DAG: [[TAG_pointer]] = !{[[TYPE_pointer:!.*]], [[TYPE_pointer]], i64 0, i64 8}
42+
// OLD-PATH-POINTER-DAG: [[TAG_S_PTR]] = !{[[TYPE_S_PTR:!.*]], [[TYPE_S_PTR]], i64 0}
43+
// OLD-PATH-POINTER-DAG: [[TAG_B_s]] = !{[[TYPE_B:!.*]], [[TYPE_S_PTR:!.*]], i64 0}
44+
//
45+
// OLD-PATH-POINTER-DAG: [[TYPE_B]] = !{!"_ZTS1B", [[TYPE_S_PTR:!.*]], i64 0}
46+
// OLD-PATH-POINTER-DAG: [[TYPE_pointer:!.*]] = !{!"any pointer", [[TYPE_char:!.*]], i64 0}
47+
// OLD-PATH-POINTER-DAG: [[TYPE_char]] = !{!"omnipotent char", {{!.*}}, i64 0}
48+
// OLD-PATH-POINTER-DAG: [[TYPE_S_PTR]] = !{!"p1 _ZTS1S", [[TYPE_pointer]], i64 0}
49+
50+
// NEW-PATH-DAG: [[TAG_S_PTR]] = !{[[TYPE_pointer:!.*]], [[TYPE_pointer]], i64 0, i64 8}
4151
// NEW-PATH-DAG: [[TAG_B_s]] = !{[[TYPE_B:!.*]], [[TYPE_pointer]], i64 0, i64 8}
4252
//
4353
// NEW-PATH-DAG: [[TYPE_B]] = !{[[TYPE_char:!.*]], i64 8, !"_ZTS1B", [[TYPE_pointer]], i64 0, i64 8}
4454
// NEW-PATH-DAG: [[TYPE_pointer]] = !{[[TYPE_char:!.*]], i64 8, !"any pointer"}
4555
// NEW-PATH-DAG: [[TYPE_char]] = !{{{!.*}}, i64 1, !"omnipotent char"}
56+
57+
// NEW-PATH-POINTER-DAG: [[TAG_S_PTR]] = !{[[TYPE_S_PTR:!.*]], [[TYPE_S_PTR]], i64 0, i64 8}
58+
// NEW-PATH-POINTER-DAG: [[TAG_B_s]] = !{[[TYPE_B:!.*]], [[TYPE_S_PTR]], i64 0, i64 8}
59+
//
60+
// NEW-PATH-POINTER-DAG: [[TYPE_B]] = !{[[TYPE_char:!.*]], i64 8, !"_ZTS1B", [[TYPE_S_PTR]], i64 0, i64 8}
61+
// NEW-PATH-POINTER-DAG: [[TYPE_S_PTR]] = !{[[TYPE_pointer:!.+]], i64 8, !"p1 _ZTS1S"}
62+
// NEW-PATH-POINTER-DAG: [[TYPE_pointer]] = !{[[TYPE_char:!.*]], i64 8, !"any pointer"}
63+
// NEW-PATH-POINTER-DAG: [[TYPE_char]] = !{{{!.*}}, i64 1, !"omnipotent char"}

llvm/lib/Transforms/Scalar/MergedLoadStoreMotion.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,7 @@
8484
#include "llvm/Support/raw_ostream.h"
8585
#include "llvm/Transforms/Scalar.h"
8686
#include "llvm/Transforms/Utils/BasicBlockUtils.h"
87+
#include "llvm/Transforms/Utils/Local.h"
8788

8889
using namespace llvm;
8990

@@ -255,7 +256,8 @@ void MergedLoadStoreMotion::sinkStoresAndGEPs(BasicBlock *BB, StoreInst *S0,
255256
BasicBlock::iterator InsertPt = BB->getFirstInsertionPt();
256257
// Intersect optional metadata.
257258
S0->andIRFlags(S1);
258-
S0->dropUnknownNonDebugMetadata();
259+
260+
combineMetadataForCSE(S0, S1, true);
259261
S0->applyMergedLocation(S0->getDebugLoc(), S1->getDebugLoc());
260262
S0->mergeDIAssignID(S1);
261263

0 commit comments

Comments
 (0)