Repository: pyccel/pyccel
Pull request #593 (2020-12-11 10:34:32)

Extend OpenMP support by adding more pragmas
This PR is about extending the support of OpenMP by adding more Construct and Directives and their clauses:

- Cover all the constructs that are inside the documentation;
- Add clauses to the new constructs;
- Support combined constructs;
- Add tests for new pragmas;
- Update the documentation to fit new changes and fixes.

EmilyBourne: What is the status of this PR?
nhamidn: > What is the status of this PR?

there is two pragmas left and some tests
EmilyBourne: Have you thought about creating an `OmpAnnotatedComment` class to reduce code duplication?
nhamidn: > Have you thought about creating an `OmpAnnotatedComment` class to reduce code duplication?

it will be good, I'm gonna do it, but not for all the directives because there are some differences
EmilyBourne: I wonder if we should create a file for the OpenMP types (e.g. `pyccel/ast/omp.py`). It seems strange to have them in `core.py` as they are not a core element, even if they have always been there historically
nhamidn: > I wonder if we should create a file for the OpenMP types (e.g. `pyccel/ast/omp.py`)? It seems strange to have them in `core.py` as they are not a core element, even if they have always been there historically

it's a good idea
EmilyBourne: Don't forget to remove the `@xfail` marks on everything you've fixed
EmilyBourne: This is starting to look very clean :+1:
Good work :smiley:
EmilyBourne: There is an openmp test which is xpassing could you correct the mark please
nhamidn: > There is an openmp test which is xpassing could you correct the mark please

this test is passing on Linux and windows but it's failing on Macos
EmilyBourne: > > There is an openmp test which is xpassing could you correct the mark please
> 
> this test is passing on Linux and windows but it's failing on Macos

Ah ok. The xfail mark can be passed a condition (see [here](https://docs.pytest.org/en/latest/reference.html#pytest.mark.xfail) ) to indicate this. Do you know what is causing this problem? It's rare for the problem to only exist on mac
nhamidn: > here

i really dont know, i have macos and the test is passing on my computer for fortran
EmilyBourne: > > here
> 
> i really dont know, i have macos and the test is passing on my computer for fortran

That's very strange. So then we need to fix #516 and #517 to know what the problem is?
nhamidn: > > > here
> > 
> > 
> > i really dont know, i have macos and the test is passing on my computer for fortran
> 
> That's very strange. So then we need to fix #516 and #517 to know what the problem is?

yes, I think it's related to the OpenMP library linking because the compilation fails
nhamidn: > > > There is an openmp test which is xpassing could you correct the mark please
> > 
> > 
> > this test is passing on Linux and windows but it's failing on Macos
> 
> Ah ok. The xfail mark can be passed a condition (see [here](https://docs.pytest.org/en/latest/reference.html#pytest.mark.xfail) ) to indicate this. Do you know what is causing this problem? It's rare for the problem to only exist on mac

now the test failed on Linux and windows, this is strange I'm gonna mark it as xfail in all platforms 
EmilyBourne: The xpass that I spotted is in the C tests. It is still marked as xpass after your last push actually. So maybe there are a few odd things here
nhamidn: > The xpass that I spotted is in the C tests. It is still marked as xpass after your last push actually. So maybe there are a few odd things here

aah okay, I'm testing right now 
EmilyBourne: You might want to also modify the windows tests while you are testing. They are not with the rest unfortunately (probably due to issue #517) but are [here](https://github.com/pyccel/pyccel/blob/master/.github/workflows/Github_pytest.yml#L57-L64)

Patch:
diff --git a/pyccel/ast/core.py b/pyccel/ast/core.py
index 48eea33f..e101b14f 100644
--- a/pyccel/ast/core.py
+++ b/pyccel/ast/core.py
@@ -97,11 +97,7 @@ __all__ = (
 #    'operator',
 #    'op_registry',
     'process_shape',
-    'subs',
-    'OMP_For_Loop',
-    'OMP_Parallel_Construct',
-    'OMP_Single_Construct',
-    'Omp_End_Clause'
+    'subs'
 )
 
 #==============================================================================
@@ -3151,7 +3147,7 @@ class AnnotatedComment(Basic):
     Parameters
     ----------
     accel : str
-       accelerator id. One among {'omp', 'acc'}
+       accelerator id. One among {'acc'}
 
     txt: str
         statement to print
@@ -3159,8 +3155,8 @@ class AnnotatedComment(Basic):
     Examples
     --------
     >>> from pyccel.ast.core import AnnotatedComment
-    >>> AnnotatedComment('omp', 'parallel')
-    AnnotatedComment(omp, parallel)
+    >>> AnnotatedComment('acc', 'parallel')
+    AnnotatedComment(acc, parallel)
     """
     _attribute_nodes = ()
 
@@ -3183,26 +3179,6 @@ class AnnotatedComment(Basic):
         args = (self.accel, self.txt)
         return args
 
-class OMP_For_Loop(AnnotatedComment):
-    """ Represents an OpenMP Loop construct. """
-    def __init__(self, txt):
-        super().__init__('omp', txt)
-
-class OMP_Parallel_Construct(AnnotatedComment):
-    """ Represents an OpenMP Parallel construct. """
-    def __init__(self, txt):
-        super().__init__('omp', txt)
-
-class OMP_Single_Construct(AnnotatedComment):
-    """ Represents an OpenMP Single construct. """
-    def __init__(self, txt):
-        super().__init__('omp', txt)
-
-class Omp_End_Clause(AnnotatedComment):
-    """ Represents the End of an OpenMP block. """
-    def __init__(self, txt):
-        super().__init__('omp', txt)
-
 class CommentBlock(Basic):
 
     """ Represents a Block of Comments
diff --git a/pyccel/ast/omp.py b/pyccel/ast/omp.py
new file mode 100644
index 00000000..8ca26648
--- /dev/null
+++ b/pyccel/ast/omp.py
@@ -0,0 +1,155 @@
+# coding: utf-8
+#------------------------------------------------------------------------------------------#
+# This file is part of Pyccel which is released under MIT License. See the LICENSE file or #
+# go to https://github.com/pyccel/pyccel/blob/master/LICENSE for full license details.     #
+#------------------------------------------------------------------------------------------#
+"""
+OpenMP has several constructs and directives, and this file contains the OpenMP types that are supported.
+We represent some types with the OmpAnnotatedComment type.
+These types are detailed on our documentation:
+https://github.com/pyccel/pyccel/blob/master/tutorial/openmp.md
+"""
+
+from .basic import Basic
+
+class OmpAnnotatedComment(Basic):
+
+    """Represents an OpenMP Annotated Comment in the code.
+
+    Parameters
+    ----------
+
+    txt: str
+        statement to print
+
+    combined: List (Optional)
+        constructs to be combined with the current construct
+
+    Examples
+    --------
+    >>> from pyccel.ast.omp import OmpAnnotatedComment
+    >>> OmpAnnotatedComment('parallel')
+    OmpAnnotatedComment(parallel)
+    """
+    _attribute_nodes = ()
+    _is_multiline = False
+
+    def __init__(self, txt, combined=None):
+        self._txt = txt
+        self._combined = combined
+        super().__init__()
+
+    @property
+    def is_multiline(self):
+        """Used to check if the construct needs brackets."""
+        return self._is_multiline
+
+    @property
+    def name(self):
+        """Name of the construct."""
+        return ''
+
+    @property
+    def txt(self):
+        """Used to store clauses."""
+        return self._txt
+
+    @property
+    def combined(self):
+        """Used to store the combined construct of a directive."""
+        return self._combined
+
+    def __getnewargs__(self):
+        """Used for Pickling self."""
+
+        args = (self.txt, self.combined)
+        return args
+
+class OMP_For_Loop(OmpAnnotatedComment):
+    """ Represents an OpenMP Loop construct. """
+    def __init__(self, txt):
+        super().__init__(txt)
+
+    @property
+    def name(self):
+        """Name of the construct."""
+        return 'for'
+
+class OMP_Parallel_Construct(OmpAnnotatedComment):
+    """ Represents an OpenMP Parallel construct. """
+    _is_multiline = True
+    @property
+    def name(self):
+        """Name of the construct."""
+        return 'parallel'
+
+class OMP_Task_Construct(OmpAnnotatedComment):
+    """ Represents an OpenMP Task construct. """
+    _is_multiline = True
+    def __init__(self, txt):
+        super().__init__(txt)
+
+class OMP_Single_Construct(OmpAnnotatedComment):
+    """ Represents an OpenMP Single construct. """
+    _is_multiline = True
+    def __init__(self, txt):
+        super().__init__(txt)
+
+class OMP_Critical_Construct(OmpAnnotatedComment):
+    """ Represents an OpenMP Critical construct. """
+    _is_multiline = True
+    def __init__(self, txt):
+        super().__init__(txt)
+
+class OMP_Master_Construct(OmpAnnotatedComment):
+    """ Represents OpenMP Master construct. """
+    _is_multiline = True
+    def __init__(self, txt):
+        super().__init__(txt)
+
+class OMP_Masked_Construct(OmpAnnotatedComment):
+    """ Represents OpenMP Masked construct. """
+    _is_multiline = True
+    @property
+    def name(self):
+        """Name of the construct."""
+        return 'masked'
+
+class OMP_Cancel_Construct(OmpAnnotatedComment):
+    """ Represents OpenMP Cancel construct. """
+    def __init__(self, txt):
+        super().__init__(txt)
+
+class OMP_Target_Construct(OmpAnnotatedComment):
+    """ Represents OpenMP Target construct. """
+    _is_multiline = True
+    @property
+    def name(self):
+        """Name of the construct."""
+        return 'target'
+
+
+class OMP_Teams_Construct(OmpAnnotatedComment):
+    """ Represents OpenMP Teams construct. """
+    _is_multiline = True
+    @property
+    def name(self):
+        """Name of the construct."""
+        return 'teams'
+
+class OMP_Sections_Construct(OmpAnnotatedComment):
+    """ Represents OpenMP Sections construct. """
+    _is_multiline = True
+    def __init__(self, txt):
+        super().__init__(txt)
+
+class OMP_Section_Construct(OmpAnnotatedComment):
+    """ Represent OpenMP Section construct. """
+    _is_multiline = True
+    def __init__(self, txt):
+        super().__init__(txt)
+
+class Omp_End_Clause(OmpAnnotatedComment):
+    """ Represents the End of an OpenMP block. """
+    def __init__(self, txt):
+        super().__init__(txt)
diff --git a/pyccel/codegen/printing/ccode.py b/pyccel/codegen/printing/ccode.py
index 87a1ac65..74bd2e4c 100644
--- a/pyccel/codegen/printing/ccode.py
+++ b/pyccel/codegen/printing/ccode.py
@@ -1488,17 +1488,22 @@ class CCodePrinter(CodePrinter):
         return ''
 
     #=================== OMP ==================
-    def _print_OMP_For_Loop(self, expr):
-        omp_expr   = str(expr.txt)
-        return '#pragma omp for{}\n{{'.format(omp_expr)
 
-    def _print_OMP_Parallel_Construct(self, expr):
-        omp_expr   = str(expr.txt)
-        return '#pragma omp {}\n{{'.format(omp_expr)
-
-    def _print_OMP_Single_Construct(self, expr):
-        omp_expr   = str(expr.txt)
-        return '#pragma omp {}\n{{'.format(omp_expr)
+    def _print_OmpAnnotatedComment(self, expr):
+        clauses = ''
+        if expr.combined:
+            clauses = ' ' + expr.combined
+        clauses += str(expr.txt)
+        omp_expr = '#pragma omp {}{}'.format(expr.name, clauses)
+
+        if expr.is_multiline:
+            if expr.combined is None:
+                omp_expr += '\n{'
+            elif (expr.combined and "for" not in expr.combined):
+                if ("masked taskloop" not in expr.combined) and ("distribute" not in expr.combined):
+                    omp_expr += '\n{'
+
+        return omp_expr
 
     def _print_Omp_End_Clause(self, expr):
         return '}'
diff --git a/pyccel/codegen/printing/fcode.py b/pyccel/codegen/printing/fcode.py
index f21af2a3..68df73ca 100644
--- a/pyccel/codegen/printing/fcode.py
+++ b/pyccel/codegen/printing/fcode.py
@@ -30,6 +30,7 @@ from pyccel.ast.itertoolsext import Product
 from pyccel.ast.core import (Assign, AliasAssign, Declare,
                              CodeBlock, Dlist, AsName,
                              If, IfSection)
+
 from pyccel.ast.variable  import (Variable, TupleVariable,
                              IndexedElement,
                              DottedName, PyccelArraySize)
@@ -1857,27 +1858,28 @@ class FCodePrinter(CodePrinter):
                 '{epilog}').format(prolog=prolog, body=body, epilog=epilog)
 
     # .....................................................
-    #                   OpenMP statements
+    #               Print OpenMP AnnotatedComment
     # .....................................................
-    def _print_OMP_Parallel_Construct(self, expr):
-        omp_expr   = str(expr.txt)
-        ompexpr = '!$omp {}\n'.format(omp_expr)
-        return ompexpr
+
+    def _print_OmpAnnotatedComment(self, expr):
+        clauses = ''
+        if expr.combined:
+            combined = expr.combined.replace("for", "do")
+            clauses = ' ' + combined
+
+        omp_expr = '!$omp {}'.format(expr.name.replace("for", "do"))
+        clauses += str(expr.txt).replace("cancel for", "cancel do")
+        omp_expr = '{}{}\n'.format(omp_expr, clauses)
+
+        return omp_expr
 
     def _print_Omp_End_Clause(self, expr):
         omp_expr = str(expr.txt)
+        if "section" in omp_expr and "sections" not in omp_expr:
+            return ''
         omp_expr = omp_expr.replace("for", "do")
-        ompexpr = '!$omp {}\n'.format(omp_expr)
-        return ompexpr
-
-    def _print_OMP_Single_Construct(self, expr):
-        omp_expr   = str(expr.txt)
-        ompexpr = '!$omp {}\n'.format(omp_expr)
-        return ompexpr
-
-    def _print_OMP_For_Loop(self, expr):
-        omp_expr   = str(expr.txt)
-        return '!$omp do{}\n'.format(omp_expr)
+        omp_expr = '!$omp {}\n'.format(omp_expr)
+        return omp_expr
 
     # .....................................................
     def _print_OMP_Parallel(self, expr):
diff --git a/pyccel/parser/grammar/openmp.tx b/pyccel/parser/grammar/openmp.tx
index 9726860e..06b3cd04 100644
--- a/pyccel/parser/grammar/openmp.tx
+++ b/pyccel/parser/grammar/openmp.tx
@@ -5,7 +5,7 @@ Openmp:
   statements*=OpenmpStmt
 ;
 
-OpenmpStmt: 
+OpenmpStmt:
   '#$' 'omp' stmt=OmpConstructOrDirective
 ;
 
@@ -13,78 +13,169 @@ OpenmpStmt:
 //         Constructs and Directives
 ////////////////////////////////////////////////////
 OmpConstructOrDirective:
-    OmpParallelConstruct 
+    OmpParallelConstruct
   | OmpLoopConstruct
   | OmpSingleConstruct
   | OmpEndClause
+  | OmpCriticalConstruct
+  | OmpBarrierConstruct
+  | OmpMasterConstruct
+  | OmpMaskedConstruct
+  | OmpTaskLoopConstruct
+  | OmpSimdConstruct
+  | OmpAtomicConstruct
+  | OmpTaskWaitConstruct
+  | OmpTaskyieldConstruct
+  | OmpTaskConstruct
+  | OmpFlushConstruct
+  | OmpCancelConstruct
+  | OmpTargetConstruct
+  | OmpTeamsConstruct
+  | OmpDistributeConstruct
+  | OmpSectionsConstruct
+  | OmpSectionConstruct
 ;
 ////////////////////////////////////////////////////
 
 ////////////////////////////////////////////////////
 //     Constructs and Directives definitions
 ////////////////////////////////////////////////////
-OmpParallelConstruct: 'parallel' clauses*=OmpParallelClause;
-OmpLoopConstruct:      'for'       clauses*=OmpLoopClause;
-OmpSingleConstruct:   'single'   clauses*=OmpSingleClause;
+OmpParallelConstruct:   'parallel'        combined=ParallelCombined? clauses*=AllOmpClauses;
+OmpLoopConstruct:       'for'             clauses*=AllOmpClauses;
+OmpTaskLoopConstruct:   name='taskloop'   clauses*=AllOmpClauses;
+OmpSingleConstruct:     name='single'     clauses*=AllOmpClauses;
+OmpCriticalConstruct:   name='critical'   clauses*=AllOmpClauses;
+OmpMaskedConstruct:     'masked'          combined=MaskedCombined? clauses*=AllOmpClauses;
+OmpSimdConstruct:       name='simd'       clauses*=AllOmpClauses;
+OmpAtomicConstruct:     name='atomic'     clauses*=AllOmpClauses; // Not all clauses were added (can't test them).
+OmpTaskConstruct:       name='task'       clauses*=AllOmpClauses;
+OmpCancelConstruct:     name='cancel'     clauses*=OmpCancelType;
+OmpTargetConstruct:     'target'          combined=TargetCombined? clauses*=AllOmpClauses;
+OmpTeamsConstruct:      'teams'           combined=TeamsCombined? clauses*=AllOmpClauses;
+OmpDistributeConstruct: name='distribute' clauses*=AllOmpClauses;
+OmpSectionsConstruct:   name='sections'   clauses*=AllOmpClauses;
+OmpFlushConstruct:      name='flush'      clauses*=AllOmpClauses;
+OmpSectionConstruct:    name='section';
+OmpBarrierConstruct:    name='barrier';
+OmpMasterConstruct:     name='master';
+OmpTaskWaitConstruct:   name='taskwait';
+OmpTaskyieldConstruct:  name='taskyield';
+////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////
+//         Combined Constructs
+////////////////////////////////////////////////////
+
+ParallelCombined: OmpForSimd | OmpMaskedTaskloop | OmpPSections;
+MaskedCombined:   OmpTaskloopSimd;
+TeamsCombined:    OmpDistributeCombined;
+TargetCombined:   OmpTargetParallel | OmpTargetTeams;
+////////////////////////////////////////////////////
+
+////////////////////////////////////////////////////
+//         Combined Constructs
+////////////////////////////////////////////////////
+
+OmpForSimd: fname='for' sname='simd'?;
+OmpMaskedTaskloop: mname='masked' (tname='taskloop' sname='simd'?)?;
+OmpPSections: sname='sections';
+OmpTaskloopSimd: tname='taskloop' sname='simd'?;
+OmpDistributeCombined: dname='distribute' (sname='simd' | (pname='parallel' fname='for' ssname='simd'?))?;
+OmpTargetParallel: pname='parallel' (fname='for' sname='simd'?)?;
+OmpTargetTeams: tname='teams' (dname='distribute' (sname='simd' | (pname='parallel' fname='for' ssname='simd'?))?)?;
 ////////////////////////////////////////////////////
 
 ////////////////////////////////////////////////////
 //      Clauses for Constructs and Directives
 ////////////////////////////////////////////////////
-OmpParallelClause:
-    OmpNumThread
+
+AllOmpClauses:
+    OmpAtomicClause
+  | AtomicMemoryClause
+  | OmpPriority
   | OmpDefault
   | OmpPrivate
   | OmpShared
   | OmpFirstPrivate
-  | OmpCopyin
+  | OmpUntied
+  | OmpMergeable
   | OmpReduction
-  | OmpProcBind
-;
-
-OmpLoopClause:
-    OmpPrivate
-  | OmpFirstPrivate
+  | OmpinReduction // Deprecated in OpenMP 5.0 for TaskLoop/Task Constructs
+  | OmpDepend // TODO : depend-modifier, dependence-type: (source, sink)
+  | FlushList
   | OmpLastPrivate
+  | OmpMap
+  | OmpNumTeams
+  | OmpThreadLimit
   | OmpLinear
-  | OmpReduction
-  | OmpSchedule
   | OmpCollapse
+  | OmpFilter
+  | OmpNumThread
+  | OmpCopyin
+  | OmpProcBind
+  | OmpCriticalName
+  | OmpNumTasks
+  | OmpGrainSize
+  | OmpNogroup
+  | OmpSchedule
   | OmpOrdered
+  | OmpFinal
 ;
 
-OmpSingleClause:
-    OmpPrivate
-  | OmpFirstPrivate
-;
 ////////////////////////////////////////////////////
 
 ////////////////////////////////////////////////////
 //              Clauses definitions
 ////////////////////////////////////////////////////
 OmpNumThread: 'num_threads' '(' thread=ThreadIndex ')';
+OmpNumTeams: 'num_teams' '(' teams=TeamIndex ')';
+OmpNumTasks: 'num_tasks' '(' tasks=TaskIndex ')';
+OmpThreadLimit: 'thread_limit' '(' limit=ThreadIndex ')';
+OmpGrainSize: 'grainsize' '(' tasks=TaskIndex ')';
+OmpFinal: 'final' '(' final=TaskIndex ')';
 OmpDefault: 'default' '(' status=OmpDefaultStatus ')';
 OmpProcBind: 'proc_bind' '(' status=OmpProcBindStatus ')';
+OmpMap: 'map' '(' mtype=OmpMapType? args+=ID[','] ')'; // TODO NH : Array and shaping
 OmpPrivate: 'private' '(' args+=ID[','] ')';
 OmpShared: 'shared' '(' args+=ID[','] ')';
 OmpFirstPrivate: 'firstprivate' '(' args+=ID[','] ')';
 OmpLastPrivate: 'lastprivate' '(' args+=ID[','] ')';
 OmpCopyin: 'copyin' '(' args+=ID[','] ')';
+OmpDepend: 'depend' '('dtype=OmpDependenceType ':' args+=ID[','] ')';
 OmpReduction: 'reduction' '('op=OmpReductionOperator ':' args+=ID[','] ')';
+OmpinReduction: ctype='in_reduction' '('op=OmpReductionOperator ':' args+=ID[','] ')';
 OmpCollapse: 'collapse' '(' n=INT ')';
 OmpLinear: 'linear' '(' val=ID ':' step=INT ')';
 OmpOrdered: 'ordered' ('(' n=INT ')')?;
 OmpSchedule: 'schedule' '(' kind=OmpScheduleKind (',' chunk_size=INT)? ')';
-OmpEndClause: 'end' construct=OpenmpConstructs (simd='simd')? (nowait='nowait')?;
+OmpEndClause: 'end' construct*=OpenmpConstructs (simd='simd')? (nowait='nowait')?;
+OmpCriticalName: '(' args=ID ')';
+OmpFilter: name='filter' '(' n=INT ')';
+OmpPriority: name='priority' '(' n=PriorityIndex ')';
+OmpUntied: name='untied';
+OmpMergeable: name='mergeable';
+OmpNogroup: name='nogroup';
+OmpAtomicClause: name=AtomicClause;
+AtomicMemoryClause: name=AtomicMClause;
+FlushList: '(' args+=ID[','] ')';
+OmpCancelType: name=CancelType;
 ////////////////////////////////////////////////////
 
 ////////////////////////////////////////////////////
+CancelType: ('parallel' | 'sections' | 'taskgroup' | 'for');
 OmpScheduleKind: ('static' | 'dynamic' | 'guided' | 'auto' | 'runtime' );
 OmpProcBindStatus: ('master' | 'close' | 'spread');
 OmpReductionOperator: ('+' | '-' | '*' | '/');
+OmpDependenceType: ('in' | 'out' | 'inout' | 'mutexinoutset' | 'depobj');
 OmpDefaultStatus: ('private' | 'firstprivate' | 'shared' | 'none');
-OpenmpConstructs: ('single' | 'parallel' | 'for');
+OmpMapType: (('always' | 'close' | ('mapper' '(' ID ')') ',')? ('tofrom' | 'from' | 'to' | 'alloc' | 'release' | 'delete')) ':';
+OpenmpConstructs: ('simd' | 'masked' | 'master' | 'single' | 'parallel' | 'for' | 'critical' ('(' ID  ')')? | 'task' | 'target' | 'teams' | 'sections' | 'section');
 
+AtomicClause: ('write' | 'read' | 'update' | 'capture' | 'compare' | 'weak');
+AtomicMClause: ('seq_cst' | 'acq_rel' | 'release' | 'acquire' | 'relaxed');
 ThreadIndex: (ID | INT);
+TaskIndex: (ID | INT);
+TeamIndex: (ID | INT);
+PriorityIndex: (ID | INT);
 NotaStmt: /.*$/;
 ////////////////////////////////////////////////////
diff --git a/pyccel/parser/semantic.py b/pyccel/parser/semantic.py
index c47e03ac..ff0d7579 100644
--- a/pyccel/parser/semantic.py
+++ b/pyccel/parser/semantic.py
@@ -853,6 +853,8 @@ class SemanticParser(BasicParser):
         return expr
     def _visit_AnnotatedComment(self, expr, **settings):
         return expr
+    def _visit_OmpAnnotatedComment(self, expr, **settings):
+        return expr
     def _visit_Literal(self, expr, **settings):
         return expr
     def _visit_PythonComplex(self, expr, **settings):
diff --git a/pyccel/parser/syntax/openmp.py b/pyccel/parser/syntax/openmp.py
index aedffceb..6c621e04 100644
--- a/pyccel/parser/syntax/openmp.py
+++ b/pyccel/parser/syntax/openmp.py
@@ -11,396 +11,754 @@ from os.path import join, dirname
 from textx.metamodel import metamodel_from_file
 
 from pyccel.parser.syntax.basic import BasicStmt
-from pyccel.ast.core import OMP_For_Loop, OMP_Parallel_Construct, OMP_Single_Construct, Omp_End_Clause
+
+from pyccel.ast.omp import (OmpAnnotatedComment, OMP_For_Loop, OMP_Parallel_Construct,
+                            OMP_Single_Construct, Omp_End_Clause, OMP_Critical_Construct,
+                            OMP_Master_Construct, OMP_Masked_Construct, OMP_Task_Construct,
+                            OMP_Cancel_Construct, OMP_Target_Construct, OMP_Teams_Construct,
+                            OMP_Sections_Construct, OMP_Section_Construct)
 
 DEBUG = False
 
+class OmpConstruct(BasicStmt):
+    """Class representing all OpenMP constructs."""
+    def __init__(self, omp_type, vclauses, **kwargs):
+        name     = kwargs.pop('name', None)
+        clauses  = kwargs.pop('clauses', None)
+        combined = kwargs.pop('combined', None)
+
+        _valid_clauses = vclauses
+
+        com = None
+        if combined:
+            if 'for' in combined.expr:
+                _valid_clauses += _valid_loop_clauses
+            if 'simd' in combined.expr:
+                _valid_clauses += _valid_simd_clauses
+            if 'taskloop' in combined.expr:
+                _valid_clauses += _valid_taskloop_clauses
+            if 'masked' in combined.expr:
+                _valid_clauses += (OmpFilter,)
+            if 'sections' in combined.expr:
+                _valid_clauses += _valid_sections_clauses
+            if 'distribute' in combined.expr:
+                _valid_clauses += _valid_Distribute_clauses
+            if 'parallel' in combined.expr:
+                _valid_clauses += _valid_parallel_clauses
+            if 'teams' in combined.expr:
+                _valid_clauses += _valid_teams_clauses
+            com = combined.expr
+
+        txt = ''
+        if name:
+            txt += name
+        if clauses:
+            txt += check_get_clauses(self, _valid_clauses, clauses, combined)
+
+        if combined:
+            self._expr = omp_type(txt, com)
+        else:
+            self._expr = omp_type(txt)
+
+        super().__init__(**kwargs)
+
+    @property
+    def expr(self):
+        if DEBUG:
+            print("> {}: expr".format(type(self).__name__))
+
+        return self._expr
+
+class OmpClauses(BasicStmt):
+    """Class representing the clause expr."""
+    _expr = None
+    @property
+    def expr(self):
+        if DEBUG:
+            print("> {}: expr".format(type(self).__name__))
+
+        return self._expr
+
+def check_get_clauses(name, valid_clauses, clauses, combined = None):
+    """
+    Function to check if the clauses are correct for a given construct.
+    """
+    txt = ''
+    for clause in clauses:
+        if isinstance(clause, valid_clauses) and \
+           not (isinstance(clause, OmpCopyin) and isinstance(combined, OmpTargetParallel)):
+            txt = '{0} {1}'.format(txt, clause.expr)
+        else:
+            msg = "Wrong clause " + type(clause).__name__
+            raise TypeError(msg)
+    return txt
+
+
 class Openmp(object):
     """Class for Openmp syntax."""
     def __init__(self, **kwargs):
-        """
-        Constructor for Openmp.
-
-        """
         self.statements = kwargs.pop('statements', [])
 
 class OpenmpStmt(BasicStmt):
-    """Class representing a ."""
+    """Class representing an OpenMP statement."""
     def __init__(self, **kwargs):
-        """
-        """
         self.stmt = kwargs.pop('stmt')
 
-        super(OpenmpStmt, self).__init__(**kwargs)
+        super().__init__(**kwargs)
 
     @property
     def expr(self):
         if DEBUG:
-            print("> OpenmpStmt: expr")
+            print("> {}: expr".format(type(self).__name__))
 
         stmt = self.stmt
-        if isinstance(stmt, OmpEndClause):
-            return stmt.expr
-        elif isinstance(stmt, OmpParallelConstruct):
-            return stmt.expr
-        elif isinstance(stmt, OmpLoopConstruct):
-            return stmt.expr
-        elif isinstance(stmt, OmpSingleConstruct):
+        if isinstance(stmt, omp_directives):
             return stmt.expr
         else:
             raise TypeError('Wrong stmt for OpenmpStmt')
 
-class OmpParallelConstruct(BasicStmt):
-    """Class representing a ."""
+class OmpParallelConstruct(OmpConstruct):
+    """Class representing the Parallel construct."""
     def __init__(self, **kwargs):
-        """
-        """
-        self.clauses = kwargs.pop('clauses')
+        super().__init__(OMP_Parallel_Construct, _valid_parallel_clauses, **kwargs)
 
-        super(OmpParallelConstruct, self).__init__(**kwargs)
+class OmpLoopConstruct(OmpConstruct):
+    """Class representing the For loop construct."""
+    def __init__(self, **kwargs):
+        super().__init__(OMP_For_Loop, _valid_loop_clauses, **kwargs)
 
-    @property
-    def expr(self):
-        if DEBUG:
-            print("> OmpParallelConstruct: expr")
-
-        _valid_clauses = (OmpNumThread, \
-                         OmpDefault, \
-                         OmpPrivate, \
-                         OmpShared, \
-                         OmpFirstPrivate, \
-                         OmpCopyin, \
-                         OmpReduction, \
-                         OmpProcBind)
-
-        txt = 'parallel'
-        for clause in self.clauses:
-            if isinstance(clause, _valid_clauses):
-                txt = '{0} {1}'.format(txt, clause.expr)
-            else:
-                raise TypeError('Wrong clause for OmpParallelConstruct')
+class OmpTaskLoopConstruct(OmpConstruct):
+    """Class representing the Taskloop construct."""
+    def __init__(self, **kwargs):
+        super().__init__(OmpAnnotatedComment, (_valid_taskloop_clauses + (OmpinReduction,)), **kwargs)
 
-        return OMP_Parallel_Construct(txt)
+class OmpTaskConstruct(OmpConstruct):
+    """Class representing the Task construct """
+    def __init__(self, **kwargs):
+        super().__init__(OMP_Task_Construct, _valid_task_clauses, **kwargs)
 
-class OmpLoopConstruct(BasicStmt):
-    """Class representing a ."""
+class OmpSingleConstruct(OmpConstruct):
+    """Class representing the Single construct."""
     def __init__(self, **kwargs):
-        """
-        """
-        self.clauses = kwargs.pop('clauses')
+        super().__init__(OMP_Single_Construct, _valid_single_clauses, **kwargs)
 
-        super(OmpLoopConstruct, self).__init__(**kwargs)
+class OmpCriticalConstruct(OmpConstruct):
+    """Class representing the Critical construct."""
+    def __init__(self, **kwargs):
+        super().__init__(OMP_Critical_Construct, (OmpCriticalName,), **kwargs)
 
-    @property
-    def expr(self):
-        if DEBUG:
-            print("> OmpLoopConstruct: expr")
+class OmpSimdConstruct(OmpConstruct):
+    """Class representing the Simd construct."""
+    def __init__(self, **kwargs):
+        super().__init__(OmpAnnotatedComment, _valid_simd_clauses, **kwargs)
 
-        _valid_clauses = (OmpPrivate, \
-                         OmpFirstPrivate, \
-                         OmpLastPrivate, \
-                         OmpReduction, \
-                         OmpSchedule, \
-                         OmpCollapse, \
-                         OmpLinear, \
-                         OmpOrdered)
+class OmpMasterConstruct(OmpConstruct):
+    """Class representing the master construct."""
+    def __init__(self, **kwargs):
+        super().__init__(OMP_Master_Construct, _valid_simd_clauses, **kwargs)
 
-        txt = ''
-        for clause in self.clauses:
-            if isinstance(clause, _valid_clauses):
-                txt = '{0} {1}'.format(txt, clause.expr)
-            else:
-                raise TypeError('Wrong clause for OmpLoopConstruct. Given : ', \
-                                type(clause))
-        return OMP_For_Loop(txt)
+class OmpMaskedConstruct(OmpConstruct):
+    """Class representing the Masked construct."""
+    def __init__(self, **kwargs):
+        super().__init__(OMP_Masked_Construct, (OmpFilter,), **kwargs)
 
-class OmpSingleConstruct(BasicStmt):
-    """Class representing a ."""
+class OmpSectionsConstruct(OmpConstruct):
+    """Class representing the Sections construct."""
     def __init__(self, **kwargs):
-        """
-        """
-        self.clauses = kwargs.pop('clauses')
+        super().__init__(OMP_Sections_Construct, _valid_sections_clauses, **kwargs)
 
-        super(OmpSingleConstruct, self).__init__(**kwargs)
+class OmpSectionConstruct(OmpConstruct):
+    """Class representing the Section construct."""
+    def __init__(self, **kwargs):
+        super().__init__(OMP_Section_Construct, None, **kwargs)
 
-    @property
-    def expr(self):
-        if DEBUG:
-            print("> OmpSingleConstruct: expr")
+class OmpDistributeConstruct(OmpConstruct):
+    """Class representing the Distribute construct."""
+    def __init__(self, **kwargs):
+        super().__init__(OmpAnnotatedComment, _valid_Distribute_clauses, **kwargs)
 
-        _valid_clauses = (OmpPrivate, \
-                         OmpFirstPrivate)
+class OmpBarrierConstruct(OmpConstruct):
+    """Class representing the Barrier construct."""
+    def __init__(self, **kwargs):
+        super().__init__(OmpAnnotatedComment, None, **kwargs)
 
-        txt = 'single'
-        for clause in self.clauses:
-            if isinstance(clause, _valid_clauses):
-                txt = '{0} {1}'.format(txt, clause.expr)
-            else:
-                raise TypeError('Wrong clause for OmpSingleConstruct')
+class OmpTaskWaitConstruct(OmpConstruct):
+    """Class representing the TaskWait construct."""
+    def __init__(self, **kwargs):
+        super().__init__(OmpAnnotatedComment, None, **kwargs)
+
+class OmpTaskyieldConstruct(OmpConstruct):
+    """Class representing the Taskyield construct."""
+    def __init__(self, **kwargs):
+        super().__init__(OmpAnnotatedComment, None, **kwargs)
 
-        return OMP_Single_Construct(txt)
+class OmpFlushConstruct(OmpConstruct):
+    """Class representing the Flush construct."""
+    def __init__(self, **kwargs):
+        super().__init__(OmpAnnotatedComment, (FlushList,), **kwargs)
+
+class OmpCancelConstruct(OmpConstruct):
+    """Class representing the Cancel construct."""
+    def __init__(self, **kwargs):
+        super().__init__(OMP_Cancel_Construct, (OmpCancelType,), **kwargs)
+
+class OmpTargetConstruct(OmpConstruct):
+    """Class representing the Target construct."""
+    def __init__(self, **kwargs):
+        super().__init__(OMP_Target_Construct, _valid_target_clauses, **kwargs)
+
+class OmpTeamsConstruct(OmpConstruct):
+    """Class representing the Teams construct."""
+    def __init__(self, **kwargs):
+        super().__init__(OMP_Teams_Construct, _valid_teams_clauses, **kwargs)
+
+class OmpAtomicConstruct(OmpConstruct):
+    """Class representing the Atomic construct ."""
+    def __init__(self, **kwargs):
+        super().__init__(OmpAnnotatedComment, _valid_atomic_clauses, **kwargs)
 
 class OmpEndClause(BasicStmt):
-    """Class representing a ."""
+    """Class representing the End construct."""
     def __init__(self, **kwargs):
-        """
-        """
         self.construct = kwargs.pop('construct')
         self.simd      = kwargs.pop('simd', '')
         self.nowait    = kwargs.pop('nowait', '')
 
-        super(OmpEndClause, self).__init__(**kwargs)
+        construct = ' '.join(self.construct)
+        txt = 'end {0} {1} {2}'.format(construct, self.simd, self.nowait)
+
+        self._expr = Omp_End_Clause(txt)
+
+        super().__init__(**kwargs)
 
     @property
     def expr(self):
         if DEBUG:
             print("> OmpEndClause: expr")
 
-        txt = 'end {0} {1} {2}'.format(self.construct, self.simd, self.nowait)
-        return Omp_End_Clause(txt)
+        return self._expr
 
-class OmpNumThread(BasicStmt):
-    """Class representing a ."""
+class OmpFinal(OmpClauses):
+    """Class representing the final clause"""
     def __init__(self, **kwargs):
-        """
-        """
-        self.thread = kwargs.pop('thread')
+        final = kwargs.pop('final')
 
-        super(OmpNumThread, self).__init__(**kwargs)
+        self._expr = 'final({})'.format(final)
 
-    @property
-    def expr(self):
-        # TODO check if variable exist in namespace
-        if DEBUG:
-            print("> OmpNumThread: expr")
+        super().__init__(**kwargs)
+
+class OmpNumThread(OmpClauses):
+    """Class representing the num_thread clause."""
+    def __init__(self, **kwargs):
+        thread = kwargs.pop('thread')
+
+        self._expr = 'num_threads({})'.format(thread)
 
-        thread = self.thread
-        return 'num_threads({})'.format(thread)
+        super().__init__(**kwargs)
 
-class OmpDefault(BasicStmt):
-    """Class representing a ."""
+class OmpNumTeams(OmpClauses):
+    """Class representing the num_teams clause."""
     def __init__(self, **kwargs):
-        """
-        """
-        self.status = kwargs.pop('status')
+        teams = kwargs.pop('teams')
 
-        super(OmpDefault, self).__init__(**kwargs)
+        self._expr = 'num_teams({})'.format(teams)
 
-    @property
-    def expr(self):
-        if DEBUG:
-            print("> OmpDefault: expr")
+        super().__init__(**kwargs)
 
-        return 'default({})'.format(self.status)
+class OmpThreadLimit(OmpClauses):
+    """Class representing the thread_limit clause."""
+    def __init__(self, **kwargs):
+        limit = kwargs.pop('limit')
 
-class OmpProcBind(BasicStmt):
-    """Class representing a ."""
+        self._expr = 'thread_limit({})'.format(limit)
+
+        super().__init__(**kwargs)
+
+class OmpNumTasks(OmpClauses):
+    """Class representing the num_tasks clause."""
     def __init__(self, **kwargs):
-        """
-        """
-        self.status = kwargs.pop('status')
+        tasks = kwargs.pop('tasks')
 
-        super(OmpProcBind, self).__init__(**kwargs)
+        self._expr = 'num_tasks({})'.format(tasks)
 
-    @property
-    def expr(self):
-        if DEBUG:
-            print("> OmpProcBind: expr")
+        super().__init__(**kwargs)
+
+class OmpGrainSize(OmpClauses):
+    """Class representing the grainsize clause."""
+    def __init__(self, **kwargs):
+        size = kwargs.pop('tasks')
+
+        self._expr = 'grainsize({})'.format(size)
 
-        return 'proc_bind({})'.format(self.status)
+        super().__init__(**kwargs)
 
-class OmpPrivate(BasicStmt):
-    """Class representing a ."""
+class OmpDefault(OmpClauses):
+    """Class representing the default clause."""
     def __init__(self, **kwargs):
-        """
-        """
-        self.args = kwargs.pop('args')
+        status = kwargs.pop('status')
 
-        super(OmpPrivate, self).__init__(**kwargs)
+        self._expr = 'default({})'.format(status)
 
-    @property
-    def expr(self):
-        if DEBUG:
-            print("> OmpPrivate: expr")
+        super().__init__(**kwargs)
+
+class OmpProcBind(OmpClauses):
+    """Class representing the proc_bind clause."""
+    def __init__(self, **kwargs):
+        status = kwargs.pop('status')
+
+        self._expr = 'proc_bind({})'.format(status)
 
-        # TODO check if variable exist in namespace
-        args = ', '.join(str(arg) for arg in self.args)
-        return 'private({})'.format(args)
+        super().__init__(**kwargs)
 
-class OmpShared(BasicStmt):
-    """Class representing a ."""
+class OmpPrivate(OmpClauses):
+    """Class representing the private clause."""
     def __init__(self, **kwargs):
-        """
-        """
-        self.args = kwargs.pop('args')
+        args = kwargs.pop('args')
 
-        super(OmpShared, self).__init__(**kwargs)
+        #TODO check for variables in namespace
+        txt = ', '.join(str(arg) for arg in args)
+        self._expr = 'private({})'.format(txt)
 
-    @property
-    def expr(self):
-        if DEBUG:
-            print("> OmpShared: expr")
+        super().__init__(**kwargs)
+
+class FlushList(OmpClauses):
+    """Class representing a list of variables for the flush construct."""
+    def __init__(self, **kwargs):
+        args = kwargs.pop('args')
+
+        txt = ', '.join(str(arg) for arg in args)
+        self._expr = '({})'.format(txt)
 
-        # TODO check if variable exist in namespace
-        args = ', '.join(str(arg) for arg in self.args)
-        return 'shared({})'.format(args)
+        super().__init__(**kwargs)
 
-class OmpFirstPrivate(BasicStmt):
-    """Class representing a ."""
+class OmpCriticalName(OmpClauses):
+    """Class representing the name of a critical construct."""
     def __init__(self, **kwargs):
-        """
-        """
-        self.args = kwargs.pop('args')
+        args = kwargs.pop('args')
 
-        super(OmpFirstPrivate, self).__init__(**kwargs)
+        self._expr = '({})'.format(str(args))
 
-    @property
-    def expr(self):
-        if DEBUG:
-            print("> OmpFirstPrivate: expr")
+        super().__init__(**kwargs)
+
+class OmpShared(OmpClauses):
+    """Class representing the shared clause."""
+    def __init__(self, **kwargs):
+        args = kwargs.pop('args')
+
+        txt = ', '.join(str(arg) for arg in args)
+        self._expr = 'shared({})'.format(txt)
 
-        # TODO check if variable exist in namespace
-        args = ', '.join(str(arg) for arg in self.args)
-        return 'firstprivate({})'.format(args)
+        super().__init__(**kwargs)
 
-class OmpLastPrivate(BasicStmt):
-    """Class representing a ."""
+class OmpFirstPrivate(OmpClauses):
+    """Class representing the firstprivate clause."""
     def __init__(self, **kwargs):
-        """
-        """
-        self.args = kwargs.pop('args')
+        args = kwargs.pop('args')
 
-        super(OmpLastPrivate, self).__init__(**kwargs)
+        txt = ', '.join(str(arg) for arg in args)
+        self._expr = 'firstprivate({})'.format(txt)
 
-    @property
-    def expr(self):
-        if DEBUG:
-            print("> OmpLastPrivate: expr")
+        super().__init__(**kwargs)
+
+class OmpLastPrivate(OmpClauses):
+    """Class representing the lastprivate clause."""
+    def __init__(self, **kwargs):
+        args = kwargs.pop('args')
 
-        # TODO check if variable exist in namespace
-        args = ', '.join(str(arg) for arg in self.args)
-        return 'lastprivate({})'.format(args)
+        txt = ', '.join(str(arg) for arg in args)
+        self._expr = 'lastprivate({})'.format(txt)
 
-class OmpCopyin(BasicStmt):
-    """Class representing a ."""
+        super().__init__(**kwargs)
+
+class OmpCopyin(OmpClauses):
+    """Class representing the copyin clause."""
     def __init__(self, **kwargs):
-        """
-        """
-        self.args = kwargs.pop('args')
+        args = kwargs.pop('args')
 
-        super(OmpCopyin, self).__init__(**kwargs)
+        txt = ', '.join(str(arg) for arg in args)
+        self._expr = 'copyin({})'.format(txt)
 
-    @property
-    def expr(self):
-        if DEBUG:
-            print("> OmpCopyin: expr")
+        super().__init__(**kwargs)
+
+class OmpReduction(OmpClauses):
+    """Class representing the reduction clause."""
+    def __init__(self, **kwargs):
+        op   = kwargs.pop('op')
+        args = kwargs.pop('args')
 
-        # TODO check if variable exist in namespace
-        args = ', '.join(str(arg) for arg in self.args)
-        return 'copyin({})'.format(args)
+        txt = ', '.join(str(arg) for arg in args)
+        self._expr = 'reduction({0}: {1})'.format(op, txt)
 
-class OmpReduction(BasicStmt):
-    """Class representing a ."""
+        super().__init__(**kwargs)
+
+class OmpDepend(OmpClauses):
+    """Class representing the depend clause."""
     def __init__(self, **kwargs):
-        """
-        """
-        self.op   = kwargs.pop('op')
-        self.args = kwargs.pop('args')
+        dtype   = kwargs.pop('dtype')
+        args = kwargs.pop('args')
 
-        super(OmpReduction, self).__init__(**kwargs)
+        txt = ', '.join(str(arg) for arg in args)
+        self._expr = 'depend({0}: {1})'.format(dtype, txt)
 
-    @property
-    def expr(self):
-        if DEBUG:
-            print("> OmpReduction: expr")
+        super().__init__(**kwargs)
+
+class OmpMap(OmpClauses):
+    """Class representing the map clause."""
+    def __init__(self, **kwargs):
+        mtype   = kwargs.pop('mtype')
+        args = kwargs.pop('args')
 
-        # TODO check if variable exist in namespace
-        op   = self.op
-        args = ', '.join(str(arg) for arg in self.args)
-        return 'reduction({0}: {1})'.format(op, args)
+        txt = ', '.join(str(arg) for arg in args)
+        self._expr = 'map({0} {1})'.format(mtype, txt)
 
-class OmpCollapse(BasicStmt):
-    """Class representing a ."""
+        super().__init__(**kwargs)
+
+class OmpinReduction(OmpClauses):
+    """Class representing the in_reduction clause."""
     def __init__(self, **kwargs):
-        """
-        """
-        self.n = kwargs.pop('n')
+        ctype  = kwargs.pop('ctype')
+        op     = kwargs.pop('op')
+        args   = kwargs.pop('args')
 
-        super(OmpCollapse, self).__init__(**kwargs)
+        txt = ', '.join(str(arg) for arg in args)
+        self._expr = '{0}({1}: {2})'.format(ctype, op, txt)
 
-    @property
-    def expr(self):
-        if DEBUG:
-            print("> OmpCollapse: expr")
+        super().__init__(**kwargs)
+
+class OmpCollapse(OmpClauses):
+    """Class representing the collapse clause."""
+    def __init__(self, **kwargs):
+        n = kwargs.pop('n')
 
-        return 'collapse({})'.format(self.n)
+        self._expr = 'collapse({})'.format(n)
 
-class OmpOrdered(BasicStmt):
-    """Class representing a ."""
+        super().__init__(**kwargs)
+
+class OmpOrdered(OmpClauses):
+    """Class representing the ordered clause."""
     def __init__(self, **kwargs):
-        """
-        """
-        self.n = kwargs.pop('n', None)
+        n = kwargs.pop('n', None)
 
-        super(OmpOrdered, self).__init__(**kwargs)
+        if n:
+            self._expr = 'ordered({})'.format(n)
+        else:
+            self._expr = 'ordered'
 
-    @property
-    def expr(self):
-        if DEBUG:
-            print("> OmpOrdered: expr")
+        super().__init__(**kwargs)
+
+class OmpLinear(OmpClauses):
+    """Class representing the linear clause."""
+    def __init__(self, **kwargs):
+        val  = kwargs.pop('val')
+        step = kwargs.pop('step')
+
+        self._expr = 'linear({0}:{1})'.format(val, step)
+
+        super().__init__(**kwargs)
 
-        if self.n:
-            return 'ordered({})'.format(self.n)
+class OmpSchedule(OmpClauses):
+    """Class representing the schedule clause."""
+    def __init__(self, **kwargs):
+        kind       = kwargs.pop('kind')
+        chunk_size = kwargs.pop('chunk_size', None)
+
+        if chunk_size:
+            self._expr = 'schedule({0}, {1})'.format(kind, chunk_size)
         else:
-            return 'ordered'
+            self._expr = 'schedule({0})'.format(kind)
+
+        super().__init__(**kwargs)
 
-class OmpLinear(BasicStmt):
-    """Class representing a ."""
+class OmpFilter(OmpClauses):
+    """Class representing the filter clause."""
     def __init__(self, **kwargs):
-        """
-        """
-        self.val  = kwargs.pop('val')
-        self.step = kwargs.pop('step')
+        name = kwargs.pop('name')
+        n = kwargs.pop('n')
 
-        super(OmpLinear, self).__init__(**kwargs)
+        self._expr = '{}({})'.format(name, n)
 
-    @property
-    def expr(self):
-        if DEBUG:
-            print("> OmpLinear: expr")
+        super().__init__(**kwargs)
+
+class OmpUntied(OmpClauses):
+    """Class representing the untied clause."""
+    def __init__(self, **kwargs):
+        name = kwargs.pop('name')
+
+        self._expr = name
 
-        return 'linear({0}:{1})'.format(self.val, self.step)
+        super().__init__(**kwargs)
 
-class OmpSchedule(BasicStmt):
-    """Class representing a ."""
+class OmpMergeable(OmpClauses):
+    """Class representing the mergeable clause."""
     def __init__(self, **kwargs):
-        """
-        """
-        self.kind       = kwargs.pop('kind')
-        self.chunk_size = kwargs.pop('chunk_size', None)
+        name = kwargs.pop('name')
 
-        super(OmpSchedule, self).__init__(**kwargs)
+        self._expr = name
 
-    @property
-    def expr(self):
-        if DEBUG:
-            print("> OmpSchedule: expr")
+        super().__init__(**kwargs)
+
+class OmpNogroup(OmpClauses):
+    """Class representing the nogroup clause."""
+    def __init__(self, **kwargs):
+        name = kwargs.pop('name')
+
+        self._expr = name
+
+        super().__init__(**kwargs)
+
+class OmpPriority(OmpClauses):
+    """Class representing the priority clause."""
+    def __init__(self, **kwargs):
+        name = kwargs.pop('name')
+        n = kwargs.pop('n')
+
+        self._expr = '{}({})'.format(name, n)
+
+        super().__init__(**kwargs)
+
+class OmpAtomicClause(OmpClauses):
+    """Class representing the atomic clause."""
+    def __init__(self, **kwargs):
+        name = kwargs.pop('name')
+
+        self._expr = name
+
+        super().__init__(**kwargs)
+
+class OmpCancelType(OmpClauses):
+    """Class representing the type of the cancel construct."""
+    def __init__(self, **kwargs):
+        name = kwargs.pop('name')
+
+        self._expr = name
+
+        super().__init__(**kwargs)
+
+class AtomicMemoryClause(OmpClauses):
+    """Class representing the atomic memory clause."""
+    def __init__(self, **kwargs):
+        name = kwargs.pop('name')
+
+        self._expr = name
+
+        super().__init__(**kwargs)
+
+class OmpForSimd(OmpClauses):
+    """Class representing the combined For Simd construct."""
+    def __init__(self, **kwargs):
+        fname = kwargs.pop('fname')
+        sname = kwargs.pop('sname', None)
+
+        txt = fname
+        if sname:
+            txt = txt + ' ' + sname
+        self._expr = '{}'.format(txt)
+
+        super().__init__(**kwargs)
+
+class OmpMaskedTaskloop(OmpClauses):
+    """Class representing the combined Masked Taskloop construct."""
+    def __init__(self, **kwargs):
+        mname = kwargs.pop('mname')
+        tname = kwargs.pop('tname', None)
+        sname = kwargs.pop('sname', None)
+
+        txt = mname
+        if tname:
+            txt = txt + ' ' + tname
+            if sname:
+                txt = txt + ' ' + sname
+        self._expr = '{}'.format(txt)
+
+        super().__init__(**kwargs)
+
+class OmpPSections(OmpClauses):
+    """Class representing the combined Parallel Sections construct."""
+    def __init__(self, **kwargs):
+        sname = kwargs.pop('sname')
+
+        self._expr = sname
+
+        super().__init__(**kwargs)
+
+class OmpTaskloopSimd(OmpClauses):
+    """Class representing the combined Taskloop Simd comstruct."""
+    def __init__(self, **kwargs):
+        tname = kwargs.pop('tname')
+        sname = kwargs.pop('sname', None)
+
+        txt = tname
+        if sname:
+            txt += ' ' + sname
+        self._expr = txt
+
+        super().__init__(**kwargs)
+
+class OmpDistributeCombined(OmpClauses):
+    """Class representing the combined Distribute construct."""
+    def __init__(self, **kwargs):
+        dname  = kwargs.pop('dname')
+        sname  = kwargs.pop('sname', None)
+        pname  = kwargs.pop('pname', None)
+        fname  = kwargs.pop('fname', None)
+        ssname = kwargs.pop('ssname', None)
+
+        txt = dname
+        if sname:
+            txt += ' ' + sname
+        elif pname:
+            txt += ' ' + pname
+            txt += ' ' + fname
+            if ssname:
+                txt += ' ' + ssname
+        self._expr = txt
+
+        super().__init__(**kwargs)
+
+class OmpTargetParallel(OmpClauses):
+    """Class representing the combined Target Parallel construct."""
+    def __init__(self, **kwargs):
+        pname = kwargs.pop('pname')
+        fname = kwargs.pop('fname', None)
+        sname = kwargs.pop('sname', None)
+
+        txt = pname
+        if fname:
+            txt = ' ' + fname
+            if sname:
+                txt += ' ' + sname
+        self._expr = txt
+
+        super().__init__(**kwargs)
+
+class OmpTargetTeams(OmpClauses):
+    """Class representing the combined Target Teams construct."""
+    def __init__(self, **kwargs):
+        tname  = kwargs.pop('tname')
+        dname  = kwargs.pop('dname', None)
+        sname  = kwargs.pop('sname', None)
+        pname  = kwargs.pop('pname', None)
+        fname  = kwargs.pop('fname', None)
+        ssname = kwargs.pop('ssname', None)
+
+        txt = tname
+        if dname:
+            txt += ' ' + dname
+            if sname:
+                txt += ' ' + sname
+            else:
+                txt += ' ' + pname + ' ' + fname
+                if ssname:
+                    txt += ' ' + ssname
+        self._expr = txt
+
+        super().__init__(**kwargs)
 
-        if self.chunk_size:
-            return 'schedule({0}, {1})'.format(self.kind, self.chunk_size)
-        else:
-            return 'schedule({0})'.format(self.kind)
 #################################################
 
 #################################################
-# whenever a new rule is added in the grammar, we must update the following
-# lists.
-omp_directives = [OmpParallelConstruct,
+# whenever a new rule (construct/clause) is added in the grammar, we must update the following tuples.
+
+_valid_single_clauses = (OmpPrivate,
+                         OmpFirstPrivate)
+
+_valid_atomic_clauses = (OmpAtomicClause,
+                         AtomicMemoryClause)
+
+_valid_task_clauses = (OmpPriority,
+                       OmpFinal,
+                       OmpDefault,
+                       OmpPrivate,
+                       OmpShared,
+                       OmpFirstPrivate,
+                       OmpUntied,
+                       OmpMergeable,
+                       OmpinReduction,
+                       OmpDepend)
+
+_valid_target_clauses = (OmpPrivate,
+                         OmpLastPrivate,
+                         OmpinReduction,
+                         OmpDepend,
+                         OmpMap)
+
+_valid_teams_clauses = (OmpPrivate,
+                        OmpLastPrivate,
+                        OmpShared,
+                        OmpReduction,
+                        OmpNumTeams,
+                        OmpThreadLimit)
+
+_valid_sections_clauses = (OmpPrivate,
+                           OmpFirstPrivate,
+                           OmpLastPrivate,
+                           OmpReduction)
+
+_valid_Distribute_clauses = (OmpPrivate,
+                             OmpFirstPrivate,
+                             OmpLastPrivate,
+                             OmpCollapse)
+
+_valid_simd_clauses = (OmpLinear,
+                       OmpReduction,
+                       OmpCollapse,
+                       OmpLastPrivate)
+
+_valid_taskloop_clauses = (OmpShared,
+                           OmpPrivate,
+                           OmpFirstPrivate,
+                           OmpLastPrivate,
+                           OmpReduction,
+                           OmpinReduction,
+                           OmpNumTasks,
+                           OmpGrainSize,
+                           OmpCollapse,
+                           OmpUntied,
+                           OmpMergeable,
+                           OmpNogroup,
+                           OmpPriority)
+
+_valid_loop_clauses = (OmpPrivate,
+                       OmpFirstPrivate,
+                       OmpLastPrivate,
+                       OmpReduction,
+                       OmpSchedule,
+                       OmpCollapse,
+                       OmpLinear,
+                       OmpOrdered)
+
+_valid_parallel_clauses = (OmpNumThread,
+                           OmpDefault,
+                           OmpPrivate,
+                           OmpShared,
+                           OmpFirstPrivate,
+                           OmpCopyin,
+                           OmpReduction,
+                           OmpProcBind)
+
+omp_directives = (OmpParallelConstruct,
                   OmpLoopConstruct,
                   OmpSingleConstruct,
-                  OmpEndClause]
-
-omp_clauses = [OmpCollapse,
+                  OmpEndClause,
+                  OmpCriticalConstruct,
+                  OmpBarrierConstruct,
+                  OmpMasterConstruct,
+                  OmpMaskedConstruct,
+                  OmpTaskLoopConstruct,
+                  OmpSimdConstruct,
+                  OmpAtomicConstruct,
+                  OmpTaskWaitConstruct,
+                  OmpTaskyieldConstruct,
+                  OmpTaskConstruct,
+                  OmpFlushConstruct,
+                  OmpCancelConstruct,
+                  OmpTargetConstruct,
+                  OmpTeamsConstruct,
+                  OmpDistributeConstruct,
+                  OmpSectionsConstruct,
+                  OmpSectionConstruct)
+
+omp_clauses = (OmpCollapse,
                OmpCopyin,
                OmpFirstPrivate,
                OmpLastPrivate,
@@ -413,10 +771,34 @@ omp_clauses = [OmpCollapse,
                OmpPrivate,
                OmpReduction,
                OmpSchedule,
-               OmpShared]
-
-omp_classes = [Openmp, OpenmpStmt] + omp_directives + omp_clauses
-
+               OmpShared,
+               OmpCriticalName,
+               OmpFilter,
+               OmpinReduction,
+               OmpNumTasks,
+               OmpGrainSize,
+               OmpUntied,
+               OmpMergeable,
+               OmpNogroup,
+               OmpPriority,
+               OmpAtomicClause,
+               AtomicMemoryClause,
+               OmpDepend,
+               FlushList,
+               OmpFinal,
+               OmpCancelType,
+               OmpMap,
+               OmpNumTeams,
+               OmpThreadLimit,
+               OmpForSimd,
+               OmpMaskedTaskloop,
+               OmpPSections,
+               OmpTaskloopSimd,
+               OmpDistributeCombined,
+               OmpTargetParallel,
+               OmpTargetTeams)
+
+omp_classes = (Openmp, OpenmpStmt) + omp_directives + omp_clauses
 
 this_folder = dirname(__file__)
 
diff --git a/tutorial/openmp.md b/tutorial/openmp.md
index 01a9997e..f5bcecdd 100644
--- a/tutorial/openmp.md
+++ b/tutorial/openmp.md
@@ -282,14 +282,12 @@ x2 = 0
 for i in range(0, 100):
   #$ omp atomic
   x1 = x1 + 1 #Will be executed (100 x 2) times.
-  #$ omp end atomic
 
 #$ omp single
 #$ omp taskloop
 for i in range(0, 100):
   #$ omp atomic
   x2 = x2 + 1 #Will be executed (100) times.
-  #$ omp end atomic
 #$ omp end single
 
 #$ omp end parallel
@@ -374,7 +372,7 @@ def fib(n):
   return i+j
 
 #$ omp parallel
-#$ omp omp single
+#$ omp single
 print(fib(10))
 #$ omp end single
 #$ omp end parallel
@@ -458,6 +456,8 @@ flag: 2
 
 The ``` #$ omp cancel ``` is used to request cancellation of the innermost enclosing region of the type specified.
 ```python
+import numpy as np
+v = np.array([1, -5, 3, 4, 5])
 result = 0
 #$ omp parallel
 #$ omp for private(i) reduction (+:result)
@@ -465,7 +465,7 @@ for i in range(len(v)):
   result = result + v[i]
   if result < 0:
     #$ omp cancel for
-    break
+    pass
 #$ omp end parallel
 ```
 
@@ -503,14 +503,16 @@ The ``` #$ omp distribute ``` directive specifies that the iterations of one or
 from numpy import zeros
 from pyccel.stdlib.internal.openmp import omp_get_team_num
 n = 8
+threadlimit = 4
 a = zeros(n, dtype=int)
-#$ omp target map(to: n) map(tofrom: a)
-#$ omp teams num_teams(2) thread_limit(n/2)
+#$ omp target
+#$ omp teams num_teams(2) thread_limit(threadlimit)
 #$ omp distribute
 for i in range(0, n):
-  a[i] = omp_get_team_num()
+  a[i]    = omp_get_team_num()
 #$ omp end teams
 #$ omp end target
+
 for i in range(0, n):
   print("Team num :", a[i])
 ```
@@ -535,12 +537,14 @@ Team num : 1
 
 ```python
 #$ omp sections [clause[ [,]clause] ... ]
+
 #$ omp section
 structured-block-sequence
 #$ omp end section
 #$ omp section
 structured-block-sequence
 #$ omp end section
+
 #$ omp end sections
 ```
 
@@ -556,7 +560,7 @@ sum1 = 0
 sum2 = 0
 sum3 = 0
 #$ omp parallel num_threads(2)
-#$ omp omp sections
+#$ omp sections
 
 #$ omp section
 for i in range(0, int(n/3)):
@@ -575,8 +579,8 @@ for i in range(0, n):
   sum3 = sum3 + i
 print("sum3 :", sum3, ", thread :", omp_get_thread_num())
 #$ omp end section
-#$ omp omp end sections
 
+#$ omp end sections
 #$ omp end parallel
 ```
 
@@ -588,3 +592,197 @@ sum1 : 1, thread : 0
 sum2 : 6, thread : 0
 sum3 : 28, thread : 1
 ```
+
+## Combined Constructs Usage on Pyccel
+
+### parallel for
+
+#### Syntax of *parallel for*
+
+```python
+#$ omp parallel for [clause[ [,]clause] ... ]
+loop-nest
+```
+
+#### Example
+
+The ```#$ omp parallel for``` construct specifies a parallel construct containing a worksharingloop construct with a canonical loop nest.
+
+```python
+import numpy as np
+x = np.array([2,5,4,3,2,5,7])
+result = 0
+#$ omp parallel for reduction (+:result)
+for i in range(0, len(x)):
+    result += x[i]
+print("result:", result)
+```
+
+The output of this program is :
+```shell
+❯ pyccel omp_test.py --openmp
+❯ ./omp_test
+result: 28
+```
+
+### parallel for simd
+
+#### Syntax of *parallel for simd*
+
+```python
+#$ omp parallel for simd [clause[ [,]clause] ... ]
+loop-nest
+```
+
+#### Example
+
+The ```#$ omp parallel for simd``` construct specifies a parallel construct containing only one worksharing-loop SIMD construct.
+
+```python
+import numpy as np
+x = np.array([1,2,1,2,1,2,1,2])
+y = np.array([2,1,2,1,2,1,2,1])
+z = np.zeros(8, dtype = int)
+result = 0
+#$ omp parallel for simd
+for i in range(0, 8):
+    z[i] = x[i] + y[i]
+
+for i in range(0, 8):
+    print("z[",i,"] :", z[i])
+```
+
+The output of this program is :
+```shell
+❯ pyccel omp_test.py --openmp
+❯ ./omp_test
+z[ 0 ] : 3
+z[ 1 ] : 3
+z[ 2 ] : 3
+z[ 3 ] : 3
+z[ 4 ] : 3
+z[ 5 ] : 3
+z[ 6 ] : 3
+z[ 7 ] : 3
+```
+
+### teams distribute
+
+#### Syntax of *teams distribute*
+
+```python
+#$ omp teams distribute [clause[ [,]clause] ... ]
+loop-nest
+```
+
+### teams distribute simd
+
+#### Syntax of *teams distribut simd*
+
+```python
+#$ omp teams distribute simd [clause[ [,]clause] ... ]
+loop-nest
+```
+
+### teams distribute parallel for
+
+#### Syntax of *teams distribute parallel for*
+
+```python
+#$ omp teams distribute parallel for [clause[ [,]clause] ... ]
+loop-nest
+```
+
+### target parallel
+
+#### Syntax of *target parallel*
+
+```python
+#$ omp target parallel [clause[ [,]clause] ... ]
+structured-block
+#$ omp end target parallel
+```
+
+### target parallel for
+
+#### Syntax of *target parallel for*
+
+```python
+#$ omp target parallel for [clause[ [,]clause] ... ]
+loop-nest
+```
+
+### target parallel for simd
+
+#### Syntax of *target parallel for simd*
+
+```python
+#$ omp target parallel for simd [clause[ [,]clause] ... ]
+loop-nest
+```
+
+### target teams
+
+#### Syntax of *target teams*
+
+```python
+#$ omp target teams [clause[ [,]clause] ... ]
+structured-block
+#$ omp end target teams
+```
+
+### target teams distribute
+
+#### Syntax of *target teams distribute*
+
+```python
+#$ omp target teams distribute [clause[ [,]clause] ... ]
+loop-nest
+```
+
+### target teams distribute simd
+
+#### Syntax of *target teams distribute simd*
+
+```python
+#$ omp target teams distribute simd [clause[ [,]clause] ... ]
+loop-nest
+```
+
+### target teams distribute parallel for
+
+#### Syntax of *target teams distribute parallel for*
+
+```python
+#$ omp target teams distribute parallel for [clause[ [,]clause] ... ]
+loop-nest
+```
+
+### target teams distribute parallel for simd
+
+#### Syntax of *target teams distribute parallel for simd*
+
+```python
+#$ omp target teams distribute parallel for simd [clause[ [,]clause] ... ]
+loop-nest
+```
+
+#### Example
+
+The ```#$ omp parallel for simd``` construct specifies a parallel construct containing only one worksharing-loop SIMD construct.
+
+```python
+r = 0
+#$ omp target teams distribute parallel for reduction(+:r)
+for i in range(0, 10000):
+    r = r + i
+
+print("result:",r)
+```
+
+The output of this program is :
+```shell
+❯ pyccel omp_test.py --openmp
+❯ ./omp_test
+result: 49995000
+```


Test patch:
diff --git a/tests/epyccel/modules/openmp.py b/tests/epyccel/modules/openmp.py
index 8345fb32..a24c5edc 100644
--- a/tests/epyccel/modules/openmp.py
+++ b/tests/epyccel/modules/openmp.py
@@ -124,7 +124,7 @@ def test_omp_in_final():
 
     #$ omp parallel
     #$ omp single
-    #$ omp task final (i >= 10)
+    #$ omp task final(i >= 10)
     for i in range(x):
         z = z + i
         if omp_in_final() == 1:
@@ -197,7 +197,7 @@ def test_omp_is_initial_device():
 
 def test_omp_get_initial_device():
     from pyccel.stdlib.internal.openmp import omp_get_initial_device
-    #$ omp target device(deviceid)
+    #$ omp target
     host_device = omp_get_initial_device()
     #$ omp end target
     return host_device
@@ -219,13 +219,12 @@ def test_omp_get_set_schedule():
 def test_omp_get_max_task_priority():
     from pyccel.stdlib.internal.openmp import omp_get_max_task_priority
     result = 0
+    max_task_priority_var = 0
     #$ omp parallel
     #$ omp single
-    #$ omp task priority(i)
-    for i in range(10):
-        result = result + i
-        if i == 5:
-            max_task_priority_var = omp_get_max_task_priority()
+    #$ omp task
+    max_task_priority_var = omp_get_max_task_priority()
+    #$ omp end task
     #$ omp end single
     #$ omp end parallel
     return max_task_priority_var
@@ -238,7 +237,6 @@ def omp_matmul(A, x, out):
         for j in range(len(x[0])):# pylint: disable=C0200
             for k in range(len(x)):# pylint: disable=C0200
                 out[i][j] += A[i][k] * x[k][j]
-    #$ omp end for
     #$ omp end parallel
     #to let the function compile using epyccel issue #468
     "bypass issue #468" # pylint: disable=W0105
@@ -261,10 +259,28 @@ def omp_arraysum(x):
     #$ omp for reduction (+:result)
     for i in range(0, 5):
         result += x[i]
-    #$ omp end for
     #$ omp end parallel
     return result
 
+@types('int[:]')
+def omp_arraysum_combined(x):
+    result = 0
+    #$ omp parallel for reduction (+:result)
+    for i in range(0, 5):
+        result += x[i]
+    return result
+
+@types('int')
+def omp_range_sum_critical(x):
+    result = 0
+    #$ omp parallel for num_threads(4) shared(result)
+    for i in range(0, x):
+        #$ omp critical
+        result += i
+        #$ omp end critical
+    return result
+
+
 @types('int[:]')
 def omp_arraysum_single(x):
     result = 0
@@ -275,3 +291,133 @@ def omp_arraysum_single(x):
     #$ omp end single
     #$ omp end parallel
     return result
+
+def omp_master():
+    result = 30
+    #$omp parallel num_threads(3) reduction(+:result)
+    #$omp master
+    result += 1
+    #$omp end master
+    #$omp end parallel
+    return result
+
+@types('int')
+def omp_taskloop(n):
+    result = 0
+    #$omp parallel num_threads(n)
+    #$omp taskloop
+    for i in range(0, 10): # pylint: disable=unused-variable
+        #$omp atomic
+        result = result + 1
+    #$omp end parallel
+    return result
+
+@types('int')
+def omp_tasks(x):
+    @types('int', results='int')
+    def fib(n):
+        if n < 2:
+            return n
+        #$ omp task shared(i) firstprivate(n)
+        i = fib(n-1)
+        #$ omp end task
+        #$ omp task shared(j) firstprivate(n)
+        j = fib(n-2)
+        #$ omp end task
+        #$ omp taskwait
+        return i + j
+    #$ omp parallel
+    #$ omp single
+    m = fib(x)
+    #$ omp end single
+    #$ omp end parallel
+    return m
+
+@types('int')
+def omp_simd(n):
+    from numpy import zeros
+    result = 0
+    arr = zeros(n, dtype=int)
+    #$ omp parallel num_threads(4)
+    #$ omp simd
+    for i in range(0, n):
+        arr[i] = i
+    #$ omp end parallel
+    for i in range(0, n):
+        result = result + arr[i]
+    return result
+
+def omp_flush():
+    from pyccel.stdlib.internal.openmp import omp_get_thread_num
+    flag = 0
+    #$ omp parallel num_threads(2)
+    if omp_get_thread_num() == 0:
+        #$ omp atomic update
+        flag = flag + 1
+    elif omp_get_thread_num() == 1:
+        #$ omp flush(flag)
+        while flag < 1:
+            pass
+            #$ omp flush(flag)
+        #$ omp atomic update
+        flag = flag + 1
+    #$ omp end parallel
+    return flag
+
+def omp_barrier():
+    from numpy import zeros
+    arr = zeros(1000, dtype=int)
+    result = 0
+    #$ omp parallel num_threads(3)
+    #$ omp for
+    for i in range(0, 1000):
+        arr[i] = i * 2
+
+    #$ omp barrier
+    #$ omp for reduction(+:result)
+    for i in range(0, 1000):
+        result = result + arr[i]
+    #$ omp end parallel
+    return result
+
+def combined_for_simd():
+    import numpy as np
+    x = np.array([1,2,1,2,1,2,1,2])
+    y = np.array([2,1,2,1,2,1,2,1])
+    z = np.zeros(8, dtype = int)
+    result = 0
+    #$ omp parallel for simd
+    for i in range(0, 8):
+        z[i] = x[i] + y[i]
+
+    for i in range(0, 8):
+        result = result + z[i]
+    return result
+
+def omp_sections():
+    n = 8
+    sum1 = 0
+    sum2 = 0
+    sum3 = 0
+    #$ omp parallel num_threads(2)
+    #$ omp sections
+
+    #$ omp section
+    for i in range(0, int(n/3)):
+        sum1 = sum1 + i
+    #$ omp end section
+
+    #$ omp section
+    for i in range(0, int(n/2)):
+        sum2 = sum2 + i
+    #$ omp end section
+
+    #$ omp section
+    for i in range(0, n):
+        sum3 = sum3 + i
+    #$ omp end section
+    #$ omp end sections
+
+    #$ omp end parallel
+
+    return (sum1 + sum2 + sum3)
diff --git a/tests/epyccel/test_epyccel_openmp.py b/tests/epyccel/test_epyccel_openmp.py
index d1e1be34..c2684b95 100644
--- a/tests/epyccel/test_epyccel_openmp.py
+++ b/tests/epyccel/test_epyccel_openmp.py
@@ -2,6 +2,7 @@
 # pylint: disable=wildcard-import
 import multiprocessing
 import os
+import sys
 import pytest
 import numpy as np
 import modules.openmp as openmp
@@ -121,7 +122,7 @@ def test_modules_11(language):
     set_num_threads(8)
     assert f1() == 8
 
-@pytest.mark.xfail(reason = "Tasks not supported yet for openmp !")
+@pytest.mark.xfail(reason = "arithmetic expression not managed yet inside a clause !")
 def test_modules_12(language):
     f1 = epyccel(openmp.test_omp_in_final, accelerator='openmp', language=language)
 
@@ -134,7 +135,7 @@ def test_modules_13(language):
 
 @pytest.mark.parametrize( 'language', [
         pytest.param("c", marks = [
-            pytest.mark.xfail(reason="omp_get_num_devices and omp_get_default_device unrecognized in C !"),
+            pytest.mark.xfail(sys.platform == 'darwin', reason="omp_get_num_devices and omp_get_default_device unrecognized in C !"),
             pytest.mark.c]),
         pytest.param("fortran", marks = pytest.mark.fortran)
     ]
@@ -144,30 +145,50 @@ def test_modules_14_0(language):
     f2 = epyccel(openmp.test_omp_get_num_devices, accelerator='openmp', language=language)
 
     assert f1(1) == 1
-    assert f1(0) == 0
+    assert f1(2) == 2
     assert f2() >= 0
 
-# omp_get_initial_device give a compilation error on Travis (Linux and Windows), also Target construct not implemented yet !"
 def test_modules_14_1(language):
     f3 = epyccel(openmp.test_omp_is_initial_device, accelerator='openmp', language=language)
-    # f4 = epyccel(openmp.test_omp_get_initial_device, accelerator='openmp') #Target construct not implemented yet and need a non-host device to test the function
+    f4 = epyccel(openmp.test_omp_get_initial_device, accelerator='openmp') #Needs a non-host device to test the function properly
 
     assert f3() == 1
+    assert f4() == 0
+
+@pytest.mark.parametrize( 'language', [
+        pytest.param("c", marks = [
+            pytest.mark.xfail(reason="omp_get_team_num() return a wrong result!"),
+            pytest.mark.c]),
+        pytest.param("fortran", marks = [
+            pytest.mark.xfail(reason="Compilation fails on github action"),
+            pytest.mark.fortran])
 
-@pytest.mark.xfail(reason = "Teams not supported yet for openmp !")
+    ]
+)
 def test_modules_15(language):
+    f1 = epyccel(openmp.test_omp_get_team_num, accelerator='openmp', language=language)
+
+    assert f1(0) == 0
+    assert f1(1) == 1
+
+@pytest.mark.parametrize( 'language', [
+        pytest.param("c", marks = [
+            pytest.mark.xfail(reason="omp_get_num_teams() return a wrong result!"),
+            pytest.mark.c]),
+        pytest.param("fortran", marks = [
+            pytest.mark.xfail(reason="Compilation fails on github action"),
+            pytest.mark.fortran])
+    ]
+)
+def test_modules_15_1(language):
     f1 = epyccel(openmp.test_omp_get_num_teams, accelerator='openmp', language=language)
-    f2 = epyccel(openmp.test_omp_get_team_num, accelerator='openmp', language=language)
 
     assert f1() == 2
-    assert f2(0) == 0
-    assert f2(1) == 1
 
-@pytest.mark.xfail(reason = "Tasks not supported yet for openmp !")
 def test_modules_16(language):
     f1 = epyccel(openmp.test_omp_get_max_task_priority, accelerator='openmp', language=language)
 
-    assert f1() == 5
+    assert f1() == 0 # omp_get_max_task_priority() return always 0
 
 @pytest.mark.parametrize( 'language', [
         pytest.param("c", marks = [
@@ -241,13 +262,7 @@ def test_omp_matmul_2d_2d(language):
 
     assert np.array_equal(y1, y2)
 
-@pytest.mark.parametrize( 'language', [
-        pytest.param("c", marks = [
-            pytest.mark.xfail(reason="for reduction doesn't work in C"),
-            pytest.mark.c]),
-        pytest.param("fortran", marks = pytest.mark.fortran)
-    ]
-)
+
 def test_omp_arraysum(language):
     f1 = epyccel(openmp.omp_arraysum, accelerator='openmp', language=language)
     set_num_threads = epyccel(openmp.set_num_threads, accelerator='openmp', language=language)
@@ -257,6 +272,23 @@ def test_omp_arraysum(language):
 
     assert f1(x) == np.sum(x)
 
+def test_omp_arraysum_combined(language):
+    f1 = epyccel(openmp.omp_arraysum_combined, accelerator='openmp', language=language)
+    set_num_threads = epyccel(openmp.set_num_threads, accelerator='openmp', language=language)
+    set_num_threads(4)
+    from numpy import random
+    x = random.randint(20, size=(5))
+
+    assert f1(x) == np.sum(x)
+
+def test_omp_range_sum_critical(language):
+    f1 = epyccel(openmp.omp_range_sum_critical, accelerator='openmp', language=language)
+    from numpy import random
+
+    for _ in range(0, 4):
+        x = random.randint(10, 1000)
+        assert f1(x) == openmp.omp_range_sum_critical(x)
+
 def test_omp_arraysum_single(language):
     f1 = epyccel(openmp.omp_arraysum_single, accelerator='openmp', language=language)
     set_num_threads = epyccel(openmp.set_num_threads, accelerator='openmp', language=language)
@@ -265,3 +297,56 @@ def test_omp_arraysum_single(language):
     x = random.randint(20, size=(10))
 
     assert f1(x) == np.sum(x)
+
+def test_omp_master(language):
+    f1 = epyccel(openmp.omp_master, accelerator='openmp', language=language)
+    assert f1() == openmp.omp_master()
+
+def test_omp_taskloop(language):
+    f1 = epyccel(openmp.omp_taskloop, accelerator='openmp', language=language)
+    from numpy import random
+
+    for _ in range(0, 4):
+        x = random.randint(1, 4)
+        result = 0
+        for _ in range(0, x * 10):
+            result = result + 1
+        assert result == f1(x)
+
+@pytest.mark.parametrize( 'language', [
+        pytest.param("c", marks = [
+            pytest.mark.xfail(reason="Nested functions not handled for C !"),
+            pytest.mark.c]),
+            pytest.param("fortran", marks = pytest.mark.fortran)
+    ]
+)
+def test_omp_tasks(language):
+    f1 = epyccel(openmp.omp_tasks, accelerator='openmp', language=language)
+    from numpy import random
+
+    for _ in range(0, 4):
+        x = random.randint(10, 20)
+        assert openmp.omp_tasks(x) == f1(x)
+
+def test_omp_simd(language):
+    f1 = epyccel(openmp.omp_simd, accelerator='openmp', language=language)
+    assert openmp.omp_simd(1337) == f1(1337)
+
+def test_omp_flush(language):
+    f1 = epyccel(openmp.omp_flush, accelerator='openmp', language=language)
+    assert 2 == f1()
+
+def test_omp_barrier(language):
+    f1 = epyccel(openmp.omp_barrier, accelerator='openmp', language=language)
+    f2 = openmp.omp_barrier
+    assert f1() == f2()
+
+def test_combined_for_simd(language):
+    f1 = epyccel(openmp.combined_for_simd, accelerator='openmp', language=language)
+    f2 = openmp.combined_for_simd
+    assert f1() == f2()
+
+def test_omp_sections(language):
+    f1 = epyccel(openmp.omp_sections, accelerator='openmp', language=language)
+    f2 = openmp.omp_sections
+    assert f1() == f2()