Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ include/clang/AST/ASTContext.h @@ -78,10 +78,14 @@ struct TypeInfo { uint64_t Width; unsigned Align; + unsigned SimdDefaultAlign; bool AlignIsRequired : 1; - TypeInfo() : Width(0), Align(0), AlignIsRequired(false) {} - TypeInfo(uint64_t Width, unsigned Align, bool AlignIsRequired) - : Width(Width), Align(Align), AlignIsRequired(AlignIsRequired) {} + TypeInfo() + : Width(0), Align(0), SimdDefaultAlign(0), AlignIsRequired(false) {} + TypeInfo(uint64_t Width, unsigned Align, unsigned SimdDefaultAlign, + bool AlignIsRequired) + : Width(Width), Align(Align), SimdDefaultAlign(SimdDefaultAlign), + AlignIsRequired(AlignIsRequired) {} }; /// \brief Holds long-lived AST nodes (such as types and decls) that can be Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -4684,18 +4684,18 @@ // Expressions. def ext_sizeof_alignof_function_type : Extension< - "invalid application of '%select{sizeof|alignof|vec_step}0' to a " + "invalid application of '%select{sizeof|alignof|vec_step|simd_align} to a " "function type">, InGroup; def ext_sizeof_alignof_void_type : Extension< - "invalid application of '%select{sizeof|alignof|vec_step}0' to a void " + "invalid application of '%select{sizeof|alignof|vec_step|simd_align}0' to a void " "type">, InGroup; def err_opencl_sizeof_alignof_type : Error< - "invalid application of '%select{sizeof|alignof|vec_step}0' to a void type">; + "invalid application of '%select{sizeof|alignof|vec_step|simd_align}0' to a void type">; def err_sizeof_alignof_incomplete_type : Error< - "invalid application of '%select{sizeof|alignof|vec_step}0' to an " + "invalid application of '%select{sizeof|alignof|vec_step|simd_align}0' to an " "incomplete type %1">; def err_sizeof_alignof_function_type : Error< - "invalid application of '%select{sizeof|alignof|vec_step}0' to a " + "invalid application of '%select{sizeof|alignof|vec_step|simd_align}0' to a " "function type">; def err_sizeof_alignof_bitfield : Error< "invalid application of '%select{sizeof|alignof}0' to bit-field">; Index: include/clang/Basic/TargetInfo.h =================================================================== --- include/clang/Basic/TargetInfo.h +++ include/clang/Basic/TargetInfo.h @@ -70,6 +70,7 @@ unsigned char MinGlobalAlign; unsigned char MaxAtomicPromoteWidth, MaxAtomicInlineWidth; unsigned short MaxVectorAlign; + unsigned short SimdDefaultAlign; const char *DescriptionString; const char *UserLabelPrefix; const char *MCountName; @@ -393,6 +394,8 @@ /// \brief Return the maximum vector alignment supported for the given target. unsigned getMaxVectorAlign() const { return MaxVectorAlign; } + /// \brief Return default simd alignment for the given target. + unsigned getSimdDefaultAlign() const { return SimdDefaultAlign; } /// \brief Return the size of intmax_t and uintmax_t for this target, in bits. unsigned getIntMaxTWidth() const { Index: include/clang/Basic/TokenKinds.def =================================================================== --- include/clang/Basic/TokenKinds.def +++ include/clang/Basic/TokenKinds.def @@ -503,6 +503,9 @@ KEYWORD(__builtin_astype , KEYOPENCL) KEYWORD(vec_step , KEYOPENCL|KEYALTIVEC) +// OpenMP Type Traits +KEYWORD(simd_align , KEYALL) + // Borland Extensions. KEYWORD(__pascal , KEYALL) Index: include/clang/Basic/TypeTraits.h =================================================================== --- include/clang/Basic/TypeTraits.h +++ include/clang/Basic/TypeTraits.h @@ -92,7 +92,8 @@ enum UnaryExprOrTypeTrait { UETT_SizeOf, UETT_AlignOf, - UETT_VecStep + UETT_VecStep, + UETT_OpenMPDefaultSimdAlign, }; } Index: lib/AST/ASTContext.cpp =================================================================== --- lib/AST/ASTContext.cpp +++ lib/AST/ASTContext.cpp @@ -1481,6 +1481,13 @@ uint64_t Width = 0; unsigned Align = 8; bool AlignIsRequired = false; + unsigned SimdAlign = getTargetInfo().getSimdDefaultAlign(); + // Target ppc64 with QPX: simd default alignment for pointer to double is 32. + if ((getTargetInfo().getTriple().getArch() == llvm::Triple::ppc64 || + getTargetInfo().getTriple().getArch() == llvm::Triple::ppc64le) && + getTargetInfo().getABI() == "elfv1-qpx" && T->isAnyPointerType() && + T->getPointeeType()->isSpecificBuiltinType(BuiltinType::Double)) + SimdAlign = 32; switch (T->getTypeClass()) { #define TYPE(Class, Base) #define ABSTRACT_TYPE(Class, Base) @@ -1783,7 +1790,7 @@ } assert(llvm::isPowerOf2_32(Align) && "Alignment must be power of 2"); - return TypeInfo(Width, Align, AlignIsRequired); + return TypeInfo(Width, Align, SimdAlign, AlignIsRequired); } /// toCharUnitsFromBits - Convert a size in bits to a size in characters. Index: lib/AST/ASTDumper.cpp =================================================================== --- lib/AST/ASTDumper.cpp +++ lib/AST/ASTDumper.cpp @@ -1825,6 +1825,9 @@ case UETT_VecStep: OS << " vec_step"; break; + case UETT_OpenMPDefaultSimdAlign: + OS << "simd_align"; + break; } if (Node->isArgumentType()) dumpType(Node->getArgumentType()); Index: lib/AST/ExprConstant.cpp =================================================================== --- lib/AST/ExprConstant.cpp +++ lib/AST/ExprConstant.cpp @@ -7251,6 +7251,12 @@ return false; return Success(Sizeof, E); } + case UETT_OpenMPDefaultSimdAlign: + return Success(Info.Ctx.getTypeInfo(E->isArgumentType() + ? E->getArgumentType() + : E->getArgumentExpr()->getType()) + .SimdDefaultAlign, + E); } llvm_unreachable("unknown expr/type trait"); Index: lib/AST/ItaniumMangle.cpp =================================================================== --- lib/AST/ItaniumMangle.cpp +++ lib/AST/ItaniumMangle.cpp @@ -3018,7 +3018,14 @@ case UETT_AlignOf: Out << 'a'; break; - case UETT_VecStep: + case UETT_VecStep: { + DiagnosticsEngine &Diags = Context.getDiags(); + unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, + "cannot yet mangle vec_step expression"); + Diags.Report(DiagID); + return; + } + case UETT_OpenMPDefaultSimdAlign: DiagnosticsEngine &Diags = Context.getDiags(); unsigned DiagID = Diags.getCustomDiagID(DiagnosticsEngine::Error, "cannot yet mangle vec_step expression"); Index: lib/AST/StmtPrinter.cpp =================================================================== --- lib/AST/StmtPrinter.cpp +++ lib/AST/StmtPrinter.cpp @@ -1206,6 +1206,9 @@ case UETT_VecStep: OS << "vec_step"; break; + case UETT_OpenMPDefaultSimdAlign: + OS << "simd_align"; + break; } if (Node->isArgumentType()) { OS << '('; Index: lib/Basic/TargetInfo.cpp =================================================================== --- lib/Basic/TargetInfo.cpp +++ lib/Basic/TargetInfo.cpp @@ -50,6 +50,7 @@ LargeArrayAlign = 0; MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 0; MaxVectorAlign = 0; + SimdDefaultAlign = 0; SizeType = UnsignedLong; PtrDiffType = SignedLong; IntMaxType = SignedLongLong; Index: lib/Basic/Targets.cpp =================================================================== --- lib/Basic/Targets.cpp +++ lib/Basic/Targets.cpp @@ -759,6 +759,7 @@ HasP8Crypto(false), HasDirectMove(false), HasQPX(false), HasHTM(false), HasBPERMD(false), HasExtDiv(false) { BigEndian = (Triple.getArch() != llvm::Triple::ppc64le); + SimdDefaultAlign = 16; LongDoubleWidth = LongDoubleAlign = 128; LongDoubleFormat = &llvm::APFloat::PPCDoubleDouble; } @@ -2972,6 +2973,8 @@ Features.erase(it); else if (SSELevel > NoSSE) MMX3DNowLevel = std::max(MMX3DNowLevel, MMX); + + SimdDefaultAlign = (getABI() == "avx") ? 32 : 16; return true; } Index: lib/CodeGen/CGExprScalar.cpp =================================================================== --- lib/CodeGen/CGExprScalar.cpp +++ lib/CodeGen/CGExprScalar.cpp @@ -16,6 +16,7 @@ #include "CGDebugInfo.h" #include "CGObjCRuntime.h" #include "CodeGenModule.h" +#include "TargetInfo.h" #include "clang/AST/ASTContext.h" #include "clang/AST/DeclObjC.h" #include "clang/AST/RecordLayout.h" @@ -2037,6 +2038,10 @@ return size; } + } else if (E->getKind() == UETT_OpenMPDefaultSimdAlign) { + auto Alignment = + CGF.getContext().getTypeInfo(E->getTypeOfArgument()).SimdDefaultAlign; + return Builder.getInt32(Alignment); } // If this isn't sizeof(vla), the result must be constant; use the constant Index: lib/CodeGen/CGStmtOpenMP.cpp =================================================================== --- lib/CodeGen/CGStmtOpenMP.cpp +++ lib/CodeGen/CGStmtOpenMP.cpp @@ -648,9 +648,7 @@ // OpenMP [2.8.1, Description] // If no optional parameter is specified, implementation-defined default // alignments for SIMD instructions on the target platforms are assumed. - Alignment = - CGF.CGM.getTargetCodeGenInfo().getOpenMPSimdDefaultAlignment( - E->getType()); + Alignment = CGF.getContext().getTypeInfo(E->getType()).SimdDefaultAlign; } assert((Alignment == 0 || llvm::isPowerOf2_32(Alignment)) && "alignment is not power of 2"); Index: lib/CodeGen/TargetInfo.h =================================================================== --- lib/CodeGen/TargetInfo.h +++ lib/CodeGen/TargetInfo.h @@ -218,13 +218,6 @@ virtual void getDetectMismatchOption(llvm::StringRef Name, llvm::StringRef Value, llvm::SmallString<32> &Opt) const {} - - /// Gets the target-specific default alignment used when an 'aligned' clause - /// is used with a 'simd' OpenMP directive without specifying a specific - /// alignment. - virtual unsigned getOpenMPSimdDefaultAlignment(QualType Type) const { - return 0; - } }; } Index: lib/CodeGen/TargetInfo.cpp =================================================================== --- lib/CodeGen/TargetInfo.cpp +++ lib/CodeGen/TargetInfo.cpp @@ -1628,10 +1628,6 @@ ('T' << 24); return llvm::ConstantInt::get(CGM.Int32Ty, Sig); } - - unsigned getOpenMPSimdDefaultAlignment(QualType) const override { - return getABIInfo().hasAVX() ? 32 : 16; - } }; class PS4TargetCodeGenInfo : public X86_64TargetCodeGenInfo { @@ -1737,10 +1733,6 @@ llvm::SmallString<32> &Opt) const override { Opt = "/FAILIFMISMATCH:\"" + Name.str() + "=" + Value.str() + "\""; } - - unsigned getOpenMPSimdDefaultAlignment(QualType) const override { - return hasAVX() ? 32 : 16; - } }; void WinX86_64TargetCodeGenInfo::setTargetAttributes(const Decl *D, @@ -3145,10 +3137,6 @@ bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const override; - - unsigned getOpenMPSimdDefaultAlignment(QualType) const override { - return 16; // Natural alignment for Altivec vectors. - } }; } @@ -3388,13 +3376,11 @@ }; class PPC64_SVR4_TargetCodeGenInfo : public TargetCodeGenInfo { - bool HasQPX; public: PPC64_SVR4_TargetCodeGenInfo(CodeGenTypes &CGT, PPC64_SVR4_ABIInfo::ABIKind Kind, bool HasQPX) - : TargetCodeGenInfo(new PPC64_SVR4_ABIInfo(CGT, Kind, HasQPX)), - HasQPX(HasQPX) {} + : TargetCodeGenInfo(new PPC64_SVR4_ABIInfo(CGT, Kind, HasQPX)) {} int getDwarfEHStackPointer(CodeGen::CodeGenModule &M) const override { // This is recovered from gcc output. @@ -3403,15 +3389,6 @@ bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const override; - - unsigned getOpenMPSimdDefaultAlignment(QualType QT) const override { - if (HasQPX) - if (const PointerType *PT = QT->getAs()) - if (PT->getPointeeType()->isSpecificBuiltinType(BuiltinType::Double)) - return 32; // Natural alignment for QPX doubles. - - return 16; // Natural alignment for Altivec and VSX vectors. - } }; class PPC64TargetCodeGenInfo : public DefaultTargetCodeGenInfo { @@ -3425,10 +3402,6 @@ bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const override; - - unsigned getOpenMPSimdDefaultAlignment(QualType) const override { - return 16; // Natural alignment for Altivec vectors. - } }; } Index: lib/Parse/ParseExpr.cpp =================================================================== --- lib/Parse/ParseExpr.cpp +++ lib/Parse/ParseExpr.cpp @@ -1042,6 +1042,8 @@ case tok::kw_sizeof: // unary-expression: 'sizeof' unary-expression // unary-expression: 'sizeof' '(' type-name ')' case tok::kw_vec_step: // unary-expression: OpenCL 'vec_step' expression + // unary-expression: OpenMP 'default simd alignment' expression + case tok::kw_simd_align: return ParseUnaryExprOrTypeTraitExpression(); case tok::ampamp: { // unary-expression: '&&' identifier SourceLocation AmpAmpLoc = ConsumeToken(); @@ -1636,8 +1638,9 @@ ParsedType &CastTy, SourceRange &CastRange) { - assert(OpTok.isOneOf(tok::kw_typeof, tok::kw_sizeof, tok::kw___alignof, - tok::kw_alignof, tok::kw__Alignof, tok::kw_vec_step) && + assert(OpTok.isOneOf(tok::kw_typeof, tok::kw_sizeof, tok::kw___alignof, + tok::kw_alignof, tok::kw__Alignof, tok::kw_vec_step, + tok::kw_simd_align) && "Not a typeof/sizeof/alignof/vec_step expression!"); ExprResult Operand; @@ -1722,7 +1725,7 @@ /// \endverbatim ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() { assert(Tok.isOneOf(tok::kw_sizeof, tok::kw___alignof, tok::kw_alignof, - tok::kw__Alignof, tok::kw_vec_step) && + tok::kw__Alignof, tok::kw_vec_step, tok::kw_simd_align) && "Not a sizeof/alignof/vec_step expression!"); Token OpTok = Tok; ConsumeToken(); @@ -1792,6 +1795,8 @@ ExprKind = UETT_AlignOf; else if (OpTok.is(tok::kw_vec_step)) ExprKind = UETT_VecStep; + else if (OpTok.is(tok::kw_simd_align)) + ExprKind = UETT_OpenMPDefaultSimdAlign; if (isCastExpr) return Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(), Index: lib/Sema/SemaExpr.cpp =================================================================== --- lib/Sema/SemaExpr.cpp +++ lib/Sema/SemaExpr.cpp @@ -3518,7 +3518,8 @@ // C99 6.5.3.4p1: if (T->isFunctionType() && - (TraitKind == UETT_SizeOf || TraitKind == UETT_AlignOf)) { + (TraitKind == UETT_SizeOf || TraitKind == UETT_AlignOf || + TraitKind == UETT_OpenMPDefaultSimdAlign)) { // sizeof(function)/alignof(function) is allowed as an extension. S.Diag(Loc, diag::ext_sizeof_alignof_function_type) << TraitKind << ArgRange; @@ -3620,7 +3621,8 @@ // The operand for sizeof and alignof is in an unevaluated expression context, // so side effects could result in unintended consequences. - if ((ExprKind == UETT_SizeOf || ExprKind == UETT_AlignOf) && + if ((ExprKind == UETT_SizeOf || ExprKind == UETT_AlignOf || + ExprKind == UETT_OpenMPDefaultSimdAlign) && ActiveTemplateInstantiations.empty() && E->HasSideEffects(Context, false)) Diag(E->getExprLoc(), diag::warn_side_effects_unevaluated_context); @@ -3824,6 +3826,9 @@ isInvalid = CheckAlignOfExpr(*this, E); } else if (ExprKind == UETT_VecStep) { isInvalid = CheckVecStepExpr(E); + } else if (ExprKind == UETT_OpenMPDefaultSimdAlign) { + isInvalid = + CheckUnaryExprOrTypeTraitOperand(E, UETT_OpenMPDefaultSimdAlign); } else if (E->refersToBitField()) { // C99 6.5.3.4p1. Diag(E->getExprLoc(), diag::err_sizeof_alignof_bitfield) << 0; isInvalid = true; Index: test/CodeGen/simd_align.c =================================================================== --- test/CodeGen/simd_align.c +++ test/CodeGen/simd_align.c @@ -0,0 +1,12 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -O1 -emit-llvm -o %t %s +// RUN: grep 'ret i32 16' %t + +enum e0 { E0 }; +struct s0 { + enum e0 a:31; +}; + +struct s0 t1_tmp; +int f0() { + return simd_align(t1_tmp); +} Index: test/SemaCXX/simd_align.cpp =================================================================== --- test/SemaCXX/simd_align.cpp +++ test/SemaCXX/simd_align.cpp @@ -0,0 +1,83 @@ +// RUN: %clang_cc1 -std=c++11 -fsyntax-only -triple x86_64-unknown-unknown -verify %s + +struct S0 { + int x; + static const int test0 = simd_align(x); + static const int test1 = simd_align(S0::x); + auto test2() -> char(&)[simd_align(x)]; +}; + +struct S1; // expected-note 6 {{forward declaration}} +extern S1 s1; +const int test3 = simd_align(s1); // expected-error {{invalid application of 'simd_align' to an incomplete type 'S1'}} + +struct S2 { + S2(); + S1 &s; + int x; + + int test4 = simd_align(x); // ok + int test5 = simd_align(s); // expected-error {{invalid application of 'simd_align' to an incomplete type 'S1'}} +}; + +const int test6 = simd_align(S2::x); +const int test7 = simd_align(S2::s); // expected-error {{invalid application of 'simd_align' to an incomplete type 'S1'}} + +// Arguably, these should fail like the S1 cases do: the alignment of +// 's2.x' should depend on the alignment of both x-within-S2 and +// s2-within-S3 and thus require 'S3' to be complete. If we start +// doing the appropriate recursive walk to do that, we should make +// sure that these cases don't explode. +struct S3 { + S2 s2; + + static const int test8 = simd_align(s2.x); + static const int test9 = simd_align(s2.s); // expected-error {{invalid application of 'simd_align' to an incomplete type 'S1'}} + auto test10() -> char(&)[simd_align(s2.x)]; + static const int test11 = simd_align(S3::s2.x); + static const int test12 = simd_align(S3::s2.s); // expected-error {{invalid application of 'simd_align' to an incomplete type 'S1'}} + auto test13() -> char(&)[simd_align(s2.x)]; +}; + +// Same reasoning as S3. +struct S4 { + union { + int x; + }; + static const int test0 = simd_align(x); + static const int test1 = simd_align(S0::x); + auto test2() -> char(&)[simd_align(x)]; +}; + +// Regression test for asking for the alignment of a field within an invalid +// record. +struct S5 { + S1 s; // expected-error {{incomplete type}} + int x; +}; +const int test8 = simd_align(S5::x); + +long long int test14[2]; + +static_assert(simd_align(test14) == 16, "foo"); + +static_assert(simd_align(int[2]) == simd_align(int), ""); // ok + +namespace simd_align_array_expr { + alignas(32) extern int n[2]; + static_assert(simd_align(n) == 16, ""); + + template struct S { + static int a[]; + }; + template int S::a[N]; + static_assert(simd_align(S<1>::a) == simd_align(int), ""); + static_assert(simd_align(S<1128>::a) == simd_align(int), ""); +} + +template void n(T) { + alignas(T) int T1; + char k[simd_align(T1)]; + static_assert(sizeof(k) == simd_align(long long), ""); +} +template void n(long long);