Index: include/clang/AST/ASTContext.h =================================================================== --- include/clang/AST/ASTContext.h +++ include/clang/AST/ASTContext.h @@ -1664,6 +1664,9 @@ TypeInfo getTypeInfo(const Type *T) const; TypeInfo getTypeInfo(QualType T) const { return getTypeInfo(T.getTypePtr()); } + /// \brief Get default simd alignment of the specified complete type in bits. + unsigned getOpenMPDefaultSimdAlign(QualType T) const; + /// \brief Return the size of the specified (complete) type \p T, in bits. uint64_t getTypeSize(QualType T) const { return getTypeInfo(T).Width; } uint64_t getTypeSize(const Type *T) const { return getTypeInfo(T).Width; } Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -4684,19 +4684,21 @@ // 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|__builtin_omp_required_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|__builtin_omp_required_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|__builtin_omp_required_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|__builtin_omp_required_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|__builtin_omp_required_simd_align}0' to a " "function type">; +def err_openmp_default_simd_align_expr : Error< + "invalid application of '__builtin_omp_required_simd_align' to an expression, only type is allowed">; def err_sizeof_alignof_bitfield : Error< "invalid application of '%select{sizeof|alignof}0' to bit-field">; def err_alignof_member_of_incomplete_type : Error< 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(__builtin_omp_required_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 @@ -1786,6 +1786,17 @@ return TypeInfo(Width, Align, AlignIsRequired); } +unsigned ASTContext::getOpenMPDefaultSimdAlign(QualType T) const { + 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 = 256; + return SimdAlign; +} + /// toCharUnitsFromBits - Convert a size in bits to a size in characters. CharUnits ASTContext::toCharUnitsFromBits(int64_t BitSize) const { return CharUnits::fromQuantity(BitSize / getCharWidth()); Index: lib/AST/ASTDumper.cpp =================================================================== --- lib/AST/ASTDumper.cpp +++ lib/AST/ASTDumper.cpp @@ -1829,6 +1829,9 @@ case UETT_VecStep: OS << " vec_step"; break; + case UETT_OpenMPDefaultSimdAlign: + OS << " __builtin_omp_required_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,14 @@ return false; return Success(Sizeof, E); } + case UETT_OpenMPDefaultSimdAlign: + return Success( + Info.Ctx.toCharUnitsFromBits(Info.Ctx.getOpenMPDefaultSimdAlign( + E->isArgumentType() + ? E->getArgumentType() + : E->getArgumentExpr()->getType())) + .getQuantity(), + E); } llvm_unreachable("unknown expr/type trait"); Index: lib/AST/ItaniumMangle.cpp =================================================================== --- lib/AST/ItaniumMangle.cpp +++ lib/AST/ItaniumMangle.cpp @@ -3018,13 +3018,21 @@ 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 __builtin_omp_required_simd_align expression"); + Diags.Report(DiagID); + return; + } if (SAE->isArgumentType()) { Out << 't'; mangleType(SAE->getArgumentType()); 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 << "__builtin_omp_required_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 = 128; LongDoubleWidth = LongDoubleAlign = 128; LongDoubleFormat = &llvm::APFloat::PPCDoubleDouble; } @@ -2974,6 +2975,9 @@ Features.erase(it); else if (SSELevel > NoSSE) MMX3DNowLevel = std::max(MMX3DNowLevel, MMX); + + SimdDefaultAlign = + (getABI() == "avx512") ? 512 : (getABI() == "avx") ? 256 : 128; 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,13 @@ return size; } + } else if (E->getKind() == UETT_OpenMPDefaultSimdAlign) { + auto Alignment = + CGF.getContext() + .toCharUnitsFromBits(CGF.getContext().getOpenMPDefaultSimdAlign( + E->getTypeOfArgument())) + .getQuantity(); + return llvm::ConstantInt::get(CGF.SizeTy, 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 @@ -649,8 +649,10 @@ // 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()); + CGF.getContext() + .toCharUnitsFromBits( + CGF.getContext().getOpenMPDefaultSimdAlign(E->getType())) + .getQuantity(); } 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 @@ -1576,11 +1576,9 @@ }; class X86_64TargetCodeGenInfo : public TargetCodeGenInfo { - X86AVXABILevel AVXLevel; public: X86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, X86AVXABILevel AVXLevel) - : TargetCodeGenInfo(new X86_64ABIInfo(CGT, AVXLevel)), - AVXLevel(AVXLevel) {} + : TargetCodeGenInfo(new X86_64ABIInfo(CGT, AVXLevel)) {} const X86_64ABIInfo &getABIInfo() const { return static_cast(TargetCodeGenInfo::getABIInfo()); @@ -1646,10 +1644,6 @@ ('T' << 24); return llvm::ConstantInt::get(CGM.Int32Ty, Sig); } - - unsigned getOpenMPSimdDefaultAlignment(QualType) const override { - return getNativeVectorSizeForAVXABI(AVXLevel) / 8; - } }; class PS4TargetCodeGenInfo : public X86_64TargetCodeGenInfo { @@ -1721,11 +1715,10 @@ } class WinX86_64TargetCodeGenInfo : public TargetCodeGenInfo { - X86AVXABILevel AVXLevel; public: WinX86_64TargetCodeGenInfo(CodeGen::CodeGenTypes &CGT, X86AVXABILevel AVXLevel) - : TargetCodeGenInfo(new WinX86_64ABIInfo(CGT)), AVXLevel(AVXLevel) {} + : TargetCodeGenInfo(new WinX86_64ABIInfo(CGT)) {} void setTargetAttributes(const Decl *D, llvm::GlobalValue *GV, CodeGen::CodeGenModule &CGM) const override; @@ -1755,10 +1748,6 @@ llvm::SmallString<32> &Opt) const override { Opt = "/FAILIFMISMATCH:\"" + Name.str() + "=" + Value.str() + "\""; } - - unsigned getOpenMPSimdDefaultAlignment(QualType) const override { - return getNativeVectorSizeForAVXABI(AVXLevel) / 8; - } }; void WinX86_64TargetCodeGenInfo::setTargetAttributes(const Decl *D, @@ -3167,10 +3156,6 @@ bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF, llvm::Value *Address) const override; - - unsigned getOpenMPSimdDefaultAlignment(QualType) const override { - return 16; // Natural alignment for Altivec vectors. - } }; } @@ -3410,13 +3395,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. @@ -3425,15 +3408,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 { @@ -3447,10 +3421,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___builtin_omp_required_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___builtin_omp_required_simd_align) && "Not a typeof/sizeof/alignof/vec_step expression!"); ExprResult Operand; @@ -1722,7 +1725,8 @@ /// \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___builtin_omp_required_simd_align) && "Not a sizeof/alignof/vec_step expression!"); Token OpTok = Tok; ConsumeToken(); @@ -1792,6 +1796,8 @@ ExprKind = UETT_AlignOf; else if (OpTok.is(tok::kw_vec_step)) ExprKind = UETT_VecStep; + else if (OpTok.is(tok::kw___builtin_omp_required_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 @@ -3689,7 +3689,7 @@ // C11 6.5.3.4/3, C++11 [expr.alignof]p3: // When alignof or _Alignof is applied to an array type, the result // is the alignment of the element type. - if (ExprKind == UETT_AlignOf) + if (ExprKind == UETT_AlignOf || ExprKind == UETT_OpenMPDefaultSimdAlign) ExprType = Context.getBaseElementType(ExprType); if (ExprKind == UETT_VecStep) @@ -3824,6 +3824,9 @@ isInvalid = CheckAlignOfExpr(*this, E); } else if (ExprKind == UETT_VecStep) { isInvalid = CheckVecStepExpr(E); + } else if (ExprKind == UETT_OpenMPDefaultSimdAlign) { + Diag(E->getExprLoc(), diag::err_openmp_default_simd_align_expr); + isInvalid = true; } else if (E->refersToBitField()) { // C99 6.5.3.4p1. Diag(E->getExprLoc(), diag::err_sizeof_alignof_bitfield) << 0; isInvalid = true; Index: test/CodeGen/openmp_default_simd_align.c =================================================================== --- test/CodeGen/openmp_default_simd_align.c +++ test/CodeGen/openmp_default_simd_align.c @@ -0,0 +1,11 @@ +// RUN: %clang_cc1 -triple x86_64-unknown-unknown -O1 -emit-llvm -o - %s | FileCheck %s + +enum e0 { E0 }; +struct s0 { + enum e0 a:31; +}; + +int f0() { + return __builtin_omp_required_simd_align(struct s0); + // CHECK: ret i32 16 +} Index: test/SemaCXX/openmp_default_simd_align.cpp =================================================================== --- test/SemaCXX/openmp_default_simd_align.cpp +++ test/SemaCXX/openmp_default_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 = __builtin_omp_required_simd_align(x); // expected-error {{invalid application of '__builtin_omp_required_simd_align' to an expression, only type is allowed}} + static const int test1 = __builtin_omp_required_simd_align(decltype(S0::x)); + auto test2() -> char(&)[__builtin_omp_required_simd_align(decltype(x))]; +}; + +struct S1; // expected-note 6 {{forward declaration}} +extern S1 s1; +const int test3 = __builtin_omp_required_simd_align(decltype(s1)); // expected-error {{invalid application of '__builtin_omp_required_simd_align' to an incomplete type 'decltype(s1)' (aka 'S1')}} + +struct S2 { + S2(); + S1 &s; + int x; + + int test4 = __builtin_omp_required_simd_align(decltype(x)); // ok + int test5 = __builtin_omp_required_simd_align(decltype(s)); // expected-error {{invalid application of '__builtin_omp_required_simd_align' to an incomplete type 'S1'}} +}; + +const int test6 = __builtin_omp_required_simd_align(decltype(S2::x)); +const int test7 = __builtin_omp_required_simd_align(decltype(S2::s)); // expected-error {{invalid application of '__builtin_omp_required_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 = __builtin_omp_required_simd_align(decltype(s2.x)); + static const int test9 = __builtin_omp_required_simd_align(decltype(s2.s)); // expected-error {{invalid application of '__builtin_omp_required_simd_align' to an incomplete type 'S1'}} + auto test10() -> char(&)[__builtin_omp_required_simd_align(decltype(s2.x))]; + static const int test11 = __builtin_omp_required_simd_align(decltype(S3::s2.x)); + static const int test12 = __builtin_omp_required_simd_align(decltype(S3::s2.s)); // expected-error {{invalid application of '__builtin_omp_required_simd_align' to an incomplete type 'S1'}} + auto test13() -> char(&)[__builtin_omp_required_simd_align(decltype(s2.x))]; +}; + +// Same reasoning as S3. +struct S4 { + union { + int x; + }; + static const int test0 = __builtin_omp_required_simd_align(decltype(x)); + static const int test1 = __builtin_omp_required_simd_align(decltype(S0::x)); + auto test2() -> char(&)[__builtin_omp_required_simd_align(decltype(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 = __builtin_omp_required_simd_align(decltype(S5::x)); + +long long int test14[2]; + +static_assert(__builtin_omp_required_simd_align(decltype(test14)) == 16, "foo"); + +static_assert(__builtin_omp_required_simd_align(int[2]) == __builtin_omp_required_simd_align(int), ""); // ok + +namespace __builtin_omp_required_simd_align_array_expr { + alignas(32) extern int n[2]; + static_assert(__builtin_omp_required_simd_align(decltype(n)) == 16, ""); + + template struct S { + static int a[]; + }; + template int S::a[N]; + static_assert(__builtin_omp_required_simd_align(decltype(S<1>::a)) == __builtin_omp_required_simd_align(int), ""); + static_assert(__builtin_omp_required_simd_align(decltype(S<1128>::a)) == __builtin_omp_required_simd_align(int), ""); +} + +template void n(T) { + alignas(T) int T1; + char k[__builtin_omp_required_simd_align(decltype(T1))]; + static_assert(sizeof(k) == __builtin_omp_required_simd_align(long long), ""); +} +template void n(long long);