PyForTool
Python-fortran-tool
Loading...
Searching...
No Matches
openacc.py
1"""
2This module implements the Openacc class containing the methods relative to openacc
3"""
4
5import re
6
7from pyfortool.util import debugDecor, n2name, alltext, tag
8from pyfortool.expressions import createElem, createExpr
9
10
11class Openacc():
12 """
13 Methods relative to openacc
14 """
15 @debugDecor
16 def removeACC(self):
17 """
18 Remove openACC directives
19 """
20 self.removeComments(exclDirectives=[],
21 pattern=re.compile(r'^\!\$ACC ', re.IGNORECASE))
22
23 @debugDecor
25 """
26 Remove macro !$mnh_(un)def(OPENACC) and !$mnh_(un)def(LOOP) directives
27 for other compiler than Cray
28 """
29
30 self.removeComments(exclDirectives=[],
31 pattern=re.compile(r'^\!\$mnh_undef\‍(LOOP\‍)'))
32 self.removeComments(exclDirectives=[],
33 pattern=re.compile(r'^\!\$mnh_undef\‍(OPENACC\‍)'))
34 self.removeComments(exclDirectives=[],
35 pattern=re.compile(r'^\!\$mnh_define\‍(LOOP\‍)'))
36 self.removeComments(exclDirectives=[],
37 pattern=re.compile(r'^\!\$mnh_define\‍(OPENACC\‍)'))
38
39 @debugDecor
41 """
42 By pass a bug of the CRAY compiler in which the vectorisation is not done with
43 BR_ fonctions use or locally.
44 On all expanded compute kernels with !$acc loop independent collapse(X) placed:
45 - if BR_ fonction is used : !$acc loop independent collapse(X) is removed and
46 the nested DO loops are factorised into DO CONCURRENT
47 - if a mnh_undef(OPENACC) macro is in place, !$acc loop collapse independant(X)
48 is removed
49 - if a mnh_undef(LOOP) macro is in place the nested DO loops are factorised into
50 DO CONCURRENT
51 """
52 def checkPresenceofBR(node):
53 """Return True if a BR_ (math BIT-REPRODUCTIBILITY) function is present in the node"""
54 mathBRList = ['ALOG', 'LOG', 'EXP', 'COS', 'SIN', 'ASIN', 'ATAN', 'ATAN2',
55 'P2', 'P3', 'P4']
56 namedE = node.findall('.//{*}named-E/{*}N/{*}n')
57 for el in namedE:
58 if alltext(el) in ['BR_' + e for e in mathBRList]:
59 return True
60 return False
61
62 def getStatementsInDoConstruct(node, savelist):
63 for sNode in node:
64 if 'do-construct' in tag(sNode):
65 getStatementsInDoConstruct(sNode, savelist)
66 elif 'do-stmt' not in tag(sNode):
67 savelist.append(sNode)
68
69 useNestedLoops = True # Cray compiler needs nested loops by default
70 useAccLoopIndependent = True # It needs nested !$acc loop independent collapse(X)
71 toremove = [] # list of nodes to remove
72 comments = self.findall('.//{*}C')
73
74 for comment in comments:
75 if comment.text.startswith('!$mnh_undef(LOOP)'):
76 useNestedLoops = False # Use DO CONCURRENT
77 if comment.text.startswith('!$mnh_undef(OPENACC)'):
78 useAccLoopIndependent = False
79
80 if comment.text.startswith('!$mnh_define(LOOP)'):
81 useNestedLoops = True # Use DO CONCURRENT
82 if comment.text.startswith('!$mnh_define(OPENACC)'):
83 useAccLoopIndependent = True
84
85 if comment.text.startswith('!$acc loop independent collapse('):
86 # Get the statements content in the DO-construct
87 par = self.getParent(comment)
88 ind = list(par).index(comment)
89 nestedLoop = par[ind + 1]
90 statements = []
91 getStatementsInDoConstruct(nestedLoop, statements)
92
93 # Check presence of BR_ within the statements
94 isBRPresent = False
95 for stmt in statements:
96 if checkPresenceofBR(stmt):
97 isBRPresent = True
98 break
99
100 # Remove !$acc loop independent collapse
101 # if BR_ is present or if !$mnh_undef(OPENACC)
102 if not useAccLoopIndependent or isBRPresent:
103 toremove.append((self, comment))
104
105 # Use DO CONCURRENT instead of nested-loop if BR_ is present or if !$mnh_undef(LOOP)
106 if not useNestedLoops or isBRPresent:
107 # Determine the table of indices
108 doStmt = nestedLoop.findall('.//{*}do-stmt')
109 table = {}
110 for do in reversed(doStmt):
111 table[do.find('.//{*}do-V/{*}named-E/{*}N/{*}n').text] = \
112 [alltext(do.find('.//{*}lower-bound')),
113 alltext(do.find('.//{*}upper-bound'))]
114
115 # Create the do-construct
116 inner, outer, _ = self.createDoConstruct(table,
117 indent=len(nestedLoop.tail),
118 concurrent=True)
119
120 # Insert the statements in the new do-construct
121 for stmt in statements:
122 inner.insert(-1, stmt)
123
124 # Insert the new do-construct and delete all the old do-construct
125 par.insert(ind, outer)
126 toremove.append((par, nestedLoop))
127
128 # Suppression of nodes
129 for parent, elem in toremove:
130 parent.remove(elem)
131
132 @debugDecor
133 def addACCData(self):
134 """
135 1) Add after declaration:
136 !$acc data present ( list of intent arrays)
137 2) Add at the end of the routine
138 !$acc end data
139 """
140 scopes = self.getScopes()
141 if scopes[0].path.split('/')[-1].split(':')[1][:4] == 'MODD':
142 return
143 for scope in scopes:
144 # Do not add !$acc data directives to :
145 # - MODULE or FUNCTION object,
146 # - interface subroutine from a MODI
147 # but only to SUBROUTINES
148 if 'sub:' in scope.path and 'func' not in scope.path and 'interface' not in scope.path:
149 # Look for all intent arrays only
150 arraysIntent = []
151 for var in scope.varList:
152 # intent arrays, not of type TYPE (only REAL, INTEGER, CHARACTER)
153 if var['arg'] and var['as'] and 'TYPE' not in var['t'] and \
154 var['scopePath'] == scope.path:
155 arraysIntent.append(var['n'])
156 # Check if there is any intent variables
157 if len(arraysIntent) == 0:
158 break
159
160 # 1) First !$acc data present()
161 listVar = "!$acc data present ( "
162 count = 0
163 for var in arraysIntent:
164 if count > 6:
165 listVar = listVar + '\n!$acc & '
166 count = 0
167 listVar = listVar + var + ", &"
168 count += 1
169 listVarEnd = listVar[:-3] # remove last comma and &
170 accAddMultipleLines = createExpr(listVarEnd + ')')
171 idx = scope.insertStatement(scope.indent(accAddMultipleLines[0]), first=True)
172
173 # 2) multi-lines !$acc &
174 for iLine, line in enumerate(accAddMultipleLines[1:]):
175 scope.insert(idx + 1 + iLine, line)
176
177 # 3) !$acc end data
178 comment = createElem('C', text='!$acc end data', tail='\n')
179 scope.insertStatement(scope.indent(comment), first=False)
180
181 @debugDecor
182 def addACCRoutineSeq(self, stopScopes):
183 """
184 Adds the '!$acc routine (<name>) seq' directive
185 :param stopScopes: scope paths where we stop to add the directive
186 """
187 for scope in self.getScopes():
188 if self.tree.isUnderStopScopes(scope.path, stopScopes,
189 includeInterfaces=True,
190 includeStopScopes=True):
191 name = n2name(scope[0].find('.//{*}N')).upper()
192 acc = createElem('C', text=f'!$acc routine ({name}) seq',
193 tail=scope[0].tail)
194 scope[0].tail = '\n'
195 scope.insert(1, acc)
addACCRoutineSeq(self, stopScopes)
Definition openacc.py:182