|
1 | 1 | #include "CIRGenTBAA.h"
|
| 2 | +#include "CIRGenCXXABI.h" |
2 | 3 | #include "CIRGenTypes.h"
|
3 | 4 | #include "mlir/IR/BuiltinAttributes.h"
|
4 | 5 | #include "mlir/IR/MLIRContext.h"
|
@@ -204,7 +205,7 @@ cir::TBAAAttr CIRGenTBAA::getTypeInfo(clang::QualType qty) {
|
204 | 205 | // function.
|
205 | 206 | if (isValidBaseType(qty)) {
|
206 | 207 | assert(!cir::MissingFeatures::tbaaTagForStruct());
|
207 |
| - return tbaa_NYI(mlirContext); |
| 208 | + return getValidBaseTypeInfo(qty); |
208 | 209 | }
|
209 | 210 |
|
210 | 211 | const clang::Type *ty = astContext.getCanonicalType(qty).getTypePtr();
|
@@ -248,9 +249,101 @@ mlir::ArrayAttr CIRGenTBAA::getTBAAStructInfo(clang::QualType qty) {
|
248 | 249 | }
|
249 | 250 |
|
250 | 251 | cir::TBAAAttr CIRGenTBAA::getBaseTypeInfo(clang::QualType qty) {
|
251 |
| - return tbaa_NYI(mlirContext); |
| 252 | + return isValidBaseType(qty) ? getValidBaseTypeInfo(qty) : nullptr; |
| 253 | +} |
| 254 | + |
| 255 | +cir::TBAAAttr CIRGenTBAA::getValidBaseTypeInfo(clang::QualType qty) { |
| 256 | + assert(isValidBaseType(qty) && "Must be a valid base type"); |
| 257 | + |
| 258 | + const clang::Type *ty = astContext.getCanonicalType(qty).getTypePtr(); |
| 259 | + |
| 260 | + // nullptr is a valid value in the cache, so use find rather than [] |
| 261 | + auto iter = baseTypeMetadataCache.find(ty); |
| 262 | + if (iter != baseTypeMetadataCache.end()) |
| 263 | + return iter->second; |
| 264 | + |
| 265 | + // First calculate the metadata, before recomputinyg the insertion point, as |
| 266 | + // the helper can recursively call us. |
| 267 | + auto typeNode = getBaseTypeInfoHelper(ty); |
| 268 | + LLVM_ATTRIBUTE_UNUSED auto inserted = |
| 269 | + baseTypeMetadataCache.insert({ty, typeNode}); |
| 270 | + assert(inserted.second && "BaseType metadata was already inserted"); |
| 271 | + |
| 272 | + return typeNode; |
252 | 273 | }
|
| 274 | +cir::TBAAAttr CIRGenTBAA::getBaseTypeInfoHelper(const clang::Type *ty) { |
| 275 | + using namespace clang; |
| 276 | + if (auto *tty = mlir::dyn_cast<clang::RecordType>(ty)) { |
| 277 | + const clang::RecordDecl *rd = tty->getDecl()->getDefinition(); |
| 278 | + const ASTRecordLayout &layout = astContext.getASTRecordLayout(rd); |
| 279 | + SmallVector<cir::TBAAMemberAttr, 4> fields; |
| 280 | + if (const CXXRecordDecl *cxxrd = dyn_cast<CXXRecordDecl>(rd)) { |
| 281 | + // Handle C++ base classes. Non-virtual bases can treated a kind of |
| 282 | + // field. Virtual bases are more complex and omitted, but avoid an |
| 283 | + // incomplete view for NewStructPathTBAA. |
| 284 | + if (codeGenOpts.NewStructPathTBAA && cxxrd->getNumVBases() != 0) |
| 285 | + return nullptr; |
| 286 | + for (const CXXBaseSpecifier &cxxBaseSpecifier : cxxrd->bases()) { |
| 287 | + if (cxxBaseSpecifier.isVirtual()) |
| 288 | + continue; |
| 289 | + QualType baseQTy = cxxBaseSpecifier.getType(); |
| 290 | + const CXXRecordDecl *baseRD = baseQTy->getAsCXXRecordDecl(); |
| 291 | + if (baseRD->isEmpty()) |
| 292 | + continue; |
| 293 | + auto typeNode = isValidBaseType(baseQTy) ? getValidBaseTypeInfo(baseQTy) |
| 294 | + : getTypeInfo(baseQTy); |
| 295 | + if (!typeNode) |
| 296 | + return nullptr; |
| 297 | + uint64_t offset = layout.getBaseClassOffset(baseRD).getQuantity(); |
| 298 | + [[maybe_unused]] uint64_t size = |
| 299 | + astContext.getASTRecordLayout(baseRD).getDataSize().getQuantity(); |
| 300 | + fields.push_back( |
| 301 | + cir::TBAAMemberAttr::get(mlirContext, typeNode, offset)); |
| 302 | + } |
| 303 | + // The order in which base class subobjects are allocated is |
| 304 | + // unspecified, so may differ from declaration order. In particular, |
| 305 | + // Itanium ABI will allocate a primary base first. Since we exclude |
| 306 | + // empty subobjects, the objects are not overlapping and their offsets |
| 307 | + // are unique. |
| 308 | + llvm::sort(fields, [](const cir::TBAAMemberAttr &lhs, |
| 309 | + const cir::TBAAMemberAttr &rhs) { |
| 310 | + return lhs.getOffset() < rhs.getOffset(); |
| 311 | + }); |
| 312 | + } |
| 313 | + for (FieldDecl *field : rd->fields()) { |
| 314 | + if (field->isZeroSize(astContext) || field->isUnnamedBitField()) |
| 315 | + continue; |
| 316 | + QualType fieldQTy = field->getType(); |
| 317 | + auto typeNode = isValidBaseType(fieldQTy) ? getValidBaseTypeInfo(fieldQTy) |
| 318 | + : getTypeInfo(fieldQTy); |
| 319 | + if (!typeNode) |
| 320 | + return nullptr; |
| 321 | + |
| 322 | + uint64_t bitOffset = layout.getFieldOffset(field->getFieldIndex()); |
| 323 | + uint64_t offset = astContext.toCharUnitsFromBits(bitOffset).getQuantity(); |
| 324 | + [[maybe_unused]] uint64_t size = |
| 325 | + astContext.getTypeSizeInChars(fieldQTy).getQuantity(); |
| 326 | + fields.push_back(cir::TBAAMemberAttr::get(mlirContext, typeNode, offset)); |
| 327 | + } |
| 328 | + |
| 329 | + SmallString<256> outName; |
| 330 | + if (features.CPlusPlus) { |
| 331 | + // Don't use the mangler for C code. |
| 332 | + llvm::raw_svector_ostream out(outName); |
| 333 | + types.getCXXABI().getMangleContext().mangleCanonicalTypeName( |
| 334 | + QualType(ty, 0), out); |
| 335 | + } else { |
| 336 | + outName = rd->getName(); |
| 337 | + } |
253 | 338 |
|
| 339 | + if (codeGenOpts.NewStructPathTBAA) { |
| 340 | + assert(!cir::MissingFeatures::tbaaNewStructPath()); |
| 341 | + return nullptr; |
| 342 | + } |
| 343 | + return cir::TBAAStructAttr::get(mlirContext, outName, fields); |
| 344 | + } |
| 345 | + return nullptr; |
| 346 | +} |
254 | 347 | cir::TBAAAttr CIRGenTBAA::getAccessTagInfo(TBAAAccessInfo tbaaInfo) {
|
255 | 348 | assert(!tbaaInfo.isIncomplete() &&
|
256 | 349 | "Access to an object of an incomplete type!");
|
|
0 commit comments