From 4ba71993a45d279d61d1ce9d90bcd5f7a088a3bd Mon Sep 17 00:00:00 2001 From: Sei Lisa Date: Wed, 25 Oct 2017 20:58:46 +0200 Subject: [PATCH] Optimize min/max in comparisons; undo problematic optimization. For floats: When const >= function.max, comparisons of function > const always yield FALSE. When const < function.min, comparisons of function > const always yield TRUE. When const > function.max, comparisons of function < const always yield TRUE. When const <= function.min, comparisons of function < const always yield FALSE. For integers: When min = -1, cond(function > -1) is the same as cond(!~function). When min = -1, cond(function < 0) is the same as cond(~function). To implement the above, we got rid of the cond(x < 0) -> cond(x & 0x80000000) optimization, which has caused more trouble than it has solved for just 1 byte gain. When min = 0, cond(function > 0) is the same as cond(function). When min = 0, cond(function < 1) is the same as cond(!function). Similar expressions can be obtained for max in [-1, 0], but it's not worth it, as there are no functions with -1 as maximum, and the ones with max=0 also have min=0 (always return 0). --- lslopt/lslfoldconst.py | 102 +++++++++++++++++++++++++++++++++++++---- 1 file changed, 92 insertions(+), 10 deletions(-) diff --git a/lslopt/lslfoldconst.py b/lslopt/lslfoldconst.py index a705a5a..9d4e23e 100644 --- a/lslopt/lslfoldconst.py +++ b/lslopt/lslfoldconst.py @@ -481,15 +481,53 @@ class foldconst(object): return - # This optimization turns out to be counter-productive for some - # common cases, e.g. it turns i >= 0 into !(i & 0x80000000) - # instead of the more optimal (integer)-1 < i. So we revert it - # where appropriate (in FoldTree, case '!', and above, case '|'). - if nt == '<': - if child[1]['nt'] == 'CONST' and child[1]['value'] == 0: - nt = node['nt'] = '&' - child[1]['value'] = int(-2147483648) - # Fall through to check & 0x80000000 + if nt == '<' and child[0]['t'] == child[1]['t'] == 'integer': + sym = None + for a in (0, 1): + if child[a]['nt'] == 'FNCALL': + sym = self.symtab[0][child[a]['name']] + break + + # cond(FNCALL < 0) -> cond(~FNCALL) if min == -1 + if (child[1]['nt'] == 'CONST' and child[1]['value'] == 0 + and child[0]['nt'] == 'FNCALL' + and 'min' in sym and sym['min'] == -1 + ): + node = parent[index] = {'nt':'~', 't':'integer', + 'ch':[child[0]]} + self.FoldTree(parent, index) + return + + # cond(FNCALL > -1) -> cond(!~FNCALL) if min == -1 + if (child[0]['nt'] == 'CONST' and child[0]['value'] == -1 + and child[1]['nt'] == 'FNCALL' + and 'min' in sym and sym['min'] == -1 + ): + node = parent[index] = {'nt':'!', 't':'integer', + 'ch':[{'nt':'~', 't':'integer', + 'ch':[child[1]]} + ]} + self.FoldTree(parent, index) + return + + # cond(FNCALL < 1) -> cond(!FNCALL) if min == 0 + if (child[1]['nt'] == 'CONST' and child[1]['value'] == 1 + and child[0]['nt'] == 'FNCALL' + and 'min' in sym and sym['min'] == 0 + ): + node = parent[index] = {'nt':'!', 't':'integer', + 'ch':[child[0]]} + self.FoldTree(parent, index) + return + + # cond(FNCALL > 0) -> cond(FNCALL) if min == 0 + if (child[0]['nt'] == 'CONST' and child[0]['value'] == 0 + and child[1]['nt'] == 'FNCALL' + and 'min' in sym and sym['min'] == 0 + ): + node = parent[index] = child[1] + self.FoldTree(parent, index) + return if nt == '&': @@ -1129,6 +1167,50 @@ class foldconst(object): # fall through to check for '<' if nt == '<': + if child[0]['t'] == child[1]['t'] in ('integer', 'float'): + if (child[0]['nt'] == 'CONST' + and child[1]['nt'] == 'FNCALL' + and self.FnSEF(child[1]) + ): + # CONST < FNCALL aka FNCALL > CONST + # when FNCALL.max <= CONST: always false + # when CONST < FNCALL.min: always true + if ('max' in self.symtab[0][child[1]['name']] + and child[0]['value'] >= + self.symtab[0][child[1]['name']]['max'] + ): + parent[index] = {'nt':'CONST', 't':'integer', + 'SEF':True, 'value':0} + return + if ('min' in self.symtab[0][child[1]['name']] + and child[0]['value'] < + self.symtab[0][child[1]['name']]['min'] + ): + parent[index] = {'nt':'CONST', 't':'integer', + 'SEF':True, 'value':1} + return + if (child[1]['nt'] == 'CONST' + and child[0]['nt'] == 'FNCALL' + and self.FnSEF(child[0]) + ): + # FNCALL < CONST + # when CONST > FNCALL.max: always true + # when CONST <= FNCALL.min: always false + if ('max' in self.symtab[0][child[0]['name']] + and child[1]['value'] > + self.symtab[0][child[0]['name']]['max'] + ): + parent[index] = {'nt':'CONST', 't':'integer', + 'SEF':True, 'value':1} + return + if ('min' in self.symtab[0][child[0]['name']] + and child[1]['value'] <= + self.symtab[0][child[0]['name']]['min'] + ): + parent[index] = {'nt':'CONST', 't':'integer', + 'SEF':True, 'value':0} + return + # Convert 2147483647