Skip to content

Commit

Permalink
[OPENMP] Loop canonical form analysis (Sema)
Browse files Browse the repository at this point in the history
This patch implements semantic analysis to make sure that the loop is in OpenMP canonical form.
This is the form required for 'omp simd', 'omp for' and other loop pragmas.

Differential revision: http://reviews.llvm.org/D3778

llvm-svn: 210095
  • Loading branch information
amusman committed Jun 3, 2014
1 parent fd5b234 commit a8e9d2e
Show file tree
Hide file tree
Showing 11 changed files with 1,170 additions and 25 deletions.
1 change: 1 addition & 0 deletions clang/include/clang/Basic/DiagnosticGroups.td
Expand Up @@ -678,6 +678,7 @@ def ASM : DiagGroup<"asm", [
// OpenMP warnings.
def SourceUsesOpenMP : DiagGroup<"source-uses-openmp">;
def OpenMPClauses : DiagGroup<"openmp-clauses">;
def OpenMPLoopForm : DiagGroup<"openmp-loop-form">;

// Backend warnings.
def BackendInlineAsm : DiagGroup<"inline-asm">;
Expand Down
25 changes: 25 additions & 0 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Expand Up @@ -6937,6 +6937,8 @@ def note_omp_explicit_dsa : Note<
"defined as %0">;
def note_omp_predetermined_dsa : Note<
"predetermined as %0">;
def err_omp_loop_var_dsa : Error<
"loop iteration variable may not be %0">;
def err_omp_not_for : Error<
"statement after '#pragma omp %0' must be a for loop">;
def err_omp_negative_expression_in_clause : Error<
Expand Down Expand Up @@ -6973,6 +6975,29 @@ def err_omp_aligned_twice : Error<
"a variable cannot appear in more than one aligned clause">;
def err_omp_local_var_in_threadprivate_init : Error<
"variable with local storage in initial value of threadprivate variable">;
def err_omp_loop_not_canonical_init : Error<
"initialization clause of OpenMP for loop must be of the form "
"'var = init' or 'T var = init'">;
def ext_omp_loop_not_canonical_init : ExtWarn<
"initialization clause of OpenMP for loop is not in canonical form "
"('var = init' or 'T var = init')">, InGroup<OpenMPLoopForm>;
def err_omp_loop_not_canonical_cond : Error<
"condition of OpenMP for loop must be a relational comparison "
"('<', '<=', '>', or '>=') of loop variable %0">;
def err_omp_loop_not_canonical_incr : Error<
"increment clause of OpenMP for loop must perform simple addition "
"or subtraction on loop variable %0">;
def err_omp_loop_variable_type : Error<
"variable must be of integer or %select{pointer|random access iterator}0 type">;
def err_omp_loop_incr_not_compatible : Error<
"increment expression must cause %0 to %select{decrease|increase}1 "
"on each iteration of OpenMP for loop">;
def note_omp_loop_cond_requres_compatible_incr : Note<
"loop step is expected to be %select{negative|positive}0 due to this condition">;
def err_omp_loop_cannot_use_stmt : Error<
"'%0' statement cannot be used in OpenMP for loop">;
def err_omp_simd_region_cannot_use_stmt : Error<
"'%0' statement cannot be used in OpenMP simd region">;
} // end of OpenMP category

let CategoryName = "Related Result Type Issue" in {
Expand Down
44 changes: 38 additions & 6 deletions clang/include/clang/Sema/Scope.h
Expand Up @@ -101,22 +101,30 @@ class Scope {
/// \brief This is the scope for a function-level C++ try or catch scope.
FnTryCatchScope = 0x4000,

/// \brief This is the scope of OpenMP executable directive
OpenMPDirectiveScope = 0x8000
/// \brief This is the scope of OpenMP executable directive.
OpenMPDirectiveScope = 0x8000,

/// \brief This is the scope of some OpenMP loop directive.
OpenMPLoopDirectiveScope = 0x10000,

/// \brief This is the scope of some OpenMP simd directive.
/// For example, it is used for 'omp simd', 'omp for simd'.
/// This flag is propagated to children scopes.
OpenMPSimdDirectiveScope = 0x20000
};
private:
/// The parent scope for this scope. This is null for the translation-unit
/// scope.
Scope *AnyParent;

/// Flags - This contains a set of ScopeFlags, which indicates how the scope
/// interrelates with other control flow statements.
unsigned Flags;

/// Depth - This is the depth of this scope. The translation-unit scope has
/// depth 0.
unsigned short Depth;

/// Flags - This contains a set of ScopeFlags, which indicates how the scope
/// interrelates with other control flow statements.
unsigned short Flags;

/// \brief Declarations with static linkage are mangled with the number of
/// scopes seen as a component.
unsigned short MSLocalManglingNumber;
Expand Down Expand Up @@ -360,6 +368,30 @@ class Scope {
return (getFlags() & Scope::OpenMPDirectiveScope);
}

/// \brief Determine whether this scope is some OpenMP loop directive scope
/// (for example, 'omp for', 'omp simd').
bool isOpenMPLoopDirectiveScope() const {
if (getFlags() & Scope::OpenMPLoopDirectiveScope) {
assert(isOpenMPDirectiveScope() &&
"OpenMP loop directive scope is not a directive scope");
return true;
}
return false;
}

/// \brief Determine whether this scope is (or is nested into) some OpenMP
/// loop simd directive scope (for example, 'omp simd', 'omp for simd').
bool isOpenMPSimdDirectiveScope() const {
return getFlags() & Scope::OpenMPSimdDirectiveScope;
}

/// \brief Determine whether this scope is a loop having OpenMP loop
/// directive attached.
bool isOpenMPLoopScope() const {
const Scope *P = getParent();
return P && P->isOpenMPLoopDirectiveScope();
}

/// \brief Determine whether this scope is a C++ 'try' block.
bool isTryScope() const { return getFlags() & Scope::TryScope; }

Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Sema/Sema.h
Expand Up @@ -7258,10 +7258,11 @@ class Sema {
/// \brief Initialization of data-sharing attributes stack.
void InitDataSharingAttributesStack();
void DestroyDataSharingAttributesStack();
ExprResult PerformImplicitIntegerConversion(SourceLocation OpLoc, Expr *Op);
ExprResult VerifyPositiveIntegerConstantInClause(Expr *Op,
OpenMPClauseKind CKind);
public:
ExprResult PerformOpenMPImplicitIntegerConversion(SourceLocation OpLoc,
Expr *Op);
/// \brief Called on start of new data sharing attribute block.
void StartOpenMPDSABlock(OpenMPDirectiveKind K,
const DeclarationNameInfo &DirName,
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Parse/ParseOpenMP.cpp
Expand Up @@ -86,7 +86,7 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective() {
SmallVector<OMPClause *, 5> Clauses;
SmallVector<llvm::PointerIntPair<OMPClause *, 1, bool>, OMPC_unknown + 1>
FirstClauses(OMPC_unknown + 1);
const unsigned ScopeFlags =
unsigned ScopeFlags =
Scope::FnScope | Scope::DeclScope | Scope::OpenMPDirectiveScope;
SourceLocation Loc = ConsumeToken(), EndLoc;
OpenMPDirectiveKind DKind = Tok.isAnnotation()
Expand Down Expand Up @@ -142,6 +142,9 @@ StmtResult Parser::ParseOpenMPDeclarativeOrExecutableDirective() {

StmtResult AssociatedStmt;
bool CreateDirective = true;
if (DKind == OMPD_simd)
ScopeFlags |=
Scope::OpenMPLoopDirectiveScope | Scope::OpenMPSimdDirectiveScope;
ParseScope OMPDirectiveScope(this, ScopeFlags);
{
// The body is a block scope like in Lambdas and Blocks.
Expand Down
10 changes: 10 additions & 0 deletions clang/lib/Sema/Scope.cpp
Expand Up @@ -39,6 +39,10 @@ void Scope::Init(Scope *parent, unsigned flags) {
BlockParent = parent->BlockParent;
TemplateParamParent = parent->TemplateParamParent;
MSLocalManglingParent = parent->MSLocalManglingParent;
if ((Flags & (FnScope | ClassScope | BlockScope | TemplateParamScope |
FunctionPrototypeScope | AtCatchScope | ObjCMethodScope)) ==
0)
Flags |= parent->getFlags() & OpenMPSimdDirectiveScope;
} else {
Depth = 0;
PrototypeDepth = 0;
Expand Down Expand Up @@ -178,6 +182,12 @@ void Scope::dumpImpl(raw_ostream &OS) const {
} else if (Flags & OpenMPDirectiveScope) {
OS << "OpenMPDirectiveScope";
Flags &= ~OpenMPDirectiveScope;
} else if (Flags & OpenMPLoopDirectiveScope) {
OS << "OpenMPLoopDirectiveScope";
Flags &= ~OpenMPLoopDirectiveScope;
} else if (Flags & OpenMPSimdDirectiveScope) {
OS << "OpenMPSimdDirectiveScope";
Flags &= ~OpenMPSimdDirectiveScope;
}

if (Flags)
Expand Down
5 changes: 4 additions & 1 deletion clang/lib/Sema/SemaExprCXX.cpp
Expand Up @@ -618,7 +618,10 @@ ExprResult Sema::BuildCXXThrow(SourceLocation OpLoc, Expr *Ex,
if (!getLangOpts().CXXExceptions &&
!getSourceManager().isInSystemHeader(OpLoc))
Diag(OpLoc, diag::err_exceptions_disabled) << "throw";


if (getCurScope() && getCurScope()->isOpenMPSimdDirectiveScope())
Diag(OpLoc, diag::err_omp_simd_region_cannot_use_stmt) << "throw";

if (Ex && !Ex->isTypeDependent()) {
ExprResult ExRes = CheckCXXThrowOperand(OpLoc, Ex, IsThrownVarInScope);
if (ExRes.isInvalid())
Expand Down

0 comments on commit a8e9d2e

Please sign in to comment.