154 loopVar=None, reuseLoop=True, funcList=None,
155 updateMemSet=False, updateCopy=False, addAccIndependentCollapse=True):
157 Transform array syntax into DO loops
158 :param concurrent: use 'DO CONCURRENT' instead of simple 'DO' loops
159 :param useMnhExpand: use the mnh directives to transform the entire bloc in a single loop
160 :param everywhere: transform all array syntax in DO loops
161 :param loopVar: None to create new variable for each added DO loop, or
162 a function that return the name of the variable to use for the loop control.
163 This function returns a string (name of the variable), or True to create
164 a new variable, or False to not transform this statement
165 The functions takes as arguments:
166 - lower and upper bounds as defined in the declaration statement
167 - lower and upper bounds as given in the statement
170 :param reuseLoop: if True, try to reuse loop created whith everywhere=True
171 :param funcList: list of entity names that must be recognized as array functions
172 (in addition to the intrisic ones) to discard from transformation
173 statements that make use of them. None is equivalent to an empty list.
174 :param updateMemSet: True to put affectation to constante in DO loops
175 :param updateCopy: True to put array copy in DO loops
176 :param addAccIndependentCollapse: True to add !$acc loop independent collapse(X) before
179 Notes: * With useMnhExpand, the function checks if the coding is conform to what is needed
180 for the filepp/mnh_expand tool (to not breack compatibility with this tool)
181 * Arrays are transformed only if ':' are used.
182 A=A(:) is not transformed at all (or raises an exception if found in a WHERE block)
183 A(:)=A is wrongly transformed into "DO...; A(J1)=A; ENDDO" and will produce a
185 WHERE(L) X(:)=0. is not transformed at all (unknown behaviour in case
187 * This function is not compatible with functions that return arrays:
188 X(1:5)=FUNC(1) will be transformed into "DO J1=1,5; X(J1)=FUNC(1); ENDDO"
189 x(1:5)=FUNC(X(1:5)) will be transformed into "DO J1=1,5; X(J1)=FUNC(X(J1)); ENDDO"
190 But intrinsic functions (COUNT, ANY...) are recognised and corresponding statements
192 The list of intrinsic array functions can be extended by user functions with the
229 def decode(directive):
231 Decode mnh_expand directive
232 :param directive: mnh directive text
233 :return: (table, kind) where
234 table is a dictionnary: keys are variable names, values are tuples with first
236 kind is 'array' or 'where'
244 table = directive.split(
'(')[1].split(
')')[0].split(
',')
245 table = {c.split(
'=')[0]: c.split(
'=')[1].split(
':')
247 table.pop(
'OPENACC',
None)
248 if directive.lstrip(
' ').startswith(
'!$mnh_expand'):
249 kind = directive[13:].lstrip(
' ').split(
'(')[0].strip()
251 kind = directive[17:].lstrip(
' ').split(
'(')[0].strip()
254 def updateStmt(stmt, table, kind, extraindent, parent, scope):
256 Updates the statement given the table dictionnary '(:, :)' is replaced by '(JI, JK)' if
257 table.keys() is ['JI', 'JK']
258 :param stmt: statement to update
259 :param table: dictionnary retruned by the decode function
260 :param kind: kind of mnh directives: 'array' or 'where'
261 or None if transformation is not governed by
263 :param scope: current scope
266 def addExtra(node, extra):
267 """Helper function to add indentation spaces"""
268 if extra != 0
and (node.tail
is not None)
and '\n' in node.tail:
274 node.tail = re.sub(
r"(\n[ ]*)(\Z|[^\n ]+)",
275 r"\1" + extra *
' ' +
r"\2", node.tail)
277 addExtra(stmt, extraindent)
280 elif tag(stmt) ==
'cpp':
281 i = list(parent).index(stmt)
286 parent[i - 1].tail = parent[i - 1].tail.rstrip(
' ')
287 elif tag(stmt) ==
'a-stmt':
288 sss = stmt.findall(
'./{*}E-1/{*}named-E/{*}R-LT/{*}array-R/' +
289 '{*}section-subscript-LT/{*}section-subscript')
290 if len([ss
for ss
in sss
if ':' in alltext(ss)]) != len(table):
291 raise PYFTError(
"Inside code sections to transform in DO loops, " +
292 "all affectations must use ':'.\n" +
293 "This is not the case in:\n{stmt}".format(stmt=alltext(stmt)))
294 if stmt.find(
'./{*}E-1/{*}named-E/{*}N').tail
is not None and kind
is not None:
295 raise PYFTError(
"To keep the compatibility with the filepp version of loop " +
296 "expansion, nothing must appear between array names and " +
297 "opening parethesis inside mnh directive sections.")
300 for namedE
in stmt.findall(
'.//{*}R-LT/..'):
301 scope.arrayR2parensR(namedE, table)
302 for cnt
in stmt.findall(
'.//{*}cnt'):
303 addExtra(cnt, extraindent)
304 elif tag(stmt) ==
'if-stmt':
306 "An if statement is inside a code section transformed in DO loop in %s",
309 updateStmt(stmt.find(
'./{*}action-stmt')[0], table, kind, 0, stmt, scope)
310 elif tag(stmt) ==
'if-construct':
312 "An if construct is inside a code section transformed in DO loop in %s",
315 for ifBlock
in stmt.findall(
'./{*}if-block'):
316 for child
in ifBlock:
317 if tag(child)
not in (
'if-then-stmt',
'else-if-stmt',
318 'else-stmt',
'end-if-stmt'):
319 updateStmt(child, table, kind, extraindent, ifBlock, scope)
322 addExtra(child, extraindent)
323 for cnt
in child.findall(
'.//{*}cnt'):
325 addExtra(cnt, extraindent)
326 elif tag(stmt) ==
'where-stmt':
328 stmt.tag = f
'{{{NAMESPACE}}}if-stmt'
329 stmt.text =
'IF (' + stmt.text.split(
'(', 1)[1]
331 updateStmt(stmt.find(
'./{*}action-stmt')[0], table, kind,
332 extraindent, stmt, scope)
333 mask = stmt.find(
'./{*}mask-E')
334 mask.tag = f
'{{{NAMESPACE}}}condition-E'
335 for namedE
in mask.findall(
'.//{*}R-LT/..'):
336 scope.arrayR2parensR(namedE, table)
337 for cnt
in stmt.findall(
'.//{*}cnt'):
338 addExtra(cnt, extraindent)
339 elif tag(stmt) ==
'where-construct':
340 if kind !=
'where' and kind
is not None:
341 raise PYFTError(
'To keep the compatibility with the filepp version of loop " + \
342 "expansion, no where construct must appear " + \
343 "in mnh_expand_array blocks.')
345 stmt.tag = f
'{{{NAMESPACE}}}if-construct'
347 for whereBlock
in stmt.findall(
'./{*}where-block'):
348 whereBlock.tag = f
'{{{NAMESPACE}}}if-block'
349 for child
in whereBlock:
350 if tag(child) ==
'end-where-stmt':
352 child.tag = f
'{{{NAMESPACE}}}end-if-stmt'
353 child.text =
'END IF'
355 addExtra(child, extraindent)
356 elif tag(child)
in (
'where-construct-stmt',
'else-where-stmt'):
358 addExtra(child, extraindent)
359 if tag(child) ==
'where-construct-stmt':
361 child.tag = f
'{{{NAMESPACE}}}if-then-stmt'
362 child.text =
'IF (' + child.text.split(
'(', 1)[1]
367 if '(' in child.text:
369 child.tag = f
'{{{NAMESPACE}}}else-if-stmt'
370 child.text =
'ELSE IF (' + child.text.split(
'(', 1)[1]
373 child.tag = f
'{{{NAMESPACE}}}else-stmt'
375 for mask
in child.findall(
'./{*}mask-E'):
377 mask.tag = f
'{{{NAMESPACE}}}condition-E'
379 for namedE
in mask.findall(
'.//{*}R-LT/..'):
381 scope.arrayR2parensR(namedE, table)
382 for cnt
in child.findall(
'.//{*}cnt'):
384 addExtra(cnt, extraindent)
386 updateStmt(child, table, kind, extraindent, whereBlock, scope)
388 raise PYFTError(
'Unexpected tag found in mnh_expand ' +
389 'directives: {t}'.format(t=tag(stmt)))
392 def closeLoop(loopdesc):
393 """Helper function to deal with indentation"""
395 inner, outer, indent, extraindent = loopdesc
396 if inner[-2].tail
is not None:
398 outer.tail = inner[-2].tail[:-extraindent]
399 inner[-2].tail =
'\n' + (indent + extraindent - 2) *
' '
406 def recur(elem, scope):
410 for ie, sElem
in enumerate(list(elem)):
411 if tag(sElem) ==
'C' and sElem.text.lstrip(
' ').startswith(
'!$mnh_expand')
and \
415 raise PYFTError(
'Nested mnh_directives are not allowed')
417 inEverywhere = closeLoop(inEverywhere)
420 table, kind = decode(sElem.text)
422 indent = len(sElem.tail) - len(sElem.tail.rstrip(
' '))
423 toremove.append((elem, sElem))
427 if elem[ie - 1].tail
is None:
428 elem[ie - 1].tail =
''
429 elem[ie - 1].tail += sElem.tail.replace(
'\n',
'', 1).rstrip(
' ')
432 if addAccIndependentCollapse:
433 accCollapse = createElem(
'C', text=
'!$acc loop independent collapse(' +
434 str(len(table.keys())) +
')',
435 tail=
'\n' + indent *
' ')
436 toinsert.append((elem, accCollapse, ie))
439 inner, outer, extraindent = scope.createDoConstruct(table, indent=indent,
440 concurrent=concurrent)
441 toinsert.append((elem, outer, ie))
443 elif (tag(sElem) ==
'C' and
444 sElem.text.lstrip(
' ').startswith(
'!$mnh_end_expand')
and useMnhExpand):
447 raise PYFTError(
'End mnh_directive found before begin directive ' +
448 'in {f}'.format(f=scope.getFileName()))
449 if (table, kind) != decode(sElem.text):
450 raise PYFTError(
"Opening and closing mnh directives must be conform " +
451 "in {f}".format(f=scope.getFileName()))
453 toremove.append((elem, sElem))
457 outer.tail += sElem.tail.replace(
'\n',
'', 1)
459 elem[ie - 1].tail = elem[ie - 1].tail[:-2]
463 toremove.append((elem, sElem))
464 inner.insert(-1, sElem)
466 updateStmt(sElem, table, kind, extraindent, inner, scope)
468 elif everywhere
and tag(sElem)
in (
'a-stmt',
'if-stmt',
'where-stmt',
473 if tag(sElem) ==
'a-stmt':
475 arr = sElem.find(
'./{*}E-1/{*}named-E/{*}R-LT/{*}array-R/../..')
479 nodeE2 = sElem.find(
'./{*}E-2')
481 num = len(nodeE2.findall(
'.//{*}array-R'))
488 elif (len(nodeE2) == 1
and tag(nodeE2[0]) ==
'named-E' and num == 1
and
489 nodeE2[0].find(
'.//{*}parens-R')
is None):
495 if (isMemSet
and not updateMemSet)
or (isCopy
and not updateCopy):
497 elif tag(sElem) ==
'if-stmt':
499 arr = sElem.find(
'./{*}action-stmt/{*}a-stmt/{*}E-1/' +
500 '{*}named-E/{*}R-LT/{*}array-R/../..')
503 scope.changeIfStatementsInIfConstructs(singleItem=sElem)
506 elif tag(sElem) ==
'where-stmt':
507 arr = sElem.find(
'./{*}mask-E//{*}named-E/{*}R-LT/{*}array-R/../..')
508 elif tag(sElem) ==
'where-construct':
509 arr = sElem.find(
'./{*}where-block/{*}where-construct-stmt/' +
510 '{*}mask-E//{*}named-E/{*}R-LT/{*}array-R/../..')
517 elif len(set(alltext(a).count(
':')
518 for a
in sElem.findall(
'.//{*}R-LT/{*}array-R'))) > 1:
522 elif len(set([
'ALL',
'ANY',
'COSHAPE',
'COUNT',
'CSHIFT',
'DIMENSION',
523 'DOT_PRODUCT',
'EOSHIFT',
'LBOUND',
'LCOBOUND',
'MATMUL',
524 'MAXLOC',
'MAXVAL',
'MERGE',
'MINLOC',
'MINVAL',
'PACK',
525 'PRODUCT',
'REDUCE',
'RESHAPE',
'SHAPE',
'SIZE',
'SPREAD',
526 'SUM',
'TRANSPOSE',
'UBOUND',
'UCOBOUND',
'UNPACK'] +
527 (funcList
if funcList
is not None else [])
528 ).intersection(set(n2name(nodeN)
for nodeN
529 in sElem.findall(
'.//{*}named-E/{*}N')))) > 0:
535 newtable, varNew = scope.findArrayBounds(arr, loopVar, newVarList)
538 if var
not in newVarList:
539 newVarList.append(var)
546 inEverywhere = closeLoop(inEverywhere)
549 if not (inEverywhere
and table == newtable):
551 inEverywhere = closeLoop(inEverywhere)
553 if ie != 0
and elem[ie - 1].tail
is not None:
556 tail = tailSave.get(elem[ie - 1], elem[ie - 1].tail)
557 indent = len(tail) - len(tail.rstrip(
' '))
563 inner, outer, extraindent = scope.createDoConstruct(
564 table, indent=indent, concurrent=concurrent)
565 toinsert.append((elem, outer, ie))
566 inEverywhere = (inner, outer, indent, extraindent)
567 tailSave[sElem] = sElem.tail
568 toremove.append((elem, sElem))
569 inner.insert(-1, sElem)
571 updateStmt(sElem, table, kind, extraindent, inner, scope)
574 inEverywhere = closeLoop(inEverywhere)
577 inEverywhere = closeLoop(inEverywhere)
581 inEverywhere = closeLoop(inEverywhere)
583 for scope
in self.getScopes():
586 for elem, outer, ie
in toinsert[::-1]:
587 elem.insert(ie, outer)
589 for parent, elem
in toremove:
592 self.addVar([(v[
'scopePath'], v[
'n'], f
"INTEGER :: {v['n']}",
None)
593 for v
in newVarList])
663 def inline(self, subContained, callStmt, mainScope,
664 simplify=False, loopVar=None):
666 Inline a subContainted subroutine
668 - update the main code if needed (if statement and/or elemental)
669 - copy the subContained node
670 - remove everything before the declarations variables and the variables declarations
671 - deal with optional argument
672 - from the callStmt, replace all the arguments by their names
673 - inline in the main code
674 - add local variables and use statements to the main code
675 :param subContained: xml fragment corresponding to the sub: to inline
676 :param callStmt: the call-stmt to replace
677 :param mainScope: scope of the main (calling) subroutine
678 :param simplify: try to simplify code (construct or variables becoming useless)
679 :param loopVar: None to create new variable for each added DO loop (around ELEMENTAL
681 or a function that return the name of the variable to use for the
683 This function returns a string (name of the variable), or True to create
684 a new variable, or False to not transform this statement
685 The functions takes as arguments:
686 - lower and upper bounds as defined in the declaration statement
687 - lower and upper bounds as given in the statement
691 def setPRESENTby(node, var, val):
693 Replace PRESENT(var) by .TRUE. if val is True, by .FALSE. otherwise on node
695 :param node: xml node to work on (a contained subroutine)
696 :param var: string of the name of the optional variable to check
698 for namedE
in node.findall(
'.//{*}named-E/{*}N/..'):
699 if n2name(namedE.find(
'./{*}N')).upper() ==
'PRESENT':
700 presentarg = n2name(namedE.find(
'./{*}R-LT/{*}parens-R/{*}element-LT/'
701 '{*}element/{*}named-E/{*}N'))
702 if presentarg.upper() == var.upper():
703 for nnn
in namedE[:]:
705 namedE.tag = f
'{{{NAMESPACE}}}literal-E'
706 namedE.text =
'.TRUE.' if val
else '.FALSE.'
709 parent = mainScope.getParent(callStmt)
712 if tag(parent) ==
'action-stmt':
713 mainScope.changeIfStatementsInIfConstructs(mainScope.getParent(parent))
714 parent = mainScope.getParent(callStmt)
718 prefix = subContained.findall(
'.//{*}prefix')
719 if len(prefix) > 0
and 'ELEMENTAL' in [p.text.upper()
for p
in prefix]:
721 mainScope.addArrayParenthesesInNode(callStmt)
724 mainScope.addExplicitArrayBounds(node=callStmt)
727 arrayRincallStmt = callStmt.findall(
'.//{*}array-R')
728 if len(arrayRincallStmt) > 0:
730 table, _ = mainScope.findArrayBounds(mainScope.getParent(arrayRincallStmt[0], 2),
734 for varName
in table.keys():
735 if not mainScope.varList.findVar(varName):
736 var = {
'as': [],
'asx': [],
737 'n': varName,
'i':
None,
't':
'INTEGER',
'arg':
False,
738 'use':
False,
'opt':
False,
'allocatable':
False,
739 'parameter':
False,
'init':
None,
'scopePath': mainScope.path}
740 mainScope.addVar([[mainScope.path, var[
'n'],
741 mainScope.varSpec2stmt(var),
None]])
744 inner, outer, _ = mainScope.createDoConstruct(table)
747 inner.insert(-1, callStmt)
749 parent.insert(list(parent).index(callStmt), outer)
750 parent.remove(callStmt)
752 for namedE
in callStmt.findall(
'./{*}arg-spec/{*}arg/{*}named-E'):
754 if namedE.find(
'./{*}R-LT'):
755 mainScope.arrayR2parensR(namedE, table)
758 node = copy.deepcopy(subContained)
763 varList = copy.deepcopy(self.varList)
764 for var
in [var
for var
in varList.restrict(subContained.path,
True)
765 if not var[
'arg']
and not var[
'use']]:
767 if varList.restrict(mainScope.path,
True).findVar(var[
'n']):
770 newName = re.sub(
r'_\d+$',
'', var[
'n'])
772 while (varList.restrict(subContained.path,
True).findVar(newName +
'_' + str(i))
or
773 varList.restrict(mainScope.path,
True).findVar(newName +
'_' + str(i))):
775 newName +=
'_' + str(i)
776 node.renameVar(var[
'n'], newName)
777 subst.append((var[
'n'], newName))
780 var[
'scopePath'] = mainScope.path
781 localVarToAdd.append(var)
784 for oldName, newName
in subst:
785 for var
in localVarToAdd + varList[:]:
786 if var[
'as']
is not None:
787 var[
'as'] = [[re.sub(
r'\b' + oldName +
r'\b', newName, dim[i])
788 if dim[i]
is not None else None
790 for dim
in var[
'as']]
797 localUseToAdd = node.findall(
'./{*}use-stmt')
798 for sNode
in node.findall(
'./{*}T-decl-stmt') + localUseToAdd + \
799 node.findall(
'./{*}implicit-none-stmt'):
802 while tag(node[icom]) ==
'C':
803 if node[icom].text.startswith(
'!$acc'):
804 if 'routine' in node[icom].text:
805 node.remove(node[icom])
809 node.remove(node[icom])
817 for argN
in subContained.findall(
'.//{*}subroutine-stmt/{*}dummy-arg-LT/{*}arg-N'):
818 vartable[alltext(argN).upper()] =
None
819 for iarg, arg
in enumerate(callStmt.findall(
'.//{*}arg')):
820 key = arg.find(
'.//{*}arg-N')
823 dummyName = alltext(key).upper()
826 dummyName = list(vartable.keys())[iarg]
828 nodeRLTarray = argnode.findall(
'.//{*}R-LT/{*}array-R')
829 if len(nodeRLTarray) > 0:
831 if len(nodeRLTarray) > 1
or \
832 argnode.find(
'./{*}R-LT/{*}array-R')
is None or \
833 tag(argnode) !=
'named-E':
835 raise PYFTError(
'Argument to complicated: ' + str(alltext(argnode)))
836 dim = nodeRLTarray[0].find(
'./{*}section-subscript-LT')[:]
842 argname =
"".join(argnode.itertext())
845 tmp = copy.deepcopy(argnode)
846 nodeRLT = tmp.find(
'./{*}R-LT')
847 nodeRLT.remove(nodeRLT.find(
'./{*}array-R'))
848 argname =
"".join(tmp.itertext())
849 vartable[dummyName] = {
'node': argnode,
'name': argname,
'dim': dim}
852 for dummyName
in [dummyName
for (dummyName, value)
in vartable.items()
853 if value
is not None]:
854 setPRESENTby(node, dummyName,
True)
855 for dummyName
in [dummyName
for (dummyName, value)
in vartable.items()
857 setPRESENTby(node, dummyName,
False)
860 for dummyName
in [dummyName
for (dummyName, value)
in vartable.items()
if value
is None]:
861 for nodeN
in [nodeN
for nodeN
in node.findall(
'.//{*}named-E/{*}N')
862 if n2name(nodeN).upper() == dummyName]:
865 par = node.getParent(nodeN, level=2)
866 allreadySuppressed = []
867 while par
and not removed
and par
not in allreadySuppressed:
870 if tagName
in (
'a-stmt',
'print-stmt'):
873 elif tagName ==
'call-stmt':
878 raise NotImplementedError(
'call-stmt not (yet?) implemented')
879 elif tagName
in (
'if-stmt',
'where-stmt'):
882 elif tagName
in (
'if-then-stmt',
'else-if-stmt',
'where-construct-stmt',
886 toSuppress = node.getParent(par, 2)
887 elif tagName
in (
'select-case-stmt',
'case-stmt'):
890 toSuppress = node.getParent(par, 2)
891 elif tagName.endswith(
'-block')
or tagName.endswith(
'-stmt')
or \
892 tagName.endswith(
'-construct'):
899 raise PYFTError((
"We shouldn't be here. A case may have been " +
900 "overlooked (tag={tag}).".format(tag=tagName)))
901 if toSuppress
is not None:
903 if toSuppress
not in allreadySuppressed:
906 node.removeStmtNode(toSuppress,
False, simplify)
907 allreadySuppressed.extend(list(toSuppress.iter()))
909 par = node.getParent(par)
912 for name, dummy
in vartable.items():
916 for namedE
in [namedE
for namedE
in node.findall(
'.//{*}named-E/{*}N/{*}n/../..')
917 if n2name(namedE.find(
'{*}N')).upper() == name]:
919 nodeN = namedE.find(
'./{*}N')
920 ns = nodeN.findall(
'./{*}n')
921 ns[0].text = n2name(nodeN)
927 descMain = varList.restrict(mainScope.path,
True).findVar(dummy[
'name'])
928 descSub = varList.restrict(subContained.path,
True).findVar(name)
932 if var[
'as']
is not None:
933 var[
'as'] = [[re.sub(
r'\b' + name +
r'\b', dummy[
'name'], dim[i])
934 if dim[i]
is not None else None
936 for dim
in var[
'as']]
941 nodeRLT = namedE.find(
'./{*}R-LT')
942 if nodeRLT
is not None and tag(nodeRLT[0]) !=
'component-R':
944 assert tag(nodeRLT[0])
in (
'array-R',
'parens-R'),
'Internal error'
945 slices = nodeRLT[0].findall(
'./{*}section-subscript-LT/' +
946 '{*}section-subscript')
947 slices += nodeRLT[0].findall(
'./{*}element-LT/{*}element')
950 if (descMain
is not None and len(descMain[
'as']) > 0)
or \
951 len(descSub[
'as']) > 0
or dummy[
'dim']
is not None:
953 if len(descSub[
'as']) > 0:
954 ndim = len(descSub[
'as'])
957 if dummy[
'dim']
is not None:
960 ndim = len([d
for d
in dummy[
'dim']
if ':' in alltext(d)])
963 ndim = len(descMain[
'as'])
964 ns[0].text +=
'(' + (
', '.join([
':'] * ndim)) +
')'
965 updatedNamedE = createExprPart(alltext(namedE))
966 namedE.tag = updatedNamedE.tag
967 namedE.text = updatedNamedE.text
968 for nnn
in namedE[:]:
970 namedE.extend(updatedNamedE[:])
971 slices = namedE.find(
'./{*}R-LT')[0].findall(
972 './{*}section-subscript-LT/{*}section-subscript')
978 namedE.find(
'./{*}N')[0].text = dummy[
'name']
986 for isl, sl
in enumerate(slices):
988 if len(descSub[
'as']) == 0
or descSub[
'as'][isl][1]
is None:
991 if dummy[
'dim']
is not None:
993 tagName =
'./{*}lower-bound' if i == 0
else './{*}upper-bound'
994 descSub[i] = dummy[
'dim'][isl].find(tagName)
997 if descSub[i]
is not None:
999 descSub[i] = alltext(descSub[i])
1002 if descMain
is not None and descMain[
'as'][isl][1]
is not None:
1004 descSub[i] = descMain[
'as'][isl][i]
1005 if i == 0
and descSub[i]
is None:
1008 descSub[i] =
"L" if i == 0
else "U"
1009 descSub[i] +=
"BOUND({name}, {isl})".format(
1010 name=dummy[
'name'], isl=isl + 1)
1012 descSub[0] = descSub[
'as'][isl][0]
1013 if descSub[0]
is None:
1015 descSub[1] = descSub[
'as'][isl][1]
1027 if dummy[
'dim']
is not None and \
1028 not alltext(dummy[
'dim'][isl]).strip().startswith(
':'):
1029 offset = alltext(dummy[
'dim'][isl].find(
'./{*}lower-bound'))
1031 if descMain
is not None:
1032 offset = descMain[
'as'][isl][0]
1035 elif offset.strip().startswith(
'-'):
1036 offset =
'(' + offset +
')'
1038 offset =
"LBOUND({name}, {isl})".format(
1039 name=dummy[
'name'], isl=isl + 1)
1040 if offset.upper() == descSub[0].upper():
1043 if descSub[0].strip().startswith(
'-'):
1044 offset +=
'- (' + descSub[0] +
')'
1046 offset +=
'-' + descSub[0]
1050 if tag(sl) ==
'element' or \
1051 (tag(sl) ==
'section-subscript' and ':' not in alltext(sl)):
1055 low = sl.find(
'./{*}lower-bound')
1057 low = createElem(
'lower-bound', tail=sl.text)
1058 low.append(createExprPart(descSub[0]))
1061 up = sl.find(
'./{*}upper-bound')
1063 up = createElem(
'upper-bound')
1064 up.append(createExprPart(descSub[1]))
1067 for bound
in bounds:
1069 if bound[-1].tail
is None:
1071 bound[-1].tail +=
'+' + offset
1077 if dummy[
'dim']
is not None and len(dummy[
'dim']) > len(slices):
1078 slices[-1].tail =
', '
1079 par = node.getParent(slices[-1])
1080 par.extend(dummy[
'dim'][len(slices):])
1085 updatedNamedE = createExprPart(alltext(namedE))
1086 namedE.tag = updatedNamedE.tag
1087 namedE.text = updatedNamedE.text
1088 for nnn
in namedE[:]:
1090 namedE.extend(updatedNamedE[:])
1092 node.remove(node.find(
'./{*}subroutine-stmt'))
1093 node.remove(node.find(
'./{*}end-subroutine-stmt'))
1096 mainScope.addVar([[mainScope.path, var[
'n'], mainScope.varSpec2stmt(var),
None]
1097 for var
in localVarToAdd])
1098 mainScope.addModuleVar([[mainScope.path, n2name(useStmt.find(
'.//{*}module-N//{*}N')),
1099 [n2name(v.find(
'.//{*}N'))
1100 for v
in useStmt.findall(
'.//{*}use-N')]]
1101 for useStmt
in localUseToAdd])
1104 index = list(parent).index(callStmt)
1105 parent.remove(callStmt)
1106 if callStmt.tail
is not None:
1107 if node[-1].tail
is None:
1108 node[-1].tail = callStmt.tail
1110 node[-1].tail = node[-1].tail + callStmt.tail
1111 for node
in node[::-1]:
1113 parent.insert(index, node)
1266 This function removes a statement node and:
1267 - suppress variable that became useless (if simplifyVar is True)
1268 - suppress outer loop/if if useless (if simplifyStruct is True)
1269 :param nodes: node (or list of nodes) to remove
1270 :param simplifyVar: try to simplify code (if we delete "CALL FOO(X)" and if X not used
1271 else where, we also delete it; or if the call was alone inside a
1272 if-then-endif construct, with simplifyStruct=True, the construct is also
1273 removed, and variables used in the if condition are also checked...)
1274 :param simplifyStruct: try to simplify code (if we delete "CALL FOO(X)" and if the call was
1275 alone inside a if-then-endif construct, the construct is also
1276 removed and variables used in the if condition
1277 (with simplifyVar=True) are also checked...)
1282 nodesToSuppress = []
1283 if not isinstance(nodes, list):
1286 if tag(node)
in (
'if-stmt',
'where-stmt'):
1287 action = node.find(
'./{*}action-stmt')
1288 if action
is not None and len(action) != 0:
1289 nodesToSuppress.append(action[0])
1291 nodesToSuppress.append(node)
1292 elif tag(node) ==
'}action-stmt':
1294 nodesToSuppress.append(node[0])
1296 nodesToSuppress.append(node)
1298 nodesToSuppress.append(node)
1303 for node
in nodesToSuppress:
1304 scopePath = self.getScopePath(node)
1305 if tag(node) ==
'do-construct':
1307 varToCheck.extend([(scopePath, n2name(arg))
1308 for arg
in node.find(
'./{*}do-stmt').findall(
'.//{*}N')])
1309 elif tag(node)
in (
'if-construct',
'if-stmt'):
1311 varToCheck.extend([(scopePath, n2name(arg))
1312 for arg
in node.findall(
'.//{*}condition-E//{*}N')])
1313 elif tag(node)
in (
'where-construct',
'where-stmt'):
1315 varToCheck.extend([(scopePath, n2name(arg))
1316 for arg
in node.findall(
'.//{*}mask-E//{*}N')])
1317 elif tag(node) ==
'call-stmt':
1319 varToCheck.extend([(scopePath, n2name(arg))
1320 for arg
in node.findall(
'./{*}arg-spec//{*}N')])
1322 varToCheck.append((scopePath,
1323 n2name(node.find(
'./{*}procedure-designator//{*}N'))))
1324 elif tag(node)
in (
'a-stmt',
'print-stmt'):
1325 varToCheck.extend([(scopePath, n2name(arg))
for arg
in node.findall(
'.//{*}N')])
1326 elif tag(node) ==
'selectcase-construct':
1328 varToCheck.extend([(scopePath, n2name(arg))
1329 for arg
in node.findall(
'.//{*}case-E//{*}N')])
1330 varToCheck.extend([(scopePath, n2name(arg))
1331 for arg
in node.findall(
'.//{*}case-value//{*}N')])
1335 for node
in nodesToSuppress:
1336 parent = self.getParent(node)
1337 parents[id(node)] = parent
1338 newlines =
'\n' * (alltext(node).count(
'\n')
if tag(node).endswith(
'-construct')
else 0)
1339 if node.tail
is not None or len(newlines) > 0:
1340 previous = self.getSiblings(node, after=
False)
1341 if len(previous) == 0:
1344 previous = previous[-1]
1345 if previous.tail
is None:
1347 previous.tail = (previous.tail.replace(
'\n',
'') +
1348 (node.tail
if node.tail
is not None else ''))
1352 self.removeVarIfUnused(varToCheck, excludeDummy=
True,
1353 excludeModule=
True, simplify=simplifyVar)
1356 newNodesToSuppress = []
1357 for node
in nodesToSuppress:
1358 parent = parents[id(node)]
1361 if tag(parent) ==
'action-stmt':
1362 newNodesToSuppress.append(self.getParent(parent))
1364 elif simplifyStruct:
1365 if tag(parent) ==
'do-construct' and len(
_nodesInDo(parent)) == 0:
1366 newNodesToSuppress.append(parent)
1367 elif tag(parent) ==
'if-block':
1368 parPar = self.getParent(parent)
1370 newNodesToSuppress.append(parPar)
1371 elif tag(parent) ==
'where-block':
1372 parPar = self.getParent(parent)
1374 newNodesToSuppress.append(parPar)
1375 elif tag(parent) ==
'selectcase-block':
1376 parPar = self.getParent(parent)
1378 newNodesToSuppress.append(parPar)
1380 constructNodes, otherNodes = [], []
1381 for nnn
in newNodesToSuppress:
1382 if tag(nnn).endswith(
'-construct'):
1383 if nnn
not in constructNodes:
1384 constructNodes.append(nnn)
1386 if nnn
not in otherNodes:
1387 otherNodes.append(nnn)
1389 if len(otherNodes) > 0:
1392 for nnn
in constructNodes:
1449 :param loopVariables: ordered dictionnary with loop variables as key and bounds as values.
1450 Bounds are expressed with a 2-tuple.
1451 Keys must be in the same order as the order used when addressing an
1452 element: if loopVariables.keys is [JI, JK], arrays are
1453 addressed with (JI, JK)
1454 :param indent: current indentation
1455 :param concurrent: if False, output is made of nested 'DO' loops
1456 if True, output is made of a single 'DO CONCURRENT' loop
1457 :return: (inner, outer, extraindent) with
1458 - inner the inner do-construct where statements must be added
1459 - outer the outer do-construct to be inserted somewhere
1460 - extraindent the number of added indentation
1461 (2 if concurrent else 2*len(loopVariables))
1487 for var, (lo, up)
in list(loopVariables.items())[::-1]:
1488 nodeV = createElem(
'V', tail=
'=')
1489 nodeV.append(createExprPart(var))
1490 lower, upper = createArrayBounds(lo, up,
'DOCONCURRENT')
1492 triplet = createElem(
'forall-triplet-spec')
1493 triplet.extend([nodeV, lower, upper])
1495 triplets.append(triplet)
1497 tripletLT = createElem(
'forall-triplet-spec-LT', tail=
')')
1498 for triplet
in triplets[:-1]:
1500 tripletLT.extend(triplets)
1502 dostmt = createElem(
'do-stmt', text=
'DO CONCURRENT (', tail=
'\n')
1503 dostmt.append(tripletLT)
1504 enddostmt = createElem(
'end-do-stmt', text=
'END DO')
1506 doconstruct = createElem(
'do-construct', tail=
'\n')
1507 doconstruct.extend([dostmt, enddostmt])
1508 inner = outer = doconstruct
1509 doconstruct[0].tail += (indent + 2) *
' '
1520 def makeDo(var, lo, up):
1521 doV = createElem(
'do-V', tail=
'=')
1522 doV.append(createExprPart(var))
1523 lower, upper = createArrayBounds(lo, up,
'DO')
1525 dostmt = createElem(
'do-stmt', text=
'DO ', tail=
'\n')
1526 dostmt.extend([doV, lower, upper])
1528 enddostmt = createElem(
'end-do-stmt', text=
'END DO')
1530 doconstruct = createElem(
'do-construct', tail=
'\n')
1531 doconstruct.extend([dostmt, enddostmt])
1536 for i, (var, (lo, up))
in enumerate(list(loopVariables.items())[::-1]):
1537 doconstruct = makeDo(var, lo, up)
1539 doconstruct[0].tail += (indent + 2 * i + 2) *
' '
1544 inner.insert(1, doconstruct)
1547 doconstruct.tail += (indent + 2 * i - 2) *
' '
1548 return inner, outer, 2
if concurrent
else 2 * len(loopVariables)
1573 :param item: item to remove from list
1574 :param itemPar: the parent of item (the list)
1577 nodesToSuppress = [item]
1580 i = list(itemPar).index(item)
1581 if item.tail
is not None and ',' in item.tail:
1584 item.tail = tail.replace(
',',
'')
1585 elif i != 0
and ',' in itemPar[i - 1].tail:
1587 tail = itemPar[i - 1].tail
1588 itemPar[i - 1].tail = tail.replace(
',',
'')
1594 while j < len(itemPar)
and not found:
1595 if nonCode(itemPar[j]):
1597 if itemPar[j].tail
is not None and ',' in itemPar[j].tail:
1600 tail = itemPar[j].tail
1601 itemPar[j].tail = tail.replace(
',',
'')
1611 while j >= 0
and not found:
1612 if itemPar[j].tail
is not None and ',' in itemPar[j].tail:
1615 tail = itemPar[j].tail
1616 itemPar[j].tail = tail.replace(
',',
'')
1618 if nonCode(itemPar[j]):
1626 len([e
for e
in itemPar
if not nonCode(e)]) != 1:
1627 raise RuntimeError(
"Something went wrong here....")
1630 if i + 1 < len(itemPar)
and tag(itemPar[i + 1]) ==
'cnt':
1632 reason =
'lastOnLine'
1644 elif len([itemPar[j]
for j
in range(i + 1, len(itemPar))
if not nonCode(itemPar[j])]) == 0:
1658 if reason
is not None:
1659 def _getPrecedingCnt(itemPar, i):
1661 Return the index of the preceding node which is a continuation character
1662 :param itemPar: the list containig the node to suppress
1663 :param i: the index of the current node, i-1 is the starting index for the search
1664 :return: a tuple with three elements:
1665 - the node containing the preceding '&' character
1666 - the parent of the node containing the preceding '&' character
1667 - index of the preceding '&' in the parent (previsous element
1670 - In the general case the preceding '&' belongs to the same list:
1671 USE MODD, ONLY: X, &
1673 - But it exists a special case, where the preceding '&' don't belong to
1674 the same list (in the following example, both '&' are attached to the parent):
1679 while j >= 0
and tag(itemPar[j]) ==
'C':
1681 if j >= 0
and tag(itemPar[j]) ==
'cnt':
1682 return itemPar[j], itemPar, j
1688 siblings = self.getSiblings(itemPar, before=
True, after=
False)
1689 j2 = len(siblings) - 1
1690 while j2 >= 0
and tag(siblings[j2]) ==
'C':
1692 if j2 >= 0
and tag(siblings[j2]) ==
'cnt':
1693 return siblings[j2], siblings, j2
1694 return None,
None,
None
1696 precCnt, newl, j = _getPrecedingCnt(itemPar, i)
1697 if precCnt
is not None:
1699 nodesToSuppress.append(precCnt
if reason ==
'last' else itemPar[i + 1])
1701 precCnt2, _, _ = _getPrecedingCnt(newl, j)
1702 if precCnt2
is not None:
1704 nodesToSuppress.append(precCnt2
if reason ==
'last' else precCnt)
1707 for node
in nodesToSuppress:
1714 parent = self.getParent(itemPar)
1715 i = list(parent).index(node)
1716 if i != 0
and node.tail
is not None:
1717 if parent[i - 1].tail
is None:
1718 parent[i - 1].tail =
''
1719 parent[i - 1].tail = parent[i - 1].tail + node.tail