Files
Compiler/AssemblyGenerator.cpp
2025-11-16 21:04:02 +08:00

205 lines
5.5 KiB
C++
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// AssemblyGenerator.cpp
#include "AssemblyGenerator.h"
#include <sstream>
#include <iostream>
#include <cctype>
#include <cassert>
AssemblyGenerator::AssemblyGenerator(const std::vector<Quad> &quads)
: quads_(quads), stackSize_(0) {
allocateStack();
}
void AssemblyGenerator::allocateStack() {
int offset = 0;
// 1) 给所有源变量localOffset_分配空间
for (auto &q : quads_) {
if (!q.var.empty() && localOffset_.count(q.var) == 0) {
offset += 8;
localOffset_[q.var] = offset;
}
}
// 2) 给所有临时变量t1, t2, ...)分配空间
for (auto &q : quads_) {
if (!q.result.empty() && q.result[0] == 't'
&& tempOffset_.count(q.result) == 0) {
offset += 8;
tempOffset_[q.result] = offset;
}
}
// 16 字节对齐
stackSize_ = ((offset + 15) / 16) * 16;
}
std::string AssemblyGenerator::generate() {
std::ostringstream out;
// 1) 段和全局符号声明
out << ".text\n";
out << ".globl _main\n";
// 2) 如果首条 IR 是一条 "label main",先输出 _main:,然后 prologue
size_t idx = 0;
if (!quads_.empty() && quads_[0].op == "label" && quads_[0].result == "main") {
out << "_main:\n";
emitPrologue(out);
idx = 1;
} else {
// 否则也输出 prologue
emitPrologue(out);
}
// 3) 其余指令
for (size_t i = idx; i < quads_.size(); ++i) {
emitInstruction(quads_[i], out);
}
// 4) epilogue
emitEpilogue(out);
return out.str();
}
void AssemblyGenerator::emitPrologue(std::ostream &os) const {
os << "\tstp x29, x30, [sp, #-16]! // push FP, LR\n";
os << "\tmov x29, sp\n";
if (stackSize_ > 0) {
os << "\tsub sp, sp, #" << stackSize_ << "\n";
}
}
void AssemblyGenerator::emitEpilogue(std::ostream &os) const {
if (stackSize_ > 0) {
os << "\tadd sp, sp, #" << stackSize_ << "\n";
}
os << "\tldp x29, x30, [sp], #16 // pop FP, LR\n";
os << "\tret\n";
}
void AssemblyGenerator::loadOperand(const std::string &name, std::ostream &os) const {
if (!name.empty() && std::isdigit(name[0])) {
// 立即数
os << "\tmov w9, #" << name << "\n";
}
else if (localOffset_.count(name)) {
// 局部变量
os << "\tldr w9, [x29, #-" << localOffset_.at(name) << "]\n";
}
else if (tempOffset_.count(name)) {
// 临时变量
os << "\tldr w9, [x29, #-" << tempOffset_.at(name) << "]\n";
}
else {
// 全局变量
os << "\tadrp x10, " << name << "\n";
os << "\tadd x10, x10, :lo12:" << name << "\n";
os << "\tldr w9, [x10]\n";
}
}
void AssemblyGenerator::storeResult(const std::string &name, std::ostream &os) const {
if (localOffset_.count(name)) {
// 局部变量
os << "\tstr w9, [x29, #-" << localOffset_.at(name) << "]\n";
}
else if (tempOffset_.count(name)) {
// 临时变量
os << "\tstr w9, [x29, #-" << tempOffset_.at(name) << "]\n";
}
else {
// 全局变量
os << "\tadrp x10, " << name << "\n";
os << "\tadd x10, x10, :lo12:" << name << "\n";
os << "\tstr w9, [x10]\n";
}
}
void AssemblyGenerator::emitInstruction(const Quad &q, std::ostream &os) const {
using std::string;
// 标签
if (q.op == "label") {
// 非 main 的其他标签直接原样输出
if (q.result != "main") {
os << q.result << ":\n";
}
return;
}
// 无条件跳转
if (q.op == "goto") {
os << "\tb " << q.result << "\n";
return;
}
// ifFalse x -> cmp x, #0; beq L
if (q.op == "ifFalse") {
loadOperand(q.arg1, os);
os << "\tcmp w9, #0\n";
os << "\tbeq " << q.result << "\n";
return;
}
// 赋值 =
if (q.op == "=") {
loadOperand(q.arg1, os);
storeResult(q.result, os);
return;
}
// 二元算术/逻辑运算
static const std::unordered_map<string, string> binOpMap = {
{ "+", "add" }, { "-", "sub" }, { "*", "mul" },
{ "/", "sdiv" }, { "<<", "lsl" }, { ">>", "lsr" },
{ "&", "and" }, { "|", "orr" }, { "^", "eor" }
};
if (binOpMap.count(q.op)) {
loadOperand(q.arg1, os);
os << "\tmov w10, w9\n";
loadOperand(q.arg2, os);
os << "\tmov w11, w9\n";
os << "\t" << binOpMap.at(q.op) << " w9, w10, w11\n";
storeResult(q.result, os);
return;
}
// 比较运算,使用 cset 生成布尔 0/1
static const std::unordered_map<string, string> cmpCondMap = {
{"==", "eq"}, {"!=", "ne"},
{"<", "lt"}, {">", "gt"},
{"<=", "le"}, {">=", "ge"}
};
if (cmpCondMap.count(q.op)) {
loadOperand(q.arg1, os);
os << "\tmov w10, w9\n";
loadOperand(q.arg2, os);
os << "\tmov w11, w9\n";
os << "\tcmp w10, w11\n";
os << "\tcset w9, " << cmpCondMap.at(q.op) << "\n";
storeResult(q.result, os);
return;
}
// call / param / return
if (q.op == "param") {
return;
}
if (q.op == "call") {
os << "\tbl " << q.arg1 << "\n";
os << "\tmov w9, w0\n";
storeResult(q.result, os);
return;
}
if (q.op == "return") {
if (!q.arg1.empty()) {
loadOperand(q.arg1, os);
os << "\tmov w0, w9\n";
}
return;
}
std::cerr << "Unhandled IR op: " << q.op << "\n";
}