diff --git a/src/pysrc/sysy/backend/x86_emitter.py b/src/pysrc/sysy/backend/x86_emitter.py index 71c5d08..b4d1991 100644 --- a/src/pysrc/sysy/backend/x86_emitter.py +++ b/src/pysrc/sysy/backend/x86_emitter.py @@ -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}") \ No newline at end of file diff --git a/src/pysrc/sysy/middle_ir.py b/src/pysrc/sysy/middle_ir.py index d6fe352..01fdbbc 100644 --- a/src/pysrc/sysy/middle_ir.py +++ b/src/pysrc/sysy/middle_ir.py @@ -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__() \ No newline at end of file diff --git a/src/pysrc/sysyc.py b/src/pysrc/sysyc.py index db62eee..5de1c27 100644 --- a/src/pysrc/sysyc.py +++ b/src/pysrc/sysyc.py @@ -4,7 +4,6 @@ from sysy.backend.x86_emitter import X86Emitter def main(): if len(sys.argv) != 2: - # print("Usage: sysyc.py ") print("Usage: sysyc.py ") 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() \ No newline at end of file diff --git a/src/pysrc/test_add_exec b/src/pysrc/test_add_exec new file mode 100755 index 0000000..051d8f9 Binary files /dev/null and b/src/pysrc/test_add_exec differ