mirror of
https://github.com/irmen/prog8.git
synced 2024-11-22 15:33:02 +00:00
more optimizations
This commit is contained in:
parent
31c6186245
commit
baf3adfa8a
@ -8,7 +8,7 @@ Written by Irmen de Jong (irmen@razorvine.net) - license: GNU GPL 3.0
|
||||
|
||||
from typing import List, no_type_check
|
||||
from .plyparse import Module, Subroutine, Block, Directive, Assignment, AugAssignment, Goto, Expression, IncrDecr,\
|
||||
datatype_of, coerce_constant_value, AssignmentTargets, LiteralValue, Scope
|
||||
datatype_of, coerce_constant_value, AssignmentTargets, LiteralValue, Scope, Register
|
||||
from .plylex import print_warning, print_bold
|
||||
|
||||
|
||||
@ -20,6 +20,7 @@ class Optimizer:
|
||||
def optimize(self) -> None:
|
||||
self.num_warnings = 0
|
||||
self.optimize_assignments()
|
||||
self.remove_superfluous_assignments()
|
||||
self.combine_assignments_into_multi()
|
||||
self.optimize_multiassigns()
|
||||
self.remove_unused_subroutines()
|
||||
@ -28,10 +29,25 @@ class Optimizer:
|
||||
# @todo analyse for unreachable code and remove that (f.i. code after goto or return that has no label so can never be jumped to)
|
||||
self.remove_empty_blocks()
|
||||
|
||||
def remove_superfluous_assignments(self) -> None:
|
||||
# remove consecutive assignment statements to the same target, only keep the last value (only if its a constant!)
|
||||
# this is NOT done for memory mapped variables because these often represent a volatile register of some sort!
|
||||
for scope in self.module.all_nodes(Scope):
|
||||
prev_node = None
|
||||
for node in list(scope.nodes):
|
||||
if isinstance(node, Assignment) and isinstance(prev_node, Assignment):
|
||||
if isinstance(node.right, (LiteralValue, Register)) and node.left.same_targets(prev_node.left):
|
||||
if not node.left.has_memvalue():
|
||||
scope.remove_node(prev_node)
|
||||
self.num_warnings += 1
|
||||
print_warning("{}: removed superfluous assignment".format(prev_node.sourceref))
|
||||
prev_node = node
|
||||
|
||||
def optimize_assignments(self) -> None:
|
||||
# remove assignment statements that do nothing (A=A)
|
||||
# and augmented assignments that have no effect (A+=0)
|
||||
# and augmented assignments that have no effect (x+=0, x-=0, x/=1, x//=1, x*=1)
|
||||
# convert augmented assignments to simple incr/decr if possible (A+=10 => A++ by 10)
|
||||
# simplify some calculations (x*=0, x**=0) to simple constant value assignment
|
||||
# @todo remove or simplify logical aug assigns like A |= 0, A |= true, A |= false (or perhaps turn them into byte values first?)
|
||||
for assignment in self.module.all_nodes():
|
||||
if isinstance(assignment, Assignment):
|
||||
@ -73,7 +89,7 @@ class Optimizer:
|
||||
howmuch=howmuch.value, sourceref=assignment.sourceref)
|
||||
new_stmt.target = assignment.left
|
||||
assignment.my_scope().replace_node(assignment, new_stmt)
|
||||
if assignment.operator in ("/=", "//=", "*=") and assignment.right.value == 1:
|
||||
if assignment.right.value == 1 and assignment.operator in ("/=", "//=", "*="):
|
||||
self.num_warnings += 1
|
||||
print_warning("{}: removed statement that has no effect".format(assignment.sourceref))
|
||||
assignment.my_scope().remove_node(assignment)
|
||||
|
@ -626,6 +626,47 @@ class AssignmentTargets(AstNode):
|
||||
# a list of one or more assignment targets (TargetRegisters, Register, SymbolName, or Dereference).
|
||||
nodes = attr.ib(type=list, init=True) # requires nodes in __init__
|
||||
|
||||
def has_memvalue(self) -> bool:
|
||||
for t in self.nodes:
|
||||
if isinstance(t, Dereference):
|
||||
return True
|
||||
if isinstance(t, SymbolName):
|
||||
symdef = self.my_scope().lookup(t.name)
|
||||
if isinstance(symdef, VarDef) and symdef.vartype == VarType.MEMORY:
|
||||
return True
|
||||
return False
|
||||
|
||||
def same_targets(self, other: 'AssignmentTargets') -> bool:
|
||||
if len(self.nodes) != len(other.nodes):
|
||||
return False
|
||||
# @todo be able to compare targets in different order as well (sort them)
|
||||
for t1, t2 in zip(self.nodes, other.nodes):
|
||||
if type(t1) is not type(t2):
|
||||
return False
|
||||
if isinstance(t1, TargetRegisters):
|
||||
pass
|
||||
elif isinstance(t1, Register):
|
||||
if t1 != t2: # __eq__ is defined
|
||||
return False
|
||||
elif isinstance(t1, SymbolName):
|
||||
if t1.name != t2.name:
|
||||
return False
|
||||
elif isinstance(t1, Dereference):
|
||||
if t1.size != t2.size or t1.datatype != t2.datatype:
|
||||
return False
|
||||
op1, op2 = t1.operand, t2.operand
|
||||
if type(op1) is not type(op2):
|
||||
return False
|
||||
if isinstance(op1, SymbolName):
|
||||
if op1.name != op2.name:
|
||||
return False
|
||||
else:
|
||||
if op1 != op2:
|
||||
return False
|
||||
else:
|
||||
return False
|
||||
return True
|
||||
|
||||
|
||||
@attr.s(cmp=False, slots=True, repr=False)
|
||||
class Assignment(AstNode):
|
||||
|
17
todo.ill
17
todo.ill
@ -31,6 +31,8 @@
|
||||
const .float c3t=true
|
||||
const .float c3f=false
|
||||
|
||||
memory border = $d020
|
||||
|
||||
|
||||
start:
|
||||
%breakpoint abc,def
|
||||
@ -51,6 +53,21 @@ start:
|
||||
v3t=2.23424 * v3t ; @todo store as constant float with generated name, replace value node
|
||||
XY*=2
|
||||
XY*=3
|
||||
X=3 ; @todo optimize consecutive assignments
|
||||
X=4
|
||||
X=5
|
||||
X=A=6
|
||||
A=X=6
|
||||
X=A=6
|
||||
X=A=9
|
||||
X=A=10
|
||||
v3t=1 ; @todo optimize consecutive assignments
|
||||
v3t=2
|
||||
v3t=3
|
||||
border = 0 ; @todo do not optimize consecucutive assignments to a memory var
|
||||
border = 1
|
||||
border = 2
|
||||
|
||||
XY=XY/0 ; @todo zerodiv (during expression to code generation)
|
||||
XY=XY//0 ; @todo zerodiv (during expression to code generation)
|
||||
XY*=2.23424 ; @todo store as constant float with generated name, replace value node
|
||||
|
Loading…
Reference in New Issue
Block a user