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)
1258 This function removes a statement node and:
1259 - suppress variable that became useless (if simplifyVar is True)
1260 - suppress outer loop/if if useless (if simplifyStruct is True)
1261 :param nodes: node (or list of nodes) to remove
1262 :param simplifyVar: try to simplify code (if we delete "CALL FOO(X)" and if X not used
1263 else where, we also delete it; or if the call was alone inside a
1264 if-then-endif construct, with simplifyStruct=True, the construct is also
1265 removed, and variables used in the if condition are also checked...)
1266 :param simplifyStruct: try to simplify code (if we delete "CALL FOO(X)" and if the call was
1267 alone inside a if-then-endif construct, the construct is also
1268 removed and variables used in the if condition
1269 (with simplifyVar=True) are also checked...)
1274 nodesToSuppress = []
1275 if not isinstance(nodes, list):
1278 if tag(node)
in (
'if-stmt',
'where-stmt'):
1279 action = node.find(
'./{*}action-stmt')
1280 if action
is not None and len(action) != 0:
1281 nodesToSuppress.append(action[0])
1283 nodesToSuppress.append(node)
1284 elif tag(node) ==
'}action-stmt':
1286 nodesToSuppress.append(node[0])
1288 nodesToSuppress.append(node)
1290 nodesToSuppress.append(node)
1295 for node
in nodesToSuppress:
1296 scopePath = self.getScopePath(node)
1297 if tag(node) ==
'do-construct':
1299 varToCheck.extend([(scopePath, n2name(arg))
1300 for arg
in node.find(
'./{*}do-stmt').findall(
'.//{*}N')])
1301 elif tag(node)
in (
'if-construct',
'if-stmt'):
1303 varToCheck.extend([(scopePath, n2name(arg))
1304 for arg
in node.findall(
'.//{*}condition-E//{*}N')])
1305 elif tag(node)
in (
'where-construct',
'where-stmt'):
1307 varToCheck.extend([(scopePath, n2name(arg))
1308 for arg
in node.findall(
'.//{*}mask-E//{*}N')])
1309 elif tag(node) ==
'call-stmt':
1311 varToCheck.extend([(scopePath, n2name(arg))
1312 for arg
in node.findall(
'./{*}arg-spec//{*}N')])
1314 varToCheck.append((scopePath,
1315 n2name(node.find(
'./{*}procedure-designator//{*}N'))))
1316 elif tag(node)
in (
'a-stmt',
'print-stmt'):
1317 varToCheck.extend([(scopePath, n2name(arg))
for arg
in node.findall(
'.//{*}N')])
1318 elif tag(node) ==
'selectcase-construct':
1320 varToCheck.extend([(scopePath, n2name(arg))
1321 for arg
in node.findall(
'.//{*}case-E//{*}N')])
1322 varToCheck.extend([(scopePath, n2name(arg))
1323 for arg
in node.findall(
'.//{*}case-value//{*}N')])
1327 for node
in nodesToSuppress:
1328 parent = self.getParent(node)
1329 parents[id(node)] = parent
1330 newlines =
'\n' * (alltext(node).count(
'\n')
if tag(node).endswith(
'-construct')
else 0)
1331 if node.tail
is not None or len(newlines) > 0:
1332 previous = self.getSiblings(node, after=
False)
1333 if len(previous) == 0:
1336 previous = previous[-1]
1337 if previous.tail
is None:
1339 previous.tail = (previous.tail.replace(
'\n',
'') +
1340 (node.tail
if node.tail
is not None else ''))
1344 self.removeVarIfUnused(varToCheck, excludeDummy=
True,
1345 excludeModule=
True, simplify=simplifyVar)
1348 newNodesToSuppress = []
1349 for node
in nodesToSuppress:
1350 parent = parents[id(node)]
1353 if tag(parent) ==
'action-stmt':
1354 newNodesToSuppress.append(self.getParent(parent))
1356 elif simplifyStruct:
1357 if tag(parent) ==
'do-construct' and len(
_nodesInDo(parent)) == 0:
1358 newNodesToSuppress.append(parent)
1359 elif tag(parent) ==
'if-block':
1360 parPar = self.getParent(parent)
1362 newNodesToSuppress.append(parPar)
1363 elif tag(parent) ==
'where-block':
1364 parPar = self.getParent(parent)
1366 newNodesToSuppress.append(parPar)
1367 elif tag(parent) ==
'selectcase-block':
1368 parPar = self.getParent(parent)
1370 newNodesToSuppress.append(parPar)
1372 constructNodes, otherNodes = [], []
1373 for nnn
in newNodesToSuppress:
1374 if tag(nnn).endswith(
'-construct'):
1375 if nnn
not in constructNodes:
1376 constructNodes.append(nnn)
1378 if nnn
not in otherNodes:
1379 otherNodes.append(nnn)
1381 if len(otherNodes) > 0:
1384 for nnn
in constructNodes:
1441 :param loopVariables: ordered dictionnary with loop variables as key and bounds as values.
1442 Bounds are expressed with a 2-tuple.
1443 Keys must be in the same order as the order used when addressing an
1444 element: if loopVariables.keys is [JI, JK], arrays are
1445 addressed with (JI, JK)
1446 :param indent: current indentation
1447 :param concurrent: if False, output is made of nested 'DO' loops
1448 if True, output is made of a single 'DO CONCURRENT' loop
1449 :return: (inner, outer, extraindent) with
1450 - inner the inner do-construct where statements must be added
1451 - outer the outer do-construct to be inserted somewhere
1452 - extraindent the number of added indentation
1453 (2 if concurrent else 2*len(loopVariables))
1479 for var, (lo, up)
in list(loopVariables.items())[::-1]:
1480 nodeV = createElem(
'V', tail=
'=')
1481 nodeV.append(createExprPart(var))
1482 lower, upper = createArrayBounds(lo, up,
'DOCONCURRENT')
1484 triplet = createElem(
'forall-triplet-spec')
1485 triplet.extend([nodeV, lower, upper])
1487 triplets.append(triplet)
1489 tripletLT = createElem(
'forall-triplet-spec-LT', tail=
')')
1490 for triplet
in triplets[:-1]:
1492 tripletLT.extend(triplets)
1494 dostmt = createElem(
'do-stmt', text=
'DO CONCURRENT (', tail=
'\n')
1495 dostmt.append(tripletLT)
1496 enddostmt = createElem(
'end-do-stmt', text=
'END DO')
1498 doconstruct = createElem(
'do-construct', tail=
'\n')
1499 doconstruct.extend([dostmt, enddostmt])
1500 inner = outer = doconstruct
1501 doconstruct[0].tail += (indent + 2) *
' '
1512 def makeDo(var, lo, up):
1513 doV = createElem(
'do-V', tail=
'=')
1514 doV.append(createExprPart(var))
1515 lower, upper = createArrayBounds(lo, up,
'DO')
1517 dostmt = createElem(
'do-stmt', text=
'DO ', tail=
'\n')
1518 dostmt.extend([doV, lower, upper])
1520 enddostmt = createElem(
'end-do-stmt', text=
'END DO')
1522 doconstruct = createElem(
'do-construct', tail=
'\n')
1523 doconstruct.extend([dostmt, enddostmt])
1528 for i, (var, (lo, up))
in enumerate(list(loopVariables.items())[::-1]):
1529 doconstruct = makeDo(var, lo, up)
1531 doconstruct[0].tail += (indent + 2 * i + 2) *
' '
1536 inner.insert(1, doconstruct)
1539 doconstruct.tail += (indent + 2 * i - 2) *
' '
1540 return inner, outer, 2
if concurrent
else 2 * len(loopVariables)
1565 :param item: item to remove from list
1566 :param itemPar: the parent of item (the list)
1569 nodesToSuppress = [item]
1572 i = list(itemPar).index(item)
1573 if item.tail
is not None and ',' in item.tail:
1576 item.tail = tail.replace(
',',
'')
1577 elif i != 0
and ',' in itemPar[i - 1].tail:
1579 tail = itemPar[i - 1].tail
1580 itemPar[i - 1].tail = tail.replace(
',',
'')
1586 while j < len(itemPar)
and not found:
1587 if nonCode(itemPar[j]):
1589 if itemPar[j].tail
is not None and ',' in itemPar[j].tail:
1592 tail = itemPar[j].tail
1593 itemPar[j].tail = tail.replace(
',',
'')
1603 while j >= 0
and not found:
1604 if itemPar[j].tail
is not None and ',' in itemPar[j].tail:
1607 tail = itemPar[j].tail
1608 itemPar[j].tail = tail.replace(
',',
'')
1610 if nonCode(itemPar[j]):
1618 len([e
for e
in itemPar
if not nonCode(e)]) != 1:
1619 raise RuntimeError(
"Something went wrong here....")
1622 if i + 1 < len(itemPar)
and tag(itemPar[i + 1]) ==
'cnt':
1624 reason =
'lastOnLine'
1636 elif len([itemPar[j]
for j
in range(i + 1, len(itemPar))
if not nonCode(itemPar[j])]) == 0:
1650 if reason
is not None:
1651 def _getPrecedingCnt(itemPar, i):
1653 Return the index of the preceding node which is a continuation character
1654 :param itemPar: the list containig the node to suppress
1655 :param i: the index of the current node, i-1 is the starting index for the search
1656 :return: a tuple with three elements:
1657 - the node containing the preceding '&' character
1658 - the parent of the node containing the preceding '&' character
1659 - index of the preceding '&' in the parent (previsous element
1662 - In the general case the preceding '&' belongs to the same list:
1663 USE MODD, ONLY: X, &
1665 - But it exists a special case, where the preceding '&' don't belong to
1666 the same list (in the following example, both '&' are attached to the parent):
1671 while j >= 0
and tag(itemPar[j]) ==
'C':
1673 if j >= 0
and tag(itemPar[j]) ==
'cnt':
1674 return itemPar[j], itemPar, j
1680 siblings = self.getSiblings(itemPar, before=
True, after=
False)
1681 j2 = len(siblings) - 1
1682 while j2 >= 0
and tag(siblings[j2]) ==
'C':
1684 if j2 >= 0
and tag(siblings[j2]) ==
'cnt':
1685 return siblings[j2], siblings, j2
1686 return None,
None,
None
1688 precCnt, newl, j = _getPrecedingCnt(itemPar, i)
1689 if precCnt
is not None:
1691 nodesToSuppress.append(precCnt
if reason ==
'last' else itemPar[i + 1])
1693 precCnt2, _, _ = _getPrecedingCnt(newl, j)
1694 if precCnt2
is not None:
1696 nodesToSuppress.append(precCnt2
if reason ==
'last' else precCnt)
1699 for node
in nodesToSuppress:
1706 parent = self.getParent(itemPar)
1707 i = list(parent).index(node)
1708 if i != 0
and node.tail
is not None:
1709 if parent[i - 1].tail
is None:
1710 parent[i - 1].tail =
''
1711 parent[i - 1].tail = parent[i - 1].tail + node.tail