[OPENMP 4.0] Add 'if' clause for 'cancel' directive.

Add parsing, sema analysis and codegen for 'if' clause in 'cancel' directive.

llvm-svn: 247976
This commit is contained in:
Alexey Bataev 2015-09-18 08:07:34 +00:00
parent fbbc0b8cec
commit 87933c7ced
15 changed files with 186 additions and 53 deletions

View File

@ -2127,17 +2127,21 @@ class OMPCancelDirective : public OMPExecutableDirective {
///
/// \param StartLoc Starting location of the directive kind.
/// \param EndLoc Ending location of the directive.
/// \param NumClauses Number of clauses.
///
OMPCancelDirective(SourceLocation StartLoc, SourceLocation EndLoc)
OMPCancelDirective(SourceLocation StartLoc, SourceLocation EndLoc,
unsigned NumClauses)
: OMPExecutableDirective(this, OMPCancelDirectiveClass, OMPD_cancel,
StartLoc, EndLoc, 0, 0),
StartLoc, EndLoc, NumClauses, 0),
CancelRegion(OMPD_unknown) {}
/// \brief Build an empty directive.
///
explicit OMPCancelDirective()
/// \param NumClauses Number of clauses.
explicit OMPCancelDirective(unsigned NumClauses)
: OMPExecutableDirective(this, OMPCancelDirectiveClass, OMPD_cancel,
SourceLocation(), SourceLocation(), 0, 0),
SourceLocation(), SourceLocation(), NumClauses,
0),
CancelRegion(OMPD_unknown) {}
/// \brief Set cancel region for current cancellation point.
@ -2150,17 +2154,19 @@ public:
/// \param C AST context.
/// \param StartLoc Starting location of the directive kind.
/// \param EndLoc Ending Location of the directive.
/// \param Clauses List of clauses.
///
static OMPCancelDirective *Create(const ASTContext &C,
SourceLocation StartLoc,
SourceLocation EndLoc,
OpenMPDirectiveKind CancelRegion);
static OMPCancelDirective *
Create(const ASTContext &C, SourceLocation StartLoc, SourceLocation EndLoc,
ArrayRef<OMPClause *> Clauses, OpenMPDirectiveKind CancelRegion);
/// \brief Creates an empty directive.
///
/// \param C AST context.
/// \param NumClauses Number of clauses.
///
static OMPCancelDirective *CreateEmpty(const ASTContext &C, EmptyShell);
static OMPCancelDirective *CreateEmpty(const ASTContext &C,
unsigned NumClauses, EmptyShell);
/// \brief Get cancellation region for the current cancellation point.
OpenMPDirectiveKind getCancelRegion() const { return CancelRegion; }

View File

@ -63,6 +63,9 @@
#ifndef OPENMP_TEAMS_CLAUSE
# define OPENMP_TEAMS_CLAUSE(Name)
#endif
#ifndef OPENMP_CANCEL_CLAUSE
# define OPENMP_CANCEL_CLAUSE(Name)
#endif
#ifndef OPENMP_DEFAULT_KIND
# define OPENMP_DEFAULT_KIND(Name)
#endif
@ -197,6 +200,9 @@ OPENMP_SINGLE_CLAUSE(firstprivate)
OPENMP_SINGLE_CLAUSE(copyprivate)
OPENMP_SINGLE_CLAUSE(nowait)
// Clauses allowed for OpenMP directive 'cancel'.
OPENMP_CANCEL_CLAUSE(if)
// Static attributes for 'default' clause.
OPENMP_DEFAULT_KIND(none)
OPENMP_DEFAULT_KIND(shared)
@ -313,6 +319,7 @@ OPENMP_TEAMS_CLAUSE(reduction)
#undef OPENMP_DIRECTIVE
#undef OPENMP_DIRECTIVE_EXT
#undef OPENMP_CLAUSE
#undef OPENMP_CANCEL_CLAUSE
#undef OPENMP_SINGLE_CLAUSE
#undef OPENMP_SECTIONS_CLAUSE
#undef OPENMP_PARALLEL_CLAUSE

View File

@ -7884,7 +7884,8 @@ public:
SourceLocation EndLoc,
OpenMPDirectiveKind CancelRegion);
/// \brief Called on well-formed '\#pragma omp cancel'.
StmtResult ActOnOpenMPCancelDirective(SourceLocation StartLoc,
StmtResult ActOnOpenMPCancelDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation StartLoc,
SourceLocation EndLoc,
OpenMPDirectiveKind CancelRegion);

View File

@ -2128,22 +2128,27 @@ OMPCancellationPointDirective::CreateEmpty(const ASTContext &C, EmptyShell) {
OMPCancelDirective *
OMPCancelDirective::Create(const ASTContext &C, SourceLocation StartLoc,
SourceLocation EndLoc,
SourceLocation EndLoc, ArrayRef<OMPClause *> Clauses,
OpenMPDirectiveKind CancelRegion) {
unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPCancelDirective),
llvm::alignOf<Stmt *>());
unsigned Size = llvm::RoundUpToAlignment(
sizeof(OMPCancelDirective) + sizeof(OMPClause *) * Clauses.size(),
llvm::alignOf<Stmt *>());
void *Mem = C.Allocate(Size);
OMPCancelDirective *Dir = new (Mem) OMPCancelDirective(StartLoc, EndLoc);
OMPCancelDirective *Dir =
new (Mem) OMPCancelDirective(StartLoc, EndLoc, Clauses.size());
Dir->setClauses(Clauses);
Dir->setCancelRegion(CancelRegion);
return Dir;
}
OMPCancelDirective *OMPCancelDirective::CreateEmpty(const ASTContext &C,
unsigned NumClauses,
EmptyShell) {
unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPCancelDirective),
unsigned Size = llvm::RoundUpToAlignment(sizeof(OMPCancelDirective) +
sizeof(OMPClause *) * NumClauses,
llvm::alignOf<Stmt *>());
void *Mem = C.Allocate(Size);
return new (Mem) OMPCancelDirective();
return new (Mem) OMPCancelDirective(NumClauses);
}
OMPFlushDirective *OMPFlushDirective::Create(const ASTContext &C,

View File

@ -991,7 +991,7 @@ void StmtPrinter::VisitOMPCancellationPointDirective(
void StmtPrinter::VisitOMPCancelDirective(OMPCancelDirective *Node) {
Indent() << "#pragma omp cancel "
<< getOpenMPDirectiveName(Node->getCancelRegion());
<< getOpenMPDirectiveName(Node->getCancelRegion()) << " ";
PrintOMPExecutableDirective(Node);
}
//===----------------------------------------------------------------------===//

View File

@ -360,6 +360,16 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind,
#define OPENMP_TEAMS_CLAUSE(Name) \
case OMPC_##Name: \
return true;
#include "clang/Basic/OpenMPKinds.def"
default:
break;
}
break;
case OMPD_cancel:
switch (CKind) {
#define OPENMP_CANCEL_CLAUSE(Name) \
case OMPC_##Name: \
return true;
#include "clang/Basic/OpenMPKinds.def"
default:
break;
@ -375,7 +385,6 @@ bool clang::isAllowedClauseForDirective(OpenMPDirectiveKind DKind,
case OMPD_taskwait:
case OMPD_taskgroup:
case OMPD_cancellation_point:
case OMPD_cancel:
case OMPD_ordered:
break;
}

View File

@ -2914,6 +2914,7 @@ void CGOpenMPRuntime::emitCancellationPointCall(
}
void CGOpenMPRuntime::emitCancelCall(CodeGenFunction &CGF, SourceLocation Loc,
const Expr *IfCond,
OpenMPDirectiveKind CancelRegion) {
// Build call kmp_int32 __kmpc_cancel(ident_t *loc, kmp_int32 global_tid,
// kmp_int32 cncl_kind);
@ -2921,27 +2922,34 @@ void CGOpenMPRuntime::emitCancelCall(CodeGenFunction &CGF, SourceLocation Loc,
dyn_cast_or_null<CGOpenMPRegionInfo>(CGF.CapturedStmtInfo)) {
if (OMPRegionInfo->getDirectiveKind() == OMPD_single)
return;
llvm::Value *Args[] = {
emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
CGF.Builder.getInt32(getCancellationKind(CancelRegion))};
// Ignore return result until untied tasks are supported.
auto *Result =
CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_cancel), Args);
// if (__kmpc_cancel()) {
// __kmpc_cancel_barrier();
// exit from construct;
// }
auto *ExitBB = CGF.createBasicBlock(".cancel.exit");
auto *ContBB = CGF.createBasicBlock(".cancel.continue");
auto *Cmp = CGF.Builder.CreateIsNotNull(Result);
CGF.Builder.CreateCondBr(Cmp, ExitBB, ContBB);
CGF.EmitBlock(ExitBB);
// __kmpc_cancel_barrier();
emitBarrierCall(CGF, Loc, OMPD_unknown, /*EmitChecks=*/false);
// exit from construct;
auto CancelDest =
CGF.getOMPCancelDestination(OMPRegionInfo->getDirectiveKind());
CGF.EmitBranchThroughCleanup(CancelDest);
CGF.EmitBlock(ContBB, /*IsFinished=*/true);
auto &&ThenGen = [this, Loc, CancelRegion,
OMPRegionInfo](CodeGenFunction &CGF) {
llvm::Value *Args[] = {
emitUpdateLocation(CGF, Loc), getThreadID(CGF, Loc),
CGF.Builder.getInt32(getCancellationKind(CancelRegion))};
// Ignore return result until untied tasks are supported.
auto *Result =
CGF.EmitRuntimeCall(createRuntimeFunction(OMPRTL__kmpc_cancel), Args);
// if (__kmpc_cancel()) {
// __kmpc_cancel_barrier();
// exit from construct;
// }
auto *ExitBB = CGF.createBasicBlock(".cancel.exit");
auto *ContBB = CGF.createBasicBlock(".cancel.continue");
auto *Cmp = CGF.Builder.CreateIsNotNull(Result);
CGF.Builder.CreateCondBr(Cmp, ExitBB, ContBB);
CGF.EmitBlock(ExitBB);
// __kmpc_cancel_barrier();
emitBarrierCall(CGF, Loc, OMPD_unknown, /*EmitChecks=*/false);
// exit from construct;
auto CancelDest =
CGF.getOMPCancelDestination(OMPRegionInfo->getDirectiveKind());
CGF.EmitBranchThroughCleanup(CancelDest);
CGF.EmitBlock(ContBB, /*IsFinished=*/true);
};
if (IfCond)
emitOMPIfClause(CGF, IfCond, ThenGen, [](CodeGenFunction &) {});
else
ThenGen(CGF);
}
}

View File

@ -718,9 +718,12 @@ public:
OpenMPDirectiveKind CancelRegion);
/// \brief Emit code for 'cancel' construct.
/// \param IfCond Condition in the associated 'if' clause, if it was
/// specified, nullptr otherwise.
/// \param CancelRegion Region kind for which the cancel must be emitted.
///
virtual void emitCancelCall(CodeGenFunction &CGF, SourceLocation Loc,
const Expr *IfCond,
OpenMPDirectiveKind CancelRegion);
};

View File

@ -2262,7 +2262,15 @@ void CodeGenFunction::EmitOMPCancellationPointDirective(
}
void CodeGenFunction::EmitOMPCancelDirective(const OMPCancelDirective &S) {
CGM.getOpenMPRuntime().emitCancelCall(*this, S.getLocStart(),
const Expr *IfCond = nullptr;
for (const auto *C : S.getClausesOfKind<OMPIfClause>()) {
if (C->getNameModifier() == OMPD_unknown ||
C->getNameModifier() == OMPD_cancel) {
IfCond = C->getCondition();
break;
}
}
CGM.getOpenMPRuntime().emitCancelCall(*this, S.getLocStart(), IfCond,
S.getCancelRegion());
}

View File

@ -2245,11 +2245,11 @@ StmtResult Sema::ActOnOpenMPExecutableDirective(
Res = ActOnOpenMPCancellationPointDirective(StartLoc, EndLoc, CancelRegion);
break;
case OMPD_cancel:
assert(ClausesWithImplicit.empty() &&
"No clauses are allowed for 'omp cancel' directive");
assert(AStmt == nullptr &&
"No associated statement allowed for 'omp cancel' directive");
Res = ActOnOpenMPCancelDirective(StartLoc, EndLoc, CancelRegion);
Res = ActOnOpenMPCancelDirective(ClausesWithImplicit, StartLoc, EndLoc,
CancelRegion);
AllowedNameModifiers.push_back(OMPD_cancel);
break;
case OMPD_target_data:
Res = ActOnOpenMPTargetDataDirective(ClausesWithImplicit, AStmt, StartLoc,
@ -4909,7 +4909,8 @@ Sema::ActOnOpenMPCancellationPointDirective(SourceLocation StartLoc,
CancelRegion);
}
StmtResult Sema::ActOnOpenMPCancelDirective(SourceLocation StartLoc,
StmtResult Sema::ActOnOpenMPCancelDirective(ArrayRef<OMPClause *> Clauses,
SourceLocation StartLoc,
SourceLocation EndLoc,
OpenMPDirectiveKind CancelRegion) {
if (CancelRegion != OMPD_parallel && CancelRegion != OMPD_for &&
@ -4927,7 +4928,8 @@ StmtResult Sema::ActOnOpenMPCancelDirective(SourceLocation StartLoc,
return StmtError();
}
DSAStack->setParentCancelRegion(/*Cancel=*/true);
return OMPCancelDirective::Create(Context, StartLoc, EndLoc, CancelRegion);
return OMPCancelDirective::Create(Context, StartLoc, EndLoc, Clauses,
CancelRegion);
}
OMPClause *Sema::ActOnOpenMPSingleExprClause(OpenMPClauseKind Kind, Expr *Expr,

View File

@ -2317,6 +2317,8 @@ void ASTStmtReader::VisitOMPCancellationPointDirective(
void ASTStmtReader::VisitOMPCancelDirective(OMPCancelDirective *D) {
VisitStmt(D);
// The NumClauses field was read in ReadStmtFromStream.
++Idx;
VisitOMPExecutableDirective(D);
D->setCancelRegion(static_cast<OpenMPDirectiveKind>(Record[Idx++]));
}
@ -2938,7 +2940,8 @@ Stmt *ASTReader::ReadStmtFromStream(ModuleFile &F) {
break;
case STMT_OMP_CANCEL_DIRECTIVE:
S = OMPCancelDirective::CreateEmpty(Context, Empty);
S = OMPCancelDirective::CreateEmpty(
Context, Record[ASTStmtReader::NumStmtFields], Empty);
break;
case EXPR_CXX_OPERATOR_CALL:

View File

@ -2169,6 +2169,7 @@ void ASTStmtWriter::VisitOMPCancellationPointDirective(
void ASTStmtWriter::VisitOMPCancelDirective(OMPCancelDirective *D) {
VisitStmt(D);
Record.push_back(D->getNumClauses());
VisitOMPExecutableDirective(D);
Record.push_back(D->getCancelRegion());
Code = serialization::STMT_OMP_CANCEL_DIRECTIVE;

View File

@ -10,11 +10,11 @@ int main (int argc, char **argv) {
// CHECK: int main(int argc, char **argv) {
#pragma omp parallel
{
#pragma omp cancel parallel
#pragma omp cancel parallel if(argc)
}
// CHECK: #pragma omp parallel
// CHECK-NEXT: {
// CHECK-NEXT: #pragma omp cancel parallel
// CHECK-NEXT: #pragma omp cancel parallel if(argc)
// CHECK-NEXT: }
#pragma omp sections
{
@ -26,11 +26,11 @@ int main (int argc, char **argv) {
// CHECK: }
#pragma omp for
for (int i = 0; i < argc; ++i) {
#pragma omp cancel for
#pragma omp cancel for if(cancel:argc)
}
// CHECK: #pragma omp for
// CHECK-NEXT: for (int i = 0; i < argc; ++i) {
// CHECK-NEXT: #pragma omp cancel for
// CHECK-NEXT: #pragma omp cancel for if(cancel: argc)
// CHECK-NEXT: }
#pragma omp task
{

View File

@ -6,11 +6,12 @@
#ifndef HEADER
#define HEADER
float flag;
int main (int argc, char **argv) {
// CHECK: [[GTID:%.+]] = call i32 @__kmpc_global_thread_num(
#pragma omp parallel
{
#pragma omp cancel parallel
#pragma omp cancel parallel if(flag)
argv[0][0] = argc;
}
// CHECK: call void (%ident_t*, i32, void (i32*, i32*, ...)*, ...) @__kmpc_fork_call(
@ -50,9 +51,13 @@ int main (int argc, char **argv) {
// CHECK: call void @__kmpc_for_static_fini(
#pragma omp for
for (int i = 0; i < argc; ++i) {
#pragma omp cancel for
#pragma omp cancel for if(cancel: flag)
}
// CHECK: call void @__kmpc_for_static_init_4(
// CHECK: [[FLAG:%.+]] = load float, float* @{{.+}},
// CHECK: [[BOOL:%.+]] = fcmp une float [[FLAG]], 0.000000e+00
// CHECK: br i1 [[BOOL]], label %[[THEN:[^,]+]], label %[[ELSE:[^,]+]]
// CHECK: [[THEN]]
// CHECK: [[RES:%.+]] = call i32 @__kmpc_cancel(%ident_t* {{[^,]+}}, i32 [[GTID]], i32 2)
// CHECK: [[CMP:%.+]] = icmp ne i32 [[RES]], 0
// CHECK: br i1 [[CMP]], label %[[EXIT:[^,].+]], label %[[CONTINUE:.+]]
@ -61,6 +66,8 @@ for (int i = 0; i < argc; ++i) {
// CHECK: br label
// CHECK: [[CONTINUE]]
// CHECK: br label
// CHECK: [[ELSE]]
// CHECK: br label
// CHECK: call void @__kmpc_for_static_fini(
// CHECK: call void @__kmpc_barrier(%ident_t*
#pragma omp task
@ -92,12 +99,19 @@ for (int i = 0; i < argc; ++i) {
}
// CHECK: define internal void @{{[^(]+}}(i32* {{[^,]+}}, i32* {{[^,]+}},
// CHECK: [[FLAG:%.+]] = load float, float* @{{.+}},
// CHECK: [[BOOL:%.+]] = fcmp une float [[FLAG]], 0.000000e+00
// CHECK: br i1 [[BOOL]], label %[[THEN:[^,]+]], label %[[ELSE:[^,]+]]
// CHECK: [[THEN]]
// CHECK: [[RES:%.+]] = call i32 @__kmpc_cancel(%ident_t* {{[^,]+}}, i32 {{[^,]+}}, i32 1)
// CHECK: [[CMP:%.+]] = icmp ne i32 [[RES]], 0
// CHECK: br i1 [[CMP]], label %[[EXIT:[^,]+]],
// CHECK: [[EXIT]]
// CHECK: call i32 @__kmpc_cancel_barrier(%ident_t*
// CHECK: br label %[[RETURN:.+]]
// CHECK: [[ELSE]]
// CHECK: br label
// CHECK: call void @__kmpc_barrier
// CHECK: [[RETURN]]
// CHECK: ret void

View File

@ -0,0 +1,66 @@
// RUN: %clang_cc1 -verify -fopenmp -ferror-limit 100 %s
void foo() {
}
bool foobool(int argc) {
return argc;
}
struct S1; // expected-note {{declared here}}
template <class T, class S> // expected-note {{declared here}}
int tmain(T argc, S **argv) {
#pragma omp parallel
{
#pragma omp cancel parallel if // expected-error {{expected '(' after 'if'}}
#pragma omp cancel parallel if ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp cancel parallel if () // expected-error {{expected expression}}
#pragma omp cancel parallel if (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp cancel parallel if (argc)) // expected-warning {{extra tokens at the end of '#pragma omp cancel' are ignored}}
#pragma omp cancel parallel if (argc > 0 ? argv[1] : argv[2])
#pragma omp cancel parallel if (foobool(argc)), if (true) // expected-error {{directive '#pragma omp cancel' cannot contain more than one 'if' clause}}
#pragma omp cancel parallel if (S) // expected-error {{'S' does not refer to a value}}
#pragma omp cancel parallel if (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp cancel parallel if (argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp cancel parallel if(argc)
#pragma omp cancel parallel if(cancel // expected-warning {{missing ':' after directive name modifier - ignoring}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp cancel parallel if(cancel : // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp cancel parallel if(cancel : argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp cancel parallel if(cancel : argc)
#pragma omp cancel parallel if(cancel : argc) if (for:argc) // expected-error {{directive name modifier 'for' is not allowed for '#pragma omp cancel'}}
#pragma omp cancel parallel if(cancel : argc) if (cancel:argc) // expected-error {{directive '#pragma omp cancel' cannot contain more than one 'if' clause with 'cancel' name modifier}}
#pragma omp cancel parallel if(cancel : argc) if (argc) // expected-error {{no more 'if' clause is allowed}} expected-note {{previous clause with directive name modifier specified here}}
foo();
}
return 0;
}
int main(int argc, char **argv) {
#pragma omp parallel
{
#pragma omp cancel parallel if // expected-error {{expected '(' after 'if'}}
#pragma omp cancel parallel if ( // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp cancel parallel if () // expected-error {{expected expression}}
#pragma omp cancel parallel if (argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp cancel parallel if (argc)) // expected-warning {{extra tokens at the end of '#pragma omp cancel' are ignored}}
#pragma omp cancel parallel if (argc > 0 ? argv[1] : argv[2])
#pragma omp cancel parallel if (foobool(argc)), if (true) // expected-error {{directive '#pragma omp cancel' cannot contain more than one 'if' clause}}
#pragma omp cancel parallel if (S1) // expected-error {{'S1' does not refer to a value}}
#pragma omp cancel parallel if (argv[1]=2) // expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp cancel parallel if (argc argc) // expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp cancel parallel if (1 0) // expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp cancel parallel if(if(tmain(argc, argv) // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp cancel parallel if(cancel // expected-warning {{missing ':' after directive name modifier - ignoring}} expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp cancel parallel if(cancel : // expected-error {{expected expression}} expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp cancel parallel if(cancel : argc // expected-error {{expected ')'}} expected-note {{to match this '('}}
#pragma omp cancel parallel if(cancel : argc)
#pragma omp cancel parallel if(cancel : argc) if (for:argc) // expected-error {{directive name modifier 'for' is not allowed for '#pragma omp cancel'}}
#pragma omp cancel parallel if(cancel : argc) if (cancel:argc) // expected-error {{directive '#pragma omp cancel' cannot contain more than one 'if' clause with 'cancel' name modifier}}
#pragma omp cancel parallel if(cancel : argc) if (argc) // expected-error {{no more 'if' clause is allowed}} expected-note {{previous clause with directive name modifier specified here}}
foo();
}
return tmain(argc, argv);
}