@@ -65,7 +65,7 @@ static bool isValidBaseType(clang::QualType qty) {
6565 return false ;
6666}
6767
68- cir::TBAAAttr CIRGenTBAA::getScalarTypeInfo (clang::QualType qty) {
68+ cir::TBAAScalarAttr CIRGenTBAA::getScalarTypeInfo (clang::QualType qty) {
6969 const clang::Type *ty = astContext.getCanonicalType (qty).getTypePtr ();
7070 assert (mlir::isa<clang::BuiltinType>(ty));
7171 const clang::BuiltinType *bty = mlir::dyn_cast<BuiltinType>(ty);
@@ -159,12 +159,78 @@ cir::TBAAAttr CIRGenTBAA::getTypeInfoHelper(clang::QualType qty) {
159159 // they involve a significant representation difference. We don't
160160 // currently do so, however.
161161 if (ty->isPointerType () || ty->isReferenceType ()) {
162- if (!codeGenOpts.PointerTBAA ) {
163- return cir::TBAAScalarAttr::get (mlirContext, " any pointer" ,
164- types.convertType (qty));
162+ auto anyPtr = cir::TBAAScalarAttr::get (mlirContext, " any pointer" ,
163+ types.convertType (qty));
164+ if (!codeGenOpts.PointerTBAA )
165+ return anyPtr;
166+ // C++ [basic.lval]p11 permits objects to accessed through an l-value of
167+ // similar type. Two types are similar under C++ [conv.qual]p2 if the
168+ // decomposition of the types into pointers, member pointers, and arrays has
169+ // the same structure when ignoring cv-qualifiers at each level of the
170+ // decomposition. Meanwhile, C makes T(*)[] and T(*)[N] compatible, which
171+ // would really complicate any attempt to distinguish pointers to arrays by
172+ // their bounds. It's simpler, and much easier to explain to users, to
173+ // simply treat all pointers to arrays as pointers to their element type for
174+ // aliasing purposes. So when creating a TBAA tag for a pointer type, we
175+ // recursively ignore both qualifiers and array types when decomposing the
176+ // pointee type. The only meaningful remaining structure is the number of
177+ // pointer types we encountered along the way, so we just produce the tag
178+ // "p<depth> <base type tag>". If we do find a member pointer type, for now
179+ // we just conservatively bail out with AnyPtr (below) rather than trying to
180+ // create a tag that honors the similar-type rules while still
181+ // distinguishing different kinds of member pointer.
182+ unsigned ptrDepth = 0 ;
183+ do {
184+ ptrDepth++;
185+ ty = ty->getPointeeType ()->getBaseElementTypeUnsafe ();
186+ } while (ty->isPointerType ());
187+ assert (!isa<VariableArrayType>(ty));
188+ // When the underlying type is a builtin type, we compute the pointee type
189+ // string recursively, which is implicitly more forgiving than the standards
190+ // require. Effectively, we are turning the question "are these types
191+ // compatible/similar" into "are accesses to these types allowed to alias".
192+ // In both C and C++, the latter question has special carve-outs for
193+ // signedness mismatches that only apply at the top level. As a result, we
194+ // are allowing e.g. `int *` l-values to access `unsigned *` objects.
195+ SmallString<256 > tyName;
196+
197+ if (isa<BuiltinType>(ty)) {
198+ auto scalarAttr = getScalarTypeInfo (ty->getCanonicalTypeInternal ());
199+ tyName = scalarAttr.getId ();
200+ } else {
201+ // Be conservative if the type isn't a RecordType. We are specifically
202+ // required to do this for member pointers until we implement the
203+ // similar-types rule.
204+ const auto *rt = ty->getAs <RecordType>();
205+ if (!rt)
206+ return anyPtr;
207+
208+ // For unnamed structs or unions C's compatible types rule applies. Two
209+ // compatible types in different compilation units can have different
210+ // mangled names, meaning the metadata emitted below would incorrectly
211+ // mark them as no-alias. Use AnyPtr for such types in both C and C++, as
212+ // C and C++ types may be visible when doing LTO.
213+ //
214+ // Note that using AnyPtr is overly conservative. We could summarize the
215+ // members of the type, as per the C compatibility rule in the future.
216+ // This also covers anonymous structs and unions, which have a different
217+ // compatibility rule, but it doesn't matter because you can never have a
218+ // pointer to an anonymous struct or union.
219+ if (!rt->getDecl ()->getDeclName ())
220+ return anyPtr;
221+
222+ // For non-builtin types use the mangled name of the canonical type.
223+ llvm::raw_svector_ostream tyOut (tyName);
224+ types.getCXXABI ().getMangleContext ().mangleCanonicalTypeName (
225+ QualType (ty, 0 ), tyOut);
165226 }
166- assert (!cir::MissingFeatures::tbaaPointer ());
167- return tbaa_NYI (mlirContext);
227+
228+ SmallString<256 > outName (" p" );
229+ outName += std::to_string (ptrDepth);
230+ outName += " " ;
231+ outName += tyName;
232+ return cir::TBAAScalarAttr::get (mlirContext, outName,
233+ types.convertType (qty), anyPtr);
168234 }
169235 // Accesses to arrays are accesses to objects of their element types.
170236 if (codeGenOpts.NewStructPathTBAA && ty->isArrayType ()) {
0 commit comments