r178784 - Index: include/clang/Driver/CC1Options.td
Eric Christopher
echristo at gmail.com
Thu Apr 4 13:24:28 PDT 2013
This seems... very large not to have a commit message at all?
Also could have committed the command line option and rest of this separately?
-eric
On Thu, Apr 4, 2013 at 1:14 PM, Manman Ren <mren at apple.com> wrote:
> Author: mren
> Date: Thu Apr 4 15:14:17 2013
> New Revision: 178784
>
> URL: http://llvm.org/viewvc/llvm-project?rev=178784&view=rev
> Log:
> Index: include/clang/Driver/CC1Options.td
> ===================================================================
> --- 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}
>
> Added:
> cfe/trunk/test/CodeGen/tbaa.cpp
> Modified:
> cfe/trunk/include/clang/Driver/CC1Options.td
> cfe/trunk/include/clang/Driver/Options.td
> cfe/trunk/include/clang/Frontend/CodeGenOptions.def
> cfe/trunk/lib/CodeGen/CGExpr.cpp
> cfe/trunk/lib/CodeGen/CGValue.h
> cfe/trunk/lib/CodeGen/CodeGenFunction.h
> cfe/trunk/lib/CodeGen/CodeGenModule.cpp
> cfe/trunk/lib/CodeGen/CodeGenModule.h
> cfe/trunk/lib/CodeGen/CodeGenTBAA.cpp
> cfe/trunk/lib/CodeGen/CodeGenTBAA.h
> cfe/trunk/lib/Driver/Tools.cpp
> cfe/trunk/lib/Frontend/CompilerInvocation.cpp
>
> Modified: cfe/trunk/include/clang/Driver/CC1Options.td
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/CC1Options.td?rev=178784&r1=178783&r2=178784&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Driver/CC1Options.td (original)
> +++ cfe/trunk/include/clang/Driver/CC1Options.td Thu Apr 4 15:14:17 2013
> @@ -161,6 +161,8 @@ def fuse_register_sized_bitfield_access:
> 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">,
>
> Modified: cfe/trunk/include/clang/Driver/Options.td
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Driver/Options.td?rev=178784&r1=178783&r2=178784&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Driver/Options.td (original)
> +++ cfe/trunk/include/clang/Driver/Options.td Thu Apr 4 15:14:17 2013
> @@ -587,6 +587,7 @@ def fno_spell_checking : Flag<["-"], "fn
> 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>,
>
> Modified: cfe/trunk/include/clang/Frontend/CodeGenOptions.def
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/include/clang/Frontend/CodeGenOptions.def?rev=178784&r1=178783&r2=178784&view=diff
> ==============================================================================
> --- cfe/trunk/include/clang/Frontend/CodeGenOptions.def (original)
> +++ cfe/trunk/include/clang/Frontend/CodeGenOptions.def Thu Apr 4 15:14:17 2013
> @@ -86,6 +86,7 @@ VALUE_CODEGENOPT(OptimizationLevel, 3, 0
> 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.
>
> Modified: cfe/trunk/lib/CodeGen/CGExpr.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGExpr.cpp?rev=178784&r1=178783&r2=178784&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGExpr.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CGExpr.cpp Thu Apr 4 15:14:17 2013
> @@ -1044,7 +1044,8 @@ CodeGenFunction::tryEmitAsConstant(DeclR
> 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::MDNode *CodeGenFunction::getRangeF
>
> 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 @@ llvm::Value *CodeGenFunction::EmitLoadOf
> 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 @@ void CodeGenFunction::EmitStoreOfScalar(
> 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 @@ void CodeGenFunction::EmitStoreOfScalar(
> 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 @@ LValue CodeGenFunction::EmitLValueForFie
>
> 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 @@ LValue CodeGenFunction::EmitLValueForFie
> 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 CodeGenFunction::EmitLValueForFie
>
> 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)
>
> Modified: cfe/trunk/lib/CodeGen/CGValue.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CGValue.h?rev=178784&r1=178783&r2=178784&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CGValue.h (original)
> +++ cfe/trunk/lib/CodeGen/CGValue.h Thu Apr 4 15:14:17 2013
> @@ -157,6 +157,11 @@ class LValue {
>
> 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 @@ private:
> 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 @@ public:
> 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; }
>
>
> Modified: cfe/trunk/lib/CodeGen/CodeGenFunction.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenFunction.h?rev=178784&r1=178783&r2=178784&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CodeGenFunction.h (original)
> +++ cfe/trunk/lib/CodeGen/CodeGenFunction.h Thu Apr 4 15:14:17 2013
> @@ -2211,7 +2211,9 @@ public:
> /// 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 @@ public:
> /// 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
>
> Modified: cfe/trunk/lib/CodeGen/CodeGenModule.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.cpp?rev=178784&r1=178783&r2=178784&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CodeGenModule.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CodeGenModule.cpp Thu Apr 4 15:14:17 2013
> @@ -227,6 +227,20 @@ llvm::MDNode *CodeGenModule::getTBAAStru
> 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);
>
> Modified: cfe/trunk/lib/CodeGen/CodeGenModule.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenModule.h?rev=178784&r1=178783&r2=178784&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CodeGenModule.h (original)
> +++ cfe/trunk/lib/CodeGen/CodeGenModule.h Thu Apr 4 15:14:17 2013
> @@ -501,6 +501,11 @@ public:
> 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);
>
>
> Modified: cfe/trunk/lib/CodeGen/CodeGenTBAA.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenTBAA.cpp?rev=178784&r1=178783&r2=178784&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CodeGenTBAA.cpp (original)
> +++ cfe/trunk/lib/CodeGen/CodeGenTBAA.cpp Thu Apr 4 15:14:17 2013
> @@ -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 @@ CodeGenTBAA::getTBAAStructInfo(QualType
> // 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);
> +}
>
> Modified: cfe/trunk/lib/CodeGen/CodeGenTBAA.h
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/CodeGen/CodeGenTBAA.h?rev=178784&r1=178783&r2=178784&view=diff
> ==============================================================================
> --- cfe/trunk/lib/CodeGen/CodeGenTBAA.h (original)
> +++ cfe/trunk/lib/CodeGen/CodeGenTBAA.h Thu Apr 4 15:14:17 2013
> @@ -35,6 +35,14 @@ namespace clang {
> 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 @@ class CodeGenTBAA {
> // 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 @@ public:
> /// 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
>
> Modified: cfe/trunk/lib/Driver/Tools.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Driver/Tools.cpp?rev=178784&r1=178783&r2=178784&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Driver/Tools.cpp (original)
> +++ cfe/trunk/lib/Driver/Tools.cpp Thu Apr 4 15:14:17 2013
> @@ -2105,6 +2105,8 @@ void Clang::ConstructJob(Compilation &C,
> 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");
>
> Modified: cfe/trunk/lib/Frontend/CompilerInvocation.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/lib/Frontend/CompilerInvocation.cpp?rev=178784&r1=178783&r2=178784&view=diff
> ==============================================================================
> --- cfe/trunk/lib/Frontend/CompilerInvocation.cpp (original)
> +++ cfe/trunk/lib/Frontend/CompilerInvocation.cpp Thu Apr 4 15:14:17 2013
> @@ -324,6 +324,7 @@ static bool ParseCodeGenArgs(CodeGenOpti
> 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);
>
> Added: cfe/trunk/test/CodeGen/tbaa.cpp
> URL: http://llvm.org/viewvc/llvm-project/cfe/trunk/test/CodeGen/tbaa.cpp?rev=178784&view=auto
> ==============================================================================
> --- cfe/trunk/test/CodeGen/tbaa.cpp (added)
> +++ cfe/trunk/test/CodeGen/tbaa.cpp Thu Apr 4 15:14:17 2013
> @@ -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}
>
>
> _______________________________________________
> cfe-commits mailing list
> cfe-commits at cs.uiuc.edu
> http://lists.cs.uiuc.edu/mailman/listinfo/cfe-commits
More information about the cfe-commits
mailing list