Skip to content

Commit

Permalink
[OPENMP]Delay emission of the error for unsupported types.
Browse files Browse the repository at this point in the history
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
  • Loading branch information
alexey-bataev committed Feb 27, 2019
1 parent b12ac2b commit 123ad19
Show file tree
Hide file tree
Showing 8 changed files with 214 additions and 7 deletions.
4 changes: 4 additions & 0 deletions clang/include/clang/Sema/Sema.h
Original file line number Diff line number Diff line change
Expand Up @@ -8805,6 +8805,10 @@ class Sema {
/// 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.
Expand Down
24 changes: 20 additions & 4 deletions clang/lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand All @@ -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)
Expand Down
46 changes: 46 additions & 0 deletions clang/lib/CodeGen/TargetInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6268,10 +6268,56 @@ class NVPTXTargetCodeGenInfo : public TargetCodeGenInfo {
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();
Expand Down
15 changes: 15 additions & 0 deletions clang/lib/Sema/SemaExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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());
Expand Down Expand Up @@ -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:
Expand Down
12 changes: 12 additions & 0 deletions clang/lib/Sema/SemaOpenMP.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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");

Expand Down
9 changes: 6 additions & 3 deletions clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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;
Expand All @@ -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;
Expand Down
64 changes: 64 additions & 0 deletions clang/test/OpenMP/nvptx_unsupported_type_codegen.cpp
Original file line number Diff line number Diff line change
@@ -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
47 changes: 47 additions & 0 deletions clang/test/OpenMP/nvptx_unsupported_type_messages.cpp
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 123ad19

Please sign in to comment.