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'):
801 while tag(node[1]) ==
'C' and not node[1].text.startswith(
'!$acc'):
810 for argN
in subContained.findall(
'.//{*}subroutine-stmt/{*}dummy-arg-LT/{*}arg-N'):
811 vartable[alltext(argN).upper()] =
None
812 for iarg, arg
in enumerate(callStmt.findall(
'.//{*}arg')):
813 key = arg.find(
'.//{*}arg-N')
816 dummyName = alltext(key).upper()
819 dummyName = list(vartable.keys())[iarg]
821 nodeRLTarray = argnode.findall(
'.//{*}R-LT/{*}array-R')
822 if len(nodeRLTarray) > 0:
824 if len(nodeRLTarray) > 1
or \
825 argnode.find(
'./{*}R-LT/{*}array-R')
is None or \
826 tag(argnode) !=
'named-E':
828 raise PYFTError(
'Argument to complicated: ' + str(alltext(argnode)))
829 dim = nodeRLTarray[0].find(
'./{*}section-subscript-LT')[:]
835 argname =
"".join(argnode.itertext())
838 tmp = copy.deepcopy(argnode)
839 nodeRLT = tmp.find(
'./{*}R-LT')
840 nodeRLT.remove(nodeRLT.find(
'./{*}array-R'))
841 argname =
"".join(tmp.itertext())
842 vartable[dummyName] = {
'node': argnode,
'name': argname,
'dim': dim}
845 for dummyName
in [dummyName
for (dummyName, value)
in vartable.items()
846 if value
is not None]:
847 setPRESENTby(node, dummyName,
True)
848 for dummyName
in [dummyName
for (dummyName, value)
in vartable.items()
850 setPRESENTby(node, dummyName,
False)
853 for dummyName
in [dummyName
for (dummyName, value)
in vartable.items()
if value
is None]:
854 for nodeN
in [nodeN
for nodeN
in node.findall(
'.//{*}named-E/{*}N')
855 if n2name(nodeN).upper() == dummyName]:
858 par = node.getParent(nodeN, level=2)
859 allreadySuppressed = []
860 while par
and not removed
and par
not in allreadySuppressed:
863 if tagName
in (
'a-stmt',
'print-stmt'):
866 elif tagName ==
'call-stmt':
871 raise NotImplementedError(
'call-stmt not (yet?) implemented')
872 elif tagName
in (
'if-stmt',
'where-stmt'):
875 elif tagName
in (
'if-then-stmt',
'else-if-stmt',
'where-construct-stmt',
879 toSuppress = node.getParent(par, 2)
880 elif tagName
in (
'select-case-stmt',
'case-stmt'):
883 toSuppress = node.getParent(par, 2)
884 elif tagName.endswith(
'-block')
or tagName.endswith(
'-stmt')
or \
885 tagName.endswith(
'-construct'):
892 raise PYFTError((
"We shouldn't be here. A case may have been " +
893 "overlooked (tag={tag}).".format(tag=tagName)))
894 if toSuppress
is not None:
896 if toSuppress
not in allreadySuppressed:
899 node.removeStmtNode(toSuppress,
False, simplify)
900 allreadySuppressed.extend(list(toSuppress.iter()))
902 par = node.getParent(par)
905 for name, dummy
in vartable.items():
909 for namedE
in [namedE
for namedE
in node.findall(
'.//{*}named-E/{*}N/{*}n/../..')
910 if n2name(namedE.find(
'{*}N')).upper() == name]:
912 nodeN = namedE.find(
'./{*}N')
913 ns = nodeN.findall(
'./{*}n')
914 ns[0].text = n2name(nodeN)
920 descMain = varList.restrict(mainScope.path,
True).findVar(dummy[
'name'])
921 descSub = varList.restrict(subContained.path,
True).findVar(name)
925 if var[
'as']
is not None:
926 var[
'as'] = [[re.sub(
r'\b' + name +
r'\b', dummy[
'name'], dim[i])
927 if dim[i]
is not None else None
929 for dim
in var[
'as']]
934 nodeRLT = namedE.find(
'./{*}R-LT')
935 if nodeRLT
is not None and tag(nodeRLT[0]) !=
'component-R':
937 assert tag(nodeRLT[0])
in (
'array-R',
'parens-R'),
'Internal error'
938 slices = nodeRLT[0].findall(
'./{*}section-subscript-LT/' +
939 '{*}section-subscript')
940 slices += nodeRLT[0].findall(
'./{*}element-LT/{*}element')
943 if (descMain
is not None and len(descMain[
'as']) > 0)
or \
944 len(descSub[
'as']) > 0
or dummy[
'dim']
is not None:
946 if len(descSub[
'as']) > 0:
947 ndim = len(descSub[
'as'])
950 if dummy[
'dim']
is not None:
953 ndim = len([d
for d
in dummy[
'dim']
if ':' in alltext(d)])
956 ndim = len(descMain[
'as'])
957 ns[0].text +=
'(' + (
', '.join([
':'] * ndim)) +
')'
958 updatedNamedE = createExprPart(alltext(namedE))
959 namedE.tag = updatedNamedE.tag
960 namedE.text = updatedNamedE.text
961 for nnn
in namedE[:]:
963 namedE.extend(updatedNamedE[:])
964 slices = namedE.find(
'./{*}R-LT')[0].findall(
965 './{*}section-subscript-LT/{*}section-subscript')
971 namedE.find(
'./{*}N')[0].text = dummy[
'name']
979 for isl, sl
in enumerate(slices):
981 if len(descSub[
'as']) == 0
or descSub[
'as'][isl][1]
is None:
984 if dummy[
'dim']
is not None:
986 tagName =
'./{*}lower-bound' if i == 0
else './{*}upper-bound'
987 descSub[i] = dummy[
'dim'][isl].find(tagName)
990 if descSub[i]
is not None:
992 descSub[i] = alltext(descSub[i])
995 if descMain
is not None and descMain[
'as'][isl][1]
is not None:
997 descSub[i] = descMain[
'as'][isl][i]
998 if i == 0
and descSub[i]
is None:
1001 descSub[i] =
"L" if i == 0
else "U"
1002 descSub[i] +=
"BOUND({name}, {isl})".format(
1003 name=dummy[
'name'], isl=isl + 1)
1005 descSub[0] = descSub[
'as'][isl][0]
1006 if descSub[0]
is None:
1008 descSub[1] = descSub[
'as'][isl][1]
1020 if dummy[
'dim']
is not None and \
1021 not alltext(dummy[
'dim'][isl]).strip().startswith(
':'):
1022 offset = alltext(dummy[
'dim'][isl].find(
'./{*}lower-bound'))
1024 if descMain
is not None:
1025 offset = descMain[
'as'][isl][0]
1028 elif offset.strip().startswith(
'-'):
1029 offset =
'(' + offset +
')'
1031 offset =
"LBOUND({name}, {isl})".format(
1032 name=dummy[
'name'], isl=isl + 1)
1033 if offset.upper() == descSub[0].upper():
1036 if descSub[0].strip().startswith(
'-'):
1037 offset +=
'- (' + descSub[0] +
')'
1039 offset +=
'-' + descSub[0]
1043 if tag(sl) ==
'element' or \
1044 (tag(sl) ==
'section-subscript' and ':' not in alltext(sl)):
1048 low = sl.find(
'./{*}lower-bound')
1050 low = createElem(
'lower-bound', tail=sl.text)
1051 low.append(createExprPart(descSub[0]))
1054 up = sl.find(
'./{*}upper-bound')
1056 up = createElem(
'upper-bound')
1057 up.append(createExprPart(descSub[1]))
1060 for bound
in bounds:
1062 if bound[-1].tail
is None:
1064 bound[-1].tail +=
'+' + offset
1070 if dummy[
'dim']
is not None and len(dummy[
'dim']) > len(slices):
1071 slices[-1].tail =
', '
1072 par = node.getParent(slices[-1])
1073 par.extend(dummy[
'dim'][len(slices):])
1078 updatedNamedE = createExprPart(alltext(namedE))
1079 namedE.tag = updatedNamedE.tag
1080 namedE.text = updatedNamedE.text
1081 for nnn
in namedE[:]:
1083 namedE.extend(updatedNamedE[:])
1085 node.remove(node.find(
'./{*}subroutine-stmt'))
1086 node.remove(node.find(
'./{*}end-subroutine-stmt'))
1089 mainScope.addVar([[mainScope.path, var[
'n'], mainScope.varSpec2stmt(var),
None]
1090 for var
in localVarToAdd])
1091 mainScope.addModuleVar([[mainScope.path, n2name(useStmt.find(
'.//{*}module-N//{*}N')),
1092 [n2name(v.find(
'.//{*}N'))
1093 for v
in useStmt.findall(
'.//{*}use-N')]]
1094 for useStmt
in localUseToAdd])
1097 index = list(parent).index(callStmt)
1098 parent.remove(callStmt)
1099 if callStmt.tail
is not None:
1100 if node[-1].tail
is None:
1101 node[-1].tail = callStmt.tail
1103 node[-1].tail = node[-1].tail + callStmt.tail
1104 for node
in node[::-1]:
1106 parent.insert(index, node)
1259 This function removes a statement node and:
1260 - suppress variable that became useless (if simplifyVar is True)
1261 - suppress outer loop/if if useless (if simplifyStruct is True)
1262 :param nodes: node (or list of nodes) to remove
1263 :param simplifyVar: try to simplify code (if we delete "CALL FOO(X)" and if X not used
1264 else where, we also delete it; or if the call was alone inside a
1265 if-then-endif construct, with simplifyStruct=True, the construct is also
1266 removed, and variables used in the if condition are also checked...)
1267 :param simplifyStruct: try to simplify code (if we delete "CALL FOO(X)" and if the call was
1268 alone inside a if-then-endif construct, the construct is also
1269 removed and variables used in the if condition
1270 (with simplifyVar=True) are also checked...)
1275 nodesToSuppress = []
1276 if not isinstance(nodes, list):
1279 if tag(node)
in (
'if-stmt',
'where-stmt'):
1280 action = node.find(
'./{*}action-stmt')
1281 if action
is not None and len(action) != 0:
1282 nodesToSuppress.append(action[0])
1284 nodesToSuppress.append(node)
1285 elif tag(node) ==
'}action-stmt':
1287 nodesToSuppress.append(node[0])
1289 nodesToSuppress.append(node)
1291 nodesToSuppress.append(node)
1296 for node
in nodesToSuppress:
1297 scopePath = self.getScopePath(node)
1298 if tag(node) ==
'do-construct':
1300 varToCheck.extend([(scopePath, n2name(arg))
1301 for arg
in node.find(
'./{*}do-stmt').findall(
'.//{*}N')])
1302 elif tag(node)
in (
'if-construct',
'if-stmt'):
1304 varToCheck.extend([(scopePath, n2name(arg))
1305 for arg
in node.findall(
'.//{*}condition-E//{*}N')])
1306 elif tag(node)
in (
'where-construct',
'where-stmt'):
1308 varToCheck.extend([(scopePath, n2name(arg))
1309 for arg
in node.findall(
'.//{*}mask-E//{*}N')])
1310 elif tag(node) ==
'call-stmt':
1312 varToCheck.extend([(scopePath, n2name(arg))
1313 for arg
in node.findall(
'./{*}arg-spec//{*}N')])
1315 varToCheck.append((scopePath,
1316 n2name(node.find(
'./{*}procedure-designator//{*}N'))))
1317 elif tag(node)
in (
'a-stmt',
'print-stmt'):
1318 varToCheck.extend([(scopePath, n2name(arg))
for arg
in node.findall(
'.//{*}N')])
1319 elif tag(node) ==
'selectcase-construct':
1321 varToCheck.extend([(scopePath, n2name(arg))
1322 for arg
in node.findall(
'.//{*}case-E//{*}N')])
1323 varToCheck.extend([(scopePath, n2name(arg))
1324 for arg
in node.findall(
'.//{*}case-value//{*}N')])
1328 for node
in nodesToSuppress:
1329 parent = self.getParent(node)
1330 parents[id(node)] = parent
1331 newlines =
'\n' * (alltext(node).count(
'\n')
if tag(node).endswith(
'-construct')
else 0)
1332 if node.tail
is not None or len(newlines) > 0:
1333 previous = self.getSiblings(node, after=
False)
1334 if len(previous) == 0:
1337 previous = previous[-1]
1338 if previous.tail
is None:
1340 previous.tail = (previous.tail.replace(
'\n',
'') +
1341 (node.tail
if node.tail
is not None else ''))
1345 self.removeVarIfUnused(varToCheck, excludeDummy=
True,
1346 excludeModule=
True, simplify=simplifyVar)
1349 newNodesToSuppress = []
1350 for node
in nodesToSuppress:
1351 parent = parents[id(node)]
1354 if tag(parent) ==
'action-stmt':
1355 newNodesToSuppress.append(self.getParent(parent))
1357 elif simplifyStruct:
1358 if tag(parent) ==
'do-construct' and len(
_nodesInDo(parent)) == 0:
1359 newNodesToSuppress.append(parent)
1360 elif tag(parent) ==
'if-block':
1361 parPar = self.getParent(parent)
1363 newNodesToSuppress.append(parPar)
1364 elif tag(parent) ==
'where-block':
1365 parPar = self.getParent(parent)
1367 newNodesToSuppress.append(parPar)
1368 elif tag(parent) ==
'selectcase-block':
1369 parPar = self.getParent(parent)
1371 newNodesToSuppress.append(parPar)
1373 constructNodes, otherNodes = [], []
1374 for nnn
in newNodesToSuppress:
1375 if tag(nnn).endswith(
'-construct'):
1376 if nnn
not in constructNodes:
1377 constructNodes.append(nnn)
1379 if nnn
not in otherNodes:
1380 otherNodes.append(nnn)
1382 if len(otherNodes) > 0:
1385 for nnn
in constructNodes:
1442 :param loopVariables: ordered dictionnary with loop variables as key and bounds as values.
1443 Bounds are expressed with a 2-tuple.
1444 Keys must be in the same order as the order used when addressing an
1445 element: if loopVariables.keys is [JI, JK], arrays are
1446 addressed with (JI, JK)
1447 :param indent: current indentation
1448 :param concurrent: if False, output is made of nested 'DO' loops
1449 if True, output is made of a single 'DO CONCURRENT' loop
1450 :return: (inner, outer, extraindent) with
1451 - inner the inner do-construct where statements must be added
1452 - outer the outer do-construct to be inserted somewhere
1453 - extraindent the number of added indentation
1454 (2 if concurrent else 2*len(loopVariables))
1480 for var, (lo, up)
in list(loopVariables.items())[::-1]:
1481 nodeV = createElem(
'V', tail=
'=')
1482 nodeV.append(createExprPart(var))
1483 lower, upper = createArrayBounds(lo, up,
'DOCONCURRENT')
1485 triplet = createElem(
'forall-triplet-spec')
1486 triplet.extend([nodeV, lower, upper])
1488 triplets.append(triplet)
1490 tripletLT = createElem(
'forall-triplet-spec-LT', tail=
')')
1491 for triplet
in triplets[:-1]:
1493 tripletLT.extend(triplets)
1495 dostmt = createElem(
'do-stmt', text=
'DO CONCURRENT (', tail=
'\n')
1496 dostmt.append(tripletLT)
1497 enddostmt = createElem(
'end-do-stmt', text=
'END DO')
1499 doconstruct = createElem(
'do-construct', tail=
'\n')
1500 doconstruct.extend([dostmt, enddostmt])
1501 inner = outer = doconstruct
1502 doconstruct[0].tail += (indent + 2) *
' '
1513 def makeDo(var, lo, up):
1514 doV = createElem(
'do-V', tail=
'=')
1515 doV.append(createExprPart(var))
1516 lower, upper = createArrayBounds(lo, up,
'DO')
1518 dostmt = createElem(
'do-stmt', text=
'DO ', tail=
'\n')
1519 dostmt.extend([doV, lower, upper])
1521 enddostmt = createElem(
'end-do-stmt', text=
'END DO')
1523 doconstruct = createElem(
'do-construct', tail=
'\n')
1524 doconstruct.extend([dostmt, enddostmt])
1529 for i, (var, (lo, up))
in enumerate(list(loopVariables.items())[::-1]):
1530 doconstruct = makeDo(var, lo, up)
1532 doconstruct[0].tail += (indent + 2 * i + 2) *
' '
1537 inner.insert(1, doconstruct)
1540 doconstruct.tail += (indent + 2 * i - 2) *
' '
1541 return inner, outer, 2
if concurrent
else 2 * len(loopVariables)
1566 :param item: item to remove from list
1567 :param itemPar: the parent of item (the list)
1570 nodesToSuppress = [item]
1573 i = list(itemPar).index(item)
1574 if item.tail
is not None and ',' in item.tail:
1577 item.tail = tail.replace(
',',
'')
1578 elif i != 0
and ',' in itemPar[i - 1].tail:
1580 tail = itemPar[i - 1].tail
1581 itemPar[i - 1].tail = tail.replace(
',',
'')
1587 while j < len(itemPar)
and not found:
1588 if nonCode(itemPar[j]):
1590 if itemPar[j].tail
is not None and ',' in itemPar[j].tail:
1593 tail = itemPar[j].tail
1594 itemPar[j].tail = tail.replace(
',',
'')
1604 while j >= 0
and not found:
1605 if itemPar[j].tail
is not None and ',' in itemPar[j].tail:
1608 tail = itemPar[j].tail
1609 itemPar[j].tail = tail.replace(
',',
'')
1611 if nonCode(itemPar[j]):
1619 len([e
for e
in itemPar
if not nonCode(e)]) != 1:
1620 raise RuntimeError(
"Something went wrong here....")
1623 if i + 1 < len(itemPar)
and tag(itemPar[i + 1]) ==
'cnt':
1625 reason =
'lastOnLine'
1637 elif len([itemPar[j]
for j
in range(i + 1, len(itemPar))
if not nonCode(itemPar[j])]) == 0:
1651 if reason
is not None:
1652 def _getPrecedingCnt(itemPar, i):
1654 Return the index of the preceding node which is a continuation character
1655 :param itemPar: the list containig the node to suppress
1656 :param i: the index of the current node, i-1 is the starting index for the search
1657 :return: a tuple with three elements:
1658 - the node containing the preceding '&' character
1659 - the parent of the node containing the preceding '&' character
1660 - index of the preceding '&' in the parent (previsous element
1663 - In the general case the preceding '&' belongs to the same list:
1664 USE MODD, ONLY: X, &
1666 - But it exists a special case, where the preceding '&' don't belong to
1667 the same list (in the following example, both '&' are attached to the parent):
1672 while j >= 0
and tag(itemPar[j]) ==
'C':
1674 if j >= 0
and tag(itemPar[j]) ==
'cnt':
1675 return itemPar[j], itemPar, j
1681 siblings = self.getSiblings(itemPar, before=
True, after=
False)
1682 j2 = len(siblings) - 1
1683 while j2 >= 0
and tag(siblings[j2]) ==
'C':
1685 if j2 >= 0
and tag(siblings[j2]) ==
'cnt':
1686 return siblings[j2], siblings, j2
1687 return None,
None,
None
1689 precCnt, newl, j = _getPrecedingCnt(itemPar, i)
1690 if precCnt
is not None:
1692 nodesToSuppress.append(precCnt
if reason ==
'last' else itemPar[i + 1])
1694 precCnt2, _, _ = _getPrecedingCnt(newl, j)
1695 if precCnt2
is not None:
1697 nodesToSuppress.append(precCnt2
if reason ==
'last' else precCnt)
1700 for node
in nodesToSuppress:
1707 parent = self.getParent(itemPar)
1708 i = list(parent).index(node)
1709 if i != 0
and node.tail
is not None:
1710 if parent[i - 1].tail
is None:
1711 parent[i - 1].tail =
''
1712 parent[i - 1].tail = parent[i - 1].tail + node.tail