OpenADFortTk (SourceProcessing)
|
00001 ''' 00002 canonicalization routines 00003 ''' 00004 00005 from _Setup import * 00006 00007 from PyUtil.debugManager import DebugManager 00008 from PyUtil.symtab import Symtab,SymtabEntry,SymtabError,globalTypeTable 00009 from PyUtil.typetab import TypetabEntry 00010 from PyUtil.argreplacement import replaceArgs 00011 00012 from PyFort.intrinsic import is_intrinsic,getGenericName, isUsedNonStandard,getBuiltInTypes 00013 from PyFort.inference import InferenceError,expressionType,appType,isArrayReference,canonicalTypeClass,expressionShape,isSpecExpression 00014 import PyFort.flow as flow 00015 import PyFort.fortExp as fe 00016 import PyFort.fortStmts as fs 00017 import PyFort.fortUnit as fortUnit 00018 import Canon.function2subroutine as function2subroutine 00019 import Canon.subroutinizedIntrinsics as subroutinizedIntrinsics 00020 00021 import copy 00022 import itertools 00023 00024 _tmp_prefix = 'oad_ctmp' 00025 00026 class CanonError(Exception): 00027 '''exception for errors that occur during canonicalization''' 00028 _keepGoing=False 00029 00030 @staticmethod 00031 def keepGoing(): 00032 CanonError._keepGoing=True 00033 00034 def __init__(self,msg,lineNumber): 00035 self.msg = msg 00036 self.lineNumber = lineNumber 00037 00038 def __str__(self): 00039 errString='\nERROR: CanonError at line '+str(self.lineNumber)+': '+str(self.msg) 00040 return (errString) 00041 00042 class UnitCanonicalizer(object): 00043 'class to facilitate canonicalization on a per-unit basis' 00044 00045 _hoistConstantsFlag = False 00046 _hoistStringsFlag = False 00047 _functionBlockFlag = False 00048 _createResultDeclFlag = False 00049 _keepFunctionDecl = True 00050 _subroutinizeIntegerFunctions = False 00051 00052 _ourPassiveTypes=[fs.IntegerStmt,fs.CharacterStmt] 00053 _ourPassiveTypeIds=[getBuiltInTypes().index((fs.CharacterStmt,4)), 00054 getBuiltInTypes().index((fs.IntegerStmt,4)), 00055 getBuiltInTypes().index((fs.IntegerStmt,8))] 00056 00057 @staticmethod 00058 def setHoistConstantsFlag(hoistConstantsFlag): 00059 UnitCanonicalizer._hoistConstantsFlag = hoistConstantsFlag 00060 00061 @staticmethod 00062 def setHoistStringsFlag(hoistStringsFlag): 00063 UnitCanonicalizer._hoistStringsFlag = hoistStringsFlag 00064 00065 @staticmethod 00066 def setFunctionBlockFlag(functionBlockFlag): 00067 UnitCanonicalizer._functionBlockFlag = functionBlockFlag 00068 00069 @staticmethod 00070 def setCreateResultDeclFlag(createResultFlag): 00071 UnitCanonicalizer._createResultDeclFlag = createResultFlag 00072 00073 @staticmethod 00074 def setKeepFunctionDef(keepFunctionDefFlag): 00075 UnitCanonicalizer._keepFunctionDecl = keepFunctionDefFlag 00076 00077 @staticmethod 00078 def setSubroutinizeIntegerFunctions(flag): 00079 UnitCanonicalizer._subroutinizeIntegerFunctions = flag 00080 00081 _overloadingMode = False 00082 00083 @staticmethod 00084 def setOverloadingMode(): 00085 UnitCanonicalizer._overloadingMode = True 00086 00087 def __init__(self,aUnit,srModuleUsed=False): 00088 self.__myUnit = aUnit 00089 self.__myNewDecls = [] 00090 self.__myNewExecs = [] 00091 self.__tempCounter = 0 00092 self.__recursionDepth = 0 00093 self.__outParam = '' 00094 self.__resultDecl = None 00095 self.__processedFunctions = [] 00096 self.__stmtFunctionStmts = [] 00097 00098 def shouldSubroutinizeFunction(self,theApp,parentStmt): 00099 ''' 00100 A function should be subroutinized if it is an intrinsic and subroutinizedIntrinsics.shouldSubroutinize 00101 returns true or if is not an intrinsic 00102 ''' 00103 DebugManager.debug('UnitCanonicalizer.shouldSubroutinizeFunction called on "'+str(theApp)+'"') 00104 if not isinstance(theApp,fe.App): 00105 raise CanonError('UnitCanonicalizer.shouldSubroutinizeFunction called on non-App object '+str(theApp),parentStmt.lineNumber) 00106 if isinstance(theApp.head,fe.Sel): 00107 return False 00108 theSymtabEntry = self.__myUnit.symtab.lookup_name(theApp.head) 00109 if theSymtabEntry: 00110 if isinstance(theSymtabEntry.entryKind,SymtabEntry.StatementFunctionEntryKind): 00111 return False 00112 if isinstance(theSymtabEntry.entryKind,SymtabEntry.VariableEntryKind): 00113 raise CanonError('UnitCanonicalizer.shouldSubroutinizeFunction called on array reference '+str(theApp)+" with "+theSymtabEntry.debug(theApp.head),parentStmt.lineNumber) 00114 try: 00115 appTypeEntry = appType(theApp,self.__myUnit.symtab,parentStmt.lineNumber) 00116 except InferenceError,errorObj: 00117 DebugManager.warning("cannot determine return type and canonicalize function call; "+errorObj.msg,parentStmt.lineNumber) 00118 return False 00119 if is_intrinsic(theApp.head): 00120 if UnitCanonicalizer._overloadingMode: 00121 return False 00122 baseType=appTypeEntry.getBaseTypeEntry() 00123 DebugManager.debug('UnitCanonicalizer.shouldSubroutinizeFunction: It\'s an intrinsic of type '+appTypeEntry.debug()) 00124 return subroutinizedIntrinsics.shouldSubroutinize(theApp) and (UnitCanonicalizer._subroutinizeIntegerFunctions or not (isinstance(baseType.entryKind,TypetabEntry.BuiltInEntryKind) and (baseType.entryKind.type_name=='integer_4'))) 00125 elif isinstance(appTypeEntry.entryKind,TypetabEntry.NamedTypeEntryKind): 00126 # this is an implicit initialization; do not subroutinize 00127 return False 00128 else: 00129 # need to fix for case where app.head is a type (implicit initialization) 00130 return True 00131 00132 def __fixSpecExpression(self,theExp,lineNumber): 00133 ''' we can safely drop some slice expressions if the inquiry fynction does not refer to it ''' 00134 if (isinstance(theExp,fe.App) and theExp.head.lower() in ["size","lbound","ubound"] 00135 and 00136 len(theExp.args)==2) : 00137 dim=None 00138 if (isinstance(theExp.args[1],fe.NamedParam) and theExp.args[1].myId.lower()=="dim" and fe._int_re.match(theExp.args[1].myRHS)): 00139 dim=int(theExp.args[1].myRHS) 00140 elif(fe._int_re.match(theExp.args[1])): 00141 dim=int(theExp.args[1]) 00142 if dim: 00143 argDims=[] 00144 for pos,argDim in enumerate(theExp.args[0].args): 00145 if pos+1!=dim: 00146 argDims.append(fe.Zslice()) 00147 else: 00148 argDims.append(argDim) 00149 # now replace it 00150 theExp.args[0].args=argDims 00151 00152 def __newTemp(self,anExpression,parentStmt): 00153 '''The new temporary variable assumes the value of anExpression''' 00154 theNewTemp = _tmp_prefix + str(self.__tempCounter) 00155 self.__tempCounter += 1 00156 expTypeEntry = expressionType(anExpression,self.__myUnit.symtab,parentStmt.lineNumber) 00157 if isinstance(expTypeEntry.entryKind,TypetabEntry.CharacterEntryKind): 00158 charLenEntry=globalTypeTable.charLenTab.lookupCharLenId(expTypeEntry.entryKind.charLenId) 00159 varTypeClass=fs.CharacterStmt 00160 typeKind=charLenEntry.getCharLenExp() 00161 varModifierList=[typeKind] 00162 else: 00163 (varTypeClass,typeKind)=globalTypeTable.intrinsicIdToTypeMap[expTypeEntry.getBaseTypeId()] 00164 varModifierList=[] 00165 varShape=expressionShape(anExpression,self.__myUnit.symtab,parentStmt.lineNumber) 00166 if isinstance(expTypeEntry.entryKind,TypetabEntry.BuiltInEntryKind) and expTypeEntry.entryKind.type_name=='real_8': 00167 print >>sys.stderr,'WARNING: Temp variable forced to 8-byte float (real -> double)' 00168 DebugManager.debug('replaced with '+str(theNewTemp)+' of type '+expTypeEntry.debug()) 00169 typeAttrList=[] 00170 needsAlloc=False 00171 if varShape: 00172 declDimArgs=[] 00173 for dim in varShape: 00174 if (not isSpecExpression(dim,self.__myUnit.symtab,parentStmt.lineNumber)): 00175 self.__fixSpecExpression(dim,parentStmt.lineNumber) 00176 if (not isSpecExpression(dim,self.__myUnit.symtab,parentStmt.lineNumber)): 00177 needsAlloc=True 00178 declDimArgs.append(fe.Zslice()) 00179 else: 00180 declDimArgs.append(dim) 00181 typeAttrList.append(fe.App('dimension',declDimArgs)) 00182 if needsAlloc: 00183 typeAttrList.append("allocatable") 00184 DebugManager.warning("temporary "+theNewTemp+" declared as allocatable but allocation logic is as of yet not implented",parentStmt.lineNumber) 00185 theNewDecl = varTypeClass(varModifierList,typeAttrList,[theNewTemp]) 00186 typeId = globalTypeTable.getType(theNewDecl,self.__myUnit.symtab) 00187 self.__myNewDecls.append(theNewDecl) 00188 self.__myUnit.symtab.enter_name(theNewTemp, 00189 SymtabEntry(SymtabEntry.VariableEntryKind(), 00190 type=(varTypeClass,varModifierList), 00191 dimensions=varShape, 00192 origin='temp', 00193 typetab_id=typeId)) 00194 return (theNewTemp,varTypeClass,varModifierList) 00195 00196 def __canonicalizeIntrinsicEllipsisRec(self,head,args): 00197 if (len(args)==2): 00198 return fe.App(head,args) 00199 else: 00200 return fe.App(head,[args[0],self.__canonicalizeIntrinsicEllipsisRec(head,args[1:])]) 00201 00202 def __canonicalizeFuncCall(self,theFuncCall,parentStmt): 00203 '''turn a function call into a subroutine call 00204 returns the new temp created as return value for the new subroutine call''' 00205 DebugManager.debug(self.__recursionDepth*'|\t'+'converting function call "'+str(theFuncCall)+'" to a subroutine call') 00206 self.__recursionDepth += 1 00207 DebugManager.debug((self.__recursionDepth-1)*'|\t'+'| creating new temp for the result of the subroutine that replaces "'+str(theFuncCall)+'":',newLine=False) 00208 (theNewTemp,newTempType,newTempTypeMods) = self.__newTemp(theFuncCall,parentStmt) 00209 newArgs = [theNewTemp] 00210 newSubName='' 00211 if is_intrinsic(theFuncCall.head): 00212 funcName=getGenericName(theFuncCall.head) 00213 newSubName = subroutinizedIntrinsics.makeName(funcName) 00214 argRanks=[] 00215 for arg in theFuncCall.args: 00216 argS=expressionShape(arg,self.__myUnit.symtab,parentStmt.lineNumber) 00217 if argS: 00218 argRanks.append(len(argS)) 00219 else: 00220 argRanks.append(0) 00221 (d,t)=canonicalTypeClass(newTempType,newTempTypeMods) 00222 if (d): 00223 subroutinizedIntrinsics.markRequired(funcName,t,argRanks) 00224 else: 00225 for t in subroutinizedIntrinsics.typeList: 00226 subroutinizedIntrinsics.markRequired(funcName,t,argRanks) 00227 if funcName in ('max','min') and len(theFuncCall.args)>2 : 00228 self.__recursionDepth -= 1 00229 return self.__canonicalizeFuncCall(self.__canonicalizeIntrinsicEllipsisRec(theFuncCall.head,theFuncCall.args),parentStmt) 00230 else: 00231 newSubName = subroutinizedIntrinsics.call_prefix + theFuncCall.head 00232 self.__myNewExecs.append(self.__canonicalizeSubCallStmt(\ 00233 fs.CallStmt(newSubName, 00234 theFuncCall.args+newArgs, 00235 lineNumber=parentStmt.lineNumber, 00236 label=False, 00237 lead=parentStmt.lead))) 00238 DebugManager.debug((self.__recursionDepth-1)*'|\t'+'|_') 00239 self.__recursionDepth -= 1 00240 return theNewTemp 00241 00242 def __hoistExpression(self,theExpression,parentStmt,paramName,forceIt=False): 00243 # function calls that are to be turned into subroutine calls 00244 # -> return the temp that carries the value for the new subcall 00245 # or alternatively if paramName is set return the construct 00246 # for a named parameter expression 00247 if isinstance(theExpression,fe.App) and \ 00248 not isArrayReference(theExpression,self.__myUnit.symtab,parentStmt.lineNumber) and \ 00249 self.shouldSubroutinizeFunction(theExpression,parentStmt): 00250 DebugManager.debug('it is a function call to be subroutinized') 00251 return self.__canonicalizeFuncCall(theExpression,parentStmt) 00252 # if argument is a variable reference then don't hoist 00253 if (not forceIt and 00254 (isinstance(theExpression,str) and fe.is_id(theExpression)) 00255 or 00256 (isinstance(theExpression,fe.App) and isArrayReference(theExpression,self.__myUnit.symtab,parentStmt.lineNumber)) 00257 or 00258 isinstance(theExpression,fe.Sel)): 00259 return theExpression 00260 00261 # Anything else: create an assignment to a temporary and return that temporary 00262 (theNewTemp,newTempType,newTempTypeMods) = self.__newTemp(theExpression,parentStmt) 00263 self.__myNewExecs.append(self.__canonicalizeAssignStmt(fs.AssignStmt(theNewTemp, 00264 theExpression, 00265 lineNumber=parentStmt.lineNumber, 00266 label=False, 00267 lead=parentStmt.lead))) 00268 if (paramName): 00269 return fe.NamedParam(paramName,theNewTemp) 00270 else: 00271 return theNewTemp 00272 00273 def __canonicalizeExpression(self,theExpression,parentStmt): 00274 '''Canonicalize an expression tree by recursively replacing function calls with subroutine calls 00275 returns an expression that replaces theExpression''' 00276 DebugManager.debug(self.__recursionDepth*'|\t'+'canonicalizing expression "'+str(theExpression)+'"',newLine=False) 00277 self.__recursionDepth += 1 00278 replacementExpression = theExpression 00279 # variable or constant -> do nothing 00280 if isinstance(theExpression, str): 00281 DebugManager.debug(', which is a string (should be a constant or a variable => no canonicalization necessary)') 00282 # application expressions 00283 elif isinstance(theExpression,fe.App): 00284 if isinstance(theExpression.head,fe.App): 00285 replacementExpression.head = self.__canonicalizeExpression(theExpression.head,parentStmt) 00286 # array reference -. do nothing 00287 elif isArrayReference(theExpression,self.__myUnit.symtab,parentStmt.lineNumber): 00288 DebugManager.debug(', which is an array reference (no canonicalization necessary)') 00289 # function calls to subroutinize -> subroutinize and recursively canonicalize args 00290 elif self.shouldSubroutinizeFunction(theExpression,parentStmt): 00291 DebugManager.debug(', it\'s a function call (subroutinized)') 00292 replacementExpression = self.__canonicalizeFuncCall(theExpression,parentStmt) 00293 # function calls that won't be subroutinized -> recursively canonicalize args 00294 else: 00295 DebugManager.debug(', it\'s a function call (non-subroutinized)') 00296 replacementArgs = [] 00297 for arg in theExpression.args: 00298 replacementArgs.append(self.__canonicalizeExpression(arg,parentStmt)) 00299 replacementHead = theExpression.head 00300 if not isinstance(theExpression.head,fe.Sel): 00301 aSymtabEntry=self.__myUnit.symtab.lookup_name(theExpression.head) 00302 # see if it is a statement function and expand it 00303 if (aSymtabEntry and isinstance(aSymtabEntry.entryKind,SymtabEntry.StatementFunctionEntryKind)): 00304 parentStmt.beenModified = True 00305 replacementExpression=self.__expandStmtFunExp(fe.App(replacementHead,replacementArgs)) 00306 # check whether we need to convert the function to the generic name (e.g. alog => log) 00307 else: 00308 if (is_intrinsic(theExpression.head) and theExpression.head.lower() != getGenericName(theExpression.head)) : 00309 parentStmt.beenModified = True 00310 replacementHead = getGenericName(theExpression.head) 00311 replacementExpression = fe.App(replacementHead,replacementArgs) 00312 # Unary operation -> recursively canonicalize the sole subexpression 00313 elif isinstance(theExpression,fe.Unary): 00314 DebugManager.debug(', which is a unary op. with exp: "'+str(theExpression.exp)+'"') 00315 replacementExpression = theExpression.__class__(self.__canonicalizeExpression(theExpression.exp,parentStmt)) 00316 # Binary operation -> recursively canonicalize both subexpressions 00317 elif isinstance(theExpression,fe.Ops): 00318 DebugManager.debug(', which is a binary op. with a1="'+str(theExpression.a1)+'", a2="'+str(theExpression.a2)+'"') 00319 a1Result = self.__canonicalizeExpression(theExpression.a1,parentStmt) 00320 a2result = self.__canonicalizeExpression(theExpression.a2,parentStmt) 00321 replacementExpression = fe.Ops(theExpression.op,a1Result,a2result) 00322 # Everything else... 00323 else: 00324 DebugManager.debug(', which is of type '+str(theExpression.__class__)+' that is assumed to require no canonicalization') 00325 DebugManager.debug((self.__recursionDepth-1)*'|\t'+'|_') 00326 self.__recursionDepth -= 1 00327 return replacementExpression 00328 00329 def __canonicalizeSubCallStmt(self,aSubCallStmt): 00330 ''' 00331 Canonicalize a subroutine call by hoisting all arguments 00332 (except simple variables) to temporaries. 00333 ''' 00334 DebugManager.debug(self.__recursionDepth*'|\t'+'canonicalizing subroutine call statement "'+str(aSubCallStmt)+'"') 00335 self.__recursionDepth += 1 00336 # canonicalize each of the the expressions that serve as arguments 00337 replacementArgs = [] 00338 # certain non-standard intrinsics (e.g. free) are subroutines rather than functions 00339 if (not isUsedNonStandard(aSubCallStmt.head)): 00340 for anArg in aSubCallStmt.args: 00341 paramName=None 00342 if isinstance(anArg,fe.NamedParam): 00343 paramName=anArg.myId 00344 anArg=anArg.myRHS 00345 DebugManager.debug((self.__recursionDepth - 1)*'|\t'+'|- argument "'+str(anArg)+'" ',newLine=False) 00346 argType=None 00347 argTypeMod=None 00348 try: 00349 argType = expressionType(anArg,self.__myUnit.symtab,aSubCallStmt.lineNumber) 00350 except InferenceError, e : 00351 DebugManager.warning("cannot canonicalize argument >"+str(anArg)+"< parsed as "+repr(anArg)+" because: "+e.msg,aSubCallStmt.lineNumber) 00352 replacementArgs.append(anArg) 00353 continue 00354 # constant character expressions 00355 if argType is not None and (isinstance(argType.entryKind,TypetabEntry.CharacterEntryKind) or \ 00356 (isinstance(argType.entryKind,TypetabEntry.BuiltInEntryKind) and argType.entryKind.type_name=='character')): 00357 if not self._hoistStringsFlag: 00358 DebugManager.debug('is a string expression (which we aren\'t hoisting)') 00359 replacementArgs.append(anArg) 00360 elif isinstance(anArg,str) and self.__myUnit.symtab.lookup_name(anArg): 00361 DebugManager.debug('is a string variable (which we aren\'t hoisting)') 00362 replacementArgs.append(anArg) 00363 elif isinstance(anArg,fe.App) and isArrayReference(anArg,self.__myUnit.symtab,aSubCallStmt.lineNumber): 00364 DebugManager.debug('is a character array reference (which we aren\'t hoisting)') 00365 replacementArgs.append(anArg) 00366 else: 00367 DebugManager.debug('is a string expression to be hoisted:',newLine=False) 00368 replacementArgs.append(self.__hoistExpression(anArg,aSubCallStmt,paramName)) 00369 # other constant expressions 00370 elif fe.isConstantExpression(anArg): 00371 if not self._hoistConstantsFlag: 00372 DebugManager.debug('is a constant expression (which we aren\'t hoisting)') 00373 replacementArgs.append(anArg) 00374 else: 00375 DebugManager.debug('is a constant expression to be hoisted:',newLine=False) 00376 replacementArgs.append(self.__hoistExpression(anArg,aSubCallStmt,paramName)) 00377 # variables (with VariableEntry in symbol table) -> do nothing except for pointers to subroutinized functions and PARAMTERs 00378 elif isinstance(anArg,str): 00379 symtabEntry=self.__myUnit.symtab.lookup_name(anArg) 00380 if (symtabEntry 00381 and 00382 (globalTypeTable.lookupTypeId(symtabEntry.typetab_id).isExternal() 00383 or 00384 isinstance(symtabEntry.entryKind,SymtabEntry.FunctionEntryKind))): 00385 if (function2subroutine.wasSubroutinized(symtabEntry.getScopePrefix(self.__myUnit)+anArg)) : 00386 replacementArgs.append(function2subroutine.name_init+anArg); 00387 aSubCallStmt.beenModified=True 00388 DebugManager.debug('is an identifier referring to a subroutinized function') 00389 else : 00390 DebugManager.warning('argument '+anArg+' in call to '+aSubCallStmt.head+' is classified as a function but we have not seen the definition and will assume it is not going to be subroutinized' ,lineNumber=aSubCallStmt.lineNumber) 00391 replacementArgs.append(anArg) 00392 elif (symtabEntry and symtabEntry.constInit and self._hoistConstantsFlag): 00393 DebugManager.debug('is a PARAMETER identifier to be hoisted:',newLine=False) 00394 replacementArgs.append(self.__hoistExpression(anArg,aSubCallStmt,paramName,True)) 00395 else : 00396 DebugManager.debug('is an identifier') 00397 replacementArgs.append(anArg) 00398 # Array References -> do nothing 00399 elif isinstance(anArg,fe.App) and isArrayReference(anArg,self.__myUnit.symtab,aSubCallStmt.lineNumber): 00400 DebugManager.debug('is an array reference') 00401 replacementArgs.append(anArg) 00402 # everything else -> hoist and create an assignment to a temp variable 00403 else: 00404 DebugManager.debug('is a nontrivial expression to be hoisted:',newLine=False) 00405 replacementArgs.append(self.__hoistExpression(anArg,aSubCallStmt,paramName)) 00406 else : 00407 DebugManager.warning('arguments in call to a non-standard intrinsic subroutine '+str(aSubCallStmt.head)+' are not hoisted',lineNumber=aSubCallStmt.lineNumber) 00408 replacementArgs=aSubCallStmt.args 00409 # replace aCallStmt with the canonicalized version 00410 replacementStatement = fs.CallStmt(aSubCallStmt.head, 00411 replacementArgs, 00412 lineNumber=aSubCallStmt.lineNumber, 00413 label=aSubCallStmt.label, 00414 lead=aSubCallStmt.lead, 00415 internal=aSubCallStmt.internal) 00416 DebugManager.debug((self.__recursionDepth-1)*'|\t'+'|_') 00417 self.__recursionDepth -= 1 00418 return replacementStatement 00419 00420 def __canonicalizeAssignStmt(self,anAssignStmt): 00421 '''Canonicalize an assigment statement by removing function calls from the rhs''' 00422 DebugManager.debug(self.__recursionDepth*'|\t'+'canonicalizing assignment statement "'+str(anAssignStmt)+'"') 00423 self.__recursionDepth += 1 00424 replacementStatement = fs.AssignStmt(anAssignStmt.get_lhs(), 00425 self.__canonicalizeExpression(anAssignStmt.get_rhs(),anAssignStmt), 00426 lineNumber=anAssignStmt.lineNumber, 00427 label=anAssignStmt.label, 00428 lead=anAssignStmt.lead) 00429 DebugManager.debug((self.__recursionDepth-1)*'|\t'+'|_') 00430 self.__recursionDepth -= 1 00431 return replacementStatement 00432 00433 def __canonicalizeIfNonThenStmt(self,anIfNonThenStmt): 00434 '''Canonicalize if stmt (without "then") by converting to an if-then construct and then recursively 00435 canonicalizing the test component and the conditionally executed statement''' 00436 # the replacement statement should be the endif 00437 DebugManager.debug(self.__recursionDepth*'|\t'+'canonicalizing if statement (without "then") "'+str(anIfNonThenStmt)+'" => replacing with an if-then statement') 00438 handleDoTermination=False 00439 if (anIfNonThenStmt.label 00440 and 00441 self.__myUnit.symtab.labelRefs.has_key(str(anIfNonThenStmt.label)) 00442 and 00443 any(map(lambda l: isinstance(l,fs.DoStmt),self.__myUnit.symtab.labelRefs[str(anIfNonThenStmt.label)]))): 00444 # DO terminated by IfNonThenStmt 00445 # if there is only one reference we can save it by moving the label to a new END DO that follows the replacement of anIfNonThenStmt : 00446 if (len(self.__myUnit.symtab.labelRefs[str(anIfNonThenStmt.label)])==1) : 00447 handleDoTermination=True 00448 else : 00449 e=CanonError('IF statement "'+str(anIfNonThenStmt)+'" terminates DO construct "'\ 00450 +str((filter(lambda l: isinstance(l,fs.DoStmt),self.__myUnit.symtab.labelRefs[str(anIfNonThenStmt.label)]))[0])\ 00451 +'" and cannot be converted to an IF construct because references to its label other than from the above DO construct exist; list of all references: ['\ 00452 +' ; '.join('line '+str(l.lineNumber)+": "+str(l) for l in self.__myUnit.symtab.labelRefs[str(anIfNonThenStmt.label)])\ 00453 +"]", 00454 anIfNonThenStmt.lineNumber) 00455 if CanonError._keepGoing: 00456 DebugManager.warning(e.msg,e.lineNumber,DebugManager.WarnType.ifStmtToIfConstr) 00457 else: 00458 raise e 00459 self.__recursionDepth += 1 00460 # first append the new IfThenStmt 00461 newLabel=(not handleDoTermination) and anIfNonThenStmt.label or None # if we handle the do termination the label moves to a new END DO 00462 self.__myNewExecs.append(fs.IfThenStmt(self.__canonicalizeExpression(anIfNonThenStmt.test,anIfNonThenStmt), 00463 ifFormatStr=anIfNonThenStmt.ifFormatStr, 00464 thenFormatStr='then', 00465 lineNumber=anIfNonThenStmt.lineNumber, 00466 label=newLabel, 00467 lead=anIfNonThenStmt.lead)) 00468 self.__recursionDepth -= 1 00469 # append the canonicalized version of the executable statement 00470 anIfNonThenStmt.stmt.lead = anIfNonThenStmt.lead+' ' 00471 self.__canonicalizeExecStmt(anIfNonThenStmt.stmt) 00472 self.__recursionDepth += 1 00473 # insert the endif statement as the replacement 00474 newEndIf=fs.EndifStmt(lead=anIfNonThenStmt.lead) 00475 replacementStatement=None 00476 if handleDoTermination: 00477 self.__myNewExecs.append(newEndIf) 00478 # new END DO with label that was on anIfNonThenStmt 00479 replacementStatement=fs.EnddoStmt(None,label=anIfNonThenStmt.label,lead=anIfNonThenStmt.lead) 00480 else: 00481 replacementStatement = newEndIf 00482 DebugManager.debug((self.__recursionDepth-1)*'|\t'+'|_') 00483 self.__recursionDepth -= 1 00484 return replacementStatement 00485 00486 def __canonicalizeIfThenStmt(self,anIfThenStmt): 00487 '''Canonicalize if-then stmt by canonicalizing the test component 00488 returns a list of statements that replace anIfThenStmt''' 00489 DebugManager.debug(self.__recursionDepth*'|\t'+'canonicalizing if-then statement "'+str(anIfThenStmt)+'"') 00490 self.__recursionDepth += 1 00491 replacementStatement = fs.IfThenStmt(self.__canonicalizeExpression(anIfThenStmt.test,anIfThenStmt), 00492 lineNumber=anIfThenStmt.lineNumber, 00493 label=anIfThenStmt.label, 00494 lead=anIfThenStmt.lead) 00495 DebugManager.debug((self.__recursionDepth-1)*'|\t'+'|_') 00496 self.__recursionDepth -= 1 00497 return replacementStatement 00498 00499 def __canonicalizeElseifStmt(self,anElseifStmt): 00500 '''Canonicalize anElseifStmt by canonicalizing the test component. Returns a canonicalized ElseifStmt that replaces anElseifStmt''' 00501 DebugManager.debug(self.__recursionDepth*'|\t'+'canonicalizing elseif-then statement "'+str(anElseifStmt)+'"') 00502 self.__recursionDepth += 1 00503 newExecsLength = len(self.__myNewExecs) 00504 replacementStatement = fs.ElseifStmt(self.__canonicalizeExpression(anElseifStmt.test,anElseifStmt), 00505 lineNumber=anElseifStmt.lineNumber, 00506 label=anElseifStmt.label, 00507 lead=anElseifStmt.lead) 00508 if len(self.__myNewExecs) > newExecsLength: # this is the case iff some new statements were inserted 00509 e=CanonError('elseif test-component "'+str(anElseifStmt.test)+'" requires hoisting, but the placement of the extra assignment(s) is problematic.',anElseifStmt.lineNumber) 00510 if CanonError._keepGoing: 00511 DebugManager.warning(e.msg,e.lineNumber,DebugManager.WarnType.hoisting) 00512 else: 00513 raise e 00514 DebugManager.debug((self.__recursionDepth-1)*'|\t'+'|_') 00515 self.__recursionDepth -= 1 00516 return replacementStatement 00517 00518 def __canonicalizeDoStmt(self,aDoStmt): 00519 ''' 00520 Canonicalize aDoStmt statement by canonicalizing the loop start, end, and stride expressions. Returns a canonicalized DoStmt that replaces aDoStmt. 00521 ''' 00522 DebugManager.debug(self.__recursionDepth*'|\t'+'canonicalizing do statement "'+str(aDoStmt)+'"') 00523 self.__recursionDepth += 1 00524 replacementStatement = aDoStmt 00525 if aDoStmt.loopControl: 00526 replacementStart = self.__canonicalizeExpression(aDoStmt.loopControl.start,aDoStmt) 00527 newExecsLength = len(self.__myNewExecs) 00528 replacementStatement = fs.DoStmt(aDoStmt.doName, 00529 aDoStmt.doLabel, 00530 fe.LoopControl(aDoStmt.loopControl.var, 00531 replacementStart, 00532 self.__canonicalizeExpression(aDoStmt.loopControl.end,aDoStmt), 00533 self.__canonicalizeExpression(aDoStmt.loopControl.stride,aDoStmt)), 00534 lineNumber=aDoStmt.lineNumber, 00535 label=aDoStmt.label, 00536 lead=aDoStmt.lead) 00537 if len(self.__myNewExecs) > newExecsLength: # this is the case iff loopControl.end or loopControl.stride required hoisting 00538 raise CanonError('Either loopControl.end "'+str(aDoStmt.loopControl.end)+'" or loopControl.stride "'+str(aDoStmt.loopControl.stride)+'" for DoStmt "'+str(aDoStmt)+'" requires hoisting, but the placement of the extra assignment(s) is problematic.',aDoStmt.lineNumber) 00539 DebugManager.debug((self.__recursionDepth-1)*'|\t'+'|_') 00540 self.__recursionDepth -= 1 00541 return replacementStatement 00542 00543 def __canonicalizeWhileStmt(self,aWhileStmt): 00544 ''' 00545 Canonicalize aWhileStmt statement by canonicalizing the test expression. Returns a canonicalized while statement that replaces aWhileStmt. 00546 ''' 00547 DebugManager.debug(self.__recursionDepth*'|\t'+'canonicalizing while statement "'+str(aWhileStmt)+'"') 00548 self.__recursionDepth += 1 00549 newExecsLength = len(self.__myNewExecs) 00550 replacementStatement = fs.WhileStmt(self.__canonicalizeExpression(aWhileStmt.testExpression,aWhileStmt), 00551 lineNumber=aWhileStmt.lineNumber, 00552 label=aWhileStmt.label, 00553 lead=aWhileStmt.lead) 00554 if len(self.__myNewExecs) > newExecsLength: # this is the case iff some new statements were inserted 00555 raise CanonError('while statement test expression "'+str(aWhileStmt.testExpression)+'" requires hoisting, but the placement of the extra assignment(s) is problematic.',aWhileStmt.lineNumber) 00556 DebugManager.debug((self.__recursionDepth-1)*'|\t'+'|_') 00557 self.__recursionDepth -= 1 00558 return replacementStatement 00559 00560 def __canonicalizeSelectCaseStmt(self,aSelectCaseStmt): 00561 ''' 00562 Canonicalize aSelectCaseStmt by canonicalizing the case expression. Returns a canonicalized select case statement that replaces aSelectCaseStmt. 00563 ''' 00564 DebugManager.debug(self.__recursionDepth*'|\t'+'canonicalizing select case statement "'+str(aSelectCaseStmt)+'"') 00565 self.__recursionDepth += 1 00566 replacementStatement = fs.SelectCaseStmt(self.__canonicalizeExpression(aSelectCaseStmt.caseExpression,aSelectCaseStmt), 00567 lineNumber=aSelectCaseStmt.lineNumber, 00568 label=aSelectCaseStmt.label, 00569 lead=aSelectCaseStmt.lead) 00570 DebugManager.debug((self.__recursionDepth-1)*'|\t'+'|_') 00571 self.__recursionDepth -= 1 00572 return replacementStatement 00573 00574 def __canonicalizeIOExpression(self,exp,parentStmt,paramName=None): 00575 ''' 00576 Canonicalize an expression from an IO statement by hoisting any function calls 00577 ''' 00578 DebugManager.debug(self.__recursionDepth*'|\t'+'canonicalizing an IO statement"'+str(parentStmt)+'"') 00579 self.__recursionDepth += 1 00580 newExp = exp 00581 if isinstance(exp,fe.App): 00582 appTypeId=appType(exp,self.__myUnit.symtab,parentStmt.lineNumber) 00583 if ((not isArrayReference(exp,self.__myUnit.symtab,parentStmt.lineNumber)) 00584 and 00585 (not appTypeId in UnitCanonicalizer._ourPassiveTypeIds)): 00586 newExp = self.__hoistExpression(exp,parentStmt,paramName) 00587 elif isinstance(exp,fe.Ops): 00588 newExp = fe.Ops(exp.op, 00589 self.__canonicalizeIOExpression(exp.a1,parentStmt), 00590 self.__canonicalizeIOExpression(exp.a2,parentStmt)) 00591 elif isinstance(exp,fe.ParenExp): 00592 newExp = fe.ParenExp(self.__canonicalizeIOExpression(exp.exp,parentStmt)) 00593 elif isinstance(exp,fe.Umi): 00594 newExp = fe.Umi(self.__canonicalizeIOExpression(exp.exp,parentStmt)) 00595 elif isinstance(exp,fe.Upl): 00596 newExp = fe.Upl(self.__canonicalizeIOExpression(exp.exp,parentStmt)) 00597 elif isinstance(exp,fe.Not): 00598 newExp = fe.Not(self.__canonicalizeIOExpression(exp.exp,parentStmt)) 00599 elif isinstance(exp,fe.MultiParenExp): 00600 newList = [] 00601 for item in exp.expList: 00602 newList.append(self.__canonicalizeIOExpression(item,parentStmt)) 00603 newExp = fe.MultiParenExp(newList) 00604 DebugManager.debug((self.__recursionDepth-1)*'|\t'+'|_') 00605 self.__recursionDepth -= 1 00606 return newExp 00607 00608 def __canonicalizeIOStmt(self,anIOStmt): 00609 ''' 00610 Canonicalize an IOStmt by canonicalizing the ioCtrlSpecList and the itemList. Returns a canonicalized IO statement that replaces anIOStmt. 00611 ''' 00612 DebugManager.debug(self.__recursionDepth*'|\t'+'canonicalizing an IO statement"'+str(anIOStmt)+'"') 00613 self.__recursionDepth += 1 00614 replacementStmt = anIOStmt 00615 for item in replacementStmt.itemList: 00616 newExp = self.__canonicalizeIOExpression(item,replacementStmt) 00617 if newExp != item: 00618 index = replacementStmt.itemList.index(item) 00619 replacementStmt.itemList.insert(index,newExp) 00620 replacementStmt.itemList.remove(item) 00621 replacementStmt.modified = True 00622 DebugManager.debug((self.__recursionDepth-1)*'|\t'+'|_') 00623 self.__recursionDepth -= 1 00624 return replacementStmt 00625 00626 def __expandStmtFunExp(self,anExp): 00627 newSon = anExp 00628 if isinstance(anExp,fe.App): 00629 for stmtFnStmt in self.__stmtFunctionStmts: 00630 newArgs = [] 00631 for anArg in anExp.args: 00632 newArgs.append(self.__expandStmtFunExp(anArg)) 00633 if anExp.head == stmtFnStmt.name: 00634 newSon = fe.ParenExp(stmtFnStmt.body) 00635 # replace args 00636 newSon = replaceArgs(str(newSon),stmtFnStmt.args,newArgs) 00637 else: 00638 newSon = fe.App(anExp.head,newArgs) 00639 elif isinstance(anExp,fe.Ops): 00640 newSon = fe.Ops(anExp.op, 00641 self.__expandStmtFunExp(anExp.a1), 00642 self.__expandStmtFunExp(anExp.a2)) 00643 elif isinstance(anExp,fe.ParenExp): 00644 newSon = fe.ParenExp(self.__expandStmtFunExp(anExp.exp)) 00645 elif isinstance(anExp,fe.Umi): 00646 newSon = fe.Umi(self.__expandStmtFunExp(anExp.exp)) 00647 elif isinstance(anExp,fe.Upl): 00648 newSon = fe.Upl(self.__expandStmtFunExp(anExp.exp)) 00649 elif isinstance(anExp,fe.Not): 00650 newSon = fe.Not(self.__expandStmtFunExp(anExp.exp)) 00651 elif isinstance(anExp,fe.MultiParenExp): 00652 newList = [] 00653 for item in anExp.expList: 00654 newList.append(self.__expandStmtFunExp(item)) 00655 newSon = fe.MultiParenExp(newList) 00656 return newSon 00657 00658 00659 def __expandStmtFunction(self,anExecStmt): 00660 if hasattr(anExecStmt,'_sons'): 00661 for aSon in anExecStmt.get_sons(): 00662 theSon = getattr(anExecStmt,aSon) 00663 newSon = self.__expandStmtFunExp(theSon) 00664 anExecStmt.set_son(aSon,newSon) 00665 return anExecStmt 00666 00667 def __canonicalizeExecStmt(self,anExecStmt): 00668 # We were previously working with the assumption that an original statement is modified as part of the canonicalization process 00669 # if and only if at least one new statement has been added. 00670 # This is not true, as for example we canonicalize y = alog(x) to y = log(x) 00671 # hence, we have added a flag "beenModified" which indicates that an expression should be replaced by the canonicalized version 00672 anExecStmt.beenModified = False 00673 newExecsLength = len(self.__myNewExecs) # store the current number of execs (to determine afterwards whether we've added some) 00674 replacementStatement = anExecStmt 00675 replacementStatement = self.__expandStmtFunction(replacementStatement) 00676 if isinstance(anExecStmt,fs.CallStmt): 00677 replacementStatement = self.__canonicalizeSubCallStmt(anExecStmt) 00678 elif isinstance(anExecStmt,fs.AssignStmt): 00679 replacementStatement = self.__canonicalizeAssignStmt(anExecStmt) 00680 elif isinstance(anExecStmt,fs.IfNonThenStmt): 00681 replacementStatement = self.__canonicalizeIfNonThenStmt(anExecStmt) 00682 elif isinstance(anExecStmt,fs.IfThenStmt): 00683 replacementStatement = self.__canonicalizeIfThenStmt(anExecStmt) 00684 elif isinstance(anExecStmt,fs.ElseifStmt): 00685 replacementStatement = self.__canonicalizeElseifStmt(anExecStmt) 00686 elif isinstance(anExecStmt,fs.DoStmt): 00687 replacementStatement = self.__canonicalizeDoStmt(anExecStmt) 00688 elif isinstance(anExecStmt,fs.WhileStmt): 00689 replacementStatement = self.__canonicalizeWhileStmt(anExecStmt) 00690 elif isinstance(anExecStmt,fs.SelectCaseStmt): 00691 replacementStatement = self.__canonicalizeSelectCaseStmt(anExecStmt) 00692 elif isinstance(anExecStmt,fs.IOStmt): 00693 replacementStatement = self.__canonicalizeIOStmt(anExecStmt) 00694 else: 00695 DebugManager.debug('Statement "'+str(anExecStmt)+'" is assumed to require no canonicalization') 00696 if self.__recursionDepth != 0: 00697 raise CanonError('Recursion depth did not resolve to zero when canonicalizing '+str(anExecStmt),anExecStmt.lineNumber) 00698 # determine whether a change was made 00699 if anExecStmt.beenModified or \ 00700 len(self.__myNewExecs) > newExecsLength: # some new statements were inserted 00701 self.__myNewExecs.append(replacementStatement) # => replace anExecStmt with the canonicalized version 00702 else: # no new statements were inserted 00703 self.__myNewExecs.append(anExecStmt) # => leave anExecStmt alone 00704 00705 def __canonicalizeFunctionDecls(self,aDecl,subroutineBlock): 00706 if isinstance(aDecl,fs.StmtFnStmt): 00707 self.__stmtFunctionStmts.append(aDecl) 00708 if self._keepFunctionDecl: 00709 self.__myNewDecls.append(aDecl) 00710 if isinstance(aDecl,fs.FunctionStmt): 00711 self.setFunctionBlockFlag(True) 00712 (self.__outParam,subroutineStmt) = function2subroutine.\ 00713 convertFunctionOrEntryStmt(aDecl,self.__myUnit) 00714 subroutineBlock.append(subroutineStmt) 00715 self.__resultDecl = function2subroutine.\ 00716 createResultDecl(aDecl,self.__outParam) 00717 self.setCreateResultDeclFlag(True) 00718 elif not self._functionBlockFlag: 00719 if not self._keepFunctionDecl: 00720 self.__myNewDecls.append(aDecl) 00721 elif isinstance(aDecl,fs.EndStmt): 00722 newEndStmt = fs.EndSubroutineStmt(lineNumber=aDecl.lineNumber,label=aDecl.label,lead=aDecl.lead) 00723 subroutineBlock.append(newEndStmt) 00724 self.__myNewDecls.extend(subroutineBlock) 00725 self.setFunctionBlockFlag(False) 00726 elif isinstance(aDecl,fs.Comments): 00727 if aDecl.rawline.strip() == '': 00728 pass 00729 else: 00730 subroutineBlock.append(aDecl) 00731 elif self._createResultDeclFlag \ 00732 and not isinstance(aDecl,fs.UseStmt): 00733 if self.__resultDecl is not None: 00734 subroutineBlock.append(self.__resultDecl) 00735 self.setCreateResultDeclFlag(False) 00736 elif isinstance(aDecl,fs.TypeDecl): 00737 (aDecl,resultDecl,resultDeclFlag) = function2subroutine.updateTypeDecl(\ 00738 aDecl,self.__outParam,self.__myNewDecls) 00739 self.setCreateResultDeclFlag(not resultDeclFlag) 00740 if resultDeclFlag: 00741 subroutineBlock.append(resultDecl) 00742 if aDecl is not None: 00743 subroutineBlock.append(aDecl) 00744 else: 00745 subroutineBlock.append(aDecl) 00746 00747 def __createFuncSubPairs(self): 00748 oldFuncnewSubPairs = [] 00749 for aSubUnit in self.__myUnit.ulist: 00750 if isinstance(aSubUnit.uinfo,fs.SubroutineStmt) and \ 00751 aSubUnit.uinfo.name.startswith(function2subroutine.name_init): 00752 if aSubUnit.uinfo.name[0:6] != function2subroutine.name_init : 00753 raise CanonError('Tried to strip "'+aSubUnit.uinfo.name[0:6]+'"' \ 00754 +' from the beginning of "'+aSubUnit.uinfo.name+'"',aSubUnit.uinfo.lineNumber) 00755 DebugManager.debug('searching declarations to convert old function name "'+aSubUnit.uinfo.name[6:]+'"' \ 00756 +' to new subroutine name "'+aSubUnit.uinfo.name+'"') 00757 oldFuncnewSubPairs.append([aSubUnit.uinfo.name[6:], 00758 aSubUnit.uinfo.name]) 00759 return oldFuncnewSubPairs 00760 00761 def __processInterfaceBlocks(self,oldFuncnewSubPairs): 00762 interfaceBlockFlag = False 00763 interfaceBlock = [] 00764 self.__myNewDecls = [] 00765 for aDecl in self.__myUnit.decls: 00766 # accumulate an interface block and process it 00767 if interfaceBlockFlag: 00768 interfaceBlock.append(aDecl) 00769 if isinstance(aDecl,fs.EndInterfaceStmt): 00770 newInterfaceBlock = function2subroutine.\ 00771 convertInterfaceBlock(interfaceBlock,oldFuncnewSubPairs,self._keepFunctionDecl) 00772 self.__myNewDecls.extend(newInterfaceBlock) 00773 interfaceBlockFlag = False 00774 interfaceBlock = [] 00775 elif isinstance(aDecl,fs.InterfaceStmt): 00776 interfaceBlockFlag = True 00777 interfaceBlock.append(aDecl) 00778 # if not part of the interface block, convert decls and add them 00779 else: 00780 (newDecl,modified) = function2subroutine.\ 00781 convertFunctionDecl(aDecl,oldFuncnewSubPairs) 00782 if (not modified): 00783 self.__myNewDecls.append(aDecl) 00784 else: 00785 if (self._keepFunctionDecl): 00786 self.__myNewDecls.append(aDecl) 00787 self.__myNewDecls.append(newDecl) 00788 00789 def __createNewSubroutine(self,aUnit,subroutineDecls): 00790 if isinstance(aUnit.uinfo,fs.FunctionStmt): 00791 DebugManager.debug(5*'-'+'>'+'called __createNewSubroutine ' \ 00792 + 'on unit "'+str(aUnit)+'",' \ 00793 + 'with subroutineDecls='+str(subroutineDecls)+',' \ 00794 +' with symtab "'+aUnit.symtab.debug()+'"') 00795 self.__processedFunctions.append(aUnit.uinfo.name) 00796 if self._keepFunctionDecl: 00797 newUnit = function2subroutine.\ 00798 convertFunction(aUnit,self.__myNewExecs,subroutineDecls) 00799 # if the unit has no parent, then it was the original unit. 00800 if aUnit.parent is None: 00801 # create a parent 00802 aUnit.parent = fortUnit.Unit() 00803 # append new unit & original unit (already processed) 00804 aUnit.parent.ulist.append(aUnit) 00805 aUnit.parent.ulist.append(newUnit) 00806 # return parent 00807 aUnit = self.__myUnit.parent 00808 else: 00809 aUnit.parent.ulist.append(newUnit) 00810 else: 00811 aUnit = function2subroutine.convertFunction(aUnit,self.__myNewExecs,subroutineDecls) 00812 return aUnit 00813 00814 def __canonicalizeExecStmts(self,execList): 00815 DebugManager.debug('canonicalizing executable statements:') 00816 for anExecStmt in execList: 00817 DebugManager.debug('[Line '+str(anExecStmt.lineNumber)+']:') 00818 try: 00819 self.__canonicalizeExecStmt(anExecStmt) 00820 except InferenceError,e: 00821 raise CanonError('Caught InferenceError: '+e.msg,anExecStmt.lineNumber) 00822 except SymtabError,e: # add a lineNumber to SymtabErrors that don't have one 00823 e.lineNumber = e.lineNumber or anExecStmt.lineNumber 00824 raise e 00825 00826 def __canonicalizeUseAndExternalStmts(self,aDecl): 00827 if (isinstance(aDecl,fs.UseStmt)): 00828 if isinstance(aDecl, fs.UseAllStmt): 00829 newRenameList=[] 00830 if aDecl.renameList: 00831 for renameItem in aDecl.renameList: 00832 scopedName=aDecl.moduleName+":"+renameItem.rhs 00833 if function2subroutine.wasSubroutinized(scopedName): 00834 newRenameList.append(fs._PointerInit(function2subroutine.name_init+renameItem.lhs, 00835 function2subroutine.name_init+renameItem.rhs)) 00836 if (self._keepFunctionDecl): 00837 newRenameList.append(renameItem) 00838 aDecl.modified=True 00839 else: 00840 newRenameList.append(renameItem) 00841 if (aDecl.modified): 00842 aDecl.renameList=newRenameList 00843 elif isinstance(aDecl, fs.UseOnlyStmt): 00844 newOnlyList=[] 00845 for onlyItem in aDecl.onlyList: 00846 if isinstance(onlyItem,fs._PointerInit): 00847 if function2subroutine.wasSubroutinized(aDecl.moduleName+":"+onlyItem.rhs): 00848 newOnlyList.append(fs._PointerInit(function2subroutine.name_init+onlyItem.lhs, 00849 function2subroutine.name_init+onlyItem.rhs)) 00850 if (self._keepFunctionDecl): 00851 newOnlyList.append(onlyItem) 00852 aDecl.modified=True 00853 else: 00854 newOnlyList.append(onlyItem) 00855 elif function2subroutine.wasSubroutinized(aDecl.moduleName+":"+onlyItem): 00856 newOnlyList.append(function2subroutine.name_init+onlyItem) 00857 if (self._keepFunctionDecl): 00858 newOnlyList.append(onlyItem) 00859 aDecl.modified=True 00860 else: 00861 newOnlyList.append(onlyItem) 00862 if (aDecl.modified): 00863 aDecl.onlyList=newOnlyList 00864 elif (isinstance(aDecl,fs.ExternalStmt)): 00865 newProcedureNames=[] 00866 for p in aDecl.procedureNames: 00867 if (function2subroutine.wasSubroutinized(p)): 00868 newProcedureNames.append(function2subroutine.name_init+p) 00869 aDecl.modified=True 00870 else: 00871 newProcedureNames.append(p) 00872 if (aDecl.modified): 00873 aDecl.procedureNames=newProcedureNames 00874 00875 00876 def canonicalizeUnit(self): 00877 '''Recursively canonicalize \p aUnit''' 00878 DebugManager.debug(('+'*55)+' Begin canonicalize unit <'+str(self.__myUnit.uinfo)+'> '+(55*'+')) 00879 DebugManager.debug('local '+self.__myUnit.symtab.debug()) 00880 DebugManager.debug('subunits (len ='+str(len(self.__myUnit.ulist))+'):') 00881 if (not self.__myUnit.parent and self.__myUnit.uinfo): # would have been added in the parent 00882 lead=self.__myUnit.uinfo.lead or '' 00883 addIt=False 00884 if self.__myUnit.ulist: 00885 addIt=True # if we have subunits add it regardless 00886 # try to get a lead and see if we have non-comment execs 00887 ncExecsIter=itertools.ifilter(lambda l: not isinstance(l, fs.Comments),self.__myUnit.execs) 00888 try : 00889 lead=ncExecsIter.next().lead 00890 addIt=True # made it here, i.e. we have execs and need to add it 00891 # see if we can get a better lead from non-comment decls 00892 ncDeclsIter=itertools.ifilter(lambda l: not isinstance(l, fs.Comments),self.__myUnit.decls) 00893 try : 00894 lead=ncDeclsIter.next().lead 00895 except StopIteration, e: 00896 pass # doesn't matter 00897 except StopIteration, e: # no exec statements, no reason to add it here. 00898 pass # still we may have to add it because of subunits 00899 if (addIt and not UnitCanonicalizer._overloadingMode): 00900 self.__myUnit.decls.insert(0, #always insert as the first decl to avoid ordering problems 00901 fs.UseAllStmt(moduleName=subroutinizedIntrinsics.getModuleName(), 00902 renameList=None, 00903 lead=lead)) 00904 newList = [] 00905 for subUnit in self.__myUnit.ulist: 00906 DebugManager.debug(5*'%'+'>'+'canon.canonicalizeUnit: ' \ 00907 +'canonicalizing subunit '+str(subUnit)) 00908 # if the unit is new, as a result of function transformation, 00909 # skip processing 00910 if isinstance(subUnit.uinfo,fs.SubroutineStmt) and \ 00911 subUnit.uinfo.name.startswith(function2subroutine.name_init): 00912 DebugManager.debug(5*'%'+'>'+'\t skipping this subunit because we generated it') 00913 newList.append(subUnit) 00914 elif subUnit.uinfo.name in self.__processedFunctions: 00915 DebugManager.debug(5*'%'+'>'+'\t skipping this subunit because we already processed it') 00916 newList.append(subUnit) 00917 else: 00918 newUnit = UnitCanonicalizer(subUnit).canonicalizeUnit() 00919 newList.append(newUnit) 00920 self.__myUnit.ulist = newList 00921 00922 subroutineBlock = [] 00923 for aDecl in self.__myUnit.decls: 00924 self.__canonicalizeUseAndExternalStmts(aDecl) 00925 self.__canonicalizeFunctionDecls(aDecl,subroutineBlock) 00926 00927 ## replace the declaration statements for the unit 00928 if not isinstance(self.__myUnit.uinfo,fs.FunctionStmt): 00929 self.__myUnit.decls = self.__myNewDecls 00930 subroutineDecls = [] 00931 else: 00932 subroutineDecls = self.__myNewDecls 00933 00934 self.__myNewDecls = [] # empty it out, the following line may add new declarations 00935 self.__canonicalizeExecStmts(self.__myUnit.execs) 00936 # set the leading whitespace for the new declarations and add them to the unit 00937 for aDecl in self.__myNewDecls: 00938 aDecl.lead = self.__myUnit.uinfo.lead+' ' 00939 if not isinstance(self.__myUnit.uinfo,fs.FunctionStmt): 00940 self.__myUnit.decls.extend(self.__myNewDecls) 00941 subroutineDecls.extend(self.__myNewDecls) 00942 00943 # replace the executable statements for the unit 00944 if not isinstance(self.__myUnit.uinfo,fs.FunctionStmt): 00945 self.__myUnit.execs = self.__myNewExecs 00946 00947 # for function units, also create a corresponding subroutine 00948 self.__myUnit = self.__createNewSubroutine(self.__myUnit,subroutineDecls) 00949 00950 # build list of old function/new subroutine name pairs 00951 oldFuncnewSubPairs = self.__createFuncSubPairs() 00952 # accumulate an interface block and process it 00953 self.__processInterfaceBlocks(oldFuncnewSubPairs) 00954 00955 self.__myUnit.decls = self.__myNewDecls 00956 00957 DebugManager.debug(('+'*54)+' End canonicalize unit <'+str(self.__myUnit.uinfo)+'> '+(54*'+')+'\n\n') 00958 00959 return self.__myUnit 00960 00961