From b22c7dc707cf3770ff3b5e5f11f11fd0aaa06d9b Mon Sep 17 00:00:00 2001 From: Dan Gohman Date: Fri, 28 Sep 2012 21:58:29 +0000 Subject: [PATCH] Add basic support for adding !tbaa.struct metadata on llvm.memcpy calls for struct assignment. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@164853 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGExprAgg.cpp | 8 ++++- lib/CodeGen/CodeGenModule.cpp | 6 ++++ lib/CodeGen/CodeGenModule.h | 1 + lib/CodeGen/CodeGenTBAA.cpp | 57 +++++++++++++++++++++++++++++++++++ lib/CodeGen/CodeGenTBAA.h | 15 +++++++++ test/CodeGen/tbaa-struct.cpp | 16 ++++++++++ 6 files changed, 102 insertions(+), 1 deletion(-) create mode 100644 test/CodeGen/tbaa-struct.cpp diff --git a/lib/CodeGen/CGExprAgg.cpp b/lib/CodeGen/CGExprAgg.cpp index 48b21d2f85..c9ffc19a8b 100644 --- a/lib/CodeGen/CGExprAgg.cpp +++ b/lib/CodeGen/CGExprAgg.cpp @@ -1362,11 +1362,17 @@ void CodeGenFunction::EmitAggregateCopy(llvm::Value *DestPtr, } } } + + // Determine the metadata to describe the position of any padding in this + // memcpy, as well as the TBAA tags for the members of the struct, in case + // the optimizer wishes to expand it in to scalar memory operations. + llvm::MDNode *TBAAStructTag = CGM.getTBAAStructInfo(Ty); Builder.CreateMemCpy(DestPtr, SrcPtr, llvm::ConstantInt::get(IntPtrTy, TypeInfo.first.getQuantity()), - alignment.getQuantity(), isVolatile); + alignment.getQuantity(), isVolatile, + /*TBAATag=*/0, TBAAStructTag); } void CodeGenFunction::MaybeEmitStdInitializerListCleanup(llvm::Value *loc, diff --git a/lib/CodeGen/CodeGenModule.cpp b/lib/CodeGen/CodeGenModule.cpp index 0a33e809b3..164031a503 100644 --- a/lib/CodeGen/CodeGenModule.cpp +++ b/lib/CodeGen/CodeGenModule.cpp @@ -202,6 +202,12 @@ llvm::MDNode *CodeGenModule::getTBAAInfoForVTablePtr() { return TBAA->getTBAAInfoForVTablePtr(); } +llvm::MDNode *CodeGenModule::getTBAAStructInfo(QualType QTy) { + if (!TBAA) + return 0; + return TBAA->getTBAAStructInfo(QTy); +} + void CodeGenModule::DecorateInstruction(llvm::Instruction *Inst, llvm::MDNode *TBAAInfo) { Inst->setMetadata(llvm::LLVMContext::MD_tbaa, TBAAInfo); diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 6e81693f7f..3b5e1425bd 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -461,6 +461,7 @@ public: llvm::MDNode *getTBAAInfo(QualType QTy); llvm::MDNode *getTBAAInfoForVTablePtr(); + llvm::MDNode *getTBAAStructInfo(QualType QTy); bool isTypeConstant(QualType QTy, bool ExcludeCtorDtor); diff --git a/lib/CodeGen/CodeGenTBAA.cpp b/lib/CodeGen/CodeGenTBAA.cpp index bab60afbb7..d9004a02ae 100644 --- a/lib/CodeGen/CodeGenTBAA.cpp +++ b/lib/CodeGen/CodeGenTBAA.cpp @@ -17,6 +17,7 @@ #include "CodeGenTBAA.h" #include "clang/AST/ASTContext.h" +#include "clang/AST/RecordLayout.h" #include "clang/AST/Mangle.h" #include "clang/Frontend/CodeGenOptions.h" #include "llvm/LLVMContext.h" @@ -167,3 +168,59 @@ CodeGenTBAA::getTBAAInfo(QualType QTy) { llvm::MDNode *CodeGenTBAA::getTBAAInfoForVTablePtr() { return MDHelper.createTBAANode("vtable pointer", getRoot()); } + +bool +CodeGenTBAA::CollectFields(uint64_t BaseOffset, + QualType QTy, + SmallVectorImpl & + Fields, + bool MayAlias) { + /* Things not handled yet include: C++ base classes, bitfields, */ + + if (const RecordType *TTy = QTy->getAs()) { + const RecordDecl *RD = TTy->getDecl()->getDefinition(); + if (RD->hasFlexibleArrayMember()) + return false; + + // TODO: Handle C++ base classes. + if (const CXXRecordDecl *Decl = dyn_cast(RD)) + if (Decl->bases_begin() != Decl->bases_end()) + return false; + + const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD); + + unsigned idx = 0; + for (RecordDecl::field_iterator i = RD->field_begin(), + e = RD->field_end(); i != e; ++i, ++idx) { + uint64_t Offset = BaseOffset + + Layout.getFieldOffset(idx) / Context.getCharWidth(); + QualType FieldQTy = i->getType(); + if (!CollectFields(Offset, FieldQTy, Fields, + MayAlias || TypeHasMayAlias(FieldQTy))) + return false; + } + return true; + } + + /* 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); + Fields.push_back(llvm::MDBuilder::TBAAStructField(Offset, Size, TBAAInfo)); + return true; +} + +llvm::MDNode * +CodeGenTBAA::getTBAAStructInfo(QualType QTy) { + const Type *Ty = Context.getCanonicalType(QTy).getTypePtr(); + + if (llvm::MDNode *N = StructMetadataCache[Ty]) + return N; + + SmallVector Fields; + if (CollectFields(0, QTy, Fields, TypeHasMayAlias(QTy))) + return MDHelper.createTBAAStructNode(Fields); + + // For now, handle any other kind of type conservatively. + return StructMetadataCache[Ty] = NULL; +} diff --git a/lib/CodeGen/CodeGenTBAA.h b/lib/CodeGen/CodeGenTBAA.h index c17a5cf03c..eedb996f3e 100644 --- a/lib/CodeGen/CodeGenTBAA.h +++ b/lib/CodeGen/CodeGenTBAA.h @@ -49,6 +49,10 @@ class CodeGenTBAA { /// MetadataCache - This maps clang::Types to llvm::MDNodes describing them. llvm::DenseMap MetadataCache; + /// StructMetadataCache - This maps clang::Types to llvm::MDNodes describing + /// them for struct assignments. + llvm::DenseMap StructMetadataCache; + llvm::MDNode *Root; llvm::MDNode *Char; @@ -60,6 +64,13 @@ class CodeGenTBAA { /// considered to be equivalent to it. llvm::MDNode *getChar(); + /// CollectFields - Collect information about the fields of a type for + /// !tbaa.struct metadata formation. Return false for an unsupported type. + bool CollectFields(uint64_t BaseOffset, + QualType Ty, + SmallVectorImpl &Fields, + bool MayAlias); + public: CodeGenTBAA(ASTContext &Ctx, llvm::LLVMContext &VMContext, const CodeGenOptions &CGO, @@ -74,6 +85,10 @@ public: /// getTBAAInfoForVTablePtr - Get the TBAA MDNode to be used for a /// dereference of a vtable pointer. llvm::MDNode *getTBAAInfoForVTablePtr(); + + /// getTBAAStructInfo - Get the TBAAStruct MDNode to be used for a memcpy of + /// the given type. + llvm::MDNode *getTBAAStructInfo(QualType QTy); }; } // end namespace CodeGen diff --git a/test/CodeGen/tbaa-struct.cpp b/test/CodeGen/tbaa-struct.cpp new file mode 100644 index 0000000000..6bff3370bf --- /dev/null +++ b/test/CodeGen/tbaa-struct.cpp @@ -0,0 +1,16 @@ +// RUN: %clang_cc1 -emit-llvm -o - -O1 %s | FileCheck %s +// +// Check that we generate !tbaa.struct metadata for struct copies. +struct A { + short s; + int i; + char c; + int j; +}; + +void copy(struct A *a, struct A *b) { + *a = *b; +} + +// CHECK: call void @llvm.memcpy.p0i8.p0i8.i64(i8* %{{.*}}, i8* %{{.*}}, i64 16, i32 4, i1 false), !tbaa.struct [[TS:!.*]] +// CHECK: [[TS]] = metadata !{i64 0, i64 2, metadata !{{.*}}, i64 4, i64 4, metadata !{{.*}}, i64 8, i64 1, metadata !{{.*}}, i64 12, i64 4, metadata !{{.*}}} -- 2.40.0