Optimize artithmetic with immediate values

This commit is contained in:
Bananymous 2024-04-29 21:19:16 +03:00
parent 351634e512
commit 2141a17d1e
1 changed files with 38 additions and 21 deletions

View File

@ -574,18 +574,27 @@ def compile_ast(node: ASTnode, compile_data: CompileData) -> None:
compile_data.code = old_code
# check if we can use temporary registers instead of stack
# If RHS is an 32 bit integer literal, we can use it as an immediate value
register = None
if node.child_rhs.nodetype == 'int_literal' and node.child_rhs.value <= 0x7FFFFFFF:
if node.child_lhs.type != 'date':
register = f'${node.child_rhs.value}'
elif node.child_rhs.value * 86400 <= 0x7FFFFFFF:
register = f'${node.child_rhs.value * 86400}'
# Otherwise, we need to use a register
usable_registers = ['%r8', '%r9', '%r10', '%r11']
register = '%rcx'
for reg in usable_registers:
valid = True
for instruction in lhs_code:
if reg in instruction.operands:
valid = False
if register is None:
register = '%rcx'
for reg in usable_registers:
valid = True
for instruction in lhs_code:
if reg in instruction.operands:
valid = False
break
if valid:
register = reg
break
if valid:
register = reg
break
# check if lhs uses call, this determines whether we need to align stack
align_stack = False
@ -595,18 +604,21 @@ def compile_ast(node: ASTnode, compile_data: CompileData) -> None:
break
# Add code for RHS calculation
compile_data.code += rhs_code
if register != '%rcx':
compile_data.code.append(Instruction('movq', ['%rax', register]))
elif not align_stack:
compile_data.code.append(Instruction('pushq', ['%rax']))
if register[0] == '$':
pass
else:
compile_data.code.append(Instruction('subq', ['$16', '%rsp']))
compile_data.code.append(Instruction('movq', ['%rax', '0(%rsp)']))
compile_data.code += rhs_code
if register != '%rcx':
compile_data.code.append(Instruction('movq', ['%rax', register]))
elif not align_stack:
compile_data.code.append(Instruction('pushq', ['%rax']))
else:
compile_data.code.append(Instruction('subq', ['$16', '%rsp']))
compile_data.code.append(Instruction('movq', ['%rax', '0(%rsp)']))
# Add code for LHS calculation
compile_data.code += lhs_code
if register != '%rcx':
if register[0] == '$' or register != '%rcx':
pass
elif not align_stack:
compile_data.code.append(Instruction('popq', [register]))
@ -615,10 +627,11 @@ def compile_ast(node: ASTnode, compile_data: CompileData) -> None:
compile_data.code.append(Instruction('addq', ['$16', '%rsp']))
# If we are adding or subtracting dates with integers, multiply the integer by number of seconds in a day
if node.child_lhs.type == 'date' and node.child_rhs.type == 'int':
# If register is immediate, this has already been done
if register[0] != '$' and node.child_lhs.type == 'date' and node.child_rhs.type == 'int':
compile_data.code.append(Instruction('imulq', ['$86400', register]))
# perform operation
# Perform operation
if node.value == '+':
compile_data.code.append(Instruction('addq', [register, '%rax']))
elif node.value == '-':
@ -626,6 +639,10 @@ def compile_ast(node: ASTnode, compile_data: CompileData) -> None:
elif node.value == '*':
compile_data.code.append(Instruction('imulq', [register, '%rax']))
elif node.value == '/':
# Division by immediate is not possible
if register[0] == '$':
compile_data.code.append(Instruction('movq', [register, '%rcx']))
register = '%rcx'
compile_data.code.append(Instruction('cqo'))
compile_data.code.append(Instruction('idivq', [register]))
elif node.value == '<':
@ -638,7 +655,7 @@ def compile_ast(node: ASTnode, compile_data: CompileData) -> None:
compile_data.code.append(Instruction('movzbq', ['%al', '%rax']))
else: assert False
# if both operands are dates, divide result by number of seconds in a day
# If both operands are dates, divide result by number of seconds in a day
if node.child_lhs.type == 'date' and node.child_rhs.type == 'date':
assert node.value == '-'
compile_data.code.append(Instruction('movq', ['$86400', register]))