Optimize consecutive mov/add/sub instructions to single instruction

This commit is contained in:
Bananymous 2024-04-29 21:53:50 +03:00
parent 1e8bdf6cd2
commit db4f37709f
1 changed files with 90 additions and 2 deletions

View File

@ -335,6 +335,7 @@ class CompileData:
i = 0
# Remove redundant movq instructions
# movq %rax, %rax
while i < len(instructions):
if instructions[i].opcode != 'movq' or instructions[i].operands[0] != instructions[i].operands[1]:
i += 1
@ -345,7 +346,11 @@ class CompileData:
i = 0
# Optimize movq to register followed by pushq register
while i < len(instructions):
# movq $1, %rax
# pushq %rax
# becomes
# pushq $1
while i < len(instructions) - 1:
if instructions[i].opcode != 'movq' or instructions[i + 1].opcode != 'pushq':
i += 1
continue
@ -360,7 +365,11 @@ class CompileData:
i = 0
# Optimize movq to rax followed by movq from rax
while i < len(instructions):
# movq $1, %rax
# movq %rax, %rcx
# becomes
# movq $1, %rcx
while i < len(instructions) - 1:
if instructions[i].opcode != 'movq' or instructions[i + 1].opcode != 'movq':
i += 1
continue
@ -379,8 +388,84 @@ class CompileData:
changed = True
if changed: continue
i = 0
# Replace negative immediate in addq/subq with positive immediate
# This is not a real optimization, but it makes the code easier to optimize
# subq $-1, %rax
# becomes
# addq $1, %rax
while i < len(instructions):
if instructions[i].opcode not in ['addq', 'subq']:
i += 1
continue
if instructions[i].operands[1][0] != '$':
i += 1
continue
value = int(instructions[i].operands[1][1:])
if value >= 0:
i += 1
continue
new_opcode = 'subq' if instructions[i].opcode == 'addq' else 'addq'
instructions[i] = Instruction(new_opcode, [instructions[i].operands[0], f'${-value}'])
changed = True
if changed: continue
i = 0
# Optimize repeated addq/subq instructions
# addq $1, %rax
# addq $2, %rax
# becomes
# addq $3, %rax
while i < len(instructions) - 1:
if instructions[i].opcode not in ['addq', 'subq']:
i += 1
continue
if instructions[i].operands[1] != instructions[i + 1].operands[1]:
i += 1
continue
lhs = int(instructions[i].operands[0][1:])
if instructions[i].opcode == 'subq': lhs = -lhs
rhs = int(instructions[i + 1].operands[0][1:])
if instructions[i + 1].opcode == 'subq': rhs = -rhs
new_value = lhs + rhs
new_opcode = 'addq' if new_value >= 0 else 'subq'
instructions[i] = Instruction(new_opcode, [f'${abs(new_value)}', instructions[i].operands[1]])
instructions.pop(i + 1)
i -= 1
changed = True
if changed: continue
i = 0
# Optimize movq immediate to register followed addq/subq with immediate
# movq $1, %rax
# addq $2, %rax
# becomes
# movq $3, %rax
while i < len(instructions) - 1:
if instructions[i].opcode != 'movq' or instructions[i + 1].opcode not in ['addq', 'subq']:
i += 1
continue
if instructions[i].operands[1] != instructions[i + 1].operands[1]:
i += 1
continue
if instructions[i].operands[0][0] != '$' or instructions[i + 1].operands[0][0] != '$':
i += 1
continue
lhs = int(instructions[i].operands[0][1:])
rhs = int(instructions[i + 1].operands[0][1:])
if instructions[i + 1].opcode == 'subq': rhs = -rhs
new_value = lhs + rhs
instructions[i] = Instruction('movq', [f'${new_value}', instructions[i].operands[1]])
instructions.pop(i + 1)
i -= 1
changed = True
if changed: continue
i = 0
# Optimize addq/subq for immediate 1
# addq $1, %rax
# becomes
# incq %rax
while i < len(instructions):
if instructions[i].opcode not in ['addq', 'subq']:
i += 1
@ -395,6 +480,9 @@ class CompileData:
i = 0
# Optimize zeroing of register
# movq $0, %rax
# becomes
# xorq %rax, %rax
while i < len(instructions):
if instructions[i].opcode != 'movq':
i += 1