Esempio n. 1
0
 def parseDataObjectsAndRemainder(specRightHandSide):
     dataObjects, remainder = splitIntoComponentsAndRemainder(specRightHandSide)
     if len(dataObjects) == 0:
         raise UsageError("no data objects defined on this line")
     if len(dataObjects) > 1 and remainder.strip() != "":
         raise UsageError("invalid right hand side specification in '%s'" %(specRightHandSide))
     parsedDataObjects = []
     for dataObject in dataObjects:
         parsedDataObjects.append(getComponentNameAndBracketContent(dataObject))
     return tuple(parsedDataObjects), remainder
Esempio n. 2
0
 def implemented(self):
     purgedRoutineElements = []
     try:
         self._updateSymbolState()
         self.checkSymbols()
         implementedRoutineElements = [
             self._implementHeader(),
             self._implementAdditionalImports()
         ]
         implementedRoutineElements += [
             region.implemented(parentRoutine=self)
             for region in self._regions
         ]
         implementedRoutineElements += [self._implementFooter()]
         purgedRoutineElements = [
             (index, text)
             for index, text in enumerate(implementedRoutineElements)
             if text != ""
         ]
     except UsageError as e:
         raise UsageError("In %s: %s" % (self.name, str(e)))
     except ScopeError as e:
         raise ScopeError("In %s: %s;\nTraceback: %s" %
                          (self.name, str(e), traceback.format_exc()))
     except Exception as e:
         raise ScopeError("In %s: %s;\nTraceback: %s" %
                          (self.name, str(e), traceback.format_exc()))
     return "\n".join([text for (index, text) in purgedRoutineElements])
Esempio n. 3
0
	def getUpperBound(domainSizeSpec):
		boundaries = domainSizeSpec.split(':')
		if len(boundaries) == 1:
			return boundaries[0].strip()
		if len(boundaries) == 2:
			return boundaries[1].strip()
		raise UsageError("Unexpected domain size specification: %s" %(domainSizeSpec))
Esempio n. 4
0
    def __init__(self, doc):
        def getCallIndexByAttribute(attributeName):
            index = {}
            for call in doc.getElementsByTagName("call"):
                identifier = call.getAttribute(attributeName)
                callList = index.get(identifier, [])
                callList.append(call)
                index[identifier] = callList
            return index

        routinesByName = {}
        for routine in doc.getElementsByTagName("routine"):
            routineName = routine.getAttribute("name")
            if routineName in routinesByName:
                raise UsageError(
                    "Duplicate subroutines found with name %s. Subroutines need to have unique names in Hybrid Fortran."
                    % (routineName))
            routinesByName[routineName] = routine

        callsByCalleeName = getCallIndexByAttribute("callee")
        callsByCallerName = getCallIndexByAttribute("caller")
        callGraphEdgesByCallerName = {}
        callGraphEdgesByCalleeName = {}

        def addCallees(routineName):
            for call in callsByCallerName.get(routineName, []):
                callerName = call.getAttribute("caller")
                if callerName != routineName:
                    raise Exception(
                        "unexpected error when constructing callgraph")
                calleeName = call.getAttribute("callee")
                edgeList = callGraphEdgesByCallerName.get(routineName, [])
                edgeList.append((callerName, calleeName))
                callGraphEdgesByCallerName[routineName] = edgeList
                edgeList = callGraphEdgesByCalleeName.get(calleeName, [])
                edgeList.append((callerName, calleeName))
                callGraphEdgesByCalleeName[calleeName] = edgeList
                addCallees(calleeName)

        callGraphRootRoutineNames = [
            routineName for routineName in routinesByName.keys()
            if len(callsByCalleeName.get(routineName, [])) == 0
        ]
        for routineName in callGraphRootRoutineNames:
            addCallees(routineName)

        #at this point we should have the complete callgraph
        self.callGraphEdgesByCallerName = callGraphEdgesByCallerName
        self.routinesByName = routinesByName
        self.callsByCalleeName = callsByCalleeName
        self.callsByCallerName = callsByCallerName
        self.doc = doc
        self.symbolsNode = createOrGetFirstNodeWithName('symbols', doc)
Esempio n. 5
0
def parseSpecification(line, keepComponentsAsList=False):
    def parseDataObjectsAndRemainder(specRightHandSide):
        dataObjects, remainder = splitIntoComponentsAndRemainder(specRightHandSide)
        if len(dataObjects) == 0:
            raise UsageError("no data objects defined on this line")
        if len(dataObjects) > 1 and remainder.strip() != "":
            raise UsageError("invalid right hand side specification in '%s'" %(specRightHandSide))
        parsedDataObjects = []
        for dataObject in dataObjects:
            parsedDataObjects.append(getComponentNameAndBracketContent(dataObject))
        return tuple(parsedDataObjects), remainder

    patterns = regexPatterns
    multiSpecMatch = patterns.multiSpecPattern.match(line)
    declarationComponents, remainder = None, None
    if multiSpecMatch:
        doublePrecisionMatch = patterns.doublePrecisionPattern.match(multiSpecMatch.group(1))
        if doublePrecisionMatch:
            #double precision type, because of the space in the type name, doesn't work with the default method :(
            declarationComponents, _ = splitIntoComponentsAndRemainder(doublePrecisionMatch.group(1))
            declarationComponents.insert(0, "double precision")
        else:
            declarationComponents, _ = splitIntoComponentsAndRemainder(multiSpecMatch.group(1))
        if len(declarationComponents) == 0 or not patterns.standardTypePattern.match(declarationComponents[0]):
            return None, None, None
        parsedDataObjects, remainder = parseDataObjectsAndRemainder(multiSpecMatch.group(2))
        if keepComponentsAsList:
            return declarationComponents, parsedDataObjects, remainder
        return ", ".join(declarationComponents), parsedDataObjects, remainder

    doublePrecisionMatch = patterns.doublePrecisionPattern.match(line)
    if doublePrecisionMatch:
        #double precision type, because of the space in the type name, doesn't work with the default method :(
        declarationComponents, remainder = splitIntoComponentsAndRemainder(doublePrecisionMatch.group(1))
        remainder = remainder.strip()
        if remainder == "" and len(declarationComponents) > 0:
            remainder = declarationComponents[-1]
            declarationComponents = declarationComponents[:-1]
        declarationComponents.insert(0, "double precision")
    else:
        declarationComponents, remainder = splitIntoComponentsAndRemainder(line)
    if remainder.strip() == "" or len(declarationComponents) == 0:
        return None, None, None
    if len(declarationComponents) == 0 or not patterns.standardTypePattern.match(declarationComponents[0]):
        return None, None, None
    parsedDataObjects, remainder = parseDataObjectsAndRemainder(remainder)
    if len(parsedDataObjects) != 1:
        raise UsageError("invalid number of data objects specified on this declaration line")
    if keepComponentsAsList:
        return declarationComponents, parsedDataObjects, remainder
    return ", ".join(declarationComponents), parsedDataObjects, remainder
Esempio n. 6
0
def implementSymbolAccessStringAndRemainder(line,
                                            suffix,
                                            symbol,
                                            iterators=[],
                                            parallelRegionTemplate=None,
                                            callee=None):
    isPointerAssignment = RegExPatterns.Instance(
    ).pointerAssignmentPattern.match(line) != None
    try:
        symbolAccessString, remainder = getSymbolAccessStringAndRemainder(
            symbol, iterators, parallelRegionTemplate, suffix, callee,
            isPointerAssignment)
    except UsageError as e:
        raise UsageError("%s; Print of Line: %s" % (str(e), line))
    return symbolAccessString, remainder
Esempio n. 7
0
def implementSymbolAccessStringAndRemainder(
	line,
	suffix,
	symbol,
	iterators=[],
	parallelRegionTemplate=None,
	callee=None,
	useDeviceVersionIfAvailable=True
):
	isPointerAssignment = regexPatterns.pointerAssignmentPattern.match(line) != None
	try:
		symbolAccessString, remainder = getSymbolAccessStringAndRemainder(
			symbol,
			iterators,
			parallelRegionTemplate,
			suffix,
			callee,
			isPointerAssignment,
			useDeviceVersionIfAvailable=useDeviceVersionIfAvailable
		)
	except UsageError as e:
		raise UsageError("%s; Print of Line: %s" %(str(e), line))
	return symbolAccessString, remainder
Esempio n. 8
0
    def processInsideDeclarationsState(self, line):
        '''process everything that happens per h90 declaration line'''
        subProcCallMatch = self.patterns.subprocCallPattern.match(line)
        parallelRegionMatch = self.patterns.parallelRegionPattern.match(line)
        domainDependantMatch = self.patterns.domainDependantPattern.match(line)
        subProcEndMatch = self.patterns.subprocEndPattern.match(line)
        templateMatch = self.patterns.templatePattern.match(line)
        templateEndMatch = self.patterns.templateEndPattern.match(line)
        branchMatch = self.patterns.branchPattern.match(line)
        dataStatementMatch = self.patterns.dataStatementPattern.match(line)

        if dataStatementMatch:
            self.processDataStatementMatch(dataStatementMatch)
            return
        if branchMatch:
            self.processBranchMatch(branchMatch)
            return
        if subProcCallMatch:
            self.switchToNewRegion("CallRegion")
            self.processCallMatch(subProcCallMatch)
            self.switchToNewRegion()
            return
        if subProcEndMatch:
            self.processProcEndMatch(subProcEndMatch)
            if self.state == "inside_branch":
                self.stateBeforeBranch = 'inside_module_body'
            else:
                self.state = 'inside_module_body'
            return
        if parallelRegionMatch:
            raise UsageError("parallel region without parallel dependants")
        if self.patterns.subprocBeginPattern.match(line):
            raise UsageError("subprocedure within subprocedure not allowed")
        if templateMatch:
            raise UsageError(
                "template directives are only allowed outside of subroutines")
        if templateEndMatch:
            raise UsageError(
                "template directives are only allowed outside of subroutines")

        if domainDependantMatch:
            if self.state == "inside_branch":
                self.stateBeforeBranch = 'inside_domainDependantRegion'
            else:
                self.state = 'inside_domainDependantRegion'
            self.switchToNewRegion()
            self.processDomainDependantMatch(domainDependantMatch)
            return

        importMatch1 = self.patterns.importPattern.match(line)
        importMatch2 = self.patterns.singleMappedImportPattern.match(line)
        importMatch3 = self.patterns.importAllPattern.match(line)
        specTuple = parseSpecification(line)
        specificationStatementMatch = self.patterns.specificationStatementPattern.match(
            line)
        if not ( \
            line.strip() == "" \
            or importMatch1 \
            or importMatch2 \
            or importMatch3 \
            or specTuple[0] \
            or specificationStatementMatch \
        ):
            if self.state == "inside_branch":
                self.stateBeforeBranch = "inside_subroutine_body"
            else:
                self.state = "inside_subroutine_body"
            self.switchToNewRegion()
            self.processInsideSubroutineBodyState(line)
            return

        self.analyseSymbolInformationOnCurrentLine(line)
        #we are never calling super and every match that would have prepared a line, would already have been covered
        #with a return -> safe to call prepareLine here.
        self.prepareLine(line, self.tab_insideSub)
Esempio n. 9
0
    def implemented(self, skipDebugPrint=False):
        def getImportLine(importedSymbols, parentRoutine):
            return parentRoutine.implementation.getImportSpecification(
                importedSymbols, RegionType.KERNEL_CALLER_DECLARATION
                if parentRoutine.isCallingKernel else RegionType.OTHER,
                parentRoutine.node.getAttribute('parallelRegionPosition'),
                parentRoutine.parallelRegionTemplates)

        parentRoutine = self._routineRef()
        declarationRegionType = RegionType.OTHER
        if parentRoutine.isCallingKernel:
            declarationRegionType = RegionType.KERNEL_CALLER_DECLARATION

        if self._additionalParametersByKernelName == None \
        or self._symbolsToAdd == None \
        or self._compactionDeclarationPrefixByCalleeName == None \
        or self._currAdditionalCompactedSubroutineParameters == None:
            raise Exception(
                "additional context not properly loaded for routine specification region in %s"
                % (parentRoutine.name))

        importsFound = False
        declaredSymbolsByScopedName = OrderedDict()
        textForKeywords = ""
        textBeforeDeclarations = ""
        textAfterDeclarations = ""
        symbolsToAddByScopedName = dict(
            (symbol.nameInScope(), symbol) for symbol in self._symbolsToAdd)
        for (line, symbols) in self._linesAndSymbols:
            if not symbols or len(symbols) == 0:
                allImportMatch = RegExPatterns.Instance(
                ).importAllPattern.match(line)
                if allImportMatch:
                    importsFound = True
                elif not importsFound:
                    textForKeywords += line.strip() + "\n"
                elif len(declaredSymbolsByScopedName.keys()) == 0:
                    textBeforeDeclarations += line.strip() + "\n"
                else:
                    textAfterDeclarations += line.strip() + "\n"
                continue
            for symbol in symbols:
                if symbol.nameInScope() in symbolsToAddByScopedName:
                    continue
                if symbol.isCompacted:
                    continue  #compacted symbols are handled as part of symbolsToAdd
                if symbol.getSpecificationTuple(line)[0]:
                    declaredSymbolsByScopedName[symbol.nameInScope()] = symbol
                    continue
                match = symbol.importPattern.match(line)
                if not match:
                    match = symbol.importMapPattern.match(line)
                if match:
                    importsFound = True
                    continue
                raise Exception(
                    "symbol %s expected to be referenced in line '%s', but all matchings have failed"
                    % (symbol.name, line))

        text = ""

        try:
            moduleNamesCompletelyImported = [
                sourceModule
                for (sourceModule, nameInScope) in self._allImports
                if nameInScope == None
            ] if self._allImports else []
            if len(self._typeParameterSymbolsByName.keys()) > 0 \
            and ConversionOptions.Instance().debugPrint \
            and not skipDebugPrint:
                text += "!<----- type parameters --\n"
            for typeParameterSymbol in self._typeParameterSymbolsByName.values(
            ):
                typeParameterSymbol.updateNameInScope(forceAutomaticName=True)
                if typeParameterSymbol.sourceModule in moduleNamesCompletelyImported \
                and not "hfauto" in typeParameterSymbol.nameInScope():
                    continue
                text += getImportLine([typeParameterSymbol], parentRoutine)
            if self._allImports:
                if len(self.
                       _allImports.keys()) > 0 and ConversionOptions.Instance(
                       ).debugPrint and not skipDebugPrint:
                    text += "!<----- synthesized imports --\n"
                for (sourceModule, nameInScope) in self._allImports:
                    if not nameInScope:
                        text += getImportLine(sourceModule, parentRoutine)
                        continue
                    if sourceModule in moduleNamesCompletelyImported:
                        continue
                    sourceName = self._allImports[(sourceModule, nameInScope)]
                    symbol = parentRoutine.symbolsByName.get(sourceName)
                    if symbol != None and symbol.sourceModule == parentRoutine._parentModule(
                    ).name:
                        continue
                    if symbol != None:
                        text += getImportLine([symbol], parentRoutine)
                    else:
                        text += "use %s, only: %s => %s" %(sourceModule, nameInScope, sourceName) \
                         if nameInScope != sourceName \
                         else "use %s, only: %s" %(sourceModule, nameInScope)
                        if ConversionOptions.Instance(
                        ).debugPrint and not skipDebugPrint:
                            text += " ! resynthesizing user input - no associated HF aware symbol found"
                        text += "\n"

            if textForKeywords != "" and ConversionOptions.Instance(
            ).debugPrint and not skipDebugPrint:
                text += "!<----- other imports and specs: ------\n"
            text += textForKeywords

            if textBeforeDeclarations != "" and ConversionOptions.Instance(
            ).debugPrint and not skipDebugPrint:
                text += "!<----- before declarations: --\n"
            text += textBeforeDeclarations
            if len(declaredSymbolsByScopedName.keys()) > 0:
                if ConversionOptions.Instance(
                ).debugPrint and not skipDebugPrint:
                    text += "!<----- declarations: -------\n"
                text += "\n".join([
                    parentRoutine.implementation.adjustDeclarationForDevice(
                        symbol.getDeclarationLine(purgeList=[]), [symbol],
                        declarationRegionType,
                        parentRoutine.node.getAttribute(
                            'parallelRegionPosition')).strip()
                    for symbol in declaredSymbolsByScopedName.values()
                ]).strip() + "\n"
            if len(self.
                   _dataSpecificationLines) > 0 and ConversionOptions.Instance(
                   ).debugPrint and not skipDebugPrint:
                text += "!<----- data specifications: --\n"
            if len(self._dataSpecificationLines) > 0:
                text += "\n".join(self._dataSpecificationLines) + "\n"
            if textAfterDeclarations != "" and ConversionOptions.Instance(
            ).debugPrint and not skipDebugPrint:
                text += "!<----- after declarations: --\n"
            text += textAfterDeclarations

            numberOfAdditionalDeclarations = (
                len(
                    sum([
                        self._additionalParametersByKernelName[kname][1]
                        for kname in self._additionalParametersByKernelName
                    ], [])) + len(self._symbolsToAdd) +
                len(parentRoutine._packedRealSymbolsByCalleeName.keys()))
            if numberOfAdditionalDeclarations > 0 and ConversionOptions.Instance(
            ).debugPrint and not skipDebugPrint:
                text += "!<----- auto emul symbols : --\n"
            defaultPurgeList = ['intent', 'public', 'parameter', 'allocatable']
            for symbol in self._symbolsToAdd:
                purgeList = defaultPurgeList
                if not symbol.isCompacted:
                    purgeList = ['public', 'parameter', 'allocatable']
                text += parentRoutine.implementation.adjustDeclarationForDevice(
                    symbol.getDeclarationLine(purgeList).strip(), [symbol],
                    declarationRegionType,
                    parentRoutine.node.getAttribute(
                        'parallelRegionPosition')).rstrip(
                        ) + " ! type %i symbol added for this subroutine\n" % (
                            symbol.declarationType)
            for callee in parentRoutine.callees:
                #this hasattr is used to test the callee for analyzability without circular imports
                if not hasattr(callee, "implementation"):
                    continue
                additionalImports, additionalDeclarations = self._additionalParametersByKernelName.get(
                    callee.name, ([], []))
                additionalImportSymbolsByName = {}
                for symbol in additionalImports:
                    additionalImportSymbolsByName[symbol.name] = symbol

                implementation = callee.implementation
                for symbol in parentRoutine.filterOutSymbolsAlreadyAliveInCurrentScope(
                        additionalDeclarations):
                    if symbol.declarationType not in [
                            DeclarationType.LOCAL_ARRAY,
                            DeclarationType.LOCAL_SCALAR
                    ]:
                        # only symbols that are local to the kernel actually need to be declared here.
                        # Everything else we should have in our own scope already, either through additional imports or
                        # through module association (we assume the kernel and its wrapper reside in the same module)
                        continue

                    #in case the array uses domain sizes in the declaration that are additional symbols themselves
                    #we need to fix them.
                    adjustedDomains = []
                    for (domName, domSize) in symbol.domains:
                        domSizeSymbol = additionalImportSymbolsByName.get(
                            domSize)
                        if domSizeSymbol is None:
                            adjustedDomains.append((domName, domSize))
                            continue
                        adjustedDomains.append(
                            (domName, domSizeSymbol.nameInScope()))
                    symbol.domains = adjustedDomains

                    text += implementation.adjustDeclarationForDevice(
                        symbol.getDeclarationLine(defaultPurgeList).strip(),
                        [symbol], declarationRegionType,
                        parentRoutine.node.getAttribute(
                            'parallelRegionPosition')).rstrip(
                            ) + " ! type %i symbol added for callee %s\n" % (
                                symbol.declarationType, callee.name)
                toBeCompacted = parentRoutine._packedRealSymbolsByCalleeName.get(
                    callee.name, [])
                if len(toBeCompacted) > 0:
                    #TODO: generalize for cases where we don't want this to be on the device
                    #(e.g. put this into Implementation class)
                    compactedArray = FrameworkArray(
                        callee.name,
                        self._compactionDeclarationPrefixByCalleeName[
                            callee.name],
                        domains=[("hfauto", str(len(toBeCompacted)))],
                        isOnDevice=True)
                    text += implementation.adjustDeclarationForDevice(
                        compactedArray.getDeclarationLine().strip(),
                        [compactedArray], declarationRegionType,
                        parentRoutine.node.getAttribute(
                            'parallelRegionPosition')).rstrip(
                            ) + " ! compaction array added for callee %s\n" % (
                                callee.name)

            declarationEndText = parentRoutine.implementation.declarationEnd(
                parentRoutine.symbolsByName.values() +
                parentRoutine.additionalImports, parentRoutine.isCallingKernel,
                parentRoutine.node, parentRoutine.parallelRegionTemplates)
            if len(declarationEndText) > 0:
                text += "!<----- impl. specific decl end : --\n"
                text += declarationEndText

            for idx, symbol in enumerate(
                    self._currAdditionalCompactedSubroutineParameters):
                text += "%s = %s(%i)" % (
                    symbol.nameInScope(),
                    limitLength(frameworkArrayName(parentRoutine.name)),
                    idx + 1) + " ! additional type %i symbol compaction\n" % (
                        symbol.declarationType)
            if ConversionOptions.Instance().debugPrint and not skipDebugPrint:
                text += "! HF is aware of the following symbols at this point: %s" % (
                    parentRoutine.symbolsByName.values())
        except UsageError as e:
            raise UsageError("Implementing %s: %s" %
                             (parentRoutine.name, str(e)))
        except Exception as e:
            raise Exception("Implementing %s: %s" %
                            (parentRoutine.name, str(e)))

        return self._sanitize(text, skipDebugPrint)