[OPENMP] Introduced type trait "__builtin_omp_required_simd_align" for default simd alignment.

Adds type trait "__builtin_omp_required_simd_align" after discussions here http://reviews.llvm.org/D9894
Differential Revision: http://reviews.llvm.org/D10597

llvm-svn: 241237
This commit is contained in:
Alexey Bataev 2015-07-02 03:40:19 +00:00
parent 85225b0a36
commit 0039651304
20 changed files with 178 additions and 51 deletions

View File

@ -1664,6 +1664,9 @@ public:
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; }

View File

@ -4698,13 +4698,15 @@ def ext_sizeof_alignof_void_type : Extension<
"invalid application of '%select{sizeof|alignof|vec_step}0' to a void "
"type">, InGroup<PointerArith>;
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<

View File

@ -70,6 +70,7 @@ protected:
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,10 @@ public:
/// \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. Generally, this
/// value is type-specific, but this alignment can be used for most of the
/// types 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 {

View File

@ -503,6 +503,9 @@ ALIAS("read_write", __read_write , KEYOPENCL)
KEYWORD(__builtin_astype , KEYOPENCL)
KEYWORD(vec_step , KEYOPENCL|KEYALTIVEC)
// OpenMP Type Traits
KEYWORD(__builtin_omp_required_simd_align, KEYALL)
// Borland Extensions.
KEYWORD(__pascal , KEYALL)

View File

@ -92,7 +92,8 @@ namespace clang {
enum UnaryExprOrTypeTrait {
UETT_SizeOf,
UETT_AlignOf,
UETT_VecStep
UETT_VecStep,
UETT_OpenMPRequiredSimdAlign,
};
}

View File

@ -1786,6 +1786,17 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const {
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->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());

View File

@ -1829,6 +1829,9 @@ void ASTDumper::VisitUnaryExprOrTypeTraitExpr(
case UETT_VecStep:
OS << " vec_step";
break;
case UETT_OpenMPRequiredSimdAlign:
OS << " __builtin_omp_required_simd_align";
break;
}
if (Node->isArgumentType())
dumpType(Node->getArgumentType());

View File

@ -7251,6 +7251,13 @@ bool IntExprEvaluator::VisitUnaryExprOrTypeTraitExpr(
return false;
return Success(Sizeof, E);
}
case UETT_OpenMPRequiredSimdAlign:
assert(E->isArgumentType());
return Success(
Info.Ctx.toCharUnitsFromBits(
Info.Ctx.getOpenMPDefaultSimdAlign(E->getArgumentType()))
.getQuantity(),
E);
}
llvm_unreachable("unknown expr/type trait");

View File

@ -3018,13 +3018,21 @@ recurse:
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_OpenMPRequiredSimdAlign:
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());

View File

@ -1223,6 +1223,9 @@ void StmtPrinter::VisitUnaryExprOrTypeTraitExpr(UnaryExprOrTypeTraitExpr *Node){
case UETT_VecStep:
OS << "vec_step";
break;
case UETT_OpenMPRequiredSimdAlign:
OS << "__builtin_omp_required_simd_align";
break;
}
if (Node->isArgumentType()) {
OS << '(';

View File

@ -50,6 +50,7 @@ TargetInfo::TargetInfo(const llvm::Triple &T) : TargetOpts(), Triple(T) {
LargeArrayAlign = 0;
MaxAtomicPromoteWidth = MaxAtomicInlineWidth = 0;
MaxVectorAlign = 0;
SimdDefaultAlign = 0;
SizeType = UnsignedLong;
PtrDiffType = SignedLong;
IntMaxType = SignedLongLong;

View File

@ -759,6 +759,7 @@ public:
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;
}
@ -2988,6 +2989,9 @@ bool X86TargetInfo::handleTargetFeatures(std::vector<std::string> &Features,
Features.erase(it);
else if (SSELevel > NoSSE)
MMX3DNowLevel = std::max(MMX3DNowLevel, MMX);
SimdDefaultAlign =
(getABI() == "avx512") ? 512 : (getABI() == "avx") ? 256 : 128;
return true;
}

View File

@ -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 @@ ScalarExprEmitter::VisitUnaryExprOrTypeTraitExpr(
return size;
}
} else if (E->getKind() == UETT_OpenMPRequiredSimdAlign) {
auto Alignment =
CGF.getContext()
.toCharUnitsFromBits(CGF.getContext().getOpenMPDefaultSimdAlign(
E->getTypeOfArgument()->getPointeeType()))
.getQuantity();
return llvm::ConstantInt::get(CGF.SizeTy, Alignment);
}
// If this isn't sizeof(vla), the result must be constant; use the constant

View File

@ -649,8 +649,10 @@ static void emitAlignedClause(CodeGenFunction &CGF,
// 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()->getPointeeType()))
.getQuantity();
}
assert((Alignment == 0 || llvm::isPowerOf2_32(Alignment)) &&
"alignment is not power of 2");

View File

@ -1577,11 +1577,9 @@ public:
};
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<const X86_64ABIInfo&>(TargetCodeGenInfo::getABIInfo());
@ -1647,10 +1645,6 @@ public:
('T' << 24);
return llvm::ConstantInt::get(CGM.Int32Ty, Sig);
}
unsigned getOpenMPSimdDefaultAlignment(QualType) const override {
return getNativeVectorSizeForAVXABI(AVXLevel) / 8;
}
};
class PS4TargetCodeGenInfo : public X86_64TargetCodeGenInfo {
@ -1722,11 +1716,10 @@ void WinX86_32TargetCodeGenInfo::setTargetAttributes(const Decl *D,
}
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;
@ -1756,10 +1749,6 @@ public:
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,
@ -3171,10 +3160,6 @@ public:
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
llvm::Value *Address) const override;
unsigned getOpenMPSimdDefaultAlignment(QualType) const override {
return 16; // Natural alignment for Altivec vectors.
}
};
}
@ -3414,13 +3399,11 @@ public:
};
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.
@ -3429,15 +3412,6 @@ public:
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
llvm::Value *Address) const override;
unsigned getOpenMPSimdDefaultAlignment(QualType QT) const override {
if (HasQPX)
if (const PointerType *PT = QT->getAs<PointerType>())
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 {
@ -3451,10 +3425,6 @@ public:
bool initDwarfEHRegSizeTable(CodeGen::CodeGenFunction &CGF,
llvm::Value *Address) const override;
unsigned getOpenMPSimdDefaultAlignment(QualType) const override {
return 16; // Natural alignment for Altivec vectors.
}
};
}

View File

@ -218,13 +218,6 @@ public:
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;
}
};
}

View File

@ -1060,6 +1060,8 @@ ExprResult Parser::ParseCastExpression(bool isUnaryExpression,
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: '__builtin_omp_required_simd_align' '(' type-name ')'
case tok::kw___builtin_omp_required_simd_align:
return ParseUnaryExprOrTypeTraitExpression();
case tok::ampamp: { // unary-expression: '&&' identifier
SourceLocation AmpAmpLoc = ConsumeToken();
@ -1654,8 +1656,9 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
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;
@ -1740,7 +1743,8 @@ Parser::ParseExprAfterUnaryExprOrTypeTrait(const Token &OpTok,
/// \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();
@ -1810,6 +1814,8 @@ ExprResult Parser::ParseUnaryExprOrTypeTraitExpression() {
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_OpenMPRequiredSimdAlign;
if (isCastExpr)
return Actions.ActOnUnaryExprOrTypeTraitExpr(OpTok.getLocation(),

View File

@ -3689,7 +3689,7 @@ bool Sema::CheckUnaryExprOrTypeTraitOperand(QualType ExprType,
// 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_OpenMPRequiredSimdAlign)
ExprType = Context.getBaseElementType(ExprType);
if (ExprKind == UETT_VecStep)
@ -3824,6 +3824,9 @@ Sema::CreateUnaryExprOrTypeTraitExpr(Expr *E, SourceLocation OpLoc,
isInvalid = CheckAlignOfExpr(*this, E);
} else if (ExprKind == UETT_VecStep) {
isInvalid = CheckVecStepExpr(E);
} else if (ExprKind == UETT_OpenMPRequiredSimdAlign) {
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;

View File

@ -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
}

View File

@ -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<int> struct S {
static int a[];
};
template<int N> int S<N>::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 <typename T> 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);