mirror of
https://github.com/Sei-Lisa/LSL-PyOptimizer
synced 2025-07-01 15:48:21 +00:00
Get rid of StSw craziness and use lsllastpass to make another pass.
This has been a TODO item for long. Now that we have lsllastpass, it's actually easy to implement. Adds an LSLTypeDefaults dictionary to lslcommon, just in case the state-changing function returns a value and we need to insert a return statement. We've also added subtree-local info to lsllastpass (lost when we return to the parent after visiting a subtree). This fixes a bug where naked switch statements could appear as a result of optimization, and cause the compilation to fail.
This commit is contained in:
parent
e4eaab9e84
commit
a87022b73f
4 changed files with 77 additions and 29 deletions
|
@ -67,6 +67,10 @@ LSLType2Python = {'integer':int, 'float':float,
|
|||
'string':unicode, 'key':Key, 'vector':Vector,
|
||||
'rotation':Quaternion, 'list':list}
|
||||
|
||||
LSLTypeDefaults = {'integer':0, 'float':0.0, 'string':u'', 'key':Key(u''),
|
||||
'vector':Vector((0.,0.,0.)), 'rotation':Quaternion((0.,0.,0.,1.)),
|
||||
'list':[]}
|
||||
|
||||
def warning(txt):
|
||||
assert type(txt) == unicode
|
||||
sys.stderr.write(u"WARNING: " + txt + u"\n")
|
||||
|
|
|
@ -1543,8 +1543,6 @@ class foldconst(object):
|
|||
or child[idx]['nt'] == '{}' and not child[idx]['ch']:
|
||||
del child[idx]
|
||||
else:
|
||||
if 'StSw' in child[idx]:
|
||||
node['StSw'] = True
|
||||
idx += 1
|
||||
if issef:
|
||||
node['SEF'] = True
|
||||
|
@ -1558,19 +1556,6 @@ class foldconst(object):
|
|||
# We might be able to remove one of the branches.
|
||||
if lslfuncs.cond(child[0]['value']):
|
||||
self.FoldTree(child, 1)
|
||||
# If it has a state switch, the if() must be preserved
|
||||
# (but the else branch may be removed).
|
||||
if 'StSw' in child[1]:
|
||||
# TODO: Get rid of StSw craziness and make another pass
|
||||
# to put them under conditionals if present (if bald
|
||||
# state switches are present, it means they are the
|
||||
# result of optimization so they must be wrapped in an
|
||||
# IF statement). The current approach leaves unnecessary
|
||||
# IFs behind.
|
||||
if len(child) == 3 and child[2]['nt'] != '@':
|
||||
del child[2] # Delete ELSE if present
|
||||
return
|
||||
else:
|
||||
self.FoldStmt(child, 1)
|
||||
if len(child) == 3 and child[2]['nt'] == '@':
|
||||
# Corner case. The label is in the same scope as
|
||||
|
@ -1788,7 +1773,6 @@ class foldconst(object):
|
|||
|
||||
if nt == 'STSW':
|
||||
# State switch always has side effects.
|
||||
node['StSw'] = True
|
||||
return
|
||||
|
||||
if nt == 'SUBIDX':
|
||||
|
|
|
@ -31,6 +31,33 @@ class lastpass(object):
|
|||
nt = node['nt']
|
||||
child = node['ch'] if 'ch' in node else None
|
||||
|
||||
if nt == 'FNDEF':
|
||||
# StChAreBad will be True if this is a user-defined function,
|
||||
# where state changes are considered bad.
|
||||
# BadStCh will be True if at least one state change statement
|
||||
# is found while monitoring state changes.
|
||||
self.subinfo['StChAreBad'] = 'scope' in node
|
||||
self.BadStCh = False
|
||||
|
||||
if nt == 'IF':
|
||||
if len(child) == 2:
|
||||
# Don't monitor the children.
|
||||
self.subinfo['StChAreBad'] = False
|
||||
|
||||
if nt == 'DO':
|
||||
self.subinfo['StChAreBad'] = False
|
||||
|
||||
if nt == 'FOR':
|
||||
self.subinfo['StChAreBad'] = False
|
||||
|
||||
if nt == 'WHILE':
|
||||
self.subinfo['StChAreBad'] = False
|
||||
|
||||
if nt == 'STSW':
|
||||
if self.subinfo['StChAreBad']:
|
||||
# Found one.
|
||||
self.BadStCh = True
|
||||
|
||||
if (self.optlistadd and not self.globalmode
|
||||
and (nt == 'CONST' and node['t'] == 'list' or nt == 'LIST'
|
||||
or nt == '+' and child[0]['t'] == 'list' and
|
||||
|
@ -61,10 +88,9 @@ class lastpass(object):
|
|||
'SEF':True,
|
||||
'value':elem
|
||||
} if listnode['nt'] == 'CONST' else elem
|
||||
left = self.Cast(elemnode, 'list') if left is None else {
|
||||
'nt':'+', 't':'list', 'SEF':True,
|
||||
'ch':[left, elemnode]
|
||||
}
|
||||
left = (self.Cast(elemnode, 'list') if left is None
|
||||
else {'nt':'+', 't':'list', 'SEF':True,
|
||||
'ch':[left, elemnode]})
|
||||
del elemnode
|
||||
if left is not None: # it's none for empty lists
|
||||
parent[index] = left
|
||||
|
@ -75,9 +101,40 @@ class lastpass(object):
|
|||
del listnode, left
|
||||
|
||||
def LastPassPostOrder(self, parent, index):
|
||||
pass
|
||||
node = parent[index]
|
||||
nt = node['nt']
|
||||
child = node['ch'] if 'ch' in node else None
|
||||
|
||||
if nt == 'FNDEF':
|
||||
if 'scope' in node and self.BadStCh:
|
||||
# There is at least one bad state change statement in the
|
||||
# function (must be the result of optimization).
|
||||
# Insert dummy IF(1){...} statement covering the whole function
|
||||
# (if it returs a value, insert a return statement too).
|
||||
child[0] = {'nt':'{}', 't':None, 'ch':[
|
||||
{'nt':'IF', 't':None, 'ch':[
|
||||
{'nt':'CONST', 't':'integer', 'value':1},
|
||||
child[0]
|
||||
]}
|
||||
]}
|
||||
child = node['ch']
|
||||
if node['t'] is not None:
|
||||
# Inserting a state switch in a function that returns a
|
||||
# value must count as one of the dumbest things to do.
|
||||
# We do as best as we can: add a return statement with the
|
||||
# default value for the type.
|
||||
child[0]['ch'].append({'nt':'RETURN', 't':None, 'ch':[
|
||||
{'nt':'CONST', 't':node['t'],
|
||||
'value':lslcommon.LSLTypeDefaults[node['t']]
|
||||
}]
|
||||
})
|
||||
del self.BadStCh
|
||||
return
|
||||
|
||||
|
||||
def RecursiveLastPass(self, parent, index):
|
||||
subinfo = self.subinfo
|
||||
self.subinfo = subinfo.copy()
|
||||
self.LastPassPreOrder(parent, index)
|
||||
|
||||
if 'ch' in parent[index]:
|
||||
|
@ -88,6 +145,7 @@ class lastpass(object):
|
|||
idx += 1
|
||||
|
||||
self.LastPassPostOrder(parent, index)
|
||||
self.subinfo = subinfo
|
||||
|
||||
def LastPass(self):
|
||||
self.globalmode = False
|
||||
|
@ -95,6 +153,8 @@ class lastpass(object):
|
|||
tree = self.tree
|
||||
|
||||
# Last optimizations pass
|
||||
# self.subinfo is subtree-local info.
|
||||
self.subinfo = {}
|
||||
for idx in xrange(len(tree)):
|
||||
if tree[idx]['nt'] == 'DECL':
|
||||
self.globalmode = True
|
||||
|
|
|
@ -272,7 +272,7 @@ class Test03_Optimizer(UnitTestCase):
|
|||
vector vvvv2=vvvv;
|
||||
float ffff3 = v.z;
|
||||
integer fn(){
|
||||
if (1) state default; else return 2;
|
||||
if (1) state default;
|
||||
return fn();}
|
||||
|
||||
default{touch(integer n){
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue