【2025-11-16】现有代码上传
This commit is contained in:
204
AssemblyGenerator.cpp
Normal file
204
AssemblyGenerator.cpp
Normal file
@@ -0,0 +1,204 @@
|
||||
// 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";
|
||||
}
|
||||
Reference in New Issue
Block a user