diff options
| -rw-r--r-- | clang/include/clang/Sema/Sema.h | 4 | ||||
| -rw-r--r-- | clang/lib/AST/ASTContext.cpp | 24 | ||||
| -rw-r--r-- | clang/lib/CodeGen/TargetInfo.cpp | 46 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaExpr.cpp | 15 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaOpenMP.cpp | 12 | ||||
| -rw-r--r-- | clang/lib/Sema/SemaType.cpp | 9 | ||||
| -rw-r--r-- | clang/test/OpenMP/nvptx_unsupported_type_codegen.cpp | 64 | ||||
| -rw-r--r-- | clang/test/OpenMP/nvptx_unsupported_type_messages.cpp | 47 |
8 files changed, 214 insertions, 7 deletions
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 333f41dea5b..3408c9462e5 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/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/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp index f968c6260e8..aa4bd4139c0 100644 --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/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/clang/lib/CodeGen/TargetInfo.cpp b/clang/lib/CodeGen/TargetInfo.cpp index a130dd3cfb4..ee8c8895357 100644 --- a/clang/lib/CodeGen/TargetInfo.cpp +++ b/clang/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<RecordType>(); + 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<CXXRecordDecl>(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<unsigned>(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/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp index 266120dfdc7..157ef0b9426 100644 --- a/clang/lib/Sema/SemaExpr.cpp +++ b/clang/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/clang/lib/Sema/SemaOpenMP.cpp b/clang/lib/Sema/SemaOpenMP.cpp index 76141afd595..7fed3725edd 100644 --- a/clang/lib/Sema/SemaOpenMP.cpp +++ b/clang/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/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index f314cb0abea..3591add23da 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/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/clang/test/OpenMP/nvptx_unsupported_type_codegen.cpp b/clang/test/OpenMP/nvptx_unsupported_type_codegen.cpp new file mode 100644 index 00000000000..61accc3c72b --- /dev/null +++ b/clang/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/clang/test/OpenMP/nvptx_unsupported_type_messages.cpp b/clang/test/OpenMP/nvptx_unsupported_type_messages.cpp new file mode 100644 index 00000000000..6e0fa3b1d5b --- /dev/null +++ b/clang/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 |

