[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.
llvm-svn: 355027
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 333f41d..3408c94 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -8805,6 +8805,10 @@
/// 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 f968c62..aa4bd41 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -1902,8 +1902,16 @@
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 @@
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 a130dd3..ee8c889 100644
--- a/clang/lib/CodeGen/TargetInfo.cpp
+++ b/clang/lib/CodeGen/TargetInfo.cpp
@@ -6268,10 +6268,56 @@
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 266120d..157ef0b 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -12432,6 +12432,14 @@
}
}
+ // 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 @@
<< 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 76141af..7fed372 100644
--- a/clang/lib/Sema/SemaOpenMP.cpp
+++ b/clang/lib/Sema/SemaOpenMP.cpp
@@ -1443,6 +1443,18 @@
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 f314cb0..3591add 100644
--- a/clang/lib/Sema/SemaType.cpp
+++ b/clang/lib/Sema/SemaType.cpp
@@ -1433,7 +1433,8 @@
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 @@
// 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 @@
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 0000000..61accc3
--- /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 0000000..6e0fa3b
--- /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