Skip to content

Commit c3b8a15

Browse files
authored
[CodeGen] Add TBAA struct path info for array members (#137719)
This enables the LLVM optimizer to view accesses to distinct struct members as independent, also for array members. For example, the following two stores no longer alias: struct S { int a[10]; int b; }; void test(S *p, int i) { p->a[i] = ...; p->b = ...; } Array members were already added to TBAA struct type nodes in commit 57493e2. Here, we extend a path tag for an array subscript expression.
1 parent 1bf1e6e commit c3b8a15

File tree

3 files changed

+74
-7
lines changed

3 files changed

+74
-7
lines changed

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4595,7 +4595,32 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
45954595
E->getType(), !getLangOpts().PointerOverflowDefined, SignedIndices,
45964596
E->getExprLoc(), &arrayType, E->getBase());
45974597
EltBaseInfo = ArrayLV.getBaseInfo();
4598-
EltTBAAInfo = CGM.getTBAAInfoForSubobject(ArrayLV, E->getType());
4598+
if (!CGM.getCodeGenOpts().NewStructPathTBAA) {
4599+
// Since CodeGenTBAA::getTypeInfoHelper only handles array types for
4600+
// new struct path TBAA, we must a use a plain access.
4601+
EltTBAAInfo = CGM.getTBAAInfoForSubobject(ArrayLV, E->getType());
4602+
} else if (ArrayLV.getTBAAInfo().isMayAlias()) {
4603+
EltTBAAInfo = TBAAAccessInfo::getMayAliasInfo();
4604+
} else if (ArrayLV.getTBAAInfo().isIncomplete()) {
4605+
// The array element is complete, even if the array is not.
4606+
EltTBAAInfo = CGM.getTBAAAccessInfo(E->getType());
4607+
} else {
4608+
// The TBAA access info from the array (base) lvalue is ordinary. We will
4609+
// adapt it to create access info for the element.
4610+
EltTBAAInfo = ArrayLV.getTBAAInfo();
4611+
4612+
// We retain the TBAA struct path (BaseType and Offset members) from the
4613+
// array. In the TBAA representation, we map any array access to the
4614+
// element at index 0, as the index is generally a runtime value. This
4615+
// element has the same offset in the base type as the array itself.
4616+
// If the array lvalue had no base type, there is no point trying to
4617+
// generate one, since an array itself is not a valid base type.
4618+
4619+
// We also retain the access type from the base lvalue, but the access
4620+
// size must be updated to the size of an individual element.
4621+
EltTBAAInfo.Size =
4622+
getContext().getTypeSizeInChars(E->getType()).getQuantity();
4623+
}
45994624
} else {
46004625
// The base must be a pointer; emit it with an estimate of its alignment.
46014626
Address BaseAddr =

clang/lib/CodeGen/CodeGenTBAA.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,13 @@ static bool TypeHasMayAlias(QualType QTy) {
130130
return true;
131131
QTy = TT->desugar();
132132
}
133+
134+
// Also consider an array type as may_alias when its element type (at
135+
// any level) is marked as such.
136+
if (auto *ArrayTy = QTy->getAsArrayTypeUnsafe())
137+
if (TypeHasMayAlias(ArrayTy->getElementType()))
138+
return true;
139+
133140
return false;
134141
}
135142

clang/test/CodeGen/tbaa-array.cpp

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
1-
// RUN: %clang_cc1 -triple x86_64-linux -O1 -disable-llvm-passes %s \
1+
// RUN: %clang_cc1 -triple x86_64-linux -O1 %s \
22
// RUN: -emit-llvm -o - | FileCheck %s
3-
// RUN: %clang_cc1 -triple x86_64-linux -O1 -disable-llvm-passes %s \
3+
// RUN: %clang_cc1 -triple x86_64-linux -O1 %s \
44
// RUN: -new-struct-path-tbaa -emit-llvm -o - | \
55
// RUN: FileCheck -check-prefix=CHECK-NEW %s
66
//
@@ -10,6 +10,12 @@
1010
struct A { int i; };
1111
struct B { A a[1]; };
1212
struct C { int i; int x[3]; };
13+
struct D { int n; int arr[]; }; // flexible array member
14+
extern int AA[]; // incomplete array type
15+
16+
typedef int __attribute__((may_alias)) aliasing_int;
17+
typedef int __attribute__((may_alias)) aliasing_array[10];
18+
struct E { aliasing_int x[4]; aliasing_array y; };
1319

1420
int foo(B *b) {
1521
// CHECK-LABEL: _Z3fooP1B
@@ -28,25 +34,54 @@ int bar(C *c) {
2834

2935
int bar2(C *c) {
3036
// CHECK-NEW-LABEL: _Z4bar2P1C
31-
// CHECK-NEW: load i32, {{.*}}, !tbaa [[TAG_int:!.*]]
37+
// CHECK-NEW: load i32, {{.*}}, !tbaa [[TAG_C_x:!.*]]
3238
return c->x[2];
3339
}
3440

3541
int bar3(C *c, int j) {
3642
// CHECK-NEW-LABEL: _Z4bar3P1Ci
37-
// CHECK-NEW: load i32, {{.*}}, !tbaa [[TAG_int:!.*]]
43+
// CHECK-NEW: load i32, {{.*}}, !tbaa [[TAG_C_x]]
3844
return c->x[j];
3945
}
4046

47+
int bar4(D *d) {
48+
// CHECK-NEW-LABEL: _Z4bar4P1D
49+
// CHECK-NEW: load i32, {{.*}}, !tbaa [[TAG_int:!.*]]
50+
// CHECK-NEW: load i32, {{.*}}, !tbaa [[TAG_int:!.*]]
51+
return d->arr[d->n];
52+
}
53+
54+
int bar5(int j) {
55+
// CHECK-NEW-LABEL: _Z4bar5i
56+
// CHECK-NEW: load i32, {{.*}}, !tbaa [[TAG_int:!.*]]
57+
// CHECK-NEW: load i32, {{.*}}, !tbaa [[TAG_int:!.*]]
58+
return AA[2] + AA[j];
59+
}
60+
61+
int bar6(E *e, int j) {
62+
// CHECK-NEW-LABEL: _Z4bar6P1Ei
63+
// CHECK-NEW: load i32, {{.*}}, !tbaa [[TAG_E_x:!.*]]
64+
return e->x[j];
65+
}
66+
67+
int bar7(E *e, int j) {
68+
// CHECK-NEW-LABEL: _Z4bar7P1Ei
69+
// CHECK-NEW: load i32, {{.*}}, !tbaa [[TAG_E_y:!.*]]
70+
return e->y[j];
71+
}
72+
4173
// CHECK-DAG: [[TAG_A_i]] = !{[[TYPE_A:!.*]], [[TYPE_int:!.*]], i64 0}
4274
// CHECK-DAG: [[TYPE_A]] = !{!"_ZTS1A", !{{.*}}, i64 0}
4375
// CHECK-DAG: [[TYPE_int]] = !{!"int", !{{.*}}, i64 0}
4476

4577
// CHECK-NEW-DAG: [[TYPE_char:!.*]] = !{{{.*}}, i64 1, !"omnipotent char"}
4678
// CHECK-NEW-DAG: [[TYPE_int:!.*]] = !{[[TYPE_char]], i64 4, !"int"}
4779
// CHECK-NEW-DAG: [[TAG_int]] = !{[[TYPE_int]], [[TYPE_int]], i64 0, i64 4}
48-
// CHECK-NEW-DAG: [[TYPE_pointer:!.*]] = !{[[TYPE_char]], i64 8, !"any pointer"}
4980
// CHECK-NEW-DAG: [[TYPE_A:!.*]] = !{[[TYPE_char]], i64 4, !"_ZTS1A", [[TYPE_int]], i64 0, i64 4}
5081
// CHECK-NEW-DAG: [[TAG_A_i]] = !{[[TYPE_A]], [[TYPE_int]], i64 0, i64 4}
5182
// CHECK-NEW-DAG: [[TYPE_C:!.*]] = !{[[TYPE_char]], i64 16, !"_ZTS1C", [[TYPE_int]], i64 0, i64 4, [[TYPE_int]], i64 4, i64 12}
52-
// CHECK-NEW-DAG: [[TAG_C_i]] = !{[[TYPE_C:!.*]], [[TYPE_int:!.*]], i64 0, i64 4}
83+
// CHECK-NEW-DAG: [[TAG_C_i]] = !{[[TYPE_C]], [[TYPE_int]], i64 0, i64 4}
84+
// CHECK-NEW-DAG: [[TAG_C_x]] = !{[[TYPE_C]], [[TYPE_int]], i64 4, i64 4}
85+
// CHECK-NEW-DAG: [[TYPE_E:!.*]] = !{[[TYPE_char]], i64 56, !"_ZTS1E", [[TYPE_char]], i64 0, i64 16, [[TYPE_char]], i64 16, i64 40}
86+
// CHECK-NEW-DAG: [[TAG_E_x]] = !{[[TYPE_E]], [[TYPE_char]], i64 0, i64 4}
87+
// CHECK-NEW-DAG: [[TAG_E_y]] = !{[[TYPE_E]], [[TYPE_char]], i64 16, i64 4}

0 commit comments

Comments
 (0)