mirror of
https://github.com/irmen/prog8.git
synced 2024-11-19 11:32:17 +00:00
shifting by more than 1 bit possible
This commit is contained in:
parent
57bc7d49bc
commit
5bfca554a4
122
il65/codegen.py
122
il65/codegen.py
@ -1127,9 +1127,45 @@ class CodeGenerator:
|
||||
else:
|
||||
raise CodeError("unsupported register for aug assign", str(lvalue)) # @todo ^=.word
|
||||
elif operator == ">>=":
|
||||
raise CodeError("can not yet shift a variable amount") # XXX
|
||||
if rvalue.datatype != DataType.BYTE:
|
||||
raise CodeError("can only shift by a byte value", str(rvalue))
|
||||
r_str = rvalue.name or Parser.to_hex(rvalue.address)
|
||||
if lvalue.register == "A":
|
||||
self.p("\t\tlsr " + r_str)
|
||||
elif lvalue.register == "X":
|
||||
self.p("\t\tpha")
|
||||
self.p("\t\ttxa")
|
||||
self.p("\t\tlsr " + r_str)
|
||||
self.p("\t\ttax")
|
||||
self.p("\t\tpla")
|
||||
elif lvalue.register == "Y":
|
||||
self.p("\t\tpha")
|
||||
self.p("\t\ttya")
|
||||
self.p("\t\tlsr " + r_str)
|
||||
self.p("\t\ttay")
|
||||
self.p("\t\tpla")
|
||||
else:
|
||||
raise CodeError("unsupported lvalue register for shift", str(lvalue)) # @todo >>=.word
|
||||
elif operator == "<<=":
|
||||
raise CodeError("can not yet shift a variable amount") # XXX
|
||||
if rvalue.datatype != DataType.BYTE:
|
||||
raise CodeError("can only shift by a byte value", str(rvalue))
|
||||
r_str = rvalue.name or Parser.to_hex(rvalue.address)
|
||||
if lvalue.register == "A":
|
||||
self.p("\t\tasl " + r_str)
|
||||
elif lvalue.register == "X":
|
||||
self.p("\t\tpha")
|
||||
self.p("\t\ttxa")
|
||||
self.p("\t\tasl " + r_str)
|
||||
self.p("\t\ttax")
|
||||
self.p("\t\tpla")
|
||||
elif lvalue.register == "Y":
|
||||
self.p("\t\tpha")
|
||||
self.p("\t\ttya")
|
||||
self.p("\t\tasl " + r_str)
|
||||
self.p("\t\ttay")
|
||||
self.p("\t\tpla")
|
||||
else:
|
||||
raise CodeError("unsupported lvalue register for shift", str(lvalue)) # @todo >>=.word
|
||||
|
||||
def _generate_aug_reg_int(self, lvalue: RegisterValue, operator: str, rvalue: IntegerValue) -> None:
|
||||
r_str = rvalue.name or Parser.to_hex(rvalue.value)
|
||||
@ -1225,43 +1261,53 @@ class CodeGenerator:
|
||||
else:
|
||||
raise CodeError("unsupported register for aug assign", str(lvalue)) # @todo ^=.word
|
||||
elif operator == ">>=":
|
||||
if rvalue.value != 1:
|
||||
raise CodeError("can only shift 1 bit for now") # XXX
|
||||
if lvalue.register == "A":
|
||||
self.p("\t\tlsr a")
|
||||
elif lvalue.register == "X":
|
||||
self.p("\t\tpha")
|
||||
self.p("\t\ttxa")
|
||||
self.p("\t\tlsr a")
|
||||
self.p("\t\ttax")
|
||||
self.p("\t\tpla")
|
||||
elif lvalue.register == "Y":
|
||||
self.p("\t\tpha")
|
||||
self.p("\t\ttya")
|
||||
self.p("\t\tlsr a")
|
||||
self.p("\t\ttay")
|
||||
self.p("\t\tpla")
|
||||
else:
|
||||
raise CodeError("unsupported register for aug assign", str(lvalue)) # @todo >>=.word
|
||||
if rvalue.value > 0:
|
||||
def shifts_A(times: int) -> None:
|
||||
if times >= 8:
|
||||
self.p("\t\tlda #0")
|
||||
else:
|
||||
for _ in range(min(8, times)):
|
||||
self.p("\t\tlsr a")
|
||||
if lvalue.register == "A":
|
||||
shifts_A(rvalue.value)
|
||||
elif lvalue.register == "X":
|
||||
self.p("\t\tpha")
|
||||
self.p("\t\ttxa")
|
||||
shifts_A(rvalue.value)
|
||||
self.p("\t\ttax")
|
||||
self.p("\t\tpla")
|
||||
elif lvalue.register == "Y":
|
||||
self.p("\t\tpha")
|
||||
self.p("\t\ttya")
|
||||
shifts_A(rvalue.value)
|
||||
self.p("\t\ttay")
|
||||
self.p("\t\tpla")
|
||||
else:
|
||||
raise CodeError("unsupported register for aug assign", str(lvalue)) # @todo >>=.word
|
||||
elif operator == "<<=":
|
||||
if rvalue.value != 1:
|
||||
raise CodeError("can only shift 1 bit for now") # XXX
|
||||
if lvalue.register == "A":
|
||||
self.p("\t\tasl a")
|
||||
elif lvalue.register == "X":
|
||||
self.p("\t\tpha")
|
||||
self.p("\t\ttxa")
|
||||
self.p("\t\tasl a")
|
||||
self.p("\t\ttax")
|
||||
self.p("\t\tpla")
|
||||
elif lvalue.register == "Y":
|
||||
self.p("\t\tpha")
|
||||
self.p("\t\ttya")
|
||||
self.p("\t\tasl a")
|
||||
self.p("\t\ttay")
|
||||
self.p("\t\tpla")
|
||||
else:
|
||||
raise CodeError("unsupported register for aug assign", str(lvalue)) # @todo <<=.word
|
||||
if rvalue.value > 0:
|
||||
def shifts_A(times: int) -> None:
|
||||
if times >= 8:
|
||||
self.p("\t\tlda #0")
|
||||
else:
|
||||
for _ in range(min(8, times)):
|
||||
self.p("\t\tasl a")
|
||||
if lvalue.register == "A":
|
||||
shifts_A(rvalue.value)
|
||||
elif lvalue.register == "X":
|
||||
self.p("\t\tpha")
|
||||
self.p("\t\ttxa")
|
||||
shifts_A(rvalue.value)
|
||||
self.p("\t\ttax")
|
||||
self.p("\t\tpla")
|
||||
elif lvalue.register == "Y":
|
||||
self.p("\t\tpha")
|
||||
self.p("\t\ttya")
|
||||
shifts_A(rvalue.value)
|
||||
self.p("\t\ttay")
|
||||
self.p("\t\tpla")
|
||||
else:
|
||||
raise CodeError("unsupported register for aug assign", str(lvalue)) # @todo <<=.word
|
||||
|
||||
def _generate_aug_reg_reg(self, lvalue: RegisterValue, operator: str, rvalue: RegisterValue) -> None:
|
||||
if operator == "+=":
|
||||
|
@ -313,13 +313,13 @@ class Parser:
|
||||
for name, value in stmt.arguments or []:
|
||||
assert name is not None, "all call arguments should have a name or be matched on a named parameter"
|
||||
assignment = self.parse_assignment(name, value)
|
||||
assignment.sourceref = stmt.sourceref.copy()
|
||||
if assignment.leftvalues[0].datatype != DataType.BYTE:
|
||||
if isinstance(assignment.right, IntegerValue) and assignment.right.constant:
|
||||
# a call that doesn't expect a BYTE argument but gets one, converted from a 1-byte string most likely
|
||||
if value.startswith("'") and value.endswith("'"):
|
||||
self.print_warning("possible problematic string to byte conversion (use a .text var instead?)")
|
||||
if not assignment.is_identity():
|
||||
assignment.sourceref = stmt.sourceref.copy() # @todo why set this?
|
||||
stmt.desugared_call_arguments.append(assignment)
|
||||
if all(not isinstance(v, RegisterValue) for r, v in stmt.outputvars or []):
|
||||
# if none of the output variables are registers, we can simply generate the assignments without issues
|
||||
@ -978,15 +978,11 @@ class Parser:
|
||||
return InplaceIncrStmt(l_value, r_value, self.sourceref)
|
||||
elif r_value.value < 0:
|
||||
return InplaceDecrStmt(l_value, r_value.negative(), self.sourceref)
|
||||
else:
|
||||
self.print_warning("incr with zero, ignored")
|
||||
else:
|
||||
if r_value.value > 0:
|
||||
return InplaceDecrStmt(l_value, r_value, self.sourceref)
|
||||
elif r_value.value < 0:
|
||||
return InplaceIncrStmt(l_value, r_value.negative(), self.sourceref)
|
||||
else:
|
||||
self.print_warning("decr with zero, ignored")
|
||||
return AugmentedAssignmentStmt(l_value, operator, r_value, self.sourceref)
|
||||
|
||||
def parse_return(self, line: str) -> ReturnStmt:
|
||||
@ -1315,6 +1311,7 @@ class Optimizer:
|
||||
def optimize(self) -> ParseResult:
|
||||
print("\noptimizing parse tree")
|
||||
for block in self.parsed.all_blocks():
|
||||
self.remove_augmentedassign_incrdecr_nops(block)
|
||||
self.remove_identity_assigns(block)
|
||||
self.combine_assignments_into_multi(block)
|
||||
self.optimize_multiassigns(block)
|
||||
@ -1322,6 +1319,23 @@ class Optimizer:
|
||||
self.optimize_compare_with_zero(block)
|
||||
return self.parsed
|
||||
|
||||
def remove_augmentedassign_incrdecr_nops(self, block: Block) -> None:
|
||||
have_removed_stmts = False
|
||||
for index, stmt in enumerate(list(block.statements)):
|
||||
if isinstance(stmt, AugmentedAssignmentStmt):
|
||||
if isinstance(stmt.right, (IntegerValue, FloatValue)):
|
||||
if stmt.right.value == 0 and stmt.operator in ("+=", "-=", "|=", "<<=", ">>=", "^="):
|
||||
print("{}: removed statement that has no effect".format(stmt.sourceref))
|
||||
have_removed_stmts = True
|
||||
block.statements[index] = None
|
||||
if stmt.right.value >= 8 and stmt.operator in ("<<=", ">>="):
|
||||
print("{}: shifting that many times always results in zero".format(stmt.sourceref))
|
||||
new_stmt = AssignmentStmt(stmt.leftvalues, IntegerValue(0, stmt.sourceref), stmt.sourceref)
|
||||
block.statements[index] = new_stmt
|
||||
if have_removed_stmts:
|
||||
# remove the Nones
|
||||
block.statements = [s for s in block.statements if s is not None]
|
||||
|
||||
def optimize_compare_with_zero(self, block: Block) -> None:
|
||||
# a conditional goto that compares a value to zero will be simplified
|
||||
# the comparison operator and rvalue (0) will be removed and the if-status changed accordingly
|
||||
@ -1402,7 +1416,6 @@ class Optimizer:
|
||||
def remove_unused_subroutines(self, block: Block) -> None:
|
||||
# some symbols are used by the emitted assembly code from the code generator,
|
||||
# and should never be removed or the assembler will fail
|
||||
# @todo make this dynamic
|
||||
never_remove = {"c64.FREADUY", "c64.FTOMEMXY", "c64.FADD", "c64.FSUB",
|
||||
"c64flt.GIVUAYF", "c64flt.copy_mflt", "c64flt.float_add_one", "c64flt.float_sub_one",
|
||||
"c64flt.float_add_SW1_to_XY", "c64flt.float_sub_SW1_from_XY"}
|
||||
|
32
todo.ill
32
todo.ill
@ -5,14 +5,40 @@ output prg,basic
|
||||
import "c64lib"
|
||||
|
||||
~ main {
|
||||
const num = 44
|
||||
var var1 =22
|
||||
var .word wvar1 = 22
|
||||
const num = 2
|
||||
var var1 =2
|
||||
var .word wvar1 = 2
|
||||
|
||||
start
|
||||
|
||||
X <<= var1
|
||||
X >>= var1
|
||||
|
||||
var1 ++
|
||||
var1 += num
|
||||
X++
|
||||
X+=num
|
||||
X+=0
|
||||
X-=0
|
||||
X <<= Y
|
||||
A <<= X
|
||||
Y <<= A
|
||||
X <<= 0
|
||||
X <<= 33333
|
||||
X >>= 33333
|
||||
X <<= 2
|
||||
X <<= 7
|
||||
X <<= 8
|
||||
X <<= 22
|
||||
X >>= 0
|
||||
X >>= 1
|
||||
X >>= 2
|
||||
X >>= 7
|
||||
X >>= 8
|
||||
X >>= 22
|
||||
;XY <<= 0
|
||||
;XY <<= 1
|
||||
;XY <<= 2
|
||||
|
||||
|
||||
asm {
|
||||
|
Loading…
Reference in New Issue
Block a user