===================================================================
--- include/clang/Driver/CC1Options.td (revision 178718)
+++ include/clang/Driver/CC1Options.td (working copy)
@@ -161,6 +161,8 @@
HelpText<"Use register sized accesses to bit-fields, when possible.">;
def relaxed_aliasing : Flag<["-"], "relaxed-aliasing">,
HelpText<"Turn off Type Based Alias Analysis">;
+def struct_path_tbaa : Flag<["-"], "struct-path-tbaa">,
+ HelpText<"Turn on struct-path aware Type Based Alias Analysis">;
def masm_verbose : Flag<["-"], "masm-verbose">,
HelpText<"Generate verbose assembly output">;
def mcode_model : Separate<["-"], "mcode-model">,
Index: include/clang/Driver/Options.td
===================================================================
--- include/clang/Driver/Options.td (revision 178718)
+++ include/clang/Driver/Options.td (working copy)
@@ -587,6 +587,7 @@
Flags<[CC1Option]>, HelpText<"Disable spell-checking">;
def fno_stack_protector : Flag<["-"], "fno-stack-protector">, Group<f_Group>;
def fno_strict_aliasing : Flag<["-"], "fno-strict-aliasing">, Group<f_Group>;
+def fstruct_path_tbaa : Flag<["-"], "fstruct-path-tbaa">, Group<f_Group>;
def fno_strict_enums : Flag<["-"], "fno-strict-enums">, Group<f_Group>;
def fno_strict_overflow : Flag<["-"], "fno-strict-overflow">, Group<f_Group>;
def fno_threadsafe_statics : Flag<["-"], "fno-threadsafe-statics">, Group<f_Group>,
Index: include/clang/Frontend/CodeGenOptions.def
===================================================================
--- include/clang/Frontend/CodeGenOptions.def (revision 178718)
+++ include/clang/Frontend/CodeGenOptions.def (working copy)
@@ -85,6 +85,7 @@
VALUE_CODEGENOPT(OptimizeSize, 2, 0) ///< If -Os (==1) or -Oz (==2) is specified.
CODEGENOPT(RelaxAll , 1, 0) ///< Relax all machine code instructions.
CODEGENOPT(RelaxedAliasing , 1, 0) ///< Set when -fno-strict-aliasing is enabled.
+CODEGENOPT(StructPathTBAA , 1, 0) ///< Whether or not to use struct-path TBAA.
CODEGENOPT(SaveTempLabels , 1, 0) ///< Save temporary labels.
CODEGENOPT(SanitizeAddressZeroBaseShadow , 1, 0) ///< Map shadow memory at zero
///< offset in AddressSanitizer.
Index: lib/CodeGen/CGExpr.cpp
===================================================================
--- lib/CodeGen/CGExpr.cpp (revision 178718)
+++ lib/CodeGen/CGExpr.cpp (working copy)
@@ -1044,7 +1044,8 @@
llvm::Value *CodeGenFunction::EmitLoadOfScalar(LValue lvalue) {
return EmitLoadOfScalar(lvalue.getAddress(), lvalue.isVolatile(),
lvalue.getAlignment().getQuantity(),
- lvalue.getType(), lvalue.getTBAAInfo());
+ lvalue.getType(), lvalue.getTBAAInfo(),
+ lvalue.getTBAABaseType(), lvalue.getTBAAOffset());
}
static bool hasBooleanRepresentation(QualType Ty) {
@@ -1106,7 +1107,9 @@
llvm::Value *CodeGenFunction::EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
unsigned Alignment, QualType Ty,
- llvm::MDNode *TBAAInfo) {
+ llvm::MDNode *TBAAInfo,
+ QualType TBAABaseType,
+ uint64_t TBAAOffset) {
// For better performance, handle vector loads differently.
if (Ty->isVectorType()) {
llvm::Value *V;
@@ -1158,8 +1161,11 @@
Load->setVolatile(true);
if (Alignment)
Load->setAlignment(Alignment);
- if (TBAAInfo)
- CGM.DecorateInstruction(Load, TBAAInfo);
+ if (TBAAInfo) {
+ llvm::MDNode *TBAAPath = CGM.getTBAAStructTagInfo(TBAABaseType, TBAAInfo,
+ TBAAOffset);
+ CGM.DecorateInstruction(Load, TBAAPath);
+ }
if ((SanOpts->Bool && hasBooleanRepresentation(Ty)) ||
(SanOpts->Enum && Ty->getAs<EnumType>())) {
@@ -1217,7 +1223,8 @@
bool Volatile, unsigned Alignment,
QualType Ty,
llvm::MDNode *TBAAInfo,
- bool isInit) {
+ bool isInit, QualType TBAABaseType,
+ uint64_t TBAAOffset) {
// Handle vectors differently to get better performance.
if (Ty->isVectorType()) {
@@ -1268,15 +1275,19 @@
llvm::StoreInst *Store = Builder.CreateStore(Value, Addr, Volatile);
if (Alignment)
Store->setAlignment(Alignment);
- if (TBAAInfo)
- CGM.DecorateInstruction(Store, TBAAInfo);
+ if (TBAAInfo) {
+ llvm::MDNode *TBAAPath = CGM.getTBAAStructTagInfo(TBAABaseType, TBAAInfo,
+ TBAAOffset);
+ CGM.DecorateInstruction(Store, TBAAPath);
+ }
}
void CodeGenFunction::EmitStoreOfScalar(llvm::Value *value, LValue lvalue,
bool isInit) {
EmitStoreOfScalar(value, lvalue.getAddress(), lvalue.isVolatile(),
lvalue.getAlignment().getQuantity(), lvalue.getType(),
- lvalue.getTBAAInfo(), isInit);
+ lvalue.getTBAAInfo(), isInit, lvalue.getTBAABaseType(),
+ lvalue.getTBAAOffset());
}
/// EmitLoadOfLValue - Given an expression that represents a value lvalue, this
@@ -2494,9 +2505,12 @@
llvm::Value *addr = base.getAddress();
unsigned cvr = base.getVRQualifiers();
+ bool TBAAPath = CGM.getCodeGenOpts().StructPathTBAA;
if (rec->isUnion()) {
// For unions, there is no pointer adjustment.
assert(!type->isReferenceType() && "union has reference member");
+ // TODO: handle path-aware TBAA for union.
+ TBAAPath = false;
} else {
// For structs, we GEP to the field that the record layout suggests.
unsigned idx = CGM.getTypes().getCGRecordLayout(rec).getLLVMFieldNo(field);
@@ -2508,6 +2522,8 @@
if (cvr & Qualifiers::Volatile) load->setVolatile(true);
load->setAlignment(alignment.getQuantity());
+ // Loading the reference will disable path-aware TBAA.
+ TBAAPath = false;
if (CGM.shouldUseTBAA()) {
llvm::MDNode *tbaa;
if (mayAlias)
@@ -2541,6 +2557,16 @@
LValue LV = MakeAddrLValue(addr, type, alignment);
LV.getQuals().addCVRQualifiers(cvr);
+ if (TBAAPath) {
+ const ASTRecordLayout &Layout =
+ getContext().getASTRecordLayout(field->getParent());
+ // Set the base type to be the base type of the base LValue and
+ // update offset to be relative to the base type.
+ LV.setTBAABaseType(base.getTBAABaseType());
+ LV.setTBAAOffset(base.getTBAAOffset() +
+ Layout.getFieldOffset(field->getFieldIndex()) /
+ getContext().getCharWidth());
+ }
// __weak attribute on a field is ignored.
if (LV.getQuals().getObjCGCAttr() == Qualifiers::Weak)
Index: lib/CodeGen/CGValue.h
===================================================================
--- lib/CodeGen/CGValue.h (revision 178718)
+++ lib/CodeGen/CGValue.h (working copy)
@@ -157,6 +157,11 @@
Expr *BaseIvarExp;
+ /// Used by struct-path-aware TBAA.
+ QualType TBAABaseType;
+ /// Offset relative to the base type.
+ uint64_t TBAAOffset;
+
/// TBAAInfo - TBAA information to attach to dereferences of this LValue.
llvm::MDNode *TBAAInfo;
@@ -175,6 +180,10 @@
this->ImpreciseLifetime = false;
this->ThreadLocalRef = false;
this->BaseIvarExp = 0;
+
+ // Initialize fields for TBAA.
+ this->TBAABaseType = Type;
+ this->TBAAOffset = 0;
this->TBAAInfo = TBAAInfo;
}
@@ -232,6 +241,12 @@
Expr *getBaseIvarExp() const { return BaseIvarExp; }
void setBaseIvarExp(Expr *V) { BaseIvarExp = V; }
+ QualType getTBAABaseType() const { return TBAABaseType; }
+ void setTBAABaseType(QualType T) { TBAABaseType = T; }
+
+ uint64_t getTBAAOffset() const { return TBAAOffset; }
+ void setTBAAOffset(uint64_t O) { TBAAOffset = O; }
+
llvm::MDNode *getTBAAInfo() const { return TBAAInfo; }
void setTBAAInfo(llvm::MDNode *N) { TBAAInfo = N; }
Index: lib/CodeGen/CodeGenFunction.h
===================================================================
--- lib/CodeGen/CodeGenFunction.h (revision 178718)
+++ lib/CodeGen/CodeGenFunction.h (working copy)
@@ -2211,7 +2211,9 @@
/// the LLVM value representation.
llvm::Value *EmitLoadOfScalar(llvm::Value *Addr, bool Volatile,
unsigned Alignment, QualType Ty,
- llvm::MDNode *TBAAInfo = 0);
+ llvm::MDNode *TBAAInfo = 0,
+ QualType TBAABaseTy = QualType(),
+ uint64_t TBAAOffset = 0);
/// EmitLoadOfScalar - Load a scalar value from an address, taking
/// care to appropriately convert from the memory representation to
@@ -2224,7 +2226,9 @@
/// the LLVM value representation.
void EmitStoreOfScalar(llvm::Value *Value, llvm::Value *Addr,
bool Volatile, unsigned Alignment, QualType Ty,
- llvm::MDNode *TBAAInfo = 0, bool isInit=false);
+ llvm::MDNode *TBAAInfo = 0, bool isInit = false,
+ QualType TBAABaseTy = QualType(),
+ uint64_t TBAAOffset = 0);
/// EmitStoreOfScalar - Store a scalar value to an address, taking
/// care to appropriately convert from the memory representation to
Index: lib/CodeGen/CodeGenModule.cpp
===================================================================
--- lib/CodeGen/CodeGenModule.cpp (revision 178718)
+++ lib/CodeGen/CodeGenModule.cpp (working copy)
@@ -227,6 +227,20 @@
return TBAA->getTBAAStructInfo(QTy);
}
+llvm::MDNode *CodeGenModule::getTBAAStructTypeInfo(QualType QTy) {
+ if (!TBAA)
+ return 0;
+ return TBAA->getTBAAStructTypeInfo(QTy);
+}
+
+llvm::MDNode *CodeGenModule::getTBAAStructTagInfo(QualType BaseTy,
+ llvm::MDNode *AccessN,
+ uint64_t O) {
+ if (!TBAA)
+ return 0;
+ return TBAA->getTBAAStructTagInfo(BaseTy, AccessN, O);
+}
+
void CodeGenModule::DecorateInstruction(llvm::Instruction *Inst,
llvm::MDNode *TBAAInfo) {
Inst->setMetadata(llvm::LLVMContext::MD_tbaa, TBAAInfo);
Index: lib/CodeGen/CodeGenModule.h
===================================================================
--- lib/CodeGen/CodeGenModule.h (revision 178718)
+++ lib/CodeGen/CodeGenModule.h (working copy)
@@ -501,6 +501,11 @@
llvm::MDNode *getTBAAInfo(QualType QTy);
llvm::MDNode *getTBAAInfoForVTablePtr();
llvm::MDNode *getTBAAStructInfo(QualType QTy);
+ /// Return the MDNode in the type DAG for the given struct type.
+ llvm::MDNode *getTBAAStructTypeInfo(QualType QTy);
+ /// Return the path-aware tag for given base type, access node and offset.
+ llvm::MDNode *getTBAAStructTagInfo(QualType BaseTy, llvm::MDNode *AccessN,
+ uint64_t O);
bool isTypeConstant(QualType QTy, bool ExcludeCtorDtor);
Index: lib/CodeGen/CodeGenTBAA.cpp
===================================================================
--- lib/CodeGen/CodeGenTBAA.cpp (revision 178718)
+++ lib/CodeGen/CodeGenTBAA.cpp (working copy)
@@ -21,6 +21,7 @@
#include "clang/AST/Mangle.h"
#include "clang/AST/RecordLayout.h"
#include "clang/Frontend/CodeGenOptions.h"
+#include "llvm/ADT/SmallSet.h"
#include "llvm/IR/Constants.h"
#include "llvm/IR/LLVMContext.h"
#include "llvm/IR/Metadata.h"
@@ -225,3 +226,87 @@
// For now, handle any other kind of type conservatively.
return StructMetadataCache[Ty] = NULL;
}
+
+/// 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();
+ // RD can be struct, union, class, interface or enum.
+ // For now, we only handle struct.
+ if (RD->isStruct() && !RD->hasFlexibleArrayMember())
+ 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>()) {
+ const RecordDecl *RD = TTy->getDecl()->getDefinition();
+
+ const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
+ SmallVector <std::pair<uint64_t, llvm::MDNode*>, 4> Fields;
+ // To reduce the size of MDNode for a given struct type, we only output
+ // once for all the fields with the same scalar types.
+ // Offsets for scalar fields in the type DAG are not used.
+ llvm::SmallSet <llvm::MDNode*, 4> ScalarFieldTypes;
+ 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);
+ // Ignore this field if the type already exists.
+ if (ScalarFieldTypes.count(FieldNode))
+ continue;
+ ScalarFieldTypes.insert(FieldNode);
+ }
+ if (!FieldNode)
+ return StructTypeMetadataCache[Ty] = NULL;
+ Fields.push_back(std::make_pair(
+ Layout.getFieldOffset(idx) / Context.getCharWidth(), FieldNode));
+ }
+
+ // TODO: This is using the RTTI name. Is there a better way to get
+ // a unique string for a type?
+ SmallString<256> OutName;
+ llvm::raw_svector_ostream Out(OutName);
+ MContext.mangleCXXRTTIName(QualType(Ty, 0), Out);
+ Out.flush();
+ // Create the struct type node with a vector of pairs (offset, type).
+ return StructTypeMetadataCache[Ty] =
+ MDHelper.createTBAAStructTypeNode(OutName, Fields);
+ }
+
+ return StructMetadataCache[Ty] = NULL;
+}
+
+llvm::MDNode *
+CodeGenTBAA::getTBAAStructTagInfo(QualType BaseQTy, llvm::MDNode *AccessNode,
+ uint64_t Offset) {
+ if (!CodeGenOpts.StructPathTBAA)
+ return AccessNode;
+
+ const Type *BTy = Context.getCanonicalType(BaseQTy).getTypePtr();
+ TBAAPathTag PathTag = TBAAPathTag(BTy, AccessNode, Offset);
+ if (llvm::MDNode *N = StructTagMetadataCache[PathTag])
+ return N;
+
+ llvm::MDNode *BNode = 0;
+ if (isTBAAPathStruct(BaseQTy))
+ BNode = getTBAAStructTypeInfo(BaseQTy);
+ if (!BNode)
+ return StructTagMetadataCache[PathTag] = AccessNode;
+
+ return StructTagMetadataCache[PathTag] =
+ MDHelper.createTBAAStructTagNode(BNode, AccessNode, Offset);
+}
Index: lib/CodeGen/CodeGenTBAA.h
===================================================================
--- lib/CodeGen/CodeGenTBAA.h (revision 178718)
+++ lib/CodeGen/CodeGenTBAA.h (working copy)
@@ -35,6 +35,14 @@
namespace CodeGen {
class CGRecordLayout;
+ struct TBAAPathTag {
+ TBAAPathTag(const Type *B, const llvm::MDNode *A, uint64_t O)
+ : BaseT(B), AccessN(A), Offset(O) {}
+ const Type *BaseT;
+ const llvm::MDNode *AccessN;
+ uint64_t Offset;
+ };
+
/// CodeGenTBAA - This class organizes the cross-module state that is used
/// while lowering AST types to LLVM types.
class CodeGenTBAA {
@@ -46,8 +54,13 @@
// MDHelper - Helper for creating metadata.
llvm::MDBuilder MDHelper;
- /// MetadataCache - This maps clang::Types to llvm::MDNodes describing them.
+ /// MetadataCache - This maps clang::Types to scalar llvm::MDNodes describing
+ /// them.
llvm::DenseMap<const Type *, llvm::MDNode *> MetadataCache;
+ /// This maps clang::Types to a struct node in the type DAG.
+ llvm::DenseMap<const Type *, llvm::MDNode *> StructTypeMetadataCache;
+ /// This maps TBAAPathTags to a tag node.
+ llvm::DenseMap<TBAAPathTag, llvm::MDNode *> StructTagMetadataCache;
/// StructMetadataCache - This maps clang::Types to llvm::MDNodes describing
/// them for struct assignments.
@@ -89,9 +102,49 @@
/// getTBAAStructInfo - Get the TBAAStruct MDNode to be used for a memcpy of
/// the given type.
llvm::MDNode *getTBAAStructInfo(QualType QTy);
+
+ /// Get the MDNode in the type DAG for given struct type QType.
+ llvm::MDNode *getTBAAStructTypeInfo(QualType QType);
+ /// Get the tag MDNode for a given base type, the actual sclar access MDNode
+ /// and offset into the base type.
+ llvm::MDNode *getTBAAStructTagInfo(QualType BaseQType,
+ llvm::MDNode *AccessNode, uint64_t Offset);
};
} // end namespace CodeGen
} // end namespace clang
+namespace llvm {
+
+template<> struct DenseMapInfo<clang::CodeGen::TBAAPathTag> {
+ static clang::CodeGen::TBAAPathTag getEmptyKey() {
+ return clang::CodeGen::TBAAPathTag(
+ DenseMapInfo<const clang::Type *>::getEmptyKey(),
+ DenseMapInfo<const MDNode *>::getEmptyKey(),
+ DenseMapInfo<uint64_t>::getEmptyKey());
+ }
+
+ static clang::CodeGen::TBAAPathTag getTombstoneKey() {
+ return clang::CodeGen::TBAAPathTag(
+ DenseMapInfo<const clang::Type *>::getTombstoneKey(),
+ DenseMapInfo<const MDNode *>::getTombstoneKey(),
+ DenseMapInfo<uint64_t>::getTombstoneKey());
+ }
+
+ static unsigned getHashValue(const clang::CodeGen::TBAAPathTag &Val) {
+ return DenseMapInfo<const clang::Type *>::getHashValue(Val.BaseT) ^
+ DenseMapInfo<const MDNode *>::getHashValue(Val.AccessN) ^
+ DenseMapInfo<uint64_t>::getHashValue(Val.Offset);
+ }
+
+ static bool isEqual(const clang::CodeGen::TBAAPathTag &LHS,
+ const clang::CodeGen::TBAAPathTag &RHS) {
+ return LHS.BaseT == RHS.BaseT &&
+ LHS.AccessN == RHS.AccessN &&
+ LHS.Offset == RHS.Offset;
+ }
+};
+
+} // end namespace llvm
+
#endif
Index: lib/Driver/Tools.cpp
===================================================================
--- lib/Driver/Tools.cpp (revision 178718)
+++ lib/Driver/Tools.cpp (working copy)
@@ -2105,6 +2105,8 @@
options::OPT_fno_strict_aliasing,
getToolChain().IsStrictAliasingDefault()))
CmdArgs.push_back("-relaxed-aliasing");
+ if (Args.hasArg(options::OPT_fstruct_path_tbaa))
+ CmdArgs.push_back("-struct-path-tbaa");
if (Args.hasFlag(options::OPT_fstrict_enums, options::OPT_fno_strict_enums,
false))
CmdArgs.push_back("-fstrict-enums");
Index: lib/Frontend/CompilerInvocation.cpp
===================================================================
--- lib/Frontend/CompilerInvocation.cpp (revision 178718)
+++ lib/Frontend/CompilerInvocation.cpp (working copy)
@@ -324,6 +324,7 @@
Opts.UseRegisterSizedBitfieldAccess = Args.hasArg(
OPT_fuse_register_sized_bitfield_access);
Opts.RelaxedAliasing = Args.hasArg(OPT_relaxed_aliasing);
+ Opts.StructPathTBAA = Args.hasArg(OPT_struct_path_tbaa);
Opts.DwarfDebugFlags = Args.getLastArgValue(OPT_dwarf_debug_flags);
Opts.MergeAllConstants = !Args.hasArg(OPT_fno_merge_all_constants);
Opts.NoCommon = Args.hasArg(OPT_fno_common);
Index: test/CodeGen/tbaa.cpp
===================================================================
--- test/CodeGen/tbaa.cpp (revision 0)
+++ test/CodeGen/tbaa.cpp (working copy)
@@ -0,0 +1,217 @@
+// RUN: %clang_cc1 -O1 -disable-llvm-optzns %s -emit-llvm -o - | FileCheck %s
+// RUN: %clang_cc1 -O1 -struct-path-tbaa -disable-llvm-optzns %s -emit-llvm -o - | FileCheck %s -check-prefix=PATH
+// Test TBAA metadata generated by front-end.
+
+#include <stdint.h>
+typedef struct
+{
+ uint16_t f16;
+ uint32_t f32;
+ uint16_t f16_2;
+ uint32_t f32_2;
+} StructA;
+typedef struct
+{
+ uint16_t f16;
+ StructA a;
+ uint32_t f32;
+} StructB;
+typedef struct
+{
+ uint16_t f16;
+ StructB b;
+ uint32_t f32;
+} StructC;
+typedef struct
+{
+ uint16_t f16;
+ StructB b;
+ uint32_t f32;
+ uint8_t f8;
+} StructD;
+
+typedef struct
+{
+ uint16_t f16;
+ uint32_t f32;
+} StructS;
+typedef struct
+{
+ uint16_t f16;
+ uint32_t f32;
+} StructS2;
+
+uint32_t g(uint32_t *s, StructA *A, uint64_t count) {
+// CHECK: define i32 @{{.*}}(
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// PATH: define i32 @{{.*}}(
+// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
+// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa !5
+ *s = 1;
+ A->f32 = 4;
+ return *s;
+}
+
+uint32_t g2(uint32_t *s, StructA *A, uint64_t count) {
+// CHECK: define i32 @{{.*}}(
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i16 4, i16* %{{.*}}, align 2, !tbaa !5
+// PATH: define i32 @{{.*}}(
+// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
+// PATH: store i16 4, i16* %{{.*}}, align 2, !tbaa !8
+ *s = 1;
+ A->f16 = 4;
+ return *s;
+}
+
+uint32_t g3(StructA *A, StructB *B, uint64_t count) {
+// CHECK: define i32 @{{.*}}(
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// PATH: define i32 @{{.*}}(
+// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa !5
+// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa !9
+ A->f32 = 1;
+ B->a.f32 = 4;
+ return A->f32;
+}
+
+uint32_t g4(StructA *A, StructB *B, uint64_t count) {
+// CHECK: define i32 @{{.*}}(
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i16 4, i16* %{{.*}}, align 2, !tbaa !5
+// PATH: define i32 @{{.*}}(
+// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa !5
+// PATH: store i16 4, i16* %{{.*}}, align 2, !tbaa !11
+ A->f32 = 1;
+ B->a.f16 = 4;
+ return A->f32;
+}
+
+uint32_t g5(StructA *A, StructB *B, uint64_t count) {
+// CHECK: define i32 @{{.*}}(
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// PATH: define i32 @{{.*}}(
+// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa !5
+// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa !12
+ A->f32 = 1;
+ B->f32 = 4;
+ return A->f32;
+}
+
+uint32_t g6(StructA *A, StructB *B, uint64_t count) {
+// CHECK: define i32 @{{.*}}(
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// PATH: define i32 @{{.*}}(
+// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa !5
+// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa !13
+ A->f32 = 1;
+ B->a.f32_2 = 4;
+ return A->f32;
+}
+
+uint32_t g7(StructA *A, StructS *S, uint64_t count) {
+// CHECK: define i32 @{{.*}}(
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// PATH: define i32 @{{.*}}(
+// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa !5
+// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa !14
+ A->f32 = 1;
+ S->f32 = 4;
+ return A->f32;
+}
+
+uint32_t g8(StructA *A, StructS *S, uint64_t count) {
+// CHECK: define i32 @{{.*}}(
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i16 4, i16* %{{.*}}, align 2, !tbaa !5
+// PATH: define i32 @{{.*}}(
+// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa !5
+// PATH: store i16 4, i16* %{{.*}}, align 2, !tbaa !16
+ A->f32 = 1;
+ S->f16 = 4;
+ return A->f32;
+}
+
+uint32_t g9(StructS *S, StructS2 *S2, uint64_t count) {
+// CHECK: define i32 @{{.*}}(
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// PATH: define i32 @{{.*}}(
+// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa !14
+// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa !17
+ S->f32 = 1;
+ S2->f32 = 4;
+ return S->f32;
+}
+
+uint32_t g10(StructS *S, StructS2 *S2, uint64_t count) {
+// CHECK: define i32 @{{.*}}(
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i16 4, i16* %{{.*}}, align 2, !tbaa !5
+// PATH: define i32 @{{.*}}(
+// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa !14
+// PATH: store i16 4, i16* %{{.*}}, align 2, !tbaa !19
+ S->f32 = 1;
+ S2->f16 = 4;
+ return S->f32;
+}
+
+uint32_t g11(StructC *C, StructD *D, uint64_t count) {
+// CHECK: define i32 @{{.*}}(
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// PATH: define i32 @{{.*}}(
+// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa !20
+// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa !22
+ C->b.a.f32 = 1;
+ D->b.a.f32 = 4;
+ return C->b.a.f32;
+}
+
+uint32_t g12(StructC *C, StructD *D, uint64_t count) {
+// CHECK: define i32 @{{.*}}(
+// CHECK: store i32 1, i32* %{{.*}}, align 4, !tbaa !4
+// CHECK: store i32 4, i32* %{{.*}}, align 4, !tbaa !4
+// TODO: differentiate the two accesses.
+// PATH: define i32 @{{.*}}(
+// PATH: store i32 1, i32* %{{.*}}, align 4, !tbaa !9
+// PATH: store i32 4, i32* %{{.*}}, align 4, !tbaa !9
+ StructB *b1 = &(C->b);
+ StructB *b2 = &(D->b);
+ // b1, b2 have different context.
+ b1->a.f32 = 1;
+ b2->a.f32 = 4;
+ return b1->a.f32;
+}
+
+// CHECK: !1 = metadata !{metadata !"omnipotent char", metadata !2}
+// CHECK: !2 = metadata !{metadata !"Simple C/C++ TBAA"}
+// CHECK: !4 = metadata !{metadata !"int", metadata !1}
+// CHECK: !5 = metadata !{metadata !"short", metadata !1}
+
+// PATH: !1 = metadata !{metadata !"omnipotent char", metadata !2}
+// PATH: !4 = metadata !{metadata !"int", metadata !1}
+// PATH: !5 = metadata !{metadata !6, metadata !4, i64 4}
+// PATH: !6 = metadata !{metadata !"_ZTS7StructA", i64 0, metadata !7, i64 4, metadata !4}
+// PATH: !7 = metadata !{metadata !"short", metadata !1}
+// PATH: !8 = metadata !{metadata !6, metadata !7, i64 0}
+// PATH: !9 = metadata !{metadata !10, metadata !4, i64 8}
+// PATH: !10 = metadata !{metadata !"_ZTS7StructB", i64 0, metadata !7, i64 4, metadata !6, i64 20, metadata !4}
+// PATH: !11 = metadata !{metadata !10, metadata !7, i64 4}
+// PATH: !12 = metadata !{metadata !10, metadata !4, i64 20}
+// PATH: !13 = metadata !{metadata !10, metadata !4, i64 16}
+// PATH: !14 = metadata !{metadata !15, metadata !4, i64 4}
+// PATH: !15 = metadata !{metadata !"_ZTS7StructS", i64 0, metadata !7, i64 4, metadata !4}
+// PATH: !16 = metadata !{metadata !15, metadata !7, i64 0}
+// PATH: !17 = metadata !{metadata !18, metadata !4, i64 4}
+// PATH: !18 = metadata !{metadata !"_ZTS8StructS2", i64 0, metadata !7, i64 4, metadata !4}
+// PATH: !19 = metadata !{metadata !18, metadata !7, i64 0}
+// PATH: !20 = metadata !{metadata !21, metadata !4, i64 12}
+// PATH: !21 = metadata !{metadata !"_ZTS7StructC", i64 0, metadata !7, i64 4, metadata !10, i64 28, metadata !4}
+// PATH: !22 = metadata !{metadata !23, metadata !4, i64 12}
+// PATH: !23 = metadata !{metadata !"_ZTS7StructD", i64 0, metadata !7, i64 4, metadata !10, i64 28, metadata !4, i64 32, metadata !1}
llvm-svn: 178784
313 lines
11 KiB
C++
313 lines
11 KiB
C++
//===--- CodeGenTypes.cpp - TBAA information for LLVM CodeGen -------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file is distributed under the University of Illinois Open Source
|
|
// License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// This is the code that manages TBAA information and defines the TBAA policy
|
|
// for the optimizer to use. Relevant standards text includes:
|
|
//
|
|
// C99 6.5p7
|
|
// C++ [basic.lval] (p10 in n3126, p15 in some earlier versions)
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "CodeGenTBAA.h"
|
|
#include "clang/AST/ASTContext.h"
|
|
#include "clang/AST/Attr.h"
|
|
#include "clang/AST/Mangle.h"
|
|
#include "clang/AST/RecordLayout.h"
|
|
#include "clang/Frontend/CodeGenOptions.h"
|
|
#include "llvm/ADT/SmallSet.h"
|
|
#include "llvm/IR/Constants.h"
|
|
#include "llvm/IR/LLVMContext.h"
|
|
#include "llvm/IR/Metadata.h"
|
|
#include "llvm/IR/Type.h"
|
|
using namespace clang;
|
|
using namespace CodeGen;
|
|
|
|
CodeGenTBAA::CodeGenTBAA(ASTContext &Ctx, llvm::LLVMContext& VMContext,
|
|
const CodeGenOptions &CGO,
|
|
const LangOptions &Features, MangleContext &MContext)
|
|
: Context(Ctx), CodeGenOpts(CGO), Features(Features), MContext(MContext),
|
|
MDHelper(VMContext), Root(0), Char(0) {
|
|
}
|
|
|
|
CodeGenTBAA::~CodeGenTBAA() {
|
|
}
|
|
|
|
llvm::MDNode *CodeGenTBAA::getRoot() {
|
|
// Define the root of the tree. This identifies the tree, so that
|
|
// if our LLVM IR is linked with LLVM IR from a different front-end
|
|
// (or a different version of this front-end), their TBAA trees will
|
|
// remain distinct, and the optimizer will treat them conservatively.
|
|
if (!Root)
|
|
Root = MDHelper.createTBAARoot("Simple C/C++ TBAA");
|
|
|
|
return Root;
|
|
}
|
|
|
|
llvm::MDNode *CodeGenTBAA::getChar() {
|
|
// Define the root of the tree for user-accessible memory. C and C++
|
|
// give special powers to char and certain similar types. However,
|
|
// these special powers only cover user-accessible memory, and doesn't
|
|
// include things like vtables.
|
|
if (!Char)
|
|
Char = MDHelper.createTBAANode("omnipotent char", getRoot());
|
|
|
|
return Char;
|
|
}
|
|
|
|
static bool TypeHasMayAlias(QualType QTy) {
|
|
// Tagged types have declarations, and therefore may have attributes.
|
|
if (const TagType *TTy = dyn_cast<TagType>(QTy))
|
|
return TTy->getDecl()->hasAttr<MayAliasAttr>();
|
|
|
|
// Typedef types have declarations, and therefore may have attributes.
|
|
if (const TypedefType *TTy = dyn_cast<TypedefType>(QTy)) {
|
|
if (TTy->getDecl()->hasAttr<MayAliasAttr>())
|
|
return true;
|
|
// Also, their underlying types may have relevant attributes.
|
|
return TypeHasMayAlias(TTy->desugar());
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
llvm::MDNode *
|
|
CodeGenTBAA::getTBAAInfo(QualType QTy) {
|
|
// At -O0 TBAA is not emitted for regular types.
|
|
if (CodeGenOpts.OptimizationLevel == 0 || CodeGenOpts.RelaxedAliasing)
|
|
return NULL;
|
|
|
|
// 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();
|
|
|
|
if (llvm::MDNode *N = MetadataCache[Ty])
|
|
return N;
|
|
|
|
// Handle builtin types.
|
|
if (const BuiltinType *BTy = dyn_cast<BuiltinType>(Ty)) {
|
|
switch (BTy->getKind()) {
|
|
// Character types are special and can alias anything.
|
|
// In C++, this technically only includes "char" and "unsigned char",
|
|
// and not "signed char". In C, it includes all three. For now,
|
|
// the risk of exploiting this detail in C++ seems likely to outweigh
|
|
// the benefit.
|
|
case BuiltinType::Char_U:
|
|
case BuiltinType::Char_S:
|
|
case BuiltinType::UChar:
|
|
case BuiltinType::SChar:
|
|
return getChar();
|
|
|
|
// Unsigned types can alias their corresponding signed types.
|
|
case BuiltinType::UShort:
|
|
return getTBAAInfo(Context.ShortTy);
|
|
case BuiltinType::UInt:
|
|
return getTBAAInfo(Context.IntTy);
|
|
case BuiltinType::ULong:
|
|
return getTBAAInfo(Context.LongTy);
|
|
case BuiltinType::ULongLong:
|
|
return getTBAAInfo(Context.LongLongTy);
|
|
case BuiltinType::UInt128:
|
|
return getTBAAInfo(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] =
|
|
MDHelper.createTBAANode(BTy->getName(Features), getChar());
|
|
}
|
|
}
|
|
|
|
// Handle pointers.
|
|
// TODO: Implement C++'s type "similarity" and consider dis-"similar"
|
|
// pointers distinct.
|
|
if (Ty->isPointerType())
|
|
return MetadataCache[Ty] = MDHelper.createTBAANode("any pointer",
|
|
getChar());
|
|
|
|
// Enum types are distinct types. In C++ they have "underlying types",
|
|
// however they aren't related for TBAA.
|
|
if (const EnumType *ETy = dyn_cast<EnumType>(Ty)) {
|
|
// In C mode, two anonymous enums are compatible iff their members
|
|
// are the same -- see C99 6.2.7p1. For now, be conservative. We could
|
|
// theoretically implement this by combining information about all the
|
|
// members into a single identifying MDNode.
|
|
if (!Features.CPlusPlus &&
|
|
ETy->getDecl()->getTypedefNameForAnonDecl())
|
|
return MetadataCache[Ty] = getChar();
|
|
|
|
// In C++ mode, types have linkage, so we can rely on the ODR and
|
|
// on their mangled names, if they're external.
|
|
// 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()->getLinkage() != ExternalLinkage)
|
|
return MetadataCache[Ty] = getChar();
|
|
|
|
// TODO: This is using the RTTI name. Is there a better way to get
|
|
// a unique string for a type?
|
|
SmallString<256> OutName;
|
|
llvm::raw_svector_ostream Out(OutName);
|
|
MContext.mangleCXXRTTIName(QualType(ETy, 0), Out);
|
|
Out.flush();
|
|
return MetadataCache[Ty] = MDHelper.createTBAANode(OutName, getChar());
|
|
}
|
|
|
|
// For now, handle any other kind of type conservatively.
|
|
return MetadataCache[Ty] = getChar();
|
|
}
|
|
|
|
llvm::MDNode *CodeGenTBAA::getTBAAInfoForVTablePtr() {
|
|
return MDHelper.createTBAANode("vtable pointer", getRoot());
|
|
}
|
|
|
|
bool
|
|
CodeGenTBAA::CollectFields(uint64_t BaseOffset,
|
|
QualType QTy,
|
|
SmallVectorImpl<llvm::MDBuilder::TBAAStructField> &
|
|
Fields,
|
|
bool MayAlias) {
|
|
/* Things not handled yet include: C++ base classes, bitfields, */
|
|
|
|
if (const RecordType *TTy = QTy->getAs<RecordType>()) {
|
|
const RecordDecl *RD = TTy->getDecl()->getDefinition();
|
|
if (RD->hasFlexibleArrayMember())
|
|
return false;
|
|
|
|
// TODO: Handle C++ base classes.
|
|
if (const CXXRecordDecl *Decl = dyn_cast<CXXRecordDecl>(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<llvm::MDBuilder::TBAAStructField, 4> 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;
|
|
}
|
|
|
|
/// 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();
|
|
// RD can be struct, union, class, interface or enum.
|
|
// For now, we only handle struct.
|
|
if (RD->isStruct() && !RD->hasFlexibleArrayMember())
|
|
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>()) {
|
|
const RecordDecl *RD = TTy->getDecl()->getDefinition();
|
|
|
|
const ASTRecordLayout &Layout = Context.getASTRecordLayout(RD);
|
|
SmallVector <std::pair<uint64_t, llvm::MDNode*>, 4> Fields;
|
|
// To reduce the size of MDNode for a given struct type, we only output
|
|
// once for all the fields with the same scalar types.
|
|
// Offsets for scalar fields in the type DAG are not used.
|
|
llvm::SmallSet <llvm::MDNode*, 4> ScalarFieldTypes;
|
|
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);
|
|
// Ignore this field if the type already exists.
|
|
if (ScalarFieldTypes.count(FieldNode))
|
|
continue;
|
|
ScalarFieldTypes.insert(FieldNode);
|
|
}
|
|
if (!FieldNode)
|
|
return StructTypeMetadataCache[Ty] = NULL;
|
|
Fields.push_back(std::make_pair(
|
|
Layout.getFieldOffset(idx) / Context.getCharWidth(), FieldNode));
|
|
}
|
|
|
|
// TODO: This is using the RTTI name. Is there a better way to get
|
|
// a unique string for a type?
|
|
SmallString<256> OutName;
|
|
llvm::raw_svector_ostream Out(OutName);
|
|
MContext.mangleCXXRTTIName(QualType(Ty, 0), Out);
|
|
Out.flush();
|
|
// Create the struct type node with a vector of pairs (offset, type).
|
|
return StructTypeMetadataCache[Ty] =
|
|
MDHelper.createTBAAStructTypeNode(OutName, Fields);
|
|
}
|
|
|
|
return StructMetadataCache[Ty] = NULL;
|
|
}
|
|
|
|
llvm::MDNode *
|
|
CodeGenTBAA::getTBAAStructTagInfo(QualType BaseQTy, llvm::MDNode *AccessNode,
|
|
uint64_t Offset) {
|
|
if (!CodeGenOpts.StructPathTBAA)
|
|
return AccessNode;
|
|
|
|
const Type *BTy = Context.getCanonicalType(BaseQTy).getTypePtr();
|
|
TBAAPathTag PathTag = TBAAPathTag(BTy, AccessNode, Offset);
|
|
if (llvm::MDNode *N = StructTagMetadataCache[PathTag])
|
|
return N;
|
|
|
|
llvm::MDNode *BNode = 0;
|
|
if (isTBAAPathStruct(BaseQTy))
|
|
BNode = getTBAAStructTypeInfo(BaseQTy);
|
|
if (!BNode)
|
|
return StructTagMetadataCache[PathTag] = AccessNode;
|
|
|
|
return StructTagMetadataCache[PathTag] =
|
|
MDHelper.createTBAAStructTagNode(BNode, AccessNode, Offset);
|
|
}
|