[lab3]addl movl ret passes clang test
This commit is contained in:
@ -12,23 +12,57 @@ class X86Emitter:
|
||||
asm.append(self.emit_instruction(instr))
|
||||
return "\n".join(asm)
|
||||
|
||||
def emit_instruction(self, instr: MiddleInstruction) -> str:
|
||||
op = instr.opcode
|
||||
if op == "add":
|
||||
src1, src2 = instr.operands
|
||||
dest = instr.dest
|
||||
#TODO(Lixuan Wang): src1 src2 的类型标签还没有去除,如i32 5,会出现在汇编文件中,这是不对的
|
||||
return (
|
||||
f" movl ${src1}, %{self.map_operand(dest)}\n"
|
||||
f" addl ${src2}, %{self.map_operand(dest)}"
|
||||
)
|
||||
elif op == "ret":
|
||||
return " ret"
|
||||
def is_register(self, operand):
|
||||
return operand.startswith("%")
|
||||
|
||||
def get_operand_asm(self, operand):
|
||||
if self.is_register(operand):
|
||||
return "%" + self.map_operand(operand)
|
||||
else:
|
||||
raise NotImplementedError(f"Unsupported opcode: {op}")
|
||||
# 移除类型信息(如 'i32'),提取数值
|
||||
# 假设操作数格式为 'i32 5' 或直接为 '5'
|
||||
parts = operand.split()
|
||||
# 如果包含类型信息,取最后一个部分(数值)
|
||||
value = parts[-1] if len(parts) > 1 else operand
|
||||
try:
|
||||
# 验证是有效整数
|
||||
int(value)
|
||||
return "$" + value
|
||||
except ValueError:
|
||||
# 如果不是有效整数,抛出错误
|
||||
raise ValueError(f"Invalid immediate operand: {operand}")
|
||||
|
||||
def map_operand(self, operand: str) -> str:
|
||||
"""将虚拟寄存器映射到物理寄存器(简化版)"""
|
||||
if operand.startswith('%.'):
|
||||
return self.reg_pool[int(operand[2:]) % len(self.reg_pool)]
|
||||
if operand.startswith('%'):
|
||||
# 去掉 '%' 和 '.'(如果有)
|
||||
reg_num = operand[1:].replace('.', '')
|
||||
try:
|
||||
idx = int(reg_num)
|
||||
return self.reg_pool[idx % len(self.reg_pool)]
|
||||
except ValueError:
|
||||
return "eax" # 默认
|
||||
return operand
|
||||
|
||||
def emit_instruction(self, instr: MiddleInstruction) -> str:
|
||||
op = instr.opcode
|
||||
if op in ["add", "sub", "mul"]:
|
||||
dest_reg = self.map_operand(instr.dest)
|
||||
src1, src2 = instr.operands
|
||||
if op == "add":
|
||||
op_asm = "addl"
|
||||
elif op == "sub":
|
||||
op_asm = "subl"
|
||||
elif op == "mul":
|
||||
op_asm = "imull"
|
||||
asm = f" movl {self.get_operand_asm(src1)}, %{dest_reg}\n"
|
||||
asm += f" {op_asm} {self.get_operand_asm(src2)}, %{dest_reg}"
|
||||
return asm
|
||||
elif op == "ret":
|
||||
if instr.operands:
|
||||
op = instr.operands[0]
|
||||
return f" movl {self.get_operand_asm(op)}, %eax\n ret"
|
||||
else:
|
||||
return " ret"
|
||||
else:
|
||||
raise NotImplementedError(f"Unsupported opcode: {op}")
|
||||
@ -2,17 +2,40 @@ class MiddleFunction:
|
||||
def __init__(self, name: str):
|
||||
self.name = name
|
||||
self.basic_blocks = [] # List[MiddleBasicBlock]
|
||||
|
||||
def __repr__(self):
|
||||
return f"Function({self.name}):\n" + "\n".join(str(block) for block in self.basic_blocks)
|
||||
|
||||
def __str__(self):
|
||||
return self.__repr__()
|
||||
|
||||
def collect_used_registers(self):
|
||||
used = set()
|
||||
for block in self.basic_blocks:
|
||||
for instr in block.instructions:
|
||||
for op in instr.operands:
|
||||
if op.startswith("%"):
|
||||
used.add(op)
|
||||
# For ret, if it has operands
|
||||
if instr.opcode == "ret" and instr.operands:
|
||||
op = instr.operands[0]
|
||||
if op.startswith("%"):
|
||||
used.add(op)
|
||||
return used
|
||||
|
||||
def dead_code_elimination(self):
|
||||
used = self.collect_used_registers()
|
||||
for block in self.basic_blocks:
|
||||
block.instructions = [instr for instr in block.instructions if instr.dest is None or instr.dest in used]
|
||||
|
||||
class MiddleBasicBlock:
|
||||
def __init__(self, name: str):
|
||||
self.name = name
|
||||
self.instructions = [] # List[MiddleInstruction]
|
||||
|
||||
def __repr__(self):
|
||||
return f"BasicBlock({self.name}):\n" + "\n".join(str(instr) for instr in self.instructions)
|
||||
|
||||
def __str__(self):
|
||||
return self.__repr__()
|
||||
|
||||
@ -21,7 +44,12 @@ class MiddleInstruction:
|
||||
self.opcode = opcode # e.g., 'add'
|
||||
self.operands = operands # e.g., ['5', '7']
|
||||
self.dest = dest # e.g., '%0'
|
||||
|
||||
def __repr__(self):
|
||||
return f"{self.dest} = {self.opcode} " + ", ".join(self.operands) if self.dest else f"{self.opcode} " + ", ".join(self.operands)
|
||||
if self.dest:
|
||||
return f"{self.dest} = {self.opcode} " + ", ".join(self.operands)
|
||||
else:
|
||||
return f"{self.opcode} " + ", ".join(self.operands)
|
||||
|
||||
def __str__(self):
|
||||
return self.__repr__()
|
||||
@ -4,7 +4,6 @@ from sysy.backend.x86_emitter import X86Emitter
|
||||
|
||||
def main():
|
||||
if len(sys.argv) != 2:
|
||||
# print("Usage: sysyc.py <input.ll> <output.s>")
|
||||
print("Usage: sysyc.py <input.ll>")
|
||||
sys.exit(1)
|
||||
|
||||
@ -14,12 +13,14 @@ def main():
|
||||
|
||||
# 解析并生成汇编
|
||||
func = parse_llvm_ir(ir_text)
|
||||
print(func)
|
||||
# print("Before optimization:")
|
||||
# print(func)
|
||||
# func.dead_code_elimination()
|
||||
# print("After optimization:")
|
||||
# print(func)
|
||||
asm = X86Emitter().emit_function(func)
|
||||
|
||||
# 写入文件
|
||||
# with open(sys.argv[2], 'w') as f:
|
||||
# f.write(asm)
|
||||
print(asm)
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
main()
|
||||
BIN
src/pysrc/test_add_exec
Executable file
BIN
src/pysrc/test_add_exec
Executable file
Binary file not shown.
Reference in New Issue
Block a user