Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h (revision 214520) +++ include/clang/AST/ASTContext.h (working copy) @@ -78,9 +78,13 @@ uint64_t Width; unsigned Align; bool AlignIsRequired : 1; - TypeInfo() : Width(0), Align(0), AlignIsRequired(false) {} - TypeInfo(uint64_t Width, unsigned Align, bool AlignIsRequired) - : Width(Width), Align(Align), AlignIsRequired(AlignIsRequired) {} + bool HasAlignAttribute : 1; + TypeInfo() : Width(0), Align(0), AlignIsRequired(false), + HasAlignAttribute(false) {} + TypeInfo(uint64_t Width, unsigned Align, bool AlignIsRequired, + bool HasAlignAttribute) + : Width(Width), Align(Align), AlignIsRequired(AlignIsRequired), + HasAlignAttribute(HasAlignAttribute) {} }; /// \brief Holds long-lived AST nodes (such as types and decls) that can be @@ -1666,6 +1670,10 @@ /// alignment attribute. bool isAlignmentRequired(const Type *T) const; bool isAlignmentRequired(QualType T) const; + + /// \brief Determine if type has an explicit align attribute. + bool hasAlignAttribute(const Type *T) const; + bool hasAlignAttribute(QualType T) const; /// \brief Return the "preferred" alignment of the specified type \p T for /// the current target, in bits. Index: include/clang/Basic/LangOptions.def =================================================================== --- include/clang/Basic/LangOptions.def (revision 214520) +++ include/clang/Basic/LangOptions.def (working copy) @@ -106,6 +106,8 @@ LANGOPT(Static , 1, 0, "__STATIC__ predefined macro (as opposed to __DYNAMIC__)") VALUE_LANGOPT(PackStruct , 32, 0, "default struct packing maximum alignment") +VALUE_LANGOPT(MaxTypeAlign , 32, 0, + "default maximum alignment for types") VALUE_LANGOPT(PICLevel , 2, 0, "__PIC__ level") VALUE_LANGOPT(PIELevel , 2, 0, "__PIE__ level") LANGOPT(GNUInline , 1, 0, "GNU inline semantics") Index: include/clang/Driver/Options.td =================================================================== --- include/clang/Driver/Options.td (revision 214520) +++ include/clang/Driver/Options.td (working copy) @@ -793,6 +793,9 @@ def fno_pack_struct : Flag<["-"], "fno-pack-struct">, Group; def fpack_struct_EQ : Joined<["-"], "fpack-struct=">, Group, Flags<[CC1Option]>, HelpText<"Specify the default maximum struct packing alignment">; +def fmax_type_align_EQ : Joined<["-"], "fmax-type-align=">, Group, Flags<[CC1Option]>, + HelpText<"Specify the default maximum alignment for types">; +def fno_max_type_align : Flag<["-"], "fno-max-type-align">, Group; def fpascal_strings : Flag<["-"], "fpascal-strings">, Group, Flags<[CC1Option]>, HelpText<"Recognize and construct Pascal-style string literals">; def fpcc_struct_return : Flag<["-"], "fpcc-struct-return">, Group, Flags<[CC1Option]>, Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp (revision 214520) +++ lib/AST/ASTContext.cpp (working copy) @@ -1431,6 +1431,14 @@ return isAlignmentRequired(T.getTypePtr()); } +bool ASTContext::hasAlignAttribute(const Type *T) const { + return getTypeInfo(T).HasAlignAttribute; +} + +bool ASTContext::hasAlignAttribute(QualType T) const { + return hasAlignAttribute(T.getTypePtr()); +} + TypeInfo ASTContext::getTypeInfo(const Type *T) const { TypeInfoMap::iterator I = MemoizedTypeInfo.find(T); if (I != MemoizedTypeInfo.end()) @@ -1452,6 +1460,7 @@ uint64_t Width = 0; unsigned Align = 8; bool AlignIsRequired = false; + bool HasAlignAttribute = false; switch (T->getTypeClass()) { #define TYPE(Class, Base) #define ABSTRACT_TYPE(Class, Base) @@ -1701,6 +1710,8 @@ case Type::Typedef: { const TypedefNameDecl *Typedef = cast(T)->getDecl(); TypeInfo Info = getTypeInfo(Typedef->getUnderlyingType().getTypePtr()); + HasAlignAttribute = + (Typedef->hasAttr() || Info.HasAlignAttribute); // If the typedef has an aligned attribute on it, it overrides any computed // alignment we have. This violates the GCC documentation (which says that // attribute(aligned) can only round up) but matches its implementation. @@ -1742,7 +1753,7 @@ } assert(llvm::isPowerOf2_32(Align) && "Alignment must be power of 2"); - return TypeInfo(Width, Align, AlignIsRequired); + return TypeInfo(Width, Align, AlignIsRequired, HasAlignAttribute); } /// toCharUnitsFromBits - Convert a size in bits to a size in characters. Index: lib/CodeGen/CGExpr.cpp =================================================================== --- lib/CodeGen/CGExpr.cpp (revision 214520) +++ lib/CodeGen/CGExpr.cpp (working copy) @@ -761,6 +761,18 @@ LV = EmitArraySubscriptExpr(cast(E), /*Accessed*/true); else LV = EmitLValue(E); + ASTContext &Context = CGM.getContext(); + if (const UnaryOperator *UOPE = dyn_cast(E)) + if (UOPE->getOpcode() == UO_Deref) { + unsigned MaxAlign = Context.getLangOpts().MaxTypeAlign; + QualType T = E->getType(); + if (MaxAlign && !Context.hasAlignAttribute(T)) { + CharUnits Alignment = Context.getTypeAlignInChars(T); + if (Alignment.getQuantity() > MaxAlign) + LV.setAlignment(CharUnits::fromQuantity(MaxAlign)); + } + } + if (!isa(E) && !LV.isBitField() && LV.isSimple()) EmitTypeCheck(TCK, E->getExprLoc(), LV.getAddress(), E->getType(), LV.getAlignment()); Index: lib/Driver/Tools.cpp =================================================================== --- lib/Driver/Tools.cpp (revision 214520) +++ lib/Driver/Tools.cpp (working copy) @@ -4111,6 +4111,21 @@ CmdArgs.push_back("-fpack-struct=1"); } + // Handle -fmax-type-align=N and -fno-type-align + bool SkipMaxTypeAlign = Args.hasArg(options::OPT_fno_max_type_align); + if (Arg *A = Args.getLastArg(options::OPT_fmax_type_align_EQ)) { + if (!SkipMaxTypeAlign) { + std::string MaxTypeAlignStr = "-fmax-type-align="; + MaxTypeAlignStr += A->getValue(); + CmdArgs.push_back(Args.MakeArgString(MaxTypeAlignStr)); + } + } else if (getToolChain().getTriple().isOSDarwin()) { + if (!SkipMaxTypeAlign) { + std::string MaxTypeAlignStr = "-fmax-type-align=16"; + CmdArgs.push_back(Args.MakeArgString(MaxTypeAlignStr)); + } + } + if (KernelOrKext || isNoCommonDefault(getToolChain().getTriple())) { if (!Args.hasArg(options::OPT_fcommon)) CmdArgs.push_back("-fno-common"); Index: lib/Frontend/CompilerInvocation.cpp =================================================================== --- lib/Frontend/CompilerInvocation.cpp (revision 214520) +++ lib/Frontend/CompilerInvocation.cpp (working copy) @@ -1475,6 +1475,7 @@ Args.hasArg(OPT_fencode_extended_block_signature); Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls); Opts.PackStruct = getLastArgIntValue(Args, OPT_fpack_struct_EQ, 0, Diags); + Opts.MaxTypeAlign = getLastArgIntValue(Args, OPT_fmax_type_align_EQ, 0, Diags); Opts.PICLevel = getLastArgIntValue(Args, OPT_pic_level, 0, Diags); Opts.PIELevel = getLastArgIntValue(Args, OPT_pie_level, 0, Diags); Opts.Static = Args.hasArg(OPT_static_define); Index: test/CodeGenCXX/align-avx-complete-objects.cpp =================================================================== --- test/CodeGenCXX/align-avx-complete-objects.cpp (revision 0) +++ test/CodeGenCXX/align-avx-complete-objects.cpp (working copy) @@ -0,0 +1,57 @@ +// RUN: %clang_cc1 -x c++ %s -O0 -triple=x86_64-apple-darwin -target-feature +avx2 -fmax-type-align=16 -emit-llvm -o - -Werror | FileCheck %s +// rdar://16254558 + +typedef float AVX2Float __attribute__((__vector_size__(32))); + + +volatile float TestAlign(void) +{ + volatile AVX2Float *p = new AVX2Float; + *p = *p; + AVX2Float r = *p; + return r[0]; +} + +// CHECK: [[R:%.*]] = alloca <8 x float>, align 32 +// CHECK-NEXT: [[CALL:%.*]] = call noalias i8* @_Znwm(i64 32) +// CHECK-NEXT: [[ZERO:%.*]] = bitcast i8* [[CALL]] to <8 x float>* +// CHECK-NEXT: store <8 x float>* [[ZERO]], <8 x float>** [[P:%.*]], align 8 +// CHECK-NEXT: [[ONE:%.*]] = load <8 x float>** [[P]], align 8 +// CHECK-NEXT: [[TWO:%.*]] = load volatile <8 x float>* [[ONE]], align 16 +// CHECK-NEXT: [[THREE:%.*]] = load <8 x float>** [[P]], align 8 +// CHECK-NEXT: store volatile <8 x float> [[TWO]], <8 x float>* [[THREE]], align 16 +// CHECK-NEXT: [[FOUR:%.*]] = load <8 x float>** [[P]], align 8 +// CHECK-NEXT: [[FIVE:%.*]] = load volatile <8 x float>* [[FOUR]], align 16 +// CHECK-NEXT: store <8 x float> [[FIVE]], <8 x float>* [[R]], align 32 +// CHECK-NEXT: [[SIX:%.*]] = load <8 x float>* [[R]], align 32 +// CHECK-NEXT: [[VECEXT:%.*]] = extractelement <8 x float> [[SIX]], i32 0 +// CHECK-NEXT: ret float [[VECEXT]] + +typedef float AVX2Float_Explicitly_aligned __attribute__((__vector_size__(32))) __attribute__((aligned (32))); + +typedef AVX2Float_Explicitly_aligned AVX2Float_indirect; + +typedef AVX2Float_indirect AVX2Float_use_existing_align; + +volatile float TestAlign2(void) +{ + volatile AVX2Float_use_existing_align *p = new AVX2Float_use_existing_align; + *p = *p; + AVX2Float_use_existing_align r = *p; + return r[0]; +} + +// CHECK: [[R:%.*]] = alloca <8 x float>, align 32 +// CHECK-NEXT: [[CALL:%.*]] = call noalias i8* @_Znwm(i64 32) +// CHECK-NEXT: [[ZERO:%.*]] = bitcast i8* [[CALL]] to <8 x float>* +// CHECK-NEXT: store <8 x float>* [[ZERO]], <8 x float>** [[P:%.*]], align 8 +// CHECK-NEXT: [[ONE:%.*]] = load <8 x float>** [[P]], align 8 +// CHECK-NEXT: [[TWO:%.*]] = load volatile <8 x float>* [[ONE]], align 32 +// CHECK-NEXT: [[THREE:%.*]] = load <8 x float>** [[P]], align 8 +// CHECK-NEXT: store volatile <8 x float> [[TWO]], <8 x float>* [[THREE]], align 32 +// CHECK-NEXT: [[FOUR:%.*]] = load <8 x float>** [[P]], align 8 +// CHECK-NEXT: [[FIVE:%.*]] = load volatile <8 x float>* [[FOUR]], align 32 +// CHECK-NEXT: store <8 x float> [[FIVE]], <8 x float>* [[R]], align 32 +// CHECK-NEXT: [[SIX:%.*]] = load <8 x float>* [[R]], align 32 +// CHECK-NEXT: [[VECEXT:%.*]] = extractelement <8 x float> [[SIX]], i32 0 +// CHECK-NEXT: ret float [[VECEXT]] Index: test/Driver/darwin-max-type-align.c =================================================================== --- test/Driver/darwin-max-type-align.c (revision 0) +++ test/Driver/darwin-max-type-align.c (working copy) @@ -0,0 +1,15 @@ +// Check the -fmax-type-align=N flag +// rdar://16254558 +// +// RUN: %clang -no-canonical-prefixes -target x86_64-apple-macosx10.7.0 %s -o - -### 2>&1 | \ +// RUN: FileCheck -check-prefix=TEST0 %s +// TEST0: -fmax-type-align=16 +// RUN: %clang -no-canonical-prefixes -fmax-type-align=32 -target x86_64-apple-macosx10.7.0 %s -o - -### 2>&1 | \ +// RUN: FileCheck -check-prefix=TEST1 %s +// TEST1: -fmax-type-align=32 +// RUN: %clang -no-canonical-prefixes -fmax-type-align=32 -fno-max-type-align -target x86_64-apple-macosx10.7.0 %s -o - -### 2>&1 | \ +// RUN: FileCheck -check-prefix=TEST2 %s +// TEST2-NOT: -fmax-type-align +// RUN: %clang -no-canonical-prefixes -fno-max-type-align -target x86_64-apple-macosx10.7.0 %s -o - -### 2>&1 | \ +// RUN: FileCheck -check-prefix=TEST3 %s +// TEST3-NOT: -fmax-type-align Index: test/Driver/rewrite-legacy-objc.m =================================================================== --- test/Driver/rewrite-legacy-objc.m (revision 214520) +++ test/Driver/rewrite-legacy-objc.m (working copy) @@ -3,11 +3,11 @@ // TEST0: clang{{.*}}" "-cc1" // TEST0: "-rewrite-objc" // FIXME: CHECK-NOT is broken somehow, it doesn't work here. Check adjacency instead. -// TEST0: "-fmessage-length" "0" "-stack-protector" "1" "-mstackrealign" "-fblocks" "-fobjc-runtime=macosx-fragile" "-fencode-extended-block-signature" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fexceptions" "-fdiagnostics-show-option" +// TEST0: "-fmessage-length" "0" "-stack-protector" "1" "-mstackrealign" "-fblocks" "-fobjc-runtime=macosx-fragile" "-fencode-extended-block-signature" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fexceptions" "-fmax-type-align=16" "-fdiagnostics-show-option" // TEST0: rewrite-legacy-objc.m" // RUN: %clang -no-canonical-prefixes -target i386-apple-macosx10.9.0 -rewrite-legacy-objc %s -o - -### 2>&1 | \ // RUN: FileCheck -check-prefix=TEST1 %s // RUN: %clang -no-canonical-prefixes -target i386-apple-macosx10.6.0 -rewrite-legacy-objc %s -o - -### 2>&1 | \ // RUN: FileCheck -check-prefix=TEST2 %s -// TEST1: "-fmessage-length" "0" "-stack-protector" "1" "-mstackrealign" "-fblocks" "-fobjc-runtime=macosx-fragile" "-fobjc-subscripting-legacy-runtime" "-fencode-extended-block-signature" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fdiagnostics-show-option" -// TEST2: "-fmessage-length" "0" "-stack-protector" "1" "-mstackrealign" "-fblocks" "-fobjc-runtime=macosx-fragile" "-fencode-extended-block-signature" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fdiagnostics-show-option" +// TEST1: "-fmessage-length" "0" "-stack-protector" "1" "-mstackrealign" "-fblocks" "-fobjc-runtime=macosx-fragile" "-fobjc-subscripting-legacy-runtime" "-fencode-extended-block-signature" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fmax-type-align=16" "-fdiagnostics-show-option" +// TEST2: "-fmessage-length" "0" "-stack-protector" "1" "-mstackrealign" "-fblocks" "-fobjc-runtime=macosx-fragile" "-fencode-extended-block-signature" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fmax-type-align=16" "-fdiagnostics-show-option" Index: test/Driver/rewrite-objc.m =================================================================== --- test/Driver/rewrite-objc.m (revision 214520) +++ test/Driver/rewrite-objc.m (working copy) @@ -3,4 +3,4 @@ // TEST0: clang{{.*}}" "-cc1" // TEST0: "-rewrite-objc" // FIXME: CHECK-NOT is broken somehow, it doesn't work here. Check adjacency instead. -// TEST0: "-fmessage-length" "0" "-stack-protector" "1" "-mstackrealign" "-fblocks" "-fobjc-runtime=macosx" "-fencode-extended-block-signature" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fexceptions" "-fdiagnostics-show-option" +// TEST0: "-fmessage-length" "0" "-stack-protector" "1" "-mstackrealign" "-fblocks" "-fobjc-runtime=macosx" "-fencode-extended-block-signature" "-fno-objc-infer-related-result-type" "-fobjc-exceptions" "-fexceptions" "-fmax-type-align=16" "-fdiagnostics-show-option"