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 if directive.lstrip(
' ').startswith(
'!$mnh_expand'):
248 kind = directive[13:].lstrip(
' ').split(
'(')[0].strip()
250 kind = directive[17:].lstrip(
' ').split(
'(')[0].strip()
253 def updateStmt(stmt, table, kind, extraindent, parent, scope):
255 Updates the statement given the table dictionnary '(:, :)' is replaced by '(JI, JK)' if
256 table.keys() is ['JI', 'JK']
257 :param stmt: statement to update
258 :param table: dictionnary retruned by the decode function
259 :param kind: kind of mnh directives: 'array' or 'where'
260 or None if transformation is not governed by
262 :param scope: current scope
265 def addExtra(node, extra):
266 """Helper function to add indentation spaces"""
267 if extra != 0
and (node.tail
is not None)
and '\n' in node.tail:
273 node.tail = re.sub(
r"(\n[ ]*)(\Z|[^\n ]+)",
274 r"\1" + extra *
' ' +
r"\2", node.tail)
276 addExtra(stmt, extraindent)
279 elif tag(stmt) ==
'cpp':
280 i = list(parent).index(stmt)
285 parent[i - 1].tail = parent[i - 1].tail.rstrip(
' ')
286 elif tag(stmt) ==
'a-stmt':
287 sss = stmt.findall(
'./{*}E-1/{*}named-E/{*}R-LT/{*}array-R/' +
288 '{*}section-subscript-LT/{*}section-subscript')
289 if len([ss
for ss
in sss
if ':' in alltext(ss)]) != len(table):
290 raise PYFTError(
"Inside code sections to transform in DO loops, " +
291 "all affectations must use ':'.\n" +
292 "This is not the case in:\n{stmt}".format(stmt=alltext(stmt)))
293 if stmt.find(
'./{*}E-1/{*}named-E/{*}N').tail
is not None and kind
is not None:
294 raise PYFTError(
"To keep the compatibility with the filepp version of loop " +
295 "expansion, nothing must appear between array names and " +
296 "opening parethesis inside mnh directive sections.")
299 for namedE
in stmt.findall(
'.//{*}R-LT/..'):
300 scope.arrayR2parensR(namedE, table)
301 for cnt
in stmt.findall(
'.//{*}cnt'):
302 addExtra(cnt, extraindent)
303 elif tag(stmt) ==
'if-stmt':
305 "An if statement is inside a code section transformed in DO loop in %s",
308 updateStmt(stmt.find(
'./{*}action-stmt')[0], table, kind, 0, stmt, scope)
309 elif tag(stmt) ==
'if-construct':
311 "An if construct is inside a code section transformed in DO loop in %s",
314 for ifBlock
in stmt.findall(
'./{*}if-block'):
315 for child
in ifBlock:
316 if tag(child)
not in (
'if-then-stmt',
'else-if-stmt',
317 'else-stmt',
'end-if-stmt'):
318 updateStmt(child, table, kind, extraindent, ifBlock, scope)
321 addExtra(child, extraindent)
322 for cnt
in child.findall(
'.//{*}cnt'):
324 addExtra(cnt, extraindent)
325 elif tag(stmt) ==
'where-stmt':
327 stmt.tag = f
'{{{NAMESPACE}}}if-stmt'
328 stmt.text =
'IF (' + stmt.text.split(
'(', 1)[1]
330 updateStmt(stmt.find(
'./{*}action-stmt')[0], table, kind,
331 extraindent, stmt, scope)
332 mask = stmt.find(
'./{*}mask-E')
333 mask.tag = f
'{{{NAMESPACE}}}condition-E'
334 for namedE
in mask.findall(
'.//{*}R-LT/..'):
335 scope.arrayR2parensR(namedE, table)
336 for cnt
in stmt.findall(
'.//{*}cnt'):
337 addExtra(cnt, extraindent)
338 elif tag(stmt) ==
'where-construct':
339 if kind !=
'where' and kind
is not None:
340 raise PYFTError(
'To keep the compatibility with the filepp version of loop " + \
341 "expansion, no where construct must appear " + \
342 "in mnh_expand_array blocks.')
344 stmt.tag = f
'{{{NAMESPACE}}}if-construct'
346 for whereBlock
in stmt.findall(
'./{*}where-block'):
347 whereBlock.tag = f
'{{{NAMESPACE}}}if-block'
348 for child
in whereBlock:
349 if tag(child) ==
'end-where-stmt':
351 child.tag = f
'{{{NAMESPACE}}}end-if-stmt'
352 child.text =
'END IF'
354 addExtra(child, extraindent)
355 elif tag(child)
in (
'where-construct-stmt',
'else-where-stmt'):
357 addExtra(child, extraindent)
358 if tag(child) ==
'where-construct-stmt':
360 child.tag = f
'{{{NAMESPACE}}}if-then-stmt'
361 child.text =
'IF (' + child.text.split(
'(', 1)[1]
366 if '(' in child.text:
368 child.tag = f
'{{{NAMESPACE}}}else-if-stmt'
369 child.text =
'ELSE IF (' + child.text.split(
'(', 1)[1]
372 child.tag = f
'{{{NAMESPACE}}}else-stmt'
374 for mask
in child.findall(
'./{*}mask-E'):
376 mask.tag = f
'{{{NAMESPACE}}}condition-E'
378 for namedE
in mask.findall(
'.//{*}R-LT/..'):
380 scope.arrayR2parensR(namedE, table)
381 for cnt
in child.findall(
'.//{*}cnt'):
383 addExtra(cnt, extraindent)
385 updateStmt(child, table, kind, extraindent, whereBlock, scope)
387 raise PYFTError(
'Unexpected tag found in mnh_expand ' +
388 'directives: {t}'.format(t=tag(stmt)))
391 def closeLoop(loopdesc):
392 """Helper function to deal with indentation"""
394 inner, outer, indent, extraindent = loopdesc
395 if inner[-2].tail
is not None:
397 outer.tail = inner[-2].tail[:-extraindent]
398 inner[-2].tail =
'\n' + (indent + extraindent - 2) *
' '
405 def recur(elem, scope):
409 for ie, sElem
in enumerate(list(elem)):
410 if tag(sElem) ==
'C' and sElem.text.lstrip(
' ').startswith(
'!$mnh_expand')
and \
414 raise PYFTError(
'Nested mnh_directives are not allowed')
416 inEverywhere = closeLoop(inEverywhere)
419 table, kind = decode(sElem.text)
421 indent = len(sElem.tail) - len(sElem.tail.rstrip(
' '))
422 toremove.append((elem, sElem))
426 if elem[ie - 1].tail
is None:
427 elem[ie - 1].tail =
''
428 elem[ie - 1].tail += sElem.tail.replace(
'\n',
'', 1).rstrip(
' ')
431 if addAccIndependentCollapse:
432 accCollapse = createElem(
'C', text=
'!$acc loop independent collapse(' +
433 str(len(table.keys())) +
')',
434 tail=
'\n' + indent *
' ')
435 toinsert.append((elem, accCollapse, ie))
438 inner, outer, extraindent = scope.createDoConstruct(table, indent=indent,
439 concurrent=concurrent)
440 toinsert.append((elem, outer, ie))
442 elif (tag(sElem) ==
'C' and
443 sElem.text.lstrip(
' ').startswith(
'!$mnh_end_expand')
and useMnhExpand):
446 raise PYFTError(
'End mnh_directive found before begin directive ' +
447 'in {f}'.format(f=scope.getFileName()))
448 if (table, kind) != decode(sElem.text):
449 raise PYFTError(
"Opening and closing mnh directives must be conform " +
450 "in {f}".format(f=scope.getFileName()))
452 toremove.append((elem, sElem))
456 outer.tail += sElem.tail.replace(
'\n',
'', 1)
458 elem[ie - 1].tail = elem[ie - 1].tail[:-2]
462 toremove.append((elem, sElem))
463 inner.insert(-1, sElem)
465 updateStmt(sElem, table, kind, extraindent, inner, scope)
467 elif everywhere
and tag(sElem)
in (
'a-stmt',
'if-stmt',
'where-stmt',
472 if tag(sElem) ==
'a-stmt':
474 arr = sElem.find(
'./{*}E-1/{*}named-E/{*}R-LT/{*}array-R/../..')
478 nodeE2 = sElem.find(
'./{*}E-2')
480 num = len(nodeE2.findall(
'.//{*}array-R'))
487 elif (len(nodeE2) == 1
and tag(nodeE2[0]) ==
'named-E' and num == 1
and
488 nodeE2[0].find(
'.//{*}parens-R')
is None):
494 if (isMemSet
and not updateMemSet)
or (isCopy
and not updateCopy):
496 elif tag(sElem) ==
'if-stmt':
498 arr = sElem.find(
'./{*}action-stmt/{*}a-stmt/{*}E-1/' +
499 '{*}named-E/{*}R-LT/{*}array-R/../..')
502 scope.changeIfStatementsInIfConstructs(singleItem=sElem)
505 elif tag(sElem) ==
'where-stmt':
506 arr = sElem.find(
'./{*}mask-E//{*}named-E/{*}R-LT/{*}array-R/../..')
507 elif tag(sElem) ==
'where-construct':
508 arr = sElem.find(
'./{*}where-block/{*}where-construct-stmt/' +
509 '{*}mask-E//{*}named-E/{*}R-LT/{*}array-R/../..')
516 elif len(set(alltext(a).count(
':')
517 for a
in sElem.findall(
'.//{*}R-LT/{*}array-R'))) > 1:
521 elif len(set([
'ALL',
'ANY',
'COSHAPE',
'COUNT',
'CSHIFT',
'DIMENSION',
522 'DOT_PRODUCT',
'EOSHIFT',
'LBOUND',
'LCOBOUND',
'MATMUL',
523 'MAXLOC',
'MAXVAL',
'MERGE',
'MINLOC',
'MINVAL',
'PACK',
524 'PRODUCT',
'REDUCE',
'RESHAPE',
'SHAPE',
'SIZE',
'SPREAD',
525 'SUM',
'TRANSPOSE',
'UBOUND',
'UCOBOUND',
'UNPACK'] +
526 (funcList
if funcList
is not None else [])
527 ).intersection(set(n2name(nodeN)
for nodeN
528 in sElem.findall(
'.//{*}named-E/{*}N')))) > 0:
534 newtable, varNew = scope.findArrayBounds(arr, loopVar, newVarList)
537 if var
not in newVarList:
538 newVarList.append(var)
545 inEverywhere = closeLoop(inEverywhere)
548 if not (inEverywhere
and table == newtable):
550 inEverywhere = closeLoop(inEverywhere)
552 if ie != 0
and elem[ie - 1].tail
is not None:
555 tail = tailSave.get(elem[ie - 1], elem[ie - 1].tail)
556 indent = len(tail) - len(tail.rstrip(
' '))
562 inner, outer, extraindent = scope.createDoConstruct(
563 table, indent=indent, concurrent=concurrent)
564 toinsert.append((elem, outer, ie))
565 inEverywhere = (inner, outer, indent, extraindent)
566 tailSave[sElem] = sElem.tail
567 toremove.append((elem, sElem))
568 inner.insert(-1, sElem)
570 updateStmt(sElem, table, kind, extraindent, inner, scope)
573 inEverywhere = closeLoop(inEverywhere)
576 inEverywhere = closeLoop(inEverywhere)
580 inEverywhere = closeLoop(inEverywhere)
582 for scope
in self.getScopes():
585 for elem, outer, ie
in toinsert[::-1]:
586 elem.insert(ie, outer)
588 for parent, elem
in toremove:
591 self.addVar([(v[
'scopePath'], v[
'n'], f
"INTEGER :: {v['n']}",
None)
592 for v
in newVarList])
662 def inline(self, subContained, callStmt, mainScope,
663 simplify=False, loopVar=None):
665 Inline a subContainted subroutine
667 - update the main code if needed (if statement and/or elemental)
668 - copy the subContained node
669 - remove everything before the declarations variables and the variables declarations
670 - deal with optional argument
671 - from the callStmt, replace all the arguments by their names
672 - inline in the main code
673 - add local variables and use statements to the main code
674 :param subContained: xml fragment corresponding to the sub: to inline
675 :param callStmt: the call-stmt to replace
676 :param mainScope: scope of the main (calling) subroutine
677 :param simplify: try to simplify code (construct or variables becoming useless)
678 :param loopVar: None to create new variable for each added DO loop (around ELEMENTAL
680 or a function that return the name of the variable to use for the
682 This function returns a string (name of the variable), or True to create
683 a new variable, or False to not transform this statement
684 The functions takes as arguments:
685 - lower and upper bounds as defined in the declaration statement
686 - lower and upper bounds as given in the statement
690 def setPRESENTby(node, var, val):
692 Replace PRESENT(var) by .TRUE. if val is True, by .FALSE. otherwise on node
694 :param node: xml node to work on (a contained subroutine)
695 :param var: string of the name of the optional variable to check
697 for namedE
in node.findall(
'.//{*}named-E/{*}N/..'):
698 if n2name(namedE.find(
'./{*}N')).upper() ==
'PRESENT':
699 presentarg = n2name(namedE.find(
'./{*}R-LT/{*}parens-R/{*}element-LT/'
700 '{*}element/{*}named-E/{*}N'))
701 if presentarg.upper() == var.upper():
702 for nnn
in namedE[:]:
704 namedE.tag = f
'{{{NAMESPACE}}}literal-E'
705 namedE.text =
'.TRUE.' if val
else '.FALSE.'
708 parent = mainScope.getParent(callStmt)
711 if tag(parent) ==
'action-stmt':
712 mainScope.changeIfStatementsInIfConstructs(mainScope.getParent(parent))
713 parent = mainScope.getParent(callStmt)
717 prefix = subContained.findall(
'.//{*}prefix')
718 if len(prefix) > 0
and 'ELEMENTAL' in [p.text.upper()
for p
in prefix]:
720 mainScope.addArrayParenthesesInNode(callStmt)
723 mainScope.addExplicitArrayBounds(node=callStmt)
726 arrayRincallStmt = callStmt.findall(
'.//{*}array-R')
727 if len(arrayRincallStmt) > 0:
729 table, _ = mainScope.findArrayBounds(mainScope.getParent(arrayRincallStmt[0], 2),
733 for varName
in table.keys():
734 if not mainScope.varList.findVar(varName):
735 var = {
'as': [],
'asx': [],
736 'n': varName,
'i':
None,
't':
'INTEGER',
'arg':
False,
737 'use':
False,
'opt':
False,
'allocatable':
False,
738 'parameter':
False,
'init':
None,
'scopePath': mainScope.path}
739 mainScope.addVar([[mainScope.path, var[
'n'],
740 mainScope.varSpec2stmt(var),
None]])
743 inner, outer, _ = mainScope.createDoConstruct(table)
746 inner.insert(-1, callStmt)
748 parent.insert(list(parent).index(callStmt), outer)
749 parent.remove(callStmt)
751 for namedE
in callStmt.findall(
'./{*}arg-spec/{*}arg/{*}named-E'):
753 if namedE.find(
'./{*}R-LT'):
754 mainScope.arrayR2parensR(namedE, table)
757 node = copy.deepcopy(subContained)
762 varList = copy.deepcopy(self.varList)
763 for var
in [var
for var
in varList.restrict(subContained.path,
True)
764 if not var[
'arg']
and not var[
'use']]:
766 if varList.restrict(mainScope.path,
True).findVar(var[
'n']):
769 newName = re.sub(
r'_\d+$',
'', var[
'n'])
771 while (varList.restrict(subContained.path,
True).findVar(newName +
'_' + str(i))
or
772 varList.restrict(mainScope.path,
True).findVar(newName +
'_' + str(i))):
774 newName +=
'_' + str(i)
775 node.renameVar(var[
'n'], newName)
776 subst.append((var[
'n'], newName))
779 var[
'scopePath'] = mainScope.path
780 localVarToAdd.append(var)
783 for oldName, newName
in subst:
784 for var
in localVarToAdd + varList[:]:
785 if var[
'as']
is not None:
786 var[
'as'] = [[re.sub(
r'\b' + oldName +
r'\b', newName, dim[i])
787 if dim[i]
is not None else None
789 for dim
in var[
'as']]
796 localUseToAdd = node.findall(
'./{*}use-stmt')
797 for sNode
in node.findall(
'./{*}T-decl-stmt') + localUseToAdd + \
798 node.findall(
'./{*}implicit-none-stmt'):
800 while tag(node[1]) ==
'C' and not node[1].text.startswith(
'!$acc'):
809 for argN
in subContained.findall(
'.//{*}subroutine-stmt/{*}dummy-arg-LT/{*}arg-N'):
810 vartable[alltext(argN).upper()] =
None
811 for iarg, arg
in enumerate(callStmt.findall(
'.//{*}arg')):
812 key = arg.find(
'.//{*}arg-N')
815 dummyName = alltext(key).upper()
818 dummyName = list(vartable.keys())[iarg]
820 nodeRLTarray = argnode.findall(
'.//{*}R-LT/{*}array-R')
821 if len(nodeRLTarray) > 0:
823 if len(nodeRLTarray) > 1
or \
824 argnode.find(
'./{*}R-LT/{*}array-R')
is None or \
825 tag(argnode) !=
'named-E':
827 raise PYFTError(
'Argument to complicated: ' + str(alltext(argnode)))
828 dim = nodeRLTarray[0].find(
'./{*}section-subscript-LT')[:]
834 argname =
"".join(argnode.itertext())
837 tmp = copy.deepcopy(argnode)
838 nodeRLT = tmp.find(
'./{*}R-LT')
839 nodeRLT.remove(nodeRLT.find(
'./{*}array-R'))
840 argname =
"".join(tmp.itertext())
841 vartable[dummyName] = {
'node': argnode,
'name': argname,
'dim': dim}
844 for dummyName
in [dummyName
for (dummyName, value)
in vartable.items()
845 if value
is not None]:
846 setPRESENTby(node, dummyName,
True)
847 for dummyName
in [dummyName
for (dummyName, value)
in vartable.items()
849 setPRESENTby(node, dummyName,
False)
852 for dummyName
in [dummyName
for (dummyName, value)
in vartable.items()
if value
is None]:
853 for nodeN
in [nodeN
for nodeN
in node.findall(
'.//{*}named-E/{*}N')
854 if n2name(nodeN).upper() == dummyName]:
857 par = node.getParent(nodeN, level=2)
858 allreadySuppressed = []
859 while par
and not removed
and par
not in allreadySuppressed:
862 if tagName
in (
'a-stmt',
'print-stmt'):
865 elif tagName ==
'call-stmt':
870 raise NotImplementedError(
'call-stmt not (yet?) implemented')
871 elif tagName
in (
'if-stmt',
'where-stmt'):
874 elif tagName
in (
'if-then-stmt',
'else-if-stmt',
'where-construct-stmt',
878 toSuppress = node.getParent(par, 2)
879 elif tagName
in (
'select-case-stmt',
'case-stmt'):
882 toSuppress = node.getParent(par, 2)
883 elif tagName.endswith(
'-block')
or tagName.endswith(
'-stmt')
or \
884 tagName.endswith(
'-construct'):
891 raise PYFTError((
"We shouldn't be here. A case may have been " +
892 "overlooked (tag={tag}).".format(tag=tagName)))
893 if toSuppress
is not None:
895 if toSuppress
not in allreadySuppressed:
898 node.removeStmtNode(toSuppress,
False, simplify)
899 allreadySuppressed.extend(list(toSuppress.iter()))
901 par = node.getParent(par)
904 for name, dummy
in vartable.items():
908 for namedE
in [namedE
for namedE
in node.findall(
'.//{*}named-E/{*}N/{*}n/../..')
909 if n2name(namedE.find(
'{*}N')).upper() == name]:
911 nodeN = namedE.find(
'./{*}N')
912 ns = nodeN.findall(
'./{*}n')
913 ns[0].text = n2name(nodeN)
919 descMain = varList.restrict(mainScope.path,
True).findVar(dummy[
'name'])
920 descSub = varList.restrict(subContained.path,
True).findVar(name)
924 if var[
'as']
is not None:
925 var[
'as'] = [[re.sub(
r'\b' + name +
r'\b', dummy[
'name'], dim[i])
926 if dim[i]
is not None else None
928 for dim
in var[
'as']]
933 nodeRLT = namedE.find(
'./{*}R-LT')
934 if nodeRLT
is not None and tag(nodeRLT[0]) !=
'component-R':
936 assert tag(nodeRLT[0])
in (
'array-R',
'parens-R'),
'Internal error'
937 slices = nodeRLT[0].findall(
'./{*}section-subscript-LT/' +
938 '{*}section-subscript')
939 slices += nodeRLT[0].findall(
'./{*}element-LT/{*}element')
942 if (descMain
is not None and len(descMain[
'as']) > 0)
or \
943 len(descSub[
'as']) > 0
or dummy[
'dim']
is not None:
945 if len(descSub[
'as']) > 0:
946 ndim = len(descSub[
'as'])
949 if dummy[
'dim']
is not None:
952 ndim = len([d
for d
in dummy[
'dim']
if ':' in alltext(d)])
955 ndim = len(descMain[
'as'])
956 ns[0].text +=
'(' + (
', '.join([
':'] * ndim)) +
')'
957 updatedNamedE = createExprPart(alltext(namedE))
958 namedE.tag = updatedNamedE.tag
959 namedE.text = updatedNamedE.text
960 for nnn
in namedE[:]:
962 namedE.extend(updatedNamedE[:])
963 slices = namedE.find(
'./{*}R-LT')[0].findall(
964 './{*}section-subscript-LT/{*}section-subscript')
970 namedE.find(
'./{*}N')[0].text = dummy[
'name']
978 for isl, sl
in enumerate(slices):
980 if len(descSub[
'as']) == 0
or descSub[
'as'][isl][1]
is None:
983 if dummy[
'dim']
is not None:
985 tagName =
'./{*}lower-bound' if i == 0
else './{*}upper-bound'
986 descSub[i] = dummy[
'dim'][isl].find(tagName)
989 if descSub[i]
is not None:
991 descSub[i] = alltext(descSub[i])
994 if descMain
is not None and descMain[
'as'][isl][1]
is not None:
996 descSub[i] = descMain[
'as'][isl][i]
997 if i == 0
and descSub[i]
is None:
1000 descSub[i] =
"L" if i == 0
else "U"
1001 descSub[i] +=
"BOUND({name}, {isl})".format(
1002 name=dummy[
'name'], isl=isl + 1)
1004 descSub[0] = descSub[
'as'][isl][0]
1005 if descSub[0]
is None:
1007 descSub[1] = descSub[
'as'][isl][1]
1019 if dummy[
'dim']
is not None and \
1020 not alltext(dummy[
'dim'][isl]).strip().startswith(
':'):
1021 offset = alltext(dummy[
'dim'][isl].find(
'./{*}lower-bound'))
1023 if descMain
is not None:
1024 offset = descMain[
'as'][isl][0]
1027 elif offset.strip().startswith(
'-'):
1028 offset =
'(' + offset +
')'
1030 offset =
"LBOUND({name}, {isl})".format(
1031 name=dummy[
'name'], isl=isl + 1)
1032 if offset.upper() == descSub[0].upper():
1035 if descSub[0].strip().startswith(
'-'):
1036 offset +=
'- (' + descSub[0] +
')'
1038 offset +=
'-' + descSub[0]
1042 if tag(sl) ==
'element' or \
1043 (tag(sl) ==
'section-subscript' and ':' not in alltext(sl)):
1047 low = sl.find(
'./{*}lower-bound')
1049 low = createElem(
'lower-bound', tail=sl.text)
1050 low.append(createExprPart(descSub[0]))
1053 up = sl.find(
'./{*}upper-bound')
1055 up = createElem(
'upper-bound')
1056 up.append(createExprPart(descSub[1]))
1059 for bound
in bounds:
1061 if bound[-1].tail
is None:
1063 bound[-1].tail +=
'+' + offset
1069 if dummy[
'dim']
is not None and len(dummy[
'dim']) > len(slices):
1070 slices[-1].tail =
', '
1071 par = node.getParent(slices[-1])
1072 par.extend(dummy[
'dim'][len(slices):])
1077 updatedNamedE = createExprPart(alltext(namedE))
1078 namedE.tag = updatedNamedE.tag
1079 namedE.text = updatedNamedE.text
1080 for nnn
in namedE[:]:
1082 namedE.extend(updatedNamedE[:])
1084 node.remove(node.find(
'./{*}subroutine-stmt'))
1085 node.remove(node.find(
'./{*}end-subroutine-stmt'))
1088 mainScope.addVar([[mainScope.path, var[
'n'], mainScope.varSpec2stmt(var),
None]
1089 for var
in localVarToAdd])
1090 mainScope.addModuleVar([[mainScope.path, n2name(useStmt.find(
'.//{*}module-N//{*}N')),
1091 [n2name(v.find(
'.//{*}N'))
1092 for v
in useStmt.findall(
'.//{*}use-N')]]
1093 for useStmt
in localUseToAdd])
1096 index = list(parent).index(callStmt)
1097 parent.remove(callStmt)
1098 if callStmt.tail
is not None:
1099 if node[-1].tail
is None:
1100 node[-1].tail = callStmt.tail
1102 node[-1].tail = node[-1].tail + callStmt.tail
1103 for node
in node[::-1]:
1105 parent.insert(index, node)
1237 This function removes a statement node and:
1238 - suppress variable that became useless (if simplifyVar is True)
1239 - suppress outer loop/if if useless (if simplifyStruct is True)
1240 :param nodes: node (or list of nodes) to remove
1241 :param simplifyVar: try to simplify code (if we delete "CALL FOO(X)" and if X not used
1242 else where, we also delete it; or if the call was alone inside a
1243 if-then-endif construct, with simplifyStruct=True, the construct is also
1244 removed, and variables used in the if condition are also checked...)
1245 :param simplifyStruct: try to simplify code (if we delete "CALL FOO(X)" and if the call was
1246 alone inside a if-then-endif construct, the construct is also
1247 removed and variables used in the if condition
1248 (with simplifyVar=True) are also checked...)
1253 nodesToSuppress = []
1254 if not isinstance(nodes, list):
1257 if tag(node)
in (
'if-stmt',
'where-stmt'):
1258 action = node.find(
'./{*}action-stmt')
1259 if action
is not None and len(action) != 0:
1260 nodesToSuppress.append(action[0])
1262 nodesToSuppress.append(node)
1263 elif tag(node) ==
'}action-stmt':
1265 nodesToSuppress.append(node[0])
1267 nodesToSuppress.append(node)
1269 nodesToSuppress.append(node)
1274 for node
in nodesToSuppress:
1275 scopePath = self.getScopePath(node)
1276 if tag(node) ==
'do-construct':
1278 varToCheck.extend([(scopePath, n2name(arg))
1279 for arg
in node.find(
'./{*}do-stmt').findall(
'.//{*}N')])
1280 elif tag(node)
in (
'if-construct',
'if-stmt'):
1282 varToCheck.extend([(scopePath, n2name(arg))
1283 for arg
in node.findall(
'.//{*}condition-E//{*}N')])
1284 elif tag(node)
in (
'where-construct',
'where-stmt'):
1286 varToCheck.extend([(scopePath, n2name(arg))
1287 for arg
in node.findall(
'.//{*}mask-E//{*}N')])
1288 elif tag(node) ==
'call-stmt':
1290 varToCheck.extend([(scopePath, n2name(arg))
1291 for arg
in node.findall(
'./{*}arg-spec//{*}N')])
1293 varToCheck.append((scopePath,
1294 n2name(node.find(
'./{*}procedure-designator//{*}N'))))
1295 elif tag(node)
in (
'a-stmt',
'print-stmt'):
1296 varToCheck.extend([(scopePath, n2name(arg))
for arg
in node.findall(
'.//{*}N')])
1297 elif tag(node) ==
'selectcase-construct':
1299 varToCheck.extend([(scopePath, n2name(arg))
1300 for arg
in node.findall(
'.//{*}case-E//{*}N')])
1301 varToCheck.extend([(scopePath, n2name(arg))
1302 for arg
in node.findall(
'.//{*}case-value//{*}N')])
1306 for node
in nodesToSuppress:
1307 parent = self.getParent(node)
1308 parents[id(node)] = parent
1309 newlines =
'\n' * (alltext(node).count(
'\n')
if tag(node).endswith(
'-construct')
else 0)
1310 if node.tail
is not None or len(newlines) > 0:
1311 previous = self.getSiblings(node, after=
False)
1312 if len(previous) == 0:
1315 previous = previous[-1]
1316 if previous.tail
is None:
1318 previous.tail = (previous.tail.replace(
'\n',
'') +
1319 (node.tail
if node.tail
is not None else ''))
1323 self.removeVarIfUnused(varToCheck, excludeDummy=
True,
1324 excludeModule=
True, simplify=simplifyVar)
1327 newNodesToSuppress = []
1328 for node
in nodesToSuppress:
1329 parent = parents[id(node)]
1332 if tag(parent) ==
'action-stmt':
1333 newNodesToSuppress.append(self.getParent(parent))
1335 elif simplifyStruct:
1336 if tag(parent) ==
'do-construct' and len(
_nodesInDo(parent)) == 0:
1337 newNodesToSuppress.append(parent)
1338 elif tag(parent) ==
'if-block':
1339 parPar = self.getParent(parent)
1341 newNodesToSuppress.append(parPar)
1342 elif tag(parent) ==
'where-block':
1343 parPar = self.getParent(parent)
1345 newNodesToSuppress.append(parPar)
1346 elif tag(parent) ==
'selectcase-block':
1347 parPar = self.getParent(parent)
1349 newNodesToSuppress.append(parPar)
1351 constructNodes, otherNodes = [], []
1352 for nnn
in newNodesToSuppress:
1353 if tag(nnn).endswith(
'-construct'):
1354 if nnn
not in constructNodes:
1355 constructNodes.append(nnn)
1357 if nnn
not in otherNodes:
1358 otherNodes.append(nnn)
1360 if len(otherNodes) > 0:
1363 for nnn
in constructNodes:
1420 :param loopVariables: ordered dictionnary with loop variables as key and bounds as values.
1421 Bounds are expressed with a 2-tuple.
1422 Keys must be in the same order as the order used when addressing an
1423 element: if loopVariables.keys is [JI, JK], arrays are
1424 addressed with (JI, JK)
1425 :param indent: current indentation
1426 :param concurrent: if False, output is made of nested 'DO' loops
1427 if True, output is made of a single 'DO CONCURRENT' loop
1428 :return: (inner, outer, extraindent) with
1429 - inner the inner do-construct where statements must be added
1430 - outer the outer do-construct to be inserted somewhere
1431 - extraindent the number of added indentation
1432 (2 if concurrent else 2*len(loopVariables))
1458 for var, (lo, up)
in list(loopVariables.items())[::-1]:
1459 nodeV = createElem(
'V', tail=
'=')
1460 nodeV.append(createExprPart(var))
1461 lower, upper = createArrayBounds(lo, up,
'DOCONCURRENT')
1463 triplet = createElem(
'forall-triplet-spec')
1464 triplet.extend([nodeV, lower, upper])
1466 triplets.append(triplet)
1468 tripletLT = createElem(
'forall-triplet-spec-LT', tail=
')')
1469 for triplet
in triplets[:-1]:
1471 tripletLT.extend(triplets)
1473 dostmt = createElem(
'do-stmt', text=
'DO CONCURRENT (', tail=
'\n')
1474 dostmt.append(tripletLT)
1475 enddostmt = createElem(
'end-do-stmt', text=
'END DO')
1477 doconstruct = createElem(
'do-construct', tail=
'\n')
1478 doconstruct.extend([dostmt, enddostmt])
1479 inner = outer = doconstruct
1480 doconstruct[0].tail += (indent + 2) *
' '
1491 def makeDo(var, lo, up):
1492 doV = createElem(
'do-V', tail=
'=')
1493 doV.append(createExprPart(var))
1494 lower, upper = createArrayBounds(lo, up,
'DO')
1496 dostmt = createElem(
'do-stmt', text=
'DO ', tail=
'\n')
1497 dostmt.extend([doV, lower, upper])
1499 enddostmt = createElem(
'end-do-stmt', text=
'END DO')
1501 doconstruct = createElem(
'do-construct', tail=
'\n')
1502 doconstruct.extend([dostmt, enddostmt])
1507 for i, (var, (lo, up))
in enumerate(list(loopVariables.items())[::-1]):
1508 doconstruct = makeDo(var, lo, up)
1510 doconstruct[0].tail += (indent + 2 * i + 2) *
' '
1515 inner.insert(1, doconstruct)
1518 doconstruct.tail += (indent + 2 * i - 2) *
' '
1519 return inner, outer, 2
if concurrent
else 2 * len(loopVariables)
1544 :param item: item to remove from list
1545 :param itemPar: the parent of item (the list)
1548 nodesToSuppress = [item]
1551 i = list(itemPar).index(item)
1552 if item.tail
is not None and ',' in item.tail:
1555 item.tail = tail.replace(
',',
'')
1556 elif i != 0
and ',' in itemPar[i - 1].tail:
1558 tail = itemPar[i - 1].tail
1559 itemPar[i - 1].tail = tail.replace(
',',
'')
1565 while j < len(itemPar)
and not found:
1566 if nonCode(itemPar[j]):
1568 if itemPar[j].tail
is not None and ',' in itemPar[j].tail:
1571 tail = itemPar[j].tail
1572 itemPar[j].tail = tail.replace(
',',
'')
1582 while j >= 0
and not found:
1583 if itemPar[j].tail
is not None and ',' in itemPar[j].tail:
1586 tail = itemPar[j].tail
1587 itemPar[j].tail = tail.replace(
',',
'')
1589 if nonCode(itemPar[j]):
1597 len([e
for e
in itemPar
if not nonCode(e)]) != 1:
1598 raise RuntimeError(
"Something went wrong here....")
1601 if i + 1 < len(itemPar)
and tag(itemPar[i + 1]) ==
'cnt':
1603 reason =
'lastOnLine'
1615 elif len([itemPar[j]
for j
in range(i + 1, len(itemPar))
if not nonCode(itemPar[j])]) == 0:
1629 if reason
is not None:
1630 def _getPrecedingCnt(itemPar, i):
1632 Return the index of the preceding node which is a continuation character
1633 :param itemPar: the list containig the node to suppress
1634 :param i: the index of the current node, i-1 is the starting index for the search
1635 :return: a tuple with three elements:
1636 - the node containing the preceding '&' character
1637 - the parent of the node containing the preceding '&' character
1638 - index of the preceding '&' in the parent (previsous element
1641 - In the general case the preceding '&' belongs to the same list:
1642 USE MODD, ONLY: X, &
1644 - But it exists a special case, where the preceding '&' don't belong to
1645 the same list (in the following example, both '&' are attached to the parent):
1650 while j >= 0
and tag(itemPar[j]) ==
'C':
1652 if j >= 0
and tag(itemPar[j]) ==
'cnt':
1653 return itemPar[j], itemPar, j
1659 siblings = self.getSiblings(itemPar, before=
True, after=
False)
1660 j2 = len(siblings) - 1
1661 while j2 >= 0
and tag(siblings[j2]) ==
'C':
1663 if j2 >= 0
and tag(siblings[j2]) ==
'cnt':
1664 return siblings[j2], siblings, j2
1665 return None,
None,
None
1667 precCnt, newl, j = _getPrecedingCnt(itemPar, i)
1668 if precCnt
is not None:
1670 nodesToSuppress.append(precCnt
if reason ==
'last' else itemPar[i + 1])
1672 precCnt2, _, _ = _getPrecedingCnt(newl, j)
1673 if precCnt2
is not None:
1675 nodesToSuppress.append(precCnt2
if reason ==
'last' else precCnt)
1678 for node
in nodesToSuppress:
1685 parent = self.getParent(itemPar)
1686 i = list(parent).index(node)
1687 if i != 0
and node.tail
is not None:
1688 if parent[i - 1].tail
is None:
1689 parent[i - 1].tail =
''
1690 parent[i - 1].tail = parent[i - 1].tail + node.tail