From 138b8635bbf9070cd26ce7afc92048507a5fd66b Mon Sep 17 00:00:00 2001 From: Alexey Bataev Date: Wed, 27 Feb 2019 20:29:45 +0000 Subject: [PATCH] [OPENMP]Delay emission of the error for unsupported types. If the type is unsupported on the device side, it still must be emitted, but we should emit errors for operations with such types. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@355027 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Sema/Sema.h | 4 ++ lib/AST/ASTContext.cpp | 24 +++++-- lib/CodeGen/TargetInfo.cpp | 46 +++++++++++++ lib/Sema/SemaExpr.cpp | 15 +++++ lib/Sema/SemaOpenMP.cpp | 12 ++++ lib/Sema/SemaType.cpp | 9 ++- .../OpenMP/nvptx_unsupported_type_codegen.cpp | 64 +++++++++++++++++++ .../nvptx_unsupported_type_messages.cpp | 47 ++++++++++++++ 8 files changed, 214 insertions(+), 7 deletions(-) create mode 100644 test/OpenMP/nvptx_unsupported_type_codegen.cpp create mode 100644 test/OpenMP/nvptx_unsupported_type_messages.cpp diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 333f41dea5..3408c9462e 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -8805,6 +8805,10 @@ private: /// Check whether we're allowed to call Callee from the current function. void checkOpenMPDeviceFunction(SourceLocation Loc, FunctionDecl *Callee); + /// Check if the expression is allowed to be used in expressions for the + /// OpenMP devices. + void checkOpenMPDeviceExpr(const Expr *E); + /// Checks if a type or a declaration is disabled due to the owning extension /// being disabled, and emits diagnostic messages if it is disabled. /// \param D type or declaration to be checked. diff --git a/lib/AST/ASTContext.cpp b/lib/AST/ASTContext.cpp index f968c6260e..aa4bd4139c 100644 --- a/lib/AST/ASTContext.cpp +++ b/lib/AST/ASTContext.cpp @@ -1902,8 +1902,16 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { break; case BuiltinType::Float16: case BuiltinType::Half: - Width = Target->getHalfWidth(); - Align = Target->getHalfAlign(); + if (Target->hasFloat16Type() || !getLangOpts().OpenMP || + !getLangOpts().OpenMPIsDevice) { + Width = Target->getHalfWidth(); + Align = Target->getHalfAlign(); + } else { + assert(getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice && + "Expected OpenMP device compilation."); + Width = AuxTarget->getHalfWidth(); + Align = AuxTarget->getHalfAlign(); + } break; case BuiltinType::Float: Width = Target->getFloatWidth(); @@ -1918,8 +1926,16 @@ TypeInfo ASTContext::getTypeInfoImpl(const Type *T) const { Align = Target->getLongDoubleAlign(); break; case BuiltinType::Float128: - Width = Target->getFloat128Width(); - Align = Target->getFloat128Align(); + if (Target->hasFloat128Type() || !getLangOpts().OpenMP || + !getLangOpts().OpenMPIsDevice) { + Width = Target->getFloat128Width(); + Align = Target->getFloat128Align(); + } else { + assert(getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice && + "Expected OpenMP device compilation."); + Width = AuxTarget->getFloat128Width(); + Align = AuxTarget->getFloat128Align(); + } break; case BuiltinType::NullPtr: Width = Target->getPointerWidth(0); // C++ 3.9.1p11: sizeof(nullptr_t) diff --git a/lib/CodeGen/TargetInfo.cpp b/lib/CodeGen/TargetInfo.cpp index a130dd3cfb..ee8c889535 100644 --- a/lib/CodeGen/TargetInfo.cpp +++ b/lib/CodeGen/TargetInfo.cpp @@ -6268,10 +6268,56 @@ private: static void addNVVMMetadata(llvm::Function *F, StringRef Name, int Operand); }; +/// Checks if the type is unsupported directly by the current target. +static bool isUnsupportedType(ASTContext &Context, QualType T) { + if (!Context.getTargetInfo().hasFloat16Type() && T->isFloat16Type()) + return true; + if (!Context.getTargetInfo().hasFloat128Type() && T->isFloat128Type()) + return true; + if (!Context.getTargetInfo().hasInt128Type() && T->isIntegerType() && + Context.getTypeSize(T) > 64) + return true; + if (const auto *AT = T->getAsArrayTypeUnsafe()) + return isUnsupportedType(Context, AT->getElementType()); + const auto *RT = T->getAs(); + if (!RT) + return false; + const RecordDecl *RD = RT->getDecl(); + + // If this is a C++ record, check the bases first. + if (const CXXRecordDecl *CXXRD = dyn_cast(RD)) + for (const CXXBaseSpecifier &I : CXXRD->bases()) + if (isUnsupportedType(Context, I.getType())) + return true; + + for (const FieldDecl *I : RD->fields()) + if (isUnsupportedType(Context, I->getType())) + return true; + return false; +} + +/// Coerce the given type into an array with maximum allowed size of elements. +static ABIArgInfo coerceToIntArrayWithLimit(QualType Ty, ASTContext &Context, + llvm::LLVMContext &LLVMContext, + unsigned MaxSize) { + // Alignment and Size are measured in bits. + const uint64_t Size = Context.getTypeSize(Ty); + const uint64_t Alignment = Context.getTypeAlign(Ty); + const unsigned Div = std::min(MaxSize, Alignment); + llvm::Type *IntType = llvm::Type::getIntNTy(LLVMContext, Div); + const uint64_t NumElements = (Size + Div - 1) / Div; + return ABIArgInfo::getDirect(llvm::ArrayType::get(IntType, NumElements)); +} + ABIArgInfo NVPTXABIInfo::classifyReturnType(QualType RetTy) const { if (RetTy->isVoidType()) return ABIArgInfo::getIgnore(); + if (getContext().getLangOpts().OpenMP && + getContext().getLangOpts().OpenMPIsDevice && + isUnsupportedType(getContext(), RetTy)) + return coerceToIntArrayWithLimit(RetTy, getContext(), getVMContext(), 64); + // note: this is different from default ABI if (!RetTy->isScalarType()) return ABIArgInfo::getDirect(); diff --git a/lib/Sema/SemaExpr.cpp b/lib/Sema/SemaExpr.cpp index 266120dfdc..157ef0b942 100644 --- a/lib/Sema/SemaExpr.cpp +++ b/lib/Sema/SemaExpr.cpp @@ -12432,6 +12432,14 @@ ExprResult Sema::CreateBuiltinBinOp(SourceLocation OpLoc, } } + // Diagnose operations on the unsupported types for OpenMP device compilation. + if (getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice) { + if (Opc != BO_Assign && Opc != BO_Comma) { + checkOpenMPDeviceExpr(LHSExpr); + checkOpenMPDeviceExpr(RHSExpr); + } + } + switch (Opc) { case BO_Assign: ResultTy = CheckAssignmentOperands(LHS.get(), RHS, OpLoc, QualType()); @@ -13027,6 +13035,13 @@ ExprResult Sema::CreateBuiltinUnaryOp(SourceLocation OpLoc, << Input.get()->getSourceRange()); } } + // Diagnose operations on the unsupported types for OpenMP device compilation. + if (getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice) { + if (UnaryOperator::isIncrementDecrementOp(Opc) || + UnaryOperator::isArithmeticOp(Opc)) + checkOpenMPDeviceExpr(InputExpr); + } + switch (Opc) { case UO_PreInc: case UO_PreDec: diff --git a/lib/Sema/SemaOpenMP.cpp b/lib/Sema/SemaOpenMP.cpp index 76141afd59..7fed3725ed 100644 --- a/lib/Sema/SemaOpenMP.cpp +++ b/lib/Sema/SemaOpenMP.cpp @@ -1443,6 +1443,18 @@ void Sema::checkOpenMPDeviceFunction(SourceLocation Loc, FunctionDecl *Callee) { DeviceCallGraph[Caller].insert({Callee, Loc}); } +void Sema::checkOpenMPDeviceExpr(const Expr *E) { + assert(getLangOpts().OpenMP && getLangOpts().OpenMPIsDevice && + "OpenMP device compilation mode is expected."); + QualType Ty = E->getType(); + if ((Ty->isFloat16Type() && !Context.getTargetInfo().hasFloat16Type()) || + (Ty->isFloat128Type() && !Context.getTargetInfo().hasFloat128Type()) || + (Ty->isIntegerType() && Context.getTypeSize(Ty) == 128 && + !Context.getTargetInfo().hasInt128Type())) + targetDiag(E->getExprLoc(), diag::err_type_unsupported) + << Ty << E->getSourceRange(); +} + bool Sema::isOpenMPCapturedByRef(const ValueDecl *D, unsigned Level) const { assert(LangOpts.OpenMP && "OpenMP is not allowed"); diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index f314cb0abe..3591add23d 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -1433,7 +1433,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { break; } case DeclSpec::TST_int128: - if (!S.Context.getTargetInfo().hasInt128Type()) + if (!S.Context.getTargetInfo().hasInt128Type() && + !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice)) S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) << "__int128"; if (DS.getTypeSpecSign() == DeclSpec::TSS_unsigned) @@ -1445,7 +1446,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { // CUDA host and device may have different _Float16 support, therefore // do not diagnose _Float16 usage to avoid false alarm. // ToDo: more precise diagnostics for CUDA. - if (!S.Context.getTargetInfo().hasFloat16Type() && !S.getLangOpts().CUDA) + if (!S.Context.getTargetInfo().hasFloat16Type() && !S.getLangOpts().CUDA && + !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice)) S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) << "_Float16"; Result = Context.Float16Ty; @@ -1459,7 +1461,8 @@ static QualType ConvertDeclSpecToType(TypeProcessingState &state) { Result = Context.DoubleTy; break; case DeclSpec::TST_float128: - if (!S.Context.getTargetInfo().hasFloat128Type()) + if (!S.Context.getTargetInfo().hasFloat128Type() && + !(S.getLangOpts().OpenMP && S.getLangOpts().OpenMPIsDevice)) S.Diag(DS.getTypeSpecTypeLoc(), diag::err_type_unsupported) << "__float128"; Result = Context.Float128Ty; diff --git a/test/OpenMP/nvptx_unsupported_type_codegen.cpp b/test/OpenMP/nvptx_unsupported_type_codegen.cpp new file mode 100644 index 0000000000..61accc3c72 --- /dev/null +++ b/test/OpenMP/nvptx_unsupported_type_codegen.cpp @@ -0,0 +1,64 @@ +// Test target codegen - host bc file has to be created first. +// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple x86_64-unknown-linux -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o %t-host.bc +// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple nvptx64-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda -aux-triple x86_64-unknown-linux -emit-llvm %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-host.bc -o - | FileCheck %s +// expected-no-diagnostics + +// CHECK-DAG: [[T:%.+]] = type {{.+}}, fp128, +// CHECK-DAG: [[T1:%.+]] = type {{.+}}, i128, i128, + +struct T { + char a; + __float128 f; + char c; + T() : a(12), f(15) {} + T &operator+(T &b) { f += b.a; return *this;} +}; + +struct T1 { + char a; + __int128 f; + __int128 f1; + char c; + T1() : a(12), f(15) {} + T1 &operator+(T1 &b) { f += b.a; return *this;} +}; + +#pragma omp declare target +T a = T(); +T f = a; +// CHECK: define void @{{.+}}foo{{.+}}([[T]]* byval align {{.+}}) +void foo(T a = T()) { + return; +} +// CHECK: define [6 x i64] @{{.+}}bar{{.+}}() +T bar() { +// CHECK: bitcast [[T]]* %{{.+}} to [6 x i64]* +// CHECK-NEXT: load [6 x i64], [6 x i64]* %{{.+}}, +// CHECK-NEXT: ret [6 x i64] + return T(); +} +// CHECK: define void @{{.+}}baz{{.+}}() +void baz() { +// CHECK: call [6 x i64] @{{.+}}bar{{.+}}() +// CHECK-NEXT: bitcast [[T]]* %{{.+}} to [6 x i64]* +// CHECK-NEXT: store [6 x i64] %{{.+}}, [6 x i64]* %{{.+}}, + T t = bar(); +} +T1 a1 = T1(); +T1 f1 = a1; +// CHECK: define void @{{.+}}foo1{{.+}}([[T1]]* byval align {{.+}}) +void foo1(T1 a = T1()) { + return; +} +// CHECK: define [[T1]] @{{.+}}bar1{{.+}}() +T1 bar1() { +// CHECK: load [[T1]], [[T1]]* +// CHECK-NEXT: ret [[T1]] + return T1(); +} +// CHECK: define void @{{.+}}baz1{{.+}}() +void baz1() { +// CHECK: call [[T1]] @{{.+}}bar1{{.+}}() + T1 t = bar1(); +} +#pragma omp end declare target diff --git a/test/OpenMP/nvptx_unsupported_type_messages.cpp b/test/OpenMP/nvptx_unsupported_type_messages.cpp new file mode 100644 index 0000000000..6e0fa3b1d5 --- /dev/null +++ b/test/OpenMP/nvptx_unsupported_type_messages.cpp @@ -0,0 +1,47 @@ +// Test target codegen - host bc file has to be created first. +// RUN: %clang_cc1 -fopenmp -x c++ -triple x86_64-unknown-linux -fopenmp-targets=nvptx64-nvidia-cuda -emit-llvm-bc %s -o %t-host.bc +// RUN: %clang_cc1 -verify -fopenmp -x c++ -triple nvptx64-unknown-unknown -fopenmp-targets=nvptx64-nvidia-cuda %s -fopenmp-is-device -fopenmp-host-ir-file-path %t-host.bc -fsyntax-only + +struct T { + char a; + __float128 f; + char c; + T() : a(12), f(15) {} + T &operator+(T &b) { f += b.a; return *this;} // expected-error {{'__float128' is not supported on this target}} +}; + +struct T1 { + char a; + __int128 f; + __int128 f1; + char c; + T1() : a(12), f(15) {} + T1 &operator/(T1 &b) { f /= b.a; return *this;} +}; + +#pragma omp declare target +T a = T(); +T f = a; +void foo(T a = T()) { + a = a + f; // expected-note {{called by 'foo'}} + return; +} +T bar() { + return T(); +} +void baz() { + T t = bar(); +} +T1 a1 = T1(); +T1 f1 = a1; +void foo1(T1 a = T1()) { + a = a / f1; + return; +} +T1 bar1() { + return T1(); +} +void baz1() { + T1 t = bar1(); +} +#pragma omp end declare target -- 2.40.0