Skip to content

Commit 4c6d809

Browse files
committed
[Clang][CodeGen] Add TBAA metadata on pointer, union and array types.
Options to disable new behaviour: -Xclang -no-pointer-tbaa -Xclang -no-array-tbaa Following option enables unions to participate in struct-path TBAA: -Xclang -union-tbaa
1 parent 2d33b74 commit 4c6d809

19 files changed

+976
-682
lines changed

clang/include/clang/Basic/CodeGenOptions.def

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -217,6 +217,9 @@ ENUM_CODEGENOPT(StructReturnConvention, StructReturnConventionKind, 2, SRCK_Defa
217217
CODEGENOPT(RelaxAll , 1, 0) ///< Relax all machine code instructions.
218218
CODEGENOPT(RelaxedAliasing , 1, 0) ///< Set when -fno-strict-aliasing is enabled.
219219
CODEGENOPT(StructPathTBAA , 1, 0) ///< Whether or not to use struct-path TBAA.
220+
CODEGENOPT(UnionTBAA , 1, 0) ///< Whether or not to use struct-path TBAA on unions.
221+
CODEGENOPT(PointerTBAA , 1, 0) ///< Whether or not to generate TBAA on pointers.
222+
CODEGENOPT(ArrayTBAA , 1, 0) ///< Whether or not to generate TBAA on arrays.
220223
CODEGENOPT(NewStructPathTBAA , 1, 0) ///< Whether or not to use enhanced struct-path TBAA.
221224
CODEGENOPT(SaveTempLabels , 1, 0) ///< Save temporary labels.
222225
CODEGENOPT(SanitizeAddressUseAfterScope , 1, 0) ///< Enable use-after-scope detection

clang/include/clang/Driver/Options.td

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6835,6 +6835,15 @@ def relaxed_aliasing : Flag<["-"], "relaxed-aliasing">,
68356835
def no_struct_path_tbaa : Flag<["-"], "no-struct-path-tbaa">,
68366836
HelpText<"Turn off struct-path aware Type Based Alias Analysis">,
68376837
MarshallingInfoNegativeFlag<CodeGenOpts<"StructPathTBAA">>;
6838+
def union_tbaa : Flag<["-"], "union-tbaa">,
6839+
HelpText<"Turn on struct-path aware Type Based Alias Analysis for unions">,
6840+
MarshallingInfoFlag<CodeGenOpts<"UnionTBAA">>;
6841+
def no_pointer_tbaa : Flag<["-"], "no-pointer-tbaa">,
6842+
HelpText<"Turn off Type Based Alias Analysis for pointer types">,
6843+
MarshallingInfoNegativeFlag<CodeGenOpts<"PointerTBAA">>;
6844+
def no_array_tbaa : Flag<["-"], "no-array-tbaa">,
6845+
HelpText<"Turn off Type Based Alias Analysis for array types">,
6846+
MarshallingInfoNegativeFlag<CodeGenOpts<"ArrayTBAA">>;
68386847
def new_struct_path_tbaa : Flag<["-"], "new-struct-path-tbaa">,
68396848
HelpText<"Enable enhanced struct-path aware Type Based Alias Analysis">;
68406849
def mdebug_pass : Separate<["-"], "mdebug-pass">,

clang/lib/CodeGen/CGExpr.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4285,7 +4285,11 @@ LValue CodeGenFunction::EmitArraySubscriptExpr(const ArraySubscriptExpr *E,
42854285
E->getType(), !getLangOpts().isSignedOverflowDefined(), SignedIndices,
42864286
E->getExprLoc(), &arrayType, E->getBase());
42874287
EltBaseInfo = ArrayLV.getBaseInfo();
4288-
EltTBAAInfo = CGM.getTBAAInfoForSubobject(ArrayLV, E->getType());
4288+
// If array is member of some aggregate, keep struct path TBAA information
4289+
// about it.
4290+
EltTBAAInfo = isa<MemberExpr>(Array) && CGM.getCodeGenOpts().ArrayTBAA
4291+
? ArrayLV.getTBAAInfo()
4292+
: CGM.getTBAAInfoForSubobject(ArrayLV, E->getType());
42894293
} else {
42904294
// The base must be a pointer; emit it with an estimate of its alignment.
42914295
Addr = EmitPointerWithAlignment(E->getBase(), &EltBaseInfo, &EltTBAAInfo);
@@ -4803,8 +4807,7 @@ LValue CodeGenFunction::EmitLValueForField(LValue base,
48034807
if (base.getTBAAInfo().isMayAlias() ||
48044808
rec->hasAttr<MayAliasAttr>() || FieldType->isVectorType()) {
48054809
FieldTBAAInfo = TBAAAccessInfo::getMayAliasInfo();
4806-
} else if (rec->isUnion()) {
4807-
// TODO: Support TBAA for unions.
4810+
} else if (rec->isUnion() && !CGM.getCodeGenOpts().UnionTBAA) {
48084811
FieldTBAAInfo = TBAAAccessInfo::getMayAliasInfo();
48094812
} else {
48104813
// If no base type been assigned for the base access, then try to generate

clang/lib/CodeGen/CodeGenTBAA.cpp

Lines changed: 182 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -94,7 +94,7 @@ static bool TypeHasMayAlias(QualType QTy) {
9494
}
9595

9696
/// Check if the given type is a valid base type to be used in access tags.
97-
static bool isValidBaseType(QualType QTy) {
97+
static bool isValidBaseType(QualType QTy, const CodeGenOptions &CodeGenOpts) {
9898
if (QTy->isReferenceType())
9999
return false;
100100
if (const RecordType *TTy = QTy->getAs<RecordType>()) {
@@ -105,13 +105,154 @@ static bool isValidBaseType(QualType QTy) {
105105
if (RD->hasFlexibleArrayMember())
106106
return false;
107107
// RD can be struct, union, class, interface or enum.
108-
// For now, we only handle struct and class.
109-
if (RD->isStruct() || RD->isClass())
108+
if (RD->isStruct() || RD->isClass() ||
109+
(RD->isUnion() && CodeGenOpts.UnionTBAA))
110110
return true;
111111
}
112112
return false;
113113
}
114114

115+
// Appends unique tag for compatible pointee types.
116+
void CodeGenTBAA::appendPointeeName(llvm::raw_ostream &OS, const Type *Ty) {
117+
// Although type compatibilty in C standard requires cv-qualification
118+
// match and exact type match, here more relaxed rules are applied.
119+
//
120+
// For built-in types consider them 'compatible' if their respective
121+
// TBAA metadata tag is same(e.g. that makes 'int' and 'unsigned'
122+
// compatible).
123+
if (isa<BuiltinType>(Ty)) {
124+
llvm::MDNode *ScalarMD = getTypeInfoHelper(Ty);
125+
auto &Op = ScalarMD->getOperand(CodeGenOpts.NewStructPathTBAA ? 2 : 0);
126+
assert(isa<llvm::MDString>(Op) && "Expected MDString operand");
127+
OS << cast<llvm::MDString>(Op)->getString().str();
128+
}
129+
130+
// Non-builtin types are considered compatible if their tag matches.
131+
OS << Ty->getUnqualifiedDesugaredType()
132+
->getCanonicalTypeInternal()
133+
.getAsString();
134+
}
135+
136+
/// Return an LLVM TBAA metadata node appropriate for an access through
137+
/// an l-value of the given type. Type-based alias analysis takes advantage
138+
/// of the following rules from the language standards:
139+
///
140+
/// C 6.5p7:
141+
/// An object shall have its stored value accessed only by an lvalue
142+
/// expression that has one of the following types:
143+
/// - a type compatible with the effective type of the object,
144+
/// - a qualified version of a type compatible with the effective
145+
/// type of the object,
146+
/// - a type that is the signed or unsigned type corresponding
147+
/// to the effective type of the object,
148+
/// - a type that is the signed or unsigned type corresponding
149+
/// to a qualified version of the effective type of the object,
150+
/// - an aggregate or union type that includes one of the
151+
/// aforementioned types among its members (including,
152+
/// recursively, a member of a subaggregate or contained union), or
153+
/// - a character type.
154+
///
155+
/// C++ [basic.lval]p11:
156+
/// If a program attempts to access the stored value of an object
157+
/// through a glvalue whose type is not similar to one of the following
158+
/// types the behavior is undefined:
159+
/// - the dynamic type of the object,
160+
/// - a type that is the signed or unsigned type corresponding
161+
/// to the dynamic type of the object, or
162+
/// - a char, unsigned char, or std::byte type.
163+
///
164+
/// The C and C++ rules about effective/dynamic type are broadly similar
165+
/// and permit memory to be reused with a different type. C does not have
166+
/// an explicit operation to change the effective type of memory; any store
167+
/// can do it. While C++ arguably does have such an operation (the standard
168+
/// global `operator new(void*, size_t)`), in practice it is important to
169+
/// be just as permissive as C. We therefore treat all stores as being able to
170+
/// change the effective type of memory, regardless of language mode. That is,
171+
/// loads have both a precondition and a postcondition on the effective
172+
/// type of the memory, but stores only have a postcondition. This imposes
173+
/// an inherent limitation that TBAA can only be used to reorder loads
174+
/// before stores. This is quite restrictive, but we don't have much of a
175+
/// choice. In practice, hoisting loads is the most important optimization
176+
/// for alias analysis to enable anyway.
177+
///
178+
/// Therefore, given a load (and its precondition) and an earlier store
179+
/// (and its postcondition), the question posed to TBAA is whether there
180+
/// exists a type that is consistent with both accesses. If there isn't,
181+
/// it's fine to hoist the load because either the memory is non-overlapping
182+
/// or the precondition on the load is wrong (which would be UB).
183+
///
184+
/// LLVM TBAA says that two accesses with TBAA metadata nodes may alias if:
185+
/// - the metadata nodes are the same,
186+
/// - one of the metadata nodes is a base of the other (this can be
187+
/// recursive, but it has to be the original node that's a base,
188+
/// not just that the nodes have a common base), or
189+
/// - one of the metadata nodes is a `tbaa.struct` node (the access
190+
/// necessarily being a `memcpy`) with a subobject node that would
191+
/// be allowed to alias with the other.
192+
///
193+
/// Our job here is to produce metadata nodes that will never say that
194+
/// an alias is not allowed when there exists a type that would be consistent
195+
/// with the types of the accesses from which the nodes were produced.
196+
///
197+
/// The last clause in both language rules permits character types to
198+
/// alias objects of any type. We handle this by converting all character
199+
/// types (as well as `std::byte` and types with the `mayalias` attribute)
200+
/// to a single metadata node (the `char` node), then making sure that
201+
/// that node is a base of every other metadata node we generate.
202+
/// We can always just conservatively use this node if we aren't otherwise
203+
/// sure how to implement the language rules for a type.
204+
///
205+
/// Read literally, the C rule for aggregates permits an aggregate l-value
206+
/// (e.g. of type `struct { int x; }`) to be used to access an object that
207+
/// is not part of an aggregate object of that type (e.g. a local variable
208+
/// of type `int`). That case is perhaps sensical, but it would also permit
209+
/// e.g. an l-value of type `struct { int x; float f; }` to be used to
210+
/// access an object of type `float`, which is nonsense. We interpret this
211+
/// clause as just intending to permit objects to be accessed through an
212+
/// l-value that properly references a containing object.
213+
///
214+
/// C++ does not have an explicit rule for aggregates because in C++
215+
/// a non-member access to an aggregate l-value is always a call to a
216+
/// constructor or assignment operator, which then accesses all the
217+
/// subobjects. In general, however, our interpretation of member
218+
/// accesses is that they are also an access to the containing object
219+
/// and therefore require such an object to exist at that address;
220+
/// this permits us to just use the C rule for the accesses done by
221+
/// trivial copy/move constructors/operators.
222+
///
223+
/// Both C and C++ permit some qualification differences. In C, however,
224+
/// qualification can only differ at the outermost level, whereas C++
225+
/// allows qualification to differ in nested positions through the
226+
/// similar-types rule. This means that e.g. an l-value of type
227+
/// `const float *` is not permitted to access an object of type
228+
/// `float *` in C, but it is in C++. We use the C++ rule
229+
/// unconditionally; the C rule is needlessly strict and frequently
230+
/// violated in practice by code that we don't want to say is wrong.
231+
/// We implement this by just discarding type qualifiers within pointer-like
232+
/// types when deriving TBAA nodes; basically, we produce the TBAA node
233+
/// for the type that is unqualified at all the recursive positions
234+
/// considered by the C++ similar type rule. The implementation
235+
/// doesn't actually construct this recursively-qualified type as a
236+
/// `QualType`; it just ignores qualifiers when recursing into types.
237+
///
238+
/// The similar-type rule only really applies to the standard CVR
239+
/// qualifiers, which never affect representations. Qualifiers such as
240+
/// address spaces that may involve a representation difference would
241+
/// be totally appropriate to distinguish for TBAA purposes. However,
242+
/// the current implementation just discards all qualifiers.
243+
///
244+
/// We handle the signed/unsigned clause by just making unsigned types
245+
/// use the the metadata node for the signed variant of the type. In the
246+
/// language rules, this only applies at the outermost level, and e.g. an
247+
/// l-value of type `signed int *` is not permitted to alias an object of
248+
/// type `unsigned int *`. We choose not to distinguish those types when
249+
/// pointer-type TBAA is enabled, however.
250+
///
251+
/// After discarding qualifiers and signedness differences as above,
252+
/// the language rules come down to whether the types are compatible
253+
/// (in C) or identical (in C++). Even in C, most types are compatible
254+
/// only with themselves. The exceptions will be considered in the cases
255+
/// below.
115256
llvm::MDNode *CodeGenTBAA::getTypeInfoHelper(const Type *Ty) {
116257
uint64_t Size = Context.getTypeSizeInChars(Ty).getQuantity();
117258

@@ -184,13 +325,40 @@ llvm::MDNode *CodeGenTBAA::getTypeInfoHelper(const Type *Ty) {
184325
return getChar();
185326

186327
// Handle pointers and references.
187-
// TODO: Implement C++'s type "similarity" and consider dis-"similar"
188-
// pointers distinct.
189-
if (Ty->isPointerType() || Ty->isReferenceType())
190-
return createScalarTypeNode("any pointer", getChar(), Size);
328+
//
329+
// When PointerTBAA is disabled, all pointers and references use the same
330+
// "any pointer" TBAA node. Otherwise, we generate a type-specific TBAA
331+
// node and use the "any pointer" node as its base for compatibility between
332+
// TUs with different settings. To implement the C++ similar-type rules
333+
// (which we also adopt in C), we need to ignore qualifiers on the
334+
// pointee type, and that has to be done recursively if the pointee type
335+
// is itself a pointer-like type.
336+
//
337+
// Currently we ignore the differences between pointer-like types and just
338+
// and use this tag for the type: `p<pointer depth> <inner type tag>`.
339+
// This means we give e.g. `char **` and `char A::**` the same TBAA tag.
340+
if ((Ty->isPointerType() || Ty->isReferenceType())) {
341+
llvm::MDNode *AnyPtr = createScalarTypeNode("any pointer", getChar(), Size);
342+
if (!CodeGenOpts.PointerTBAA)
343+
return AnyPtr;
344+
unsigned PtrDepth = 0;
345+
do {
346+
PtrDepth++;
347+
Ty = Ty->getPointeeType().getTypePtr()->getUnqualifiedDesugaredType();
348+
// Any array-like type is considered a pointer-to qualification.
349+
if (Ty && Ty->isArrayType()) {
350+
Ty = Ty->getAsArrayTypeUnsafe()->getElementType().getTypePtr();
351+
}
352+
} while (!Ty->getPointeeType().isNull());
353+
std::string PtrName;
354+
llvm::raw_string_ostream OS{PtrName};
355+
OS << "p" << PtrDepth << " ";
356+
appendPointeeName(OS, Ty);
357+
return createScalarTypeNode(PtrName, AnyPtr, Size);
358+
}
191359

192360
// Accesses to arrays are accesses to objects of their element types.
193-
if (CodeGenOpts.NewStructPathTBAA && Ty->isArrayType())
361+
if (CodeGenOpts.ArrayTBAA && Ty->isArrayType())
194362
return getTypeInfo(cast<ArrayType>(Ty)->getElementType());
195363

196364
// Enum types are distinct types. In C++ they have "underlying types",
@@ -241,7 +409,7 @@ llvm::MDNode *CodeGenTBAA::getTypeInfo(QualType QTy) {
241409
// subsequent accesses to direct and indirect members of that aggregate will
242410
// be considered may-alias too.
243411
// TODO: Combine getTypeInfo() and getBaseTypeInfo() into a single function.
244-
if (isValidBaseType(QTy))
412+
if (isValidBaseType(QTy, CodeGenOpts))
245413
return getBaseTypeInfo(QTy);
246414

247415
const Type *Ty = Context.getCanonicalType(QTy).getTypePtr();
@@ -353,7 +521,7 @@ llvm::MDNode *CodeGenTBAA::getBaseTypeInfoHelper(const Type *Ty) {
353521
const CXXRecordDecl *BaseRD = BaseQTy->getAsCXXRecordDecl();
354522
if (BaseRD->isEmpty())
355523
continue;
356-
llvm::MDNode *TypeNode = isValidBaseType(BaseQTy)
524+
llvm::MDNode *TypeNode = isValidBaseType(BaseQTy, CodeGenOpts)
357525
? getBaseTypeInfo(BaseQTy)
358526
: getTypeInfo(BaseQTy);
359527
if (!TypeNode)
@@ -378,8 +546,9 @@ llvm::MDNode *CodeGenTBAA::getBaseTypeInfoHelper(const Type *Ty) {
378546
if (Field->isZeroSize(Context) || Field->isUnnamedBitfield())
379547
continue;
380548
QualType FieldQTy = Field->getType();
381-
llvm::MDNode *TypeNode = isValidBaseType(FieldQTy) ?
382-
getBaseTypeInfo(FieldQTy) : getTypeInfo(FieldQTy);
549+
llvm::MDNode *TypeNode = isValidBaseType(FieldQTy, CodeGenOpts)
550+
? getBaseTypeInfo(FieldQTy)
551+
: getTypeInfo(FieldQTy);
383552
if (!TypeNode)
384553
return nullptr;
385554

@@ -417,7 +586,7 @@ llvm::MDNode *CodeGenTBAA::getBaseTypeInfoHelper(const Type *Ty) {
417586
}
418587

419588
llvm::MDNode *CodeGenTBAA::getBaseTypeInfo(QualType QTy) {
420-
if (!isValidBaseType(QTy))
589+
if (!isValidBaseType(QTy, CodeGenOpts))
421590
return nullptr;
422591

423592
const Type *Ty = Context.getCanonicalType(QTy).getTypePtr();

clang/lib/CodeGen/CodeGenTBAA.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -158,6 +158,8 @@ class CodeGenTBAA {
158158
llvm::MDNode *createScalarTypeNode(StringRef Name, llvm::MDNode *Parent,
159159
uint64_t Size);
160160

161+
void appendPointeeName(raw_ostream &OS, const Type *Ty);
162+
161163
/// getTypeInfoHelper - An internal helper function to generate metadata used
162164
/// to describe accesses to objects of the given type.
163165
llvm::MDNode *getTypeInfoHelper(const Type *Ty);

clang/test/CXX/drs/dr158.cpp

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
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 -pedantic-errors -emit-llvm -o - | FileCheck %s
2+
// RUN: %clang_cc1 -triple x86_64-linux -std=c++11 %s -O3 -pedantic-errors -emit-llvm -o - | FileCheck %s
3+
// RUN: %clang_cc1 -triple x86_64-linux -std=c++14 %s -O3 -pedantic-errors -emit-llvm -o - | FileCheck %s
4+
// RUN: %clang_cc1 -triple x86_64-linux -std=c++1z %s -O3 -pedantic-errors -emit-llvm -o - | FileCheck %s
55

66
// dr158: yes
77

@@ -18,9 +18,9 @@ struct A {};
1818

1919
// CHECK-LABEL: define {{.*}} @_Z1g
2020
const int *(A::*const *g(const int *(A::* const **p)[3], int *(A::***q)[3]))[3] {
21-
// CHECK: load ptr, {{.*}}, !tbaa ![[MEMPTR_TBAA:[^,]*]]
21+
// CHECK: load ptr, {{.*}}, !tbaa ![[MEMPTR_TBAA_CONST:[^,]*]]
2222
const int *(A::*const *x)[3] = *p;
23-
// CHECK: store ptr null, {{.*}}, !tbaa ![[MEMPTR_TBAA]]
23+
// CHECK: store ptr null, {{.*}}, !tbaa ![[MEMPTR_TBAA:[^,]*]]
2424
*q = 0;
2525
return x;
2626
}

0 commit comments

Comments
 (0)