diff options
Diffstat (limited to 'lib/CodeGen/CodeGenTBAA.cpp')
-rw-r--r-- | lib/CodeGen/CodeGenTBAA.cpp | 265 |
1 files changed, 157 insertions, 108 deletions
diff --git a/lib/CodeGen/CodeGenTBAA.cpp b/lib/CodeGen/CodeGenTBAA.cpp index 8a75a552d9faa..f394ea288d469 100644 --- a/lib/CodeGen/CodeGenTBAA.cpp +++ b/lib/CodeGen/CodeGenTBAA.cpp @@ -25,16 +25,18 @@ #include "llvm/IR/Constants.h" #include "llvm/IR/LLVMContext.h" #include "llvm/IR/Metadata.h" +#include "llvm/IR/Module.h" #include "llvm/IR/Type.h" using namespace clang; using namespace CodeGen; -CodeGenTBAA::CodeGenTBAA(ASTContext &Ctx, llvm::LLVMContext& VMContext, +CodeGenTBAA::CodeGenTBAA(ASTContext &Ctx, llvm::Module &M, const CodeGenOptions &CGO, const LangOptions &Features, MangleContext &MContext) - : Context(Ctx), CodeGenOpts(CGO), Features(Features), MContext(MContext), - MDHelper(VMContext), Root(nullptr), Char(nullptr) { -} + : Context(Ctx), Module(M), CodeGenOpts(CGO), + Features(Features), MContext(MContext), MDHelper(M.getContext()), + Root(nullptr), Char(nullptr) +{} CodeGenTBAA::~CodeGenTBAA() { } @@ -54,10 +56,10 @@ llvm::MDNode *CodeGenTBAA::getRoot() { return Root; } -// For both scalar TBAA and struct-path aware TBAA, the scalar type has the -// same format: name, parent node, and offset. -llvm::MDNode *CodeGenTBAA::createTBAAScalarType(StringRef Name, - llvm::MDNode *Parent) { +llvm::MDNode *CodeGenTBAA::createScalarTypeNode(StringRef Name, + llvm::MDNode *Parent, + uint64_t Size) { + (void)Size; // TODO: Support generation of size-aware type nodes. return MDHelper.createTBAAScalarTypeNode(Name, Parent); } @@ -67,7 +69,7 @@ llvm::MDNode *CodeGenTBAA::getChar() { // these special powers only cover user-accessible memory, and doesn't // include things like vtables. if (!Char) - Char = createTBAAScalarType("omnipotent char", getRoot()); + Char = createScalarTypeNode("omnipotent char", getRoot(), /* Size= */ 1); return Char; } @@ -88,21 +90,27 @@ static bool TypeHasMayAlias(QualType QTy) { return false; } -llvm::MDNode * -CodeGenTBAA::getTBAAInfo(QualType QTy) { - // At -O0 or relaxed aliasing, TBAA is not emitted for regular types. - if (CodeGenOpts.OptimizationLevel == 0 || CodeGenOpts.RelaxedAliasing) - return nullptr; - - // If the type has the may_alias attribute (even on a typedef), it is - // effectively in the general char alias class. - if (TypeHasMayAlias(QTy)) - return getChar(); - - const Type *Ty = Context.getCanonicalType(QTy).getTypePtr(); +/// Check if the given type is a valid base type to be used in access tags. +static bool isValidBaseType(QualType QTy) { + if (QTy->isReferenceType()) + return false; + if (const RecordType *TTy = QTy->getAs<RecordType>()) { + const RecordDecl *RD = TTy->getDecl()->getDefinition(); + // Incomplete types are not valid base access types. + if (!RD) + return false; + if (RD->hasFlexibleArrayMember()) + return false; + // RD can be struct, union, class, interface or enum. + // For now, we only handle struct and class. + if (RD->isStruct() || RD->isClass()) + return true; + } + return false; +} - if (llvm::MDNode *N = MetadataCache[Ty]) - return N; +llvm::MDNode *CodeGenTBAA::getTypeInfoHelper(const Type *Ty) { + uint64_t Size = Context.getTypeSizeInChars(Ty).getQuantity(); // Handle builtin types. if (const BuiltinType *BTy = dyn_cast<BuiltinType>(Ty)) { @@ -120,22 +128,21 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) { // Unsigned types can alias their corresponding signed types. case BuiltinType::UShort: - return getTBAAInfo(Context.ShortTy); + return getTypeInfo(Context.ShortTy); case BuiltinType::UInt: - return getTBAAInfo(Context.IntTy); + return getTypeInfo(Context.IntTy); case BuiltinType::ULong: - return getTBAAInfo(Context.LongTy); + return getTypeInfo(Context.LongTy); case BuiltinType::ULongLong: - return getTBAAInfo(Context.LongLongTy); + return getTypeInfo(Context.LongLongTy); case BuiltinType::UInt128: - return getTBAAInfo(Context.Int128Ty); + return getTypeInfo(Context.Int128Ty); // Treat all other builtin types as distinct types. This includes // treating wchar_t, char16_t, and char32_t as distinct from their // "underlying types". default: - return MetadataCache[Ty] = - createTBAAScalarType(BTy->getName(Features), getChar()); + return createScalarTypeNode(BTy->getName(Features), getChar(), Size); } } @@ -143,14 +150,13 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) { // an object through a glvalue of other than one of the following types the // behavior is undefined: [...] a char, unsigned char, or std::byte type." if (Ty->isStdByteType()) - return MetadataCache[Ty] = getChar(); + return getChar(); - // Handle pointers. + // Handle pointers and references. // TODO: Implement C++'s type "similarity" and consider dis-"similar" // pointers distinct. - if (Ty->isPointerType()) - return MetadataCache[Ty] = createTBAAScalarType("any pointer", - getChar()); + if (Ty->isPointerType() || Ty->isReferenceType()) + return createScalarTypeNode("any pointer", getChar(), Size); // Enum types are distinct types. In C++ they have "underlying types", // however they aren't related for TBAA. @@ -160,20 +166,53 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) { // TODO: Is there a way to get a program-wide unique name for a // decl with local linkage or no linkage? if (!Features.CPlusPlus || !ETy->getDecl()->isExternallyVisible()) - return MetadataCache[Ty] = getChar(); + return getChar(); SmallString<256> OutName; llvm::raw_svector_ostream Out(OutName); MContext.mangleTypeName(QualType(ETy, 0), Out); - return MetadataCache[Ty] = createTBAAScalarType(OutName, getChar()); + return createScalarTypeNode(OutName, getChar(), Size); } // For now, handle any other kind of type conservatively. - return MetadataCache[Ty] = getChar(); + return getChar(); +} + +llvm::MDNode *CodeGenTBAA::getTypeInfo(QualType QTy) { + // At -O0 or relaxed aliasing, TBAA is not emitted for regular types. + if (CodeGenOpts.OptimizationLevel == 0 || CodeGenOpts.RelaxedAliasing) + return nullptr; + + // If the type has the may_alias attribute (even on a typedef), it is + // effectively in the general char alias class. + if (TypeHasMayAlias(QTy)) + return getChar(); + + // We need this function to not fall back to returning the "omnipotent char" + // type node for aggregate and union types. Otherwise, any dereference of an + // aggregate will result into the may-alias access descriptor, meaning all + // subsequent accesses to direct and indirect members of that aggregate will + // be considered may-alias too. + // TODO: Combine getTypeInfo() and getBaseTypeInfo() into a single function. + if (isValidBaseType(QTy)) + return getBaseTypeInfo(QTy); + + const Type *Ty = Context.getCanonicalType(QTy).getTypePtr(); + if (llvm::MDNode *N = MetadataCache[Ty]) + return N; + + // Note that the following helper call is allowed to add new nodes to the + // cache, which invalidates all its previously obtained iterators. So we + // first generate the node for the type and then add that node to the cache. + llvm::MDNode *TypeNode = getTypeInfoHelper(Ty); + return MetadataCache[Ty] = TypeNode; } -llvm::MDNode *CodeGenTBAA::getTBAAInfoForVTablePtr() { - return createTBAAScalarType("vtable pointer", getRoot()); +TBAAAccessInfo CodeGenTBAA::getVTablePtrAccessInfo(llvm::Type *VTablePtrType) { + llvm::DataLayout DL(&Module); + unsigned Size = DL.getPointerTypeSize(VTablePtrType); + return TBAAAccessInfo(createScalarTypeNode("vtable pointer", getRoot(), Size), + Size); } bool @@ -212,8 +251,8 @@ CodeGenTBAA::CollectFields(uint64_t BaseOffset, /* Otherwise, treat whatever it is as a field. */ uint64_t Offset = BaseOffset; uint64_t Size = Context.getTypeSizeInChars(QTy).getQuantity(); - llvm::MDNode *TBAAInfo = MayAlias ? getChar() : getTBAAInfo(QTy); - llvm::MDNode *TBAATag = getTBAAScalarTagInfo(TBAAInfo); + llvm::MDNode *TBAAType = MayAlias ? getChar() : getTypeInfo(QTy); + llvm::MDNode *TBAATag = getAccessTagInfo(TBAAAccessInfo(TBAAType, Size)); Fields.push_back(llvm::MDBuilder::TBAAStructField(Offset, Size, TBAATag)); return true; } @@ -233,46 +272,23 @@ CodeGenTBAA::getTBAAStructInfo(QualType QTy) { return StructMetadataCache[Ty] = nullptr; } -/// Check if the given type can be handled by path-aware TBAA. -static bool isTBAAPathStruct(QualType QTy) { - if (const RecordType *TTy = QTy->getAs<RecordType>()) { - const RecordDecl *RD = TTy->getDecl()->getDefinition(); - if (RD->hasFlexibleArrayMember()) - return false; - // RD can be struct, union, class, interface or enum. - // For now, we only handle struct and class. - if (RD->isStruct() || RD->isClass()) - return true; - } - return false; -} - -llvm::MDNode * -CodeGenTBAA::getTBAAStructTypeInfo(QualType QTy) { - const Type *Ty = Context.getCanonicalType(QTy).getTypePtr(); - assert(isTBAAPathStruct(QTy)); - - if (llvm::MDNode *N = StructTypeMetadataCache[Ty]) - return N; - - if (const RecordType *TTy = QTy->getAs<RecordType>()) { +llvm::MDNode *CodeGenTBAA::getBaseTypeInfoHelper(const Type *Ty) { + if (auto *TTy = dyn_cast<RecordType>(Ty)) { const RecordDecl *RD = TTy->getDecl()->getDefinition(); - const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); - SmallVector <std::pair<llvm::MDNode*, uint64_t>, 4> Fields; - unsigned idx = 0; - for (RecordDecl::field_iterator i = RD->field_begin(), - e = RD->field_end(); i != e; ++i, ++idx) { - QualType FieldQTy = i->getType(); - llvm::MDNode *FieldNode; - if (isTBAAPathStruct(FieldQTy)) - FieldNode = getTBAAStructTypeInfo(FieldQTy); - else - FieldNode = getTBAAInfo(FieldQTy); - if (!FieldNode) - return StructTypeMetadataCache[Ty] = nullptr; - Fields.push_back(std::make_pair( - FieldNode, Layout.getFieldOffset(idx) / Context.getCharWidth())); + SmallVector<llvm::MDBuilder::TBAAStructField, 4> Fields; + for (FieldDecl *Field : RD->fields()) { + QualType FieldQTy = Field->getType(); + llvm::MDNode *TypeNode = isValidBaseType(FieldQTy) ? + getBaseTypeInfo(FieldQTy) : getTypeInfo(FieldQTy); + if (!TypeNode) + return BaseTypeMetadataCache[Ty] = nullptr; + + uint64_t BitOffset = Layout.getFieldOffset(Field->getFieldIndex()); + uint64_t Offset = Context.toCharUnitsFromBits(BitOffset).getQuantity(); + uint64_t Size = Context.getTypeSizeInChars(FieldQTy).getQuantity(); + Fields.push_back(llvm::MDBuilder::TBAAStructField(Offset, Size, + TypeNode)); } SmallString<256> OutName; @@ -283,47 +299,80 @@ CodeGenTBAA::getTBAAStructTypeInfo(QualType QTy) { } else { OutName = RD->getName(); } + + // TODO: Support size-aware type nodes and create one here for the + // given aggregate type. + // Create the struct type node with a vector of pairs (offset, type). - return StructTypeMetadataCache[Ty] = - MDHelper.createTBAAStructTypeNode(OutName, Fields); + SmallVector<std::pair<llvm::MDNode*, uint64_t>, 4> OffsetsAndTypes; + for (const auto &Field : Fields) + OffsetsAndTypes.push_back(std::make_pair(Field.Type, Field.Offset)); + return MDHelper.createTBAAStructTypeNode(OutName, OffsetsAndTypes); } - return StructMetadataCache[Ty] = nullptr; + return nullptr; } -/// Return a TBAA tag node for both scalar TBAA and struct-path aware TBAA. -llvm::MDNode * -CodeGenTBAA::getTBAAStructTagInfo(QualType BaseQTy, llvm::MDNode *AccessNode, - uint64_t Offset) { - if (!AccessNode) +llvm::MDNode *CodeGenTBAA::getBaseTypeInfo(QualType QTy) { + if (!isValidBaseType(QTy)) + return nullptr; + + const Type *Ty = Context.getCanonicalType(QTy).getTypePtr(); + if (llvm::MDNode *N = BaseTypeMetadataCache[Ty]) + return N; + + // Note that the following helper call is allowed to add new nodes to the + // cache, which invalidates all its previously obtained iterators. So we + // first generate the node for the type and then add that node to the cache. + llvm::MDNode *TypeNode = getBaseTypeInfoHelper(Ty); + return BaseTypeMetadataCache[Ty] = TypeNode; +} + +llvm::MDNode *CodeGenTBAA::getAccessTagInfo(TBAAAccessInfo Info) { + assert(!Info.isIncomplete() && "Access to an object of an incomplete type!"); + + if (Info.isMayAlias()) + Info = TBAAAccessInfo(getChar(), Info.Size); + + if (!Info.AccessType) return nullptr; if (!CodeGenOpts.StructPathTBAA) - return getTBAAScalarTagInfo(AccessNode); + Info = TBAAAccessInfo(Info.AccessType, Info.Size); - const Type *BTy = Context.getCanonicalType(BaseQTy).getTypePtr(); - TBAAPathTag PathTag = TBAAPathTag(BTy, AccessNode, Offset); - if (llvm::MDNode *N = StructTagMetadataCache[PathTag]) + llvm::MDNode *&N = AccessTagMetadataCache[Info]; + if (N) return N; - llvm::MDNode *BNode = nullptr; - if (isTBAAPathStruct(BaseQTy)) - BNode = getTBAAStructTypeInfo(BaseQTy); - if (!BNode) - return StructTagMetadataCache[PathTag] = - MDHelper.createTBAAStructTagNode(AccessNode, AccessNode, 0); + if (!Info.BaseType) { + Info.BaseType = Info.AccessType; + assert(!Info.Offset && "Nonzero offset for an access with no base type!"); + } + return N = MDHelper.createTBAAStructTagNode(Info.BaseType, Info.AccessType, + Info.Offset); +} - return StructTagMetadataCache[PathTag] = - MDHelper.createTBAAStructTagNode(BNode, AccessNode, Offset); +TBAAAccessInfo CodeGenTBAA::mergeTBAAInfoForCast(TBAAAccessInfo SourceInfo, + TBAAAccessInfo TargetInfo) { + if (SourceInfo.isMayAlias() || TargetInfo.isMayAlias()) + return TBAAAccessInfo::getMayAliasInfo(); + return TargetInfo; } -llvm::MDNode * -CodeGenTBAA::getTBAAScalarTagInfo(llvm::MDNode *AccessNode) { - if (!AccessNode) - return nullptr; - if (llvm::MDNode *N = ScalarTagMetadataCache[AccessNode]) - return N; +TBAAAccessInfo +CodeGenTBAA::mergeTBAAInfoForConditionalOperator(TBAAAccessInfo InfoA, + TBAAAccessInfo InfoB) { + if (InfoA == InfoB) + return InfoA; + + if (!InfoA || !InfoB) + return TBAAAccessInfo(); + + if (InfoA.isMayAlias() || InfoB.isMayAlias()) + return TBAAAccessInfo::getMayAliasInfo(); - return ScalarTagMetadataCache[AccessNode] = - MDHelper.createTBAAStructTagNode(AccessNode, AccessNode, 0); + // TODO: Implement the rest of the logic here. For example, two accesses + // with same final access types result in an access to an object of that final + // access type regardless of their base types. + return TBAAAccessInfo::getMayAliasInfo(); } |