Compare commits

...

36 Commits

Author SHA1 Message Date
rain2133
50fd9cffe9 [IRPrinter&DCE]修改定义方便调试打印,在DEC中增加调试信息 2025-07-16 13:04:05 +08:00
rain2133
3419f84898 Merge remote-tracking branch 'origin/backend' into loopinfo 2025-07-15 13:09:55 +08:00
rain2133
ede6465e8c [IR]:增加默认添加ret指令逻辑 2025-07-15 12:53:03 +08:00
Lixuanwang
a509dabbf0 [backend]解决了数组访存地址计算问题,加入了参数控制的中端、后端调试选项 2025-07-15 11:32:53 +08:00
lixuanwang
e576f0a21e Merge remote-tracking branch 'origin/DCE' into backend 2025-06-27 22:44:08 +08:00
Lixuanwang
34ffa39b8a [backend] modified some comments and created a shell srcipt for test inside riscv64-vms 2025-06-25 20:59:40 +08:00
Lixuanwang
d06c5efae1 [backend] fixed bugs of deadcode elimation 2025-06-25 18:56:08 +08:00
Lixuanwang
019cb6dc0d [backend] debugging array 2025-06-25 17:07:37 +08:00
Lixuanwang
44fb098aff Merge branch 'DCE' into backend 2025-06-25 16:04:42 +08:00
Lixuanwang
6f897d797a [backend] debugging array 2025-06-25 16:02:41 +08:00
Lixuanwang
15a80bd5cd [backend] fix the logical error of constants in interference graph construction 2025-06-25 14:37:46 +08:00
Lixuanwang
c8587a6d0b [backend] introduced riscv64 2025-06-25 14:37:46 +08:00
rain2133
4c9c25aadc 修复break,continue的IR生成 2025-06-25 14:15:54 +08:00
Lixuanwang
9bb300ece5 Created a shell script for testing 2025-06-25 06:27:31 +08:00
Lixuanwang
c04f508171 [backend] implemented call function parameter passing using registers 2025-06-25 06:27:05 +08:00
rain2133
24913641f2 [backend] fix bugs of not 2025-06-25 02:24:45 +08:00
Lixuanwang
af1ad795ff [backend] fix bugs of unary ops 2025-06-25 01:07:13 +08:00
Lixuanwang
eadeadfbad [backend] introduced float instrs and regs 2025-06-24 23:24:09 +08:00
Lixuanwang
430224cfef Merge commit 'd50f76a77024d830c3dd7311ed910d689c9d5f16' into backend 2025-06-24 22:52:01 +08:00
Lixuanwang
5222027b68 [backend] almost all test passed 2025-06-24 16:03:39 +08:00
Lixuanwang
cd91cc98ed Created some shell scripts for testing 2025-06-24 15:13:02 +08:00
Lixuanwang
f72b9ccc00 [backend] fixed bugs of testcase1 2025-06-24 15:12:07 +08:00
Lixuanwang
385f2f9712 [backend] fixed the bug of physical register allocation error 2025-06-24 14:15:02 +08:00
Lixuanwang
395e6e4003 [backend] fixed many bugs 2025-06-24 03:23:45 +08:00
Lixuanwang
20cc08708a [backend] introduced debug option 2025-06-24 02:56:17 +08:00
Lixuanwang
942cb32976 [backend] fixed bugs 2025-06-24 00:42:14 +08:00
Lixuanwang
ac7569d890 Merge branch 'IROptPre' into backend 2025-06-24 00:40:36 +08:00
Lixuanwang
11cd32e6df [backend] fixed some bugs 2025-06-24 00:35:38 +08:00
Lixuanwang
617244fae7 [backend] switch to simpler implementation for inst selection 2025-06-24 00:30:33 +08:00
Lixuanwang
3c3f48ee87 [backend] fixed 1 segmentation fault 2025-06-23 22:38:29 +08:00
Lixuanwang
ab3eb253f9 [backend] debugging segmentation fault caused by branch instr 2025-06-23 17:02:29 +08:00
Lixuanwang
7d37bd7528 [backend] introduced DAG, GraphAlloc 2025-06-23 15:38:01 +08:00
Lixuanwang
af00612376 [backend] supported if 2025-06-23 06:16:19 +08:00
ladev789
10e1476ba1 [backend] test01 passed 2025-06-22 20:05:34 +08:00
ladev789
b94e87637a Merge remote-tracking branch 'origin/IRPrinter' into backend 2025-06-22 20:00:29 +08:00
ladev789
88a561177d [backend] incorrect asm output 2025-06-22 20:00:03 +08:00
30 changed files with 3774 additions and 1804 deletions

View File

@@ -22,7 +22,7 @@ add_executable(sysyc
DeadCodeElimination.cpp DeadCodeElimination.cpp
Mem2Reg.cpp Mem2Reg.cpp
Reg2Mem.cpp Reg2Mem.cpp
RISCv32Backend.cpp RISCv64Backend.cpp
) )
target_include_directories(sysyc PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include) target_include_directories(sysyc PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_compile_options(sysyc PRIVATE -frtti) target_compile_options(sysyc PRIVATE -frtti)

View File

@@ -1,8 +1,9 @@
#include "DeadCodeElimination.h" #include "DeadCodeElimination.h"
#include <iostream>
extern int DEBUG;
namespace sysy { namespace sysy {
void DeadCodeElimination::runDCEPipeline() { void DeadCodeElimination::runDCEPipeline() {
const auto& functions = pModule->getFunctions(); const auto& functions = pModule->getFunctions();
for (const auto& function : functions) { for (const auto& function : functions) {
@@ -58,6 +59,10 @@ void DeadCodeElimination::eliminateDeadStores(Function* func, bool& changed) {
if (changetag) { if (changetag) {
changed = true; changed = true;
if(DEBUG){
std::cout << "=== Dead Store Found ===\n";
SysYPrinter::printInst(storeInst);
}
usedelete(storeInst); usedelete(storeInst);
iter = instrs.erase(iter); iter = instrs.erase(iter);
} else { } else {
@@ -76,6 +81,10 @@ void DeadCodeElimination::eliminateDeadLoads(Function* func, bool& changed) {
if (inst->isBinary() || inst->isUnary() || inst->isLoad()) { if (inst->isBinary() || inst->isUnary() || inst->isLoad()) {
if (inst->getUses().empty()) { if (inst->getUses().empty()) {
changed = true; changed = true;
if(DEBUG){
std::cout << "=== Dead Load Binary Unary Found ===\n";
SysYPrinter::printInst(inst);
}
usedelete(inst); usedelete(inst);
iter = instrs.erase(iter); iter = instrs.erase(iter);
continue; continue;
@@ -101,6 +110,10 @@ void DeadCodeElimination::eliminateDeadAllocas(Function* func, bool& changed) {
func->getEntryBlock()->getArguments().end(), func->getEntryBlock()->getArguments().end(),
allocaInst) == func->getEntryBlock()->getArguments().end()) { allocaInst) == func->getEntryBlock()->getArguments().end()) {
changed = true; changed = true;
if(DEBUG){
std::cout << "=== Dead Alloca Found ===\n";
SysYPrinter::printInst(inst);
}
usedelete(inst); usedelete(inst);
iter = instrs.erase(iter); iter = instrs.erase(iter);
continue; continue;
@@ -116,8 +129,12 @@ void DeadCodeElimination::eliminateDeadIndirectiveAllocas(Function* func, bool&
FunctionAnalysisInfo* funcInfo = pCFA->getFunctionAnalysisInfo(func); FunctionAnalysisInfo* funcInfo = pCFA->getFunctionAnalysisInfo(func);
for (auto it = funcInfo->getIndirectAllocas().begin(); it != funcInfo->getIndirectAllocas().end();) { for (auto it = funcInfo->getIndirectAllocas().begin(); it != funcInfo->getIndirectAllocas().end();) {
auto &allocaInst = *it; auto &allocaInst = *it;
if (allocaInst->getUses().empty()) { if (allocaInst->getUses().empty()) {
changed = true; changed = true;
if(DEBUG){
std::cout << "=== Dead Indirect Alloca Found ===\n";
SysYPrinter::printInst(allocaInst.get());
}
it = funcInfo->getIndirectAllocas().erase(it); it = funcInfo->getIndirectAllocas().erase(it);
} else { } else {
++it; ++it;
@@ -132,6 +149,10 @@ void DeadCodeElimination::eliminateDeadGlobals(bool& changed) {
auto& global = *it; auto& global = *it;
if (global->getUses().empty()) { if (global->getUses().empty()) {
changed = true; changed = true;
if(DEBUG){
std::cout << "=== Dead Global Found ===\n";
SysYPrinter::printValue(global.get());
}
it = globals.erase(it); it = globals.erase(it);
} else { } else {
++it; ++it;
@@ -207,6 +228,12 @@ void DeadCodeElimination::eliminateDeadRedundantLoadStore(Function* func, bool&
// 可以优化直接把prevStorePointer的值存到nextStorePointer // 可以优化直接把prevStorePointer的值存到nextStorePointer
changed = true; changed = true;
nextStore->setOperand(0, prevStoreValue); nextStore->setOperand(0, prevStoreValue);
if(DEBUG){
std::cout << "=== Dead Store Load Store Found(now only del Load) ===\n";
SysYPrinter::printInst(prevStore);
SysYPrinter::printInst(loadInst);
SysYPrinter::printInst(nextStore);
}
usedelete(loadInst); usedelete(loadInst);
iter = instrs.erase(iter); iter = instrs.erase(iter);
// 删除 prevStore 这里是不是可以留给删除无用store处理 // 删除 prevStore 这里是不是可以留给删除无用store处理

View File

@@ -1,674 +0,0 @@
// LLVMIRGenerator.cpp
// TODO类型转换及其检查
// TODOsysy库函数处理
// TODO数组处理
// TODO对while、continue、break的测试
#include "LLVMIRGenerator.h"
#include <iomanip>
using namespace std;
namespace sysy {
std::string LLVMIRGenerator::generateIR(SysYParser::CompUnitContext* unit) {
// 初始化自定义IR数据结构
irModule = std::make_unique<sysy::Module>();
irBuilder = sysy::IRBuilder(); // 初始化IR构建器
tempCounter = 0;
symbolTable.clear();
tmpTable.clear();
globalVars.clear();
inFunction = false;
visitCompUnit(unit);
return irStream.str();
}
std::string LLVMIRGenerator::getNextTemp() {
std::string ret = "%." + std::to_string(tempCounter++);
tmpTable[ret] = "void";
return ret;
}
std::string LLVMIRGenerator::getLLVMType(const std::string& type) {
if (type == "int") return "i32";
if (type == "float") return "float";
if (type.find("[]") != std::string::npos)
return getLLVMType(type.substr(0, type.size()-2)) + "*";
return "i32";
}
sysy::Type* LLVMIRGenerator::getSysYType(const std::string& typeStr) {
if (typeStr == "int") return sysy::Type::getIntType();
if (typeStr == "float") return sysy::Type::getFloatType();
if (typeStr == "void") return sysy::Type::getVoidType();
// 处理指针类型等
return sysy::Type::getIntType();
}
std::any LLVMIRGenerator::visitCompUnit(SysYParser::CompUnitContext* ctx) {
auto type_i32 = Type::getIntType();
auto type_f32 = Type::getFloatType();
auto type_void = Type::getVoidType();
auto type_i32p = Type::getPointerType(type_i32);
auto type_f32p = Type::getPointerType(type_f32);
// 创建运行时库函数
irModule->createFunction("getint", sysy::FunctionType::get(type_i32, {}));
irModule->createFunction("getch", sysy::FunctionType::get(type_i32, {}));
irModule->createFunction("getfloat", sysy::FunctionType::get(type_f32, {}));
//TODO: 添加更多运行时库函数
irStream << "declare i32 @getint()\n";
irStream << "declare i32 @getch()\n";
irStream << "declare float @getfloat()\n";
//TODO: 添加更多运行时库函数的文本IR
for (auto decl : ctx->decl()) {
decl->accept(this);
}
for (auto funcDef : ctx->funcDef()) {
inFunction = true; // 进入函数定义
funcDef->accept(this);
inFunction = false; // 离开函数定义
}
return nullptr;
}
std::any LLVMIRGenerator::visitVarDecl(SysYParser::VarDeclContext* ctx) {
// TODO数组初始化
std::string type = ctx->bType()->getText();
currentVarType = getLLVMType(type);
for (auto varDef : ctx->varDef()) {
if (!inFunction) {
// 全局变量声明
std::string varName = varDef->Ident()->getText();
std::string llvmType = getLLVMType(type);
std::string value = "0"; // 默认值为 0
if (varDef->ASSIGN()) {
value = std::any_cast<std::string>(varDef->initVal()->accept(this));
} else {
std::cout << "[WR-Release-01]Warning: Global variable '" << varName
<< "' is declared without initialization, defaulting to 0.\n";
}
irStream << "@" << varName << " = dso_local global " << llvmType << " " << value << ", align 4\n";
globalVars.push_back(varName); // 记录全局变量
} else {
// 局部变量声明
varDef->accept(this);
}
}
return nullptr;
}
std::any LLVMIRGenerator::visitConstDecl(SysYParser::ConstDeclContext* ctx) {
// TODO数组初始化
std::string type = ctx->bType()->getText();
for (auto constDef : ctx->constDef()) {
if (!inFunction) {
// 全局常量声明
std::string varName = constDef->Ident()->getText();
std::string llvmType = getLLVMType(type);
std::string value = "0"; // 默认值为 0
try {
value = std::any_cast<std::string>(constDef->constInitVal()->accept(this));
} catch (...) {
throw std::runtime_error("[ERR-Release-01]Const value must be initialized upon definition.");
}
// 如果是 float 类型,转换为十六进制表示
if (llvmType == "float") {
try {
double floatValue = std::stod(value);
uint64_t hexValue = reinterpret_cast<uint64_t&>(floatValue);
std::stringstream ss;
ss << "0x" << std::hex << std::uppercase << hexValue;
value = ss.str();
} catch (...) {
throw std::runtime_error("[ERR-Release-02]Invalid float literal: " + value);
}
}
irStream << "@" << varName << " = dso_local constant " << llvmType << " " << value << ", align 4\n";
globalVars.push_back(varName); // 记录全局变量
} else {
// 局部常量声明
std::string varName = constDef->Ident()->getText();
std::string llvmType = getLLVMType(type);
std::string allocaName = getNextTemp();
std::string value = "0"; // 默认值为 0
try {
value = std::any_cast<std::string>(constDef->constInitVal()->accept(this));
} catch (...) {
throw std::runtime_error("Const value must be initialized upon definition.");
}
irStream << " " << allocaName << " = alloca " << llvmType << ", align 4\n";
if (llvmType == "float") {
try {
double floatValue = std::stod(value);
uint64_t hexValue = reinterpret_cast<uint64_t&>(floatValue);
std::stringstream ss;
ss << "0x" << std::hex << std::uppercase << hexValue;
value = ss.str();
} catch (...) {
throw std::runtime_error("Invalid float literal: " + value);
}
}
irStream << " store " << llvmType << " " << value << ", " << llvmType
<< "* " << allocaName << ", align 4\n";
symbolTable[varName] = {allocaName, llvmType};
tmpTable[allocaName] = llvmType;
}
}
return nullptr;
}
std::any LLVMIRGenerator::visitVarDef(SysYParser::VarDefContext* ctx) {
// TODO数组初始化
std::string varName = ctx->Ident()->getText();
std::string type = currentVarType;
std::string llvmType = getLLVMType(type);
std::string allocaName = getNextTemp();
irStream << " " << allocaName << " = alloca " << llvmType << ", align 4\n";
if (ctx->ASSIGN()) {
std::string value = std::any_cast<std::string>(ctx->initVal()->accept(this));
if (llvmType == "float") {
try {
double floatValue = std::stod(value);
uint64_t hexValue = reinterpret_cast<uint64_t&>(floatValue);
std::stringstream ss;
ss << "0x" << std::hex << std::uppercase << (hexValue & (0xffffffffUL << 32));
value = ss.str();
} catch (...) {
throw std::runtime_error("Invalid float literal: " + value);
}
}
irStream << " store " << llvmType << " " << value << ", " << llvmType
<< "* " << allocaName << ", align 4\n";
}
symbolTable[varName] = {allocaName, llvmType};
tmpTable[allocaName] = llvmType;
return nullptr;
}
std::any LLVMIRGenerator::visitFuncDef(SysYParser::FuncDefContext* ctx) {
currentFunction = ctx->Ident()->getText();
currentReturnType = getLLVMType(ctx->funcType()->getText());
symbolTable.clear();
tmpTable.clear();
tempCounter = 0;
hasReturn = false;
irStream << "define dso_local " << currentReturnType << " @" << currentFunction << "(";
if (ctx->funcFParams()) {
auto params = ctx->funcFParams()->funcFParam();
tempCounter += params.size();
for (size_t i = 0; i < params.size(); ++i) {
if (i > 0) irStream << ", ";
std::string paramType = getLLVMType(params[i]->bType()->getText());
irStream << paramType << " noundef %" << i;
symbolTable[params[i]->Ident()->getText()] = {"%" + std::to_string(i), paramType};
tmpTable["%" + std::to_string(i)] = paramType;
}
}
tempCounter++;
irStream << ") #0 {\n";
if (ctx->funcFParams()) {
auto params = ctx->funcFParams()->funcFParam();
for (size_t i = 0; i < params.size(); ++i) {
std::string varName = params[i]->Ident()->getText();
std::string type = params[i]->bType()->getText();
std::string llvmType = getLLVMType(type);
std::string allocaName = getNextTemp();
tmpTable[allocaName] = llvmType;
irStream << " " << allocaName << " = alloca " << llvmType << ", align 4\n";
irStream << " store " << llvmType << " " << symbolTable[varName].first << ", " << llvmType
<< "* " << allocaName << ", align 4\n";
symbolTable[varName] = {allocaName, llvmType};
}
}
ctx->blockStmt()->accept(this);
if (!hasReturn) {
if (currentReturnType == "void") {
irStream << " ret void\n";
} else {
irStream << " ret " << currentReturnType << " 0\n";
}
}
irStream << "}\n";
return nullptr;
}
std::any LLVMIRGenerator::visitBlockStmt(SysYParser::BlockStmtContext* ctx) {
for (auto item : ctx->blockItem()) {
item->accept(this);
}
return nullptr;
}
std::any LLVMIRGenerator::visitAssignStmt(SysYParser::AssignStmtContext *ctx)
{
std::string lhsAlloca = std::any_cast<std::string>(ctx->lValue()->accept(this));
std::string lhsType = symbolTable[ctx->lValue()->Ident()->getText()].second;
std::string rhs = std::any_cast<std::string>(ctx->exp()->accept(this));
if (lhsType == "float") {
try {
double floatValue = std::stod(rhs);
uint64_t hexValue = reinterpret_cast<uint64_t&>(floatValue);
std::stringstream ss;
ss << "0x" << std::hex << std::uppercase << (hexValue & (0xffffffffUL << 32));
rhs = ss.str();
} catch (...) {
throw std::runtime_error("Invalid float literal: " + rhs);
}
}
irStream << " store " << lhsType << " " << rhs << ", " << lhsType
<< "* " << lhsAlloca << ", align 4\n";
return nullptr;
}
std::any LLVMIRGenerator::visitIfStmt(SysYParser::IfStmtContext *ctx)
{
std::string cond = std::any_cast<std::string>(ctx->cond()->accept(this));
std::string trueLabel = "if.then." + std::to_string(tempCounter);
std::string falseLabel = "if.else." + std::to_string(tempCounter);
std::string mergeLabel = "if.end." + std::to_string(tempCounter++);
irStream << " br i1 " << cond << ", label %" << trueLabel << ", label %" << falseLabel << "\n";
irStream << trueLabel << ":\n";
ctx->stmt(0)->accept(this);
irStream << " br label %" << mergeLabel << "\n";
irStream << falseLabel << ":\n";
if (ctx->ELSE()) {
ctx->stmt(1)->accept(this);
}
irStream << " br label %" << mergeLabel << "\n";
irStream << mergeLabel << ":\n";
return nullptr;
}
std::any LLVMIRGenerator::visitWhileStmt(SysYParser::WhileStmtContext *ctx)
{
std::string loop_cond = "while.cond." + std::to_string(tempCounter);
std::string loop_body = "while.body." + std::to_string(tempCounter);
std::string loop_end = "while.end." + std::to_string(tempCounter++);
loopStack.push({loop_end, loop_cond});
irStream << " br label %" << loop_cond << "\n";
irStream << loop_cond << ":\n";
std::string cond = std::any_cast<std::string>(ctx->cond()->accept(this));
irStream << " br i1 " << cond << ", label %" << loop_body << ", label %" << loop_end << "\n";
irStream << loop_body << ":\n";
ctx->stmt()->accept(this);
irStream << " br label %" << loop_cond << "\n";
irStream << loop_end << ":\n";
loopStack.pop();
return nullptr;
}
std::any LLVMIRGenerator::visitBreakStmt(SysYParser::BreakStmtContext *ctx)
{
if (loopStack.empty()) {
throw std::runtime_error("Break statement outside of a loop.");
}
irStream << " br label %" << loopStack.top().breakLabel << "\n";
return nullptr;
}
std::any LLVMIRGenerator::visitContinueStmt(SysYParser::ContinueStmtContext *ctx)
{
if (loopStack.empty()) {
throw std::runtime_error("Continue statement outside of a loop.");
}
irStream << " br label %" << loopStack.top().continueLabel << "\n";
return nullptr;
}
std::any LLVMIRGenerator::visitReturnStmt(SysYParser::ReturnStmtContext *ctx)
{
hasReturn = true;
if (ctx->exp()) {
std::string value = std::any_cast<std::string>(ctx->exp()->accept(this));
irStream << " ret " << currentReturnType << " " << value << "\n";
} else {
irStream << " ret void\n";
}
return nullptr;
}
// std::any LLVMIRGenerator::visitStmt(SysYParser::StmtContext* ctx) {
// if (ctx->lValue() && ctx->ASSIGN()) {
// std::string lhsAlloca = std::any_cast<std::string>(ctx->lValue()->accept(this));
// std::string lhsType = symbolTable[ctx->lValue()->Ident()->getText()].second;
// std::string rhs = std::any_cast<std::string>(ctx->exp()->accept(this));
// if (lhsType == "float") {
// try {
// double floatValue = std::stod(rhs);
// uint64_t hexValue = reinterpret_cast<uint64_t&>(floatValue);
// std::stringstream ss;
// ss << "0x" << std::hex << std::uppercase << (hexValue & (0xffffffffUL << 32));
// rhs = ss.str();
// } catch (...) {
// throw std::runtime_error("Invalid float literal: " + rhs);
// }
// }
// irStream << " store " << lhsType << " " << rhs << ", " << lhsType
// << "* " << lhsAlloca << ", align 4\n";
// } else if (ctx->RETURN()) {
// hasReturn = true;
// if (ctx->exp()) {
// std::string value = std::any_cast<std::string>(ctx->exp()->accept(this));
// irStream << " ret " << currentReturnType << " " << value << "\n";
// } else {
// irStream << " ret void\n";
// }
// } else if (ctx->IF()) {
// std::string cond = std::any_cast<std::string>(ctx->cond()->accept(this));
// std::string trueLabel = "if.then." + std::to_string(tempCounter);
// std::string falseLabel = "if.else." + std::to_string(tempCounter);
// std::string mergeLabel = "if.end." + std::to_string(tempCounter++);
// irStream << " br i1 " << cond << ", label %" << trueLabel << ", label %" << falseLabel << "\n";
// irStream << trueLabel << ":\n";
// ctx->stmt(0)->accept(this);
// irStream << " br label %" << mergeLabel << "\n";
// irStream << falseLabel << ":\n";
// if (ctx->ELSE()) {
// ctx->stmt(1)->accept(this);
// }
// irStream << " br label %" << mergeLabel << "\n";
// irStream << mergeLabel << ":\n";
// } else if (ctx->WHILE()) {
// std::string loop_cond = "while.cond." + std::to_string(tempCounter);
// std::string loop_body = "while.body." + std::to_string(tempCounter);
// std::string loop_end = "while.end." + std::to_string(tempCounter++);
// loopStack.push({loop_end, loop_cond});
// irStream << " br label %" << loop_cond << "\n";
// irStream << loop_cond << ":\n";
// std::string cond = std::any_cast<std::string>(ctx->cond()->accept(this));
// irStream << " br i1 " << cond << ", label %" << loop_body << ", label %" << loop_end << "\n";
// irStream << loop_body << ":\n";
// ctx->stmt(0)->accept(this);
// irStream << " br label %" << loop_cond << "\n";
// irStream << loop_end << ":\n";
// loopStack.pop();
// } else if (ctx->BREAK()) {
// if (loopStack.empty()) {
// throw std::runtime_error("Break statement outside of a loop.");
// }
// irStream << " br label %" << loopStack.top().breakLabel << "\n";
// } else if (ctx->CONTINUE()) {
// if (loopStack.empty()) {
// throw std::runtime_error("Continue statement outside of a loop.");
// }
// irStream << " br label %" << loopStack.top().continueLabel << "\n";
// } else if (ctx->blockStmt()) {
// ctx->blockStmt()->accept(this);
// } else if (ctx->exp()) {
// ctx->exp()->accept(this);
// }
// return nullptr;
// }
std::any LLVMIRGenerator::visitLValue(SysYParser::LValueContext* ctx) {
std::string varName = ctx->Ident()->getText();
return symbolTable[varName].first;
}
// std::any LLVMIRGenerator::visitPrimaryExp(SysYParser::PrimaryExpContext* ctx) {
// if (ctx->lValue()) {
// std::string allocaPtr = std::any_cast<std::string>(ctx->lValue()->accept(this));
// std::string varName = ctx->lValue()->Ident()->getText();
// std::string type = symbolTable[varName].second;
// std::string temp = getNextTemp();
// irStream << " " << temp << " = load " << type << ", " << type << "* " << allocaPtr << ", align 4\n";
// tmpTable[temp] = type;
// return temp;
// } else if (ctx->exp()) {
// return ctx->exp()->accept(this);
// } else {
// return ctx->number()->accept(this);
// }
// }
std::any LLVMIRGenerator::visitPrimExp(SysYParser::PrimExpContext *ctx){
// irStream << "visitPrimExp\n";
// std::cout << "Type name: " << typeid(*(ctx->primaryExp())).name() << std::endl;
SysYParser::PrimaryExpContext* pExpCtx = ctx->primaryExp();
if (auto* lvalCtx = dynamic_cast<SysYParser::LValContext*>(pExpCtx)) {
std::string allocaPtr = std::any_cast<std::string>(lvalCtx->lValue()->accept(this));
std::string varName = lvalCtx->lValue()->Ident()->getText();
std::string type = symbolTable[varName].second;
std::string temp = getNextTemp();
irStream << " " << temp << " = load " << type << ", " << type << "* " << allocaPtr << ", align 4\n";
tmpTable[temp] = type;
return temp;
} else if (auto* expCtx = dynamic_cast<SysYParser::ParenExpContext*>(pExpCtx)) {
return expCtx->exp()->accept(this);
} else if (auto* strCtx = dynamic_cast<SysYParser::StrContext*>(pExpCtx)) {
return strCtx->string()->accept(this);
} else if (auto* numCtx = dynamic_cast<SysYParser::NumContext*>(pExpCtx)) {
return numCtx->number()->accept(this);
} else {
// 没有成功转换,说明 ctx->primaryExp() 不是 NumContext 或其他已知类型
// 可能是其他类型的表达式,或者是一个空的 PrimaryExpContext
std::cout << "Unknown primary expression type." << std::endl;
throw std::runtime_error("Unknown primary expression type.");
}
// return visitChildren(ctx);
}
std::any LLVMIRGenerator::visitParenExp(SysYParser::ParenExpContext* ctx) {
return ctx->exp()->accept(this);
}
std::any LLVMIRGenerator::visitNumber(SysYParser::NumberContext* ctx) {
if (ctx->ILITERAL()) {
return ctx->ILITERAL()->getText();
} else if (ctx->FLITERAL()) {
return ctx->FLITERAL()->getText();
}
return "";
}
std::any LLVMIRGenerator::visitString(SysYParser::StringContext *ctx)
{
if (ctx->STRING()) {
// 处理字符串常量
std::string str = ctx->STRING()->getText();
// 去掉引号
str = str.substr(1, str.size() - 2);
// 转义处理
std::string escapedStr;
for (char c : str) {
if (c == '\\') {
escapedStr += "\\\\";
} else if (c == '"') {
escapedStr += "\\\"";
} else {
escapedStr += c;
}
}
return "\"" + escapedStr + "\"";
}
return ctx->STRING()->getText();
}
std::any LLVMIRGenerator::visitUnExp(SysYParser::UnExpContext* ctx) {
if (ctx->unaryOp()) {
std::string operand = std::any_cast<std::string>(ctx->unaryExp()->accept(this));
std::string op = ctx->unaryOp()->getText();
std::string temp = getNextTemp();
std::string type = operand.substr(0, operand.find(' '));
tmpTable[temp] = type;
if (op == "-") {
irStream << " " << temp << " = sub " << type << " 0, " << operand << "\n";
} else if (op == "!") {
irStream << " " << temp << " = xor " << type << " " << operand << ", 1\n";
}
return temp;
}
return ctx->unaryExp()->accept(this);
}
std::any LLVMIRGenerator::visitCall(SysYParser::CallContext *ctx)
{
std::string funcName = ctx->Ident()->getText();
std::vector<std::string> args;
if (ctx->funcRParams()) {
for (auto argCtx : ctx->funcRParams()->exp()) {
args.push_back(std::any_cast<std::string>(argCtx->accept(this)));
}
}
std::string temp = getNextTemp();
std::string argList = "";
for (size_t i = 0; i < args.size(); ++i) {
if (i > 0) argList += ", ";
argList +=tmpTable[args[i]] + " noundef " + args[i];
}
irStream << " " << temp << " = call " << currentReturnType << " @" << funcName << "(" << argList << ")\n";
tmpTable[temp] = currentReturnType;
return temp;
}
std::any LLVMIRGenerator::visitMulExp(SysYParser::MulExpContext* ctx) {
auto unaryExps = ctx->unaryExp();
std::string left = std::any_cast<std::string>(unaryExps[0]->accept(this));
for (size_t i = 1; i < unaryExps.size(); ++i) {
std::string right = std::any_cast<std::string>(unaryExps[i]->accept(this));
std::string op = ctx->children[2*i-1]->getText();
std::string temp = getNextTemp();
std::string type = tmpTable[left];
if (op == "*") {
irStream << " " << temp << " = mul nsw " << type << " " << left << ", " << right << "\n";
} else if (op == "/") {
irStream << " " << temp << " = sdiv " << type << " " << left << ", " << right << "\n";
} else if (op == "%") {
irStream << " " << temp << " = srem " << type << " " << left << ", " << right << "\n";
}
left = temp;
tmpTable[temp] = type;
}
return left;
}
std::any LLVMIRGenerator::visitAddExp(SysYParser::AddExpContext* ctx) {
auto mulExps = ctx->mulExp();
std::string left = std::any_cast<std::string>(mulExps[0]->accept(this));
for (size_t i = 1; i < mulExps.size(); ++i) {
std::string right = std::any_cast<std::string>(mulExps[i]->accept(this));
std::string op = ctx->children[2*i-1]->getText();
std::string temp = getNextTemp();
std::string type = tmpTable[left];
if (op == "+") {
irStream << " " << temp << " = add nsw " << type << " " << left << ", " << right << "\n";
} else if (op == "-") {
irStream << " " << temp << " = sub nsw " << type << " " << left << ", " << right << "\n";
}
left = temp;
tmpTable[temp] = type;
}
return left;
}
std::any LLVMIRGenerator::visitRelExp(SysYParser::RelExpContext* ctx) {
auto addExps = ctx->addExp();
std::string left = std::any_cast<std::string>(addExps[0]->accept(this));
for (size_t i = 1; i < addExps.size(); ++i) {
std::string right = std::any_cast<std::string>(addExps[i]->accept(this));
std::string op = ctx->children[2*i-1]->getText();
std::string temp = getNextTemp();
std::string type = tmpTable[left];
if (op == "<") {
irStream << " " << temp << " = icmp slt " << type << " " << left << ", " << right << "\n";
} else if (op == ">") {
irStream << " " << temp << " = icmp sgt " << type << " " << left << ", " << right << "\n";
} else if (op == "<=") {
irStream << " " << temp << " = icmp sle " << type << " " << left << ", " << right << "\n";
} else if (op == ">=") {
irStream << " " << temp << " = icmp sge " << type << " " << left << ", " << right << "\n";
}
left = temp;
}
return left;
}
std::any LLVMIRGenerator::visitEqExp(SysYParser::EqExpContext* ctx) {
auto relExps = ctx->relExp();
std::string left = std::any_cast<std::string>(relExps[0]->accept(this));
for (size_t i = 1; i < relExps.size(); ++i) {
std::string right = std::any_cast<std::string>(relExps[i]->accept(this));
std::string op = ctx->children[2*i-1]->getText();
std::string temp = getNextTemp();
std::string type = tmpTable[left];
if (op == "==") {
irStream << " " << temp << " = icmp eq " << type << " " << left << ", " << right << "\n";
} else if (op == "!=") {
irStream << " " << temp << " = icmp ne " << type << " " << left << ", " << right << "\n";
}
left = temp;
}
return left;
}
std::any LLVMIRGenerator::visitLAndExp(SysYParser::LAndExpContext* ctx) {
auto eqExps = ctx->eqExp();
std::string left = std::any_cast<std::string>(eqExps[0]->accept(this));
for (size_t i = 1; i < eqExps.size(); ++i) {
std::string falseLabel = "land.false." + std::to_string(tempCounter);
std::string endLabel = "land.end." + std::to_string(tempCounter++);
std::string temp = getNextTemp();
irStream << " br label %" << falseLabel << "\n";
irStream << falseLabel << ":\n";
std::string right = std::any_cast<std::string>(eqExps[i]->accept(this));
irStream << " " << temp << " = and i1 " << left << ", " << right << "\n";
irStream << " br label %" << endLabel << "\n";
irStream << endLabel << ":\n";
left = temp;
}
return left;
}
std::any LLVMIRGenerator::visitLOrExp(SysYParser::LOrExpContext* ctx) {
auto lAndExps = ctx->lAndExp();
std::string left = std::any_cast<std::string>(lAndExps[0]->accept(this));
for (size_t i = 1; i < lAndExps.size(); ++i) {
std::string trueLabel = "lor.true." + std::to_string(tempCounter);
std::string endLabel = "lor.end." + std::to_string(tempCounter++);
std::string temp = getNextTemp();
irStream << " br label %" << trueLabel << "\n";
irStream << trueLabel << ":\n";
std::string right = std::any_cast<std::string>(lAndExps[i]->accept(this));
irStream << " " << temp << " = or i1 " << left << ", " << right << "\n";
irStream << " br label %" << endLabel << "\n";
irStream << endLabel << ":\n";
left = temp;
}
return left;
}
}

View File

@@ -1,859 +0,0 @@
// LLVMIRGenerator.cpp
// TODO类型转换及其检查
// TODOsysy库函数处理
// TODO数组处理
// TODO对while、continue、break的测试
#include "LLVMIRGenerator_1.h"
#include <iomanip>
#include <stdexcept>
#include <sstream>
// namespace sysy {
std::string LLVMIRGenerator::generateIR(SysYParser::CompUnitContext* unit) {
// 初始化 SysY IR 模块
module = std::make_unique<sysy::Module>();
// 清空符号表和临时变量表
symbolTable.clear();
tmpTable.clear();
irSymbolTable.clear();
irTmpTable.clear();
tempCounter = 0;
globalVars.clear();
hasReturn = false;
loopStack = std::stack<LoopLabels>();
inFunction = false;
// 访问编译单元
visitCompUnit(unit);
return irStream.str();
}
std::string LLVMIRGenerator::getNextTemp() {
std::string ret = "%." + std::to_string(tempCounter++);
tmpTable[ret] = "void";
return ret;
}
std::string LLVMIRGenerator::getIRTempName() {
return "%" + std::to_string(tempCounter++);
}
std::string LLVMIRGenerator::getLLVMType(const std::string& type) {
if (type == "int") return "i32";
if (type == "float") return "float";
if (type.find("[]") != std::string::npos)
return getLLVMType(type.substr(0, type.size() - 2)) + "*";
return "i32";
}
sysy::Type* LLVMIRGenerator::getIRType(const std::string& type) {
if (type == "int") return sysy::Type::getIntType();
if (type == "float") return sysy::Type::getFloatType();
if (type == "void") return sysy::Type::getVoidType();
if (type.find("[]") != std::string::npos) {
std::string baseType = type.substr(0, type.size() - 2);
return sysy::Type::getPointerType(getIRType(baseType));
}
return sysy::Type::getIntType(); // 默认 int
}
void LLVMIRGenerator::setIRPosition(sysy::BasicBlock* block) {
currentIRBlock = block;
}
std::any LLVMIRGenerator::visitCompUnit(SysYParser::CompUnitContext* ctx) {
for (auto decl : ctx->decl()) {
decl->accept(this);
}
for (auto funcDef : ctx->funcDef()) {
inFunction = true;
funcDef->accept(this);
inFunction = false;
}
return nullptr;
}
std::any LLVMIRGenerator::visitVarDecl(SysYParser::VarDeclContext* ctx) {
// TODO数组初始化
std::string type = ctx->bType()->getText();
currentVarType = getLLVMType(type);
sysy::Type* irType = sysy::Type::getPointerType(getIRType(type));
for (auto varDef : ctx->varDef()) {
if (!inFunction) {
// 全局变量(文本 IR
std::string varName = varDef->Ident()->getText();
std::string llvmType = getLLVMType(type);
std::string value = "0";
sysy::Value* initValue = nullptr;
if (varDef->ASSIGN()) {
value = std::any_cast<std::string>(varDef->initVal()->accept(this));
if (irTmpTable.find(value) != irTmpTable.end() && isa<sysy::ConstantValue>(irTmpTable[value])) {
initValue = irTmpTable[value];
}
}
if (llvmType == "float" && initValue) {
try {
double floatValue = std::stod(value);
uint64_t hexValue = reinterpret_cast<uint64_t&>(floatValue);
std::stringstream ss;
ss << "0x" << std::hex << std::uppercase << hexValue;
value = ss.str();
} catch (...) {
throw std::runtime_error("[ERR-Release-02]Invalid float literal: " + value);
}
}
irStream << "@" << varName << " = dso_local global " << llvmType << " " << value << ", align 4\n";
globalVars.push_back(varName);
// 全局变量SysY IR
auto globalValue = module->createGlobalValue(varName, irType, {}, initValue);
irSymbolTable[varName] = globalValue;
} else {
varDef->accept(this);
}
}
return nullptr;
}
std::any LLVMIRGenerator::visitConstDecl(SysYParser::ConstDeclContext* ctx) {
// TODO数组初始化
std::string type = ctx->bType()->getText();
currentVarType = getLLVMType(type);
sysy::Type* irType = sysy::Type::getPointerType(getIRType(type)); // 全局变量为指针类型
for (auto constDef : ctx->constDef()) {
std::string varName = constDef->Ident()->getText();
std::string llvmType = getLLVMType(type);
std::string value = "0";
sysy::Value* initValue = nullptr;
try {
value = std::any_cast<std::string>(constDef->constInitVal()->accept(this));
if (isa<sysy::ConstantValue>(irTmpTable[value])) {
initValue = irTmpTable[value];
}
} catch (...) {
throw std::runtime_error("Const value must be initialized upon definition.");
}
if (!inFunction) {
// 全局常量(文本 IR
if (llvmType == "float") {
try {
double floatValue = std::stod(value);
uint64_t hexValue = reinterpret_cast<uint64_t&>(floatValue);
std::stringstream ss;
ss << "0x" << std::hex << std::uppercase << hexValue;
value = ss.str();
} catch (...) {
throw std::runtime_error("[ERR-Release-03]Invalid float literal: " + value);
}
}
irStream << "@" << varName << " = dso_local constant " << llvmType << " " << value << ", align 4\n";
globalVars.push_back(varName);
// 全局常量SysY IR
auto globalValue = module->createGlobalValue(varName, irType, {}, initValue);
irSymbolTable[varName] = globalValue;
} else {
// 局部常量(文本 IR
std::string allocaName = getNextTemp();
if (llvmType == "float") {
try {
double floatValue = std::stod(value);
uint64_t hexValue = reinterpret_cast<uint64_t&>(floatValue);
std::stringstream ss;
ss << "0x" << std::hex << std::uppercase << hexValue;
value = ss.str();
} catch (...) {
throw std::runtime_error("Invalid float literal: " + value);
}
}
irStream << " " << allocaName << " = alloca " << llvmType << ", align 4\n";
irStream << " store " << llvmType << " " << value << ", " << llvmType
<< "* " << allocaName << ", align 4\n";
symbolTable[varName] = {allocaName, llvmType};
tmpTable[allocaName] = llvmType;
// 局部常量SysY IRTODO:这里可能有bugAI在犯蠢
sysy::IRBuilder builder(currentIRBlock);
auto allocaInst = builder.createAllocaInst(irType, {}, varName);
builder.createStoreInst(initValue, allocaInst);
irSymbolTable[varName] = allocaInst;
irTmpTable[allocaName] = allocaInst;
}
}
return nullptr;
}
std::any LLVMIRGenerator::visitVarDef(SysYParser::VarDefContext* ctx) {
// TODO数组初始化
std::string varName = ctx->Ident()->getText();
std::string llvmType = currentVarType;
sysy::Type* irType = sysy::Type::getPointerType(getIRType(currentVarType == "i32" ? "int" : "float"));
std::string allocaName = getNextTemp();
// 局部变量(文本 IR
irStream << " " << allocaName << " = alloca " << llvmType << ", align 4\n";
// 局部变量SysY IR
sysy::IRBuilder builder(currentIRBlock);
auto allocaInst = builder.createAllocaInst(irType, {}, varName);
sysy::Value* initValue = nullptr;
if (ctx->ASSIGN()) {
std::string value = std::any_cast<std::string>(ctx->initVal()->accept(this));
if (llvmType == "float") {
try {
double floatValue = std::stod(value);
uint64_t hexValue = reinterpret_cast<uint64_t&>(floatValue);
std::stringstream ss;
ss << "0x" << std::hex << std::uppercase << (hexValue & (0xffffffffUL << 32));
value = ss.str();
} catch (...) {
throw std::runtime_error("Invalid float literal: " + value);
}
}
irStream << " store " << llvmType << " " << value << ", " << llvmType
<< "* " << allocaName << ", align 4\n";
if (irTmpTable.find(value) != irTmpTable.end()) {
initValue = irTmpTable[value];
}
builder.createStoreInst(initValue, allocaInst);
}
symbolTable[varName] = {allocaName, llvmType};
tmpTable[allocaName] = llvmType;
irSymbolTable[varName] = allocaInst;//TODO:这里没看懂在干嘛
irTmpTable[allocaName] = allocaInst;//TODO:这里没看懂在干嘛
builder.createStoreInst(initValue, allocaInst);//TODO:这里没看懂在干嘛
return nullptr;
}
std::any LLVMIRGenerator::visitFuncDef(SysYParser::FuncDefContext* ctx) {
currentFunction = ctx->Ident()->getText();
currentReturnType = getLLVMType(ctx->funcType()->getText());
sysy::Type* irReturnType = getIRType(ctx->funcType()->getText());
std::vector<sysy::Type*> paramTypes;
// 清空符号表
symbolTable.clear();
tmpTable.clear();
irSymbolTable.clear();
irTmpTable.clear();
tempCounter = 0;
hasReturn = false;
// 处理函数参数(文本 IR 和 SysY IR
if (ctx->funcFParams()) {
auto params = ctx->funcFParams()->funcFParam();
for (size_t i = 0; i < params.size(); ++i) {
std::string paramType = getLLVMType(params[i]->bType()->getText());
if (i > 0) irStream << ", ";
irStream << paramType << " noundef %" << i;
symbolTable[params[i]->Ident()->getText()] = {"%" + std::to_string(i), paramType};
tmpTable["%" + std::to_string(i)] = paramType;
paramTypes.push_back(getIRType(params[i]->bType()->getText()));
}
tempCounter += params.size();
}
tempCounter++;
// 文本 IR 函数定义
irStream << "define dso_local " << currentReturnType << " @" << currentFunction << "(";
irStream << ") #0 {\n";
// SysY IR 函数定义
sysy::Type* funcType = sysy::Type::getFunctionType(irReturnType, paramTypes);
currentIRFunction = module->createFunction(currentFunction, funcType);
setIRPosition(currentIRFunction->getEntryBlock());
// 处理函数参数分配
if (ctx->funcFParams()) {
auto params = ctx->funcFParams()->funcFParam();
for (size_t i = 0; i < params.size(); ++i) {
std::string varName = params[i]->Ident()->getText();
std::string llvmType = getLLVMType(params[i]->bType()->getText());
sysy::Type* irType = getIRType(params[i]->bType()->getText());
std::string allocaName = getNextTemp();
tmpTable[allocaName] = llvmType;
// 文本 IR 分配
irStream << " " << allocaName << " = alloca " << llvmType << ", align 4\n";
irStream << " store " << llvmType << " %" << i << ", " << llvmType
<< "* " << allocaName << ", align 4\n";
// SysY IR 分配
sysy::IRBuilder builder(currentIRBlock);
auto arg = currentIRBlock->createArgument(irType, varName);
auto allocaInst = builder.createAllocaInst(sysy::Type::getPointerType(irType), {}, varName);
builder.createStoreInst(arg, allocaInst);
symbolTable[varName] = {allocaName, llvmType};
irSymbolTable[varName] = allocaInst;
irTmpTable[allocaName] = allocaInst;
}
}
ctx->blockStmt()->accept(this);
if (!hasReturn) {
if (currentReturnType == "void") {
irStream << " ret void\n";
sysy::IRBuilder builder(currentIRBlock);
builder.createReturnInst();
} else {
irStream << " ret " << currentReturnType << " 0\n";
sysy::IRBuilder builder(currentIRBlock);
builder.createReturnInst(sysy::ConstantValue::get(0));
}
}
irStream << "}\n";
currentIRFunction = nullptr;
currentIRBlock = nullptr;
return nullptr;
}
std::any LLVMIRGenerator::visitBlockStmt(SysYParser::BlockStmtContext* ctx) {
for (auto item : ctx->blockItem()) {
item->accept(this);
}
return nullptr;
}
std::any LLVMIRGenerator::visitAssignStmt(SysYParser::AssignStmtContext* ctx) {
std::string lhsAlloca = std::any_cast<std::string>(ctx->lValue()->accept(this));
std::string lhsType = symbolTable[ctx->lValue()->Ident()->getText()].second;
std::string rhs = std::any_cast<std::string>(ctx->exp()->accept(this));
sysy::Value* rhsValue = irTmpTable[rhs];
// 文本 IR
if (lhsType == "float") {
try {
double floatValue = std::stod(rhs);
uint64_t hexValue = reinterpret_cast<uint64_t&>(floatValue);
std::stringstream ss;
ss << "0x" << std::hex << std::uppercase << (hexValue & (0xffffffffUL << 32));
rhs = ss.str();
} catch (...) {
// 如果 rhs 不是字面量,假设已正确处理
throw std::runtime_error("Invalid float literal: " + rhs);
}
}
irStream << " store " << lhsType << " " << rhs << ", " << lhsType
<< "* " << lhsAlloca << ", align 4\n";
// SysY IR
sysy::IRBuilder builder(currentIRBlock);
builder.createStoreInst(rhsValue, irSymbolTable[ctx->lValue()->Ident()->getText()]);
return nullptr;
}
std::any LLVMIRGenerator::visitIfStmt(SysYParser::IfStmtContext* ctx) {
std::string cond = std::any_cast<std::string>(ctx->cond()->accept(this));
sysy::Value* condValue = irTmpTable[cond];
std::string trueLabel = "if.then." + std::to_string(tempCounter);
std::string falseLabel = "if.else." + std::to_string(tempCounter);
std::string mergeLabel = "if.end." + std::to_string(tempCounter++);
// SysY IR 基本块
sysy::BasicBlock* thenBlock = currentIRFunction->addBasicBlock(trueLabel);
sysy::BasicBlock* elseBlock = ctx->ELSE() ? currentIRFunction->addBasicBlock(falseLabel) : nullptr;
sysy::BasicBlock* mergeBlock = currentIRFunction->addBasicBlock(mergeLabel);
// 文本 IR
irStream << " br i1 " << cond << ", label %" << trueLabel << ", label %"
<< (ctx->ELSE() ? falseLabel : mergeLabel) << "\n";
// SysY IR 条件分支
sysy::IRBuilder builder(currentIRBlock);
builder.createCondBrInst(condValue, thenBlock, ctx->ELSE() ? elseBlock : mergeBlock, {}, {});
// 处理 then 分支
setIRPosition(thenBlock);
irStream << trueLabel << ":\n";
ctx->stmt(0)->accept(this);
irStream << " br label %" << mergeLabel << "\n";
builder.setPosition(thenBlock, thenBlock->end());
builder.createUncondBrInst(mergeBlock, {});
// 处理 else 分支
if (ctx->ELSE()) {
setIRPosition(elseBlock);
irStream << falseLabel << ":\n";
ctx->stmt(1)->accept(this);
irStream << " br label %" << mergeLabel << "\n";
builder.setPosition(elseBlock, elseBlock->end());
builder.createUncondBrInst(mergeBlock, {});
}
// 合并点
setIRPosition(mergeBlock);
irStream << mergeLabel << ":\n";
return nullptr;
}
std::any LLVMIRGenerator::visitWhileStmt(SysYParser::WhileStmtContext* ctx) {
std::string loopCond = "while.cond." + std::to_string(tempCounter);
std::string loopBody = "while.body." + std::to_string(tempCounter);
std::string loopEnd = "while.end." + std::to_string(tempCounter++);
// SysY IR 基本块
sysy::BasicBlock* condBlock = currentIRFunction->addBasicBlock(loopCond);
sysy::BasicBlock* bodyBlock = currentIRFunction->addBasicBlock(loopBody);
sysy::BasicBlock* endBlock = currentIRFunction->addBasicBlock(loopEnd);
loopStack.push({loopEnd, loopCond, endBlock, condBlock});
// 跳转到条件块
sysy::IRBuilder builder(currentIRBlock);
builder.createUncondBrInst(condBlock, {});
irStream << " br label %" << loopCond << "\n";
// 条件块
setIRPosition(condBlock);
irStream << loopCond << ":\n";
std::string cond = std::any_cast<std::string>(ctx->cond()->accept(this));
sysy::Value* condValue = irTmpTable[cond];
irStream << " br i1 " << cond << ", label %" << loopBody << ", label %" << loopEnd << "\n";
builder.setPosition(condBlock, condBlock->end());
builder.createCondBrInst(condValue, bodyBlock, endBlock, {}, {});
// 循环体
setIRPosition(bodyBlock);
irStream << loopBody << ":\n";
ctx->stmt()->accept(this);
irStream << " br label %" << loopCond << "\n";
builder.setPosition(bodyBlock, bodyBlock->end());
builder.createUncondBrInst(condBlock, {});
// 结束块
setIRPosition(endBlock);
irStream << loopEnd << ":\n";
loopStack.pop();
return nullptr;
}
std::any LLVMIRGenerator::visitBreakStmt(SysYParser::BreakStmtContext* ctx) {
if (loopStack.empty()) {
throw std::runtime_error("Break statement outside of a loop.");
}
irStream << " br label %" << loopStack.top().breakLabel << "\n";
sysy::IRBuilder builder(currentIRBlock);
builder.createUncondBrInst(loopStack.top().irBreakBlock, {});
return nullptr;
}
std::any LLVMIRGenerator::visitContinueStmt(SysYParser::ContinueStmtContext* ctx) {
if (loopStack.empty()) {
throw std::runtime_error("Continue statement outside of a loop.");
}
irStream << " br label %" << loopStack.top().continueLabel << "\n";
sysy::IRBuilder builder(currentIRBlock);
builder.createUncondBrInst(loopStack.top().irContinueBlock, {});
return nullptr;
}
std::any LLVMIRGenerator::visitReturnStmt(SysYParser::ReturnStmtContext* ctx) {
hasReturn = true;
sysy::IRBuilder builder(currentIRBlock);
if (ctx->exp()) {
std::string value = std::any_cast<std::string>(ctx->exp()->accept(this));
sysy::Value* irValue = irTmpTable[value];
irStream << " ret " << currentReturnType << " " << value << "\n";
builder.createReturnInst(irValue);
} else {
irStream << " ret void\n";
builder.createReturnInst();
}
return nullptr;
}
std::any LLVMIRGenerator::visitLValue(SysYParser::LValueContext* ctx) {
std::string varName = ctx->Ident()->getText();
if (irSymbolTable.find(varName) == irSymbolTable.end()) {
throw std::runtime_error("Undefined variable: " + varName);
}
// 对于 LValue返回分配的指针文本 IR 和 SysY IR 一致)
return symbolTable[varName].first;
}
std::any LLVMIRGenerator::visitPrimExp(SysYParser::PrimExpContext* ctx) {
SysYParser::PrimaryExpContext* pExpCtx = ctx->primaryExp();
if (auto* lvalCtx = dynamic_cast<SysYParser::LValContext*>(pExpCtx)) {
std::string allocaPtr = std::any_cast<std::string>(lvalCtx->lValue()->accept(this));
std::string varName = lvalCtx->lValue()->Ident()->getText();
std::string type = symbolTable[varName].second;
std::string temp = getNextTemp();
sysy::Type* irType = getIRType(type == "i32" ? "int" : "float");
// 文本 IR
irStream << " " << temp << " = load " << type << ", " << type << "* " << allocaPtr << ", align 4\n";
tmpTable[temp] = type;
// SysY IR
sysy::IRBuilder builder(currentIRBlock);
auto loadInst = builder.createLoadInst(irSymbolTable[varName], {});
irTmpTable[temp] = loadInst;
return temp;
} else if (auto* expCtx = dynamic_cast<SysYParser::ParenExpContext*>(pExpCtx)) {
return expCtx->exp()->accept(this);
} else if (auto* strCtx = dynamic_cast<SysYParser::StrContext*>(pExpCtx)) {
return strCtx->string()->accept(this);
} else if (auto* numCtx = dynamic_cast<SysYParser::NumContext*>(pExpCtx)) {
return numCtx->number()->accept(this);
} else {
// 没有成功转换,说明 ctx->primaryExp() 不是 NumContext 或其他已知类型
// 可能是其他类型的表达式,或者是一个空的 PrimaryExpContext
std::cout << "Unknown primary expression type." << std::endl;
throw std::runtime_error("Unknown primary expression type.");
}
}
std::any LLVMIRGenerator::visitParenExp(SysYParser::ParenExpContext* ctx) {
return ctx->exp()->accept(this);
}
std::any LLVMIRGenerator::visitNumber(SysYParser::NumberContext* ctx) {
std::string value;
sysy::Value* irValue = nullptr;
if (ctx->ILITERAL()) {
value = ctx->ILITERAL()->getText();
irValue = sysy::ConstantValue::get(std::stoi(value));
} else if (ctx->FLITERAL()) {
value = ctx->FLITERAL()->getText();
irValue = sysy::ConstantValue::get(std::stof(value));
} else {
value = "";
}
std::string temp = getNextTemp();
tmpTable[temp] = ctx->ILITERAL() ? "i32" : "float";
irTmpTable[temp] = irValue;
return value;
}
std::any LLVMIRGenerator::visitString(SysYParser::StringContext* ctx) {
if (ctx->STRING()) {
std::string str = ctx->STRING()->getText();
str = str.substr(1, str.size() - 2);
std::string escapedStr;
for (char c : str) {
if (c == '\\') {
escapedStr += "\\\\";
} else if (c == '"') {
escapedStr += "\\\"";
} else {
escapedStr += c;
}
}
// TODO: SysY IR 暂不支持字符串常量,返回文本 IR 结果
return "\"" + escapedStr + "\"";
}
return ctx->STRING()->getText();
}
std::any LLVMIRGenerator::visitUnExp(SysYParser::UnExpContext* ctx) {
if (ctx->unaryOp()) {
std::string operand = std::any_cast<std::string>(ctx->unaryExp()->accept(this));
sysy::Value* irOperand = irTmpTable[operand];
std::string op = ctx->unaryOp()->getText();
std::string temp = getNextTemp();
std::string type = tmpTable[operand];
sysy::Type* irType = getIRType(type == "i32" ? "int" : "float");
tmpTable[temp] = type;
// 文本 IR
if (op == "-") {
irStream << " " << temp << " = sub " << type << " 0, " << operand << "\n";
} else if (op == "!") {
irStream << " " << temp << " = xor " << type << " " << operand << ", 1\n";
}
// SysY IR
sysy::IRBuilder builder(currentIRBlock);
sysy::Instruction::Kind kind = (op == "-") ? (type == "i32" ? sysy::Instruction::kNeg : sysy::Instruction::kFNeg)
: sysy::Instruction::kNot;
auto unaryInst = builder.createUnaryInst(kind, irType, irOperand, temp);
irTmpTable[temp] = unaryInst;
return temp;
}
return ctx->unaryExp()->accept(this);
}
std::any LLVMIRGenerator::visitCall(SysYParser::CallContext* ctx) {
std::string funcName = ctx->Ident()->getText();
std::vector<std::string> args;
std::vector<sysy::Value*> irArgs;
if (ctx->funcRParams()) {
for (auto argCtx : ctx->funcRParams()->exp()) {
std::string arg = std::any_cast<std::string>(argCtx->accept(this));
args.push_back(arg);
irArgs.push_back(irTmpTable[arg]);
}
}
std::string temp = getNextTemp();
std::string argList;
for (size_t i = 0; i < args.size(); ++i) {
if (i > 0) argList += ", ";
argList += tmpTable[args[i]] + " noundef " + args[i];
}
// 文本 IR
irStream << " " << temp << " = call " << currentReturnType << " @" << funcName << "(" << argList << ")\n";
tmpTable[temp] = currentReturnType;
// SysY IR
sysy::IRBuilder builder(currentIRBlock);
sysy::Function* callee = module->getFunction(funcName);
if (!callee) {
throw std::runtime_error("Undefined function: " + funcName);
}
auto callInst = builder.createCallInst(callee, irArgs, temp);
irTmpTable[temp] = callInst;
return temp;
}
std::any LLVMIRGenerator::visitMulExp(SysYParser::MulExpContext* ctx) {
auto unaryExps = ctx->unaryExp();
std::string left = std::any_cast<std::string>(unaryExps[0]->accept(this));
sysy::Value* irLeft = irTmpTable[left];
sysy::Type* irType = irLeft->getType();
for (size_t i = 1; i < unaryExps.size(); ++i) {
std::string right = std::any_cast<std::string>(unaryExps[i]->accept(this));
sysy::Value* irRight = irTmpTable[right];
std::string op = ctx->children[2 * i - 1]->getText();
std::string temp = getNextTemp();
std::string type = tmpTable[left];
tmpTable[temp] = type;
// 文本 IR
if (op == "*") {
irStream << " " << temp << " = mul nsw " << type << " " << left << ", " << right << "\n";
} else if (op == "/") {
irStream << " " << temp << " = sdiv " << type << " " << left << ", " << right << "\n";
} else if (op == "%") {
irStream << " " << temp << " = srem " << type << " " << left << ", " << right << "\n";
}
// SysY IR
sysy::IRBuilder builder(currentIRBlock);
sysy::Instruction::Kind kind;
if (type == "i32") {
if (op == "*") kind = sysy::Instruction::kMul;
else if (op == "/") kind = sysy::Instruction::kDiv;
else kind = sysy::Instruction::kRem;
} else {
if (op == "*") kind = sysy::Instruction::kFMul;
else if (op == "/") kind = sysy::Instruction::kFDiv;
else kind = sysy::Instruction::kFRem;
}
auto binaryInst = builder.createBinaryInst(kind, irType, irLeft, irRight, temp);
irTmpTable[temp] = binaryInst;
left = temp;
irLeft = binaryInst;
}
return left;
}
std::any LLVMIRGenerator::visitAddExp(SysYParser::AddExpContext* ctx) {
auto mulExps = ctx->mulExp();
std::string left = std::any_cast<std::string>(mulExps[0]->accept(this));
sysy::Value* irLeft = irTmpTable[left];
sysy::Type* irType = irLeft->getType();
for (size_t i = 1; i < mulExps.size(); ++i) {
std::string right = std::any_cast<std::string>(mulExps[i]->accept(this));
sysy::Value* irRight = irTmpTable[right];
std::string op = ctx->children[2 * i - 1]->getText();
std::string temp = getNextTemp();
std::string type = tmpTable[left];
tmpTable[temp] = type;
// 文本 IR
if (op == "+") {
irStream << " " << temp << " = add nsw " << type << " " << left << ", " << right << "\n";
} else if (op == "-") {
irStream << " " << temp << " = sub nsw " << type << " " << left << ", " << right << "\n";
}
// SysY IR
sysy::IRBuilder builder(currentIRBlock);
sysy::Instruction::Kind kind = (type == "i32") ? (op == "+" ? sysy::Instruction::kAdd : sysy::Instruction::kSub)
: (op == "+" ? sysy::Instruction::kFAdd : sysy::Instruction::kFSub);
auto binaryInst = builder.createBinaryInst(kind, irType, irLeft, irRight, temp);
irTmpTable[temp] = binaryInst;
left = temp;
irLeft = binaryInst;
}
return left;
}
std::any LLVMIRGenerator::visitRelExp(SysYParser::RelExpContext* ctx) {
auto addExps = ctx->addExp();
std::string left = std::any_cast<std::string>(addExps[0]->accept(this));
sysy::Value* irLeft = irTmpTable[left];
sysy::Type* irType = sysy::Type::getIntType(); // 比较结果为 i1
for (size_t i = 1; i < addExps.size(); ++i) {
std::string right = std::any_cast<std::string>(addExps[i]->accept(this));
sysy::Value* irRight = irTmpTable[right];
std::string op = ctx->children[2 * i - 1]->getText();
std::string temp = getNextTemp();
std::string type = tmpTable[left];
tmpTable[temp] = "i1";
// 文本 IR
if (op == "<") {
irStream << " " << temp << " = icmp slt " << type << " " << left << ", " << right << "\n";
} else if (op == ">") {
irStream << " " << temp << " = icmp sgt " << type << " " << left << ", " << right << "\n";
} else if (op == "<=") {
irStream << " " << temp << " = icmp sle " << type << " " << left << ", " << right << "\n";
} else if (op == ">=") {
irStream << " " << temp << " = icmp sge " << type << " " << left << ", " << right << "\n";
}
// SysY IR
sysy::IRBuilder builder(currentIRBlock);
sysy::Instruction::Kind kind;
if (type == "i32") {
if (op == "<") kind = sysy::Instruction::kICmpLT;
else if (op == ">") kind = sysy::Instruction::kICmpGT;
else if (op == "<=") kind = sysy::Instruction::kICmpLE;
else kind = sysy::Instruction::kICmpGE;
} else {
if (op == "<") kind = sysy::Instruction::kFCmpLT;
else if (op == ">") kind = sysy::Instruction::kFCmpGT;
else if (op == "<=") kind = sysy::Instruction::kFCmpLE;
else kind = sysy::Instruction::kFCmpGE;
}
auto cmpInst = builder.createBinaryInst(kind, irType, irLeft, irRight, temp);
irTmpTable[temp] = cmpInst;
left = temp;
irLeft = cmpInst;
}
return left;
}
std::any LLVMIRGenerator::visitEqExp(SysYParser::EqExpContext* ctx) {
auto relExps = ctx->relExp();
std::string left = std::any_cast<std::string>(relExps[0]->accept(this));
sysy::Value* irLeft = irTmpTable[left];
sysy::Type* irType = sysy::Type::getIntType(); // 比较结果为 i1
for (size_t i = 1; i < relExps.size(); ++i) {
std::string right = std::any_cast<std::string>(relExps[i]->accept(this));
sysy::Value* irRight = irTmpTable[right];
std::string op = ctx->children[2 * i - 1]->getText();
std::string temp = getNextTemp();
std::string type = tmpTable[left];
tmpTable[temp] = "i1";
// 文本 IR
if (op == "==") {
irStream << " " << temp << " = icmp eq " << type << " " << left << ", " << right << "\n";
} else if (op == "!=") {
irStream << " " << temp << " = icmp ne " << type << " " << left << ", " << right << "\n";
}
// SysY IR
sysy::IRBuilder builder(currentIRBlock);
sysy::Instruction::Kind kind = (type == "i32") ? (op == "==" ? sysy::Instruction::kICmpEQ : sysy::Instruction::kICmpNE)
: (op == "==" ? sysy::Instruction::kFCmpEQ : sysy::Instruction::kFCmpNE);
auto cmpInst = builder.createBinaryInst(kind, irType, irLeft, irRight, temp);
irTmpTable[temp] = cmpInst;
left = temp;
irLeft = cmpInst;
}
return left;
}
std::any LLVMIRGenerator::visitLAndExp(SysYParser::LAndExpContext* ctx) {
auto eqExps = ctx->eqExp();
std::string left = std::any_cast<std::string>(eqExps[0]->accept(this));
sysy::Value* irLeft = irTmpTable[left];
for (size_t i = 1; i < eqExps.size(); ++i) {
std::string falseLabel = "land.false." + std::to_string(tempCounter);
std::string endLabel = "land.end." + std::to_string(tempCounter++);
sysy::BasicBlock* falseBlock = currentIRFunction->addBasicBlock(falseLabel);
sysy::BasicBlock* endBlock = currentIRFunction->addBasicBlock(endLabel);
std::string temp = getNextTemp();
tmpTable[temp] = "i1";
// 文本 IR
irStream << " br i1 " << left << ", label %" << falseLabel << ", label %" << endLabel << "\n";
irStream << falseLabel << ":\n";
// SysY IR
sysy::IRBuilder builder(currentIRBlock);
builder.createCondBrInst(irLeft, falseBlock, endBlock, {}, {});
setIRPosition(falseBlock);
std::string right = std::any_cast<std::string>(eqExps[i]->accept(this));
sysy::Value* irRight = irTmpTable[right];
irStream << " " << temp << " = and i1 " << left << ", " << right << "\n";
irStream << " br label %" << endLabel << "\n";
irStream << endLabel << ":\n";
// SysY IR 逻辑与(通过基本块实现短路求值)
builder.setPosition(falseBlock, falseBlock->end());
auto andInst = builder.createBinaryInst(sysy::Instruction::kICmpEQ, sysy::Type::getIntType(), irLeft, irRight, temp);
builder.createUncondBrInst(endBlock, {});
irTmpTable[temp] = andInst;
left = temp;
irLeft = andInst;
setIRPosition(endBlock);
}
return left;
}
std::any LLVMIRGenerator::visitLOrExp(SysYParser::LOrExpContext* ctx) {
auto lAndExps = ctx->lAndExp();
std::string left = std::any_cast<std::string>(lAndExps[0]->accept(this));
sysy::Value* irLeft = irTmpTable[left];
for (size_t i = 1; i < lAndExps.size(); ++i) {
std::string trueLabel = "lor.true." + std::to_string(tempCounter);
std::string endLabel = "lor.end." + std::to_string(tempCounter++);
sysy::BasicBlock* trueBlock = currentIRFunction->addBasicBlock(trueLabel);
sysy::BasicBlock* endBlock = currentIRFunction->addBasicBlock(endLabel);
std::string temp = getNextTemp();
tmpTable[temp] = "i1";
// 文本 IR
irStream << " br i1 " << left << ", label %" << trueLabel << ", label %" << endLabel << "\n";
irStream << trueLabel << ":\n";
// SysY IR
sysy::IRBuilder builder(currentIRBlock);
builder.createCondBrInst(irLeft, trueBlock, endBlock, {}, {});
setIRPosition(trueBlock);
std::string right = std::any_cast<std::string>(lAndExps[i]->accept(this));
sysy::Value* irRight = irTmpTable[right];
irStream << " " << temp << " = or i1 " << left << ", " << right << "\n";
irStream << " br label %" << endLabel << "\n";
irStream << endLabel << ":\n";
// SysY IR 逻辑或(通过基本块实现短路求值)
builder.setPosition(trueBlock, trueBlock->end());
auto orInst = builder.createBinaryInst(sysy::Instruction::kICmpEQ, sysy::Type::getIntType(), irLeft, irRight, temp);
builder.createUncondBrInst(endBlock, {});
irTmpTable[temp] = orInst;
left = temp;
irLeft = orInst;
setIRPosition(endBlock);
}
return left;
}
// } // namespace sysy

File diff suppressed because it is too large Load Diff

View File

@@ -6,60 +6,93 @@
#include <vector> #include <vector>
#include <map> #include <map>
#include <set> #include <set>
#include <memory>
#include <iostream>
#include <functional> // For std::function
namespace sysy { namespace sysy {
class RISCv32CodeGen { class RISCv32CodeGen {
public: public:
explicit RISCv32CodeGen(Module* mod) : module(mod) {}
std::string code_gen(); // 生成模块的汇编代码
private:
Module* module;
// 物理寄存器
enum class PhysicalReg { enum class PhysicalReg {
T0, T1, T2, T3, T4, T5, T6, // x5-x7, x28-x31 ZERO, RA, SP, GP, TP, T0, T1, T2, S0, S1, A0, A1, A2, A3, A4, A5, A6, A7, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, T3, T4, T5, T6,
A0, A1, A2, A3, A4, A5, A6, A7 // x10-x17 F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15,F16, F17, F18, F19, F20, F21, F22, F23, F24, F25, F26, F27, F28, F29, F30, F31
};
static const std::vector<PhysicalReg> allocable_regs;
// 操作数
struct Operand {
enum class Kind { Reg, Imm, Label };
Kind kind;
Value* value; // 用于寄存器
std::string label; // 用于标签或立即数
Operand(Kind k, Value* v) : kind(k), value(v), label("") {}
Operand(Kind k, const std::string& l) : kind(k), value(nullptr), label(l) {}
}; };
// RISC-V 指令 // Move DAGNode and RegAllocResult to public section
struct RISCv32Inst { struct DAGNode {
std::string opcode; enum NodeKind { CONSTANT, LOAD, STORE, BINARY, CALL, RETURN, BRANCH, ALLOCA_ADDR, UNARY };
std::vector<Operand> operands; NodeKind kind;
RISCv32Inst(const std::string& op, const std::vector<Operand>& ops) Value* value = nullptr; // For IR Value
: opcode(op), operands(ops) {} std::string inst; // Generated RISC-V instruction(s) for this node
std::string result_vreg; // Virtual register assigned to this node's result
std::vector<DAGNode*> operands;
std::vector<DAGNode*> users; // For debugging and potentially optimizations
DAGNode(NodeKind k) : kind(k) {}
// Debugging / helper
std::string getNodeKindString() const {
switch (kind) {
case CONSTANT: return "CONSTANT";
case LOAD: return "LOAD";
case STORE: return "STORE";
case BINARY: return "BINARY";
case CALL: return "CALL";
case RETURN: return "RETURN";
case BRANCH: return "BRANCH";
case ALLOCA_ADDR: return "ALLOCA_ADDR";
case UNARY: return "UNARY";
default: return "UNKNOWN";
}
}
}; };
// 寄存器分配结果
struct RegAllocResult { struct RegAllocResult {
std::map<Value*, PhysicalReg> reg_map; // 虚拟寄存器到物理寄存器的映射 std::map<std::string, PhysicalReg> vreg_to_preg; // Virtual register to Physical Register mapping
std::map<Value*, int> stack_map; // 虚拟寄存器到堆栈槽的映射 std::map<Value*, int> stack_map; // Value (AllocaInst) to stack offset
int stack_size; // 堆栈帧大小 int stack_size = 0; // Total stack frame size for locals and spills
}; };
// 后端方法 RISCv32CodeGen(Module* mod) : module(mod) {}
std::string code_gen();
std::string module_gen(); std::string module_gen();
std::string function_gen(Function* func); std::string function_gen(Function* func);
std::string basicBlock_gen(BasicBlock* bb, const RegAllocResult& alloc); // 修改 basicBlock_gen 的声明,添加 int block_idx 参数
std::vector<RISCv32Inst> instruction_gen(Instruction* inst); std::string basicBlock_gen(BasicBlock* bb, const RegAllocResult& alloc, int block_idx);
// DAG related
std::vector<std::unique_ptr<DAGNode>> build_dag(BasicBlock* bb);
void select_instructions(DAGNode* node, const RegAllocResult& alloc);
// 改变 emit_instructions 的参数,使其可以直接添加汇编指令到 main ss
void emit_instructions(DAGNode* node, std::stringstream& ss, const RegAllocResult& alloc, std::set<DAGNode*>& emitted_nodes);
// Register Allocation related
std::map<Instruction*, std::set<std::string>> liveness_analysis(Function* func);
std::map<std::string, std::set<std::string>> build_interference_graph(
const std::map<Instruction*, std::set<std::string>>& live_sets);
void color_graph(std::map<std::string, PhysicalReg>& vreg_to_preg,
const std::map<std::string, std::set<std::string>>& interference_graph);
RegAllocResult register_allocation(Function* func); RegAllocResult register_allocation(Function* func);
void eliminate_phi(Function* func); void eliminate_phi(Function* func); // Phi elimination is typically done before DAG building
std::map<Instruction*, std::set<Value*>> liveness_analysis(Function* func);
std::map<Value*, std::set<Value*>> build_interference_graph( // Utility
const std::map<Instruction*, std::set<Value*>>& live_sets);
std::string reg_to_string(PhysicalReg reg); std::string reg_to_string(PhysicalReg reg);
void print_dag(const std::vector<std::unique_ptr<DAGNode>>& dag, const std::string& bb_name);
private:
static const std::vector<PhysicalReg> allocable_regs;
std::map<Value*, std::string> value_vreg_map; // Maps IR Value* to its virtual register name
Module* module;
int vreg_counter = 0; // Counter for unique virtual register names
int alloca_offset_counter = 0; // Counter for alloca offsets
// 新增一个成员变量来存储当前函数的所有 DAGNode以确保其生命周期贯穿整个函数代码生成
// 这样可以在多个 BasicBlock_gen 调用中访问到完整的 DAG 节点
std::vector<std::unique_ptr<DAGNode>> current_function_dag_nodes;
// 为空标签定义一个伪名称前缀,加上块索引以确保唯一性
const std::string ENTRY_BLOCK_PSEUDO_NAME = "entry_block_";
}; };
} // namespace sysy } // namespace sysy

1383
src/RISCv64Backend.cpp Normal file

File diff suppressed because it is too large Load Diff

122
src/RISCv64Backend.h Normal file
View File

@@ -0,0 +1,122 @@
#ifndef RISCV64_BACKEND_H
#define RISCV64_BACKEND_H
#include "IR.h"
#include <string>
#include <vector>
#include <map>
#include <set>
#include <memory>
#include <iostream>
#include <functional> // For std::function
extern int DEBUG;
extern int DEEPDEBUG;
namespace sysy {
class RISCv64CodeGen {
public:
enum class PhysicalReg {
ZERO, RA, SP, GP, TP, T0, T1, T2, S0, S1, A0, A1, A2, A3, A4, A5, A6, A7, S2, S3, S4, S5, S6, S7, S8, S9, S10, S11, T3, T4, T5, T6,
F0, F1, F2, F3, F4, F5, F6, F7, F8, F9, F10, F11, F12, F13, F14, F15,F16, F17, F18, F19, F20, F21, F22, F23, F24, F25, F26, F27, F28, F29, F30, F31
};
// Move DAGNode and RegAllocResult to public section
struct DAGNode {
enum NodeKind { CONSTANT, LOAD, STORE, BINARY, CALL, RETURN, BRANCH, ALLOCA_ADDR, UNARY };
NodeKind kind;
Value* value = nullptr; // For IR Value
std::string inst; // Generated RISC-V instruction(s) for this node
std::string result_vreg; // Virtual register assigned to this node's result
std::vector<DAGNode*> operands;
std::vector<DAGNode*> users; // For debugging and potentially optimizations
DAGNode(NodeKind k) : kind(k) {}
// Debugging / helper
std::string getNodeKindString() const {
switch (kind) {
case CONSTANT: return "CONSTANT";
case LOAD: return "LOAD";
case STORE: return "STORE";
case BINARY: return "BINARY";
case CALL: return "CALL";
case RETURN: return "RETURN";
case BRANCH: return "BRANCH";
case ALLOCA_ADDR: return "ALLOCA_ADDR";
case UNARY: return "UNARY";
default: return "UNKNOWN";
}
}
};
struct RegAllocResult {
std::map<std::string, PhysicalReg> vreg_to_preg; // Virtual register to Physical Register mapping
std::map<Value*, int> stack_map; // Value (AllocaInst) to stack offset
int stack_size = 0; // Total stack frame size for locals and spills
};
RISCv64CodeGen(Module* mod) : module(mod) {}
std::string code_gen();
std::string module_gen();
std::string function_gen(Function* func);
// 修改 basicBlock_gen 的声明,添加 int block_idx 参数
std::string basicBlock_gen(BasicBlock* bb, const RegAllocResult& alloc, int block_idx);
// DAG related
std::vector<std::unique_ptr<DAGNode>> build_dag(BasicBlock* bb);
void select_instructions(DAGNode* node, const RegAllocResult& alloc);
// 改变 emit_instructions 的参数,使其可以直接添加汇编指令到 main ss
void emit_instructions(DAGNode* node, std::stringstream& ss, const RegAllocResult& alloc, std::set<DAGNode*>& emitted_nodes);
// Register Allocation related
std::map<Instruction*, std::set<std::string>> liveness_analysis(Function* func);
std::map<std::string, std::set<std::string>> build_interference_graph(
const std::map<Instruction*, std::set<std::string>>& live_sets);
void color_graph(std::map<std::string, PhysicalReg>& vreg_to_preg,
const std::map<std::string, std::set<std::string>>& interference_graph);
RegAllocResult register_allocation(Function* func);
void eliminate_phi(Function* func); // Phi elimination is typically done before DAG building
// Utility
std::string reg_to_string(PhysicalReg reg);
void print_dag(const std::vector<std::unique_ptr<DAGNode>>& dag, const std::string& bb_name);
private:
static const std::vector<PhysicalReg> allocable_regs;
std::map<Value*, std::string> value_vreg_map; // Maps IR Value* to its virtual register name
Module* module;
int vreg_counter = 0; // Counter for unique virtual register names
int alloca_offset_counter = 0; // Counter for alloca offsets
// 新增一个成员变量来存储当前函数的所有 DAGNode以确保其生命周期贯穿整个函数代码生成
// 这样可以在多个 BasicBlock_gen 调用中访问到完整的 DAG 节点
std::vector<std::unique_ptr<DAGNode>> current_function_dag_nodes;
// 为空标签定义一个伪名称前缀,加上块索引以确保唯一性
const std::string ENTRY_BLOCK_PSEUDO_NAME = "entry_block_";
// !!! 修改get_operand_node 辅助函数现在需要传入 value_to_node 和 nodes_storage 的引用
// 因为它们是 build_dag 局部管理的
DAGNode* get_operand_node(
Value* val_ir,
std::map<Value*, DAGNode*>& value_to_node,
std::vector<std::unique_ptr<DAGNode>>& nodes_storage
);
// !!! 新增create_node 辅助函数也需要传入 value_to_node 和 nodes_storage 的引用
// 并且它应该不再是 lambda而是一个真正的成员函数
DAGNode* create_node(
DAGNode::NodeKind kind,
Value* val,
std::map<Value*, DAGNode*>& value_to_node,
std::vector<std::unique_ptr<DAGNode>>& nodes_storage
);
std::vector<std::unique_ptr<Instruction>> temp_instructions_storage; // 用于存储 build_dag 中创建的临时 BinaryInst
};
} // namespace sysy
#endif // RISCV64_BACKEND_H

View File

@@ -204,6 +204,7 @@ std::any SysYIRGenerator::visitFuncType(SysYParser::FuncTypeContext *ctx) {
std::any SysYIRGenerator::visitFuncDef(SysYParser::FuncDefContext *ctx){ std::any SysYIRGenerator::visitFuncDef(SysYParser::FuncDefContext *ctx){
// 更新作用域 // 更新作用域
module->enterNewScope(); module->enterNewScope();
HasReturnInst = false;
auto name = ctx->Ident()->getText(); auto name = ctx->Ident()->getText();
std::vector<Type *> paramTypes; std::vector<Type *> paramTypes;
@@ -243,6 +244,18 @@ std::any SysYIRGenerator::visitFuncDef(SysYParser::FuncDefContext *ctx){
visitBlockItem(item); visitBlockItem(item);
} }
if(HasReturnInst == false) {
// 如果没有return语句则默认返回0
if (returnType != Type::getVoidType()) {
Value* returnValue = ConstantValue::get(0);
if (returnType == Type::getFloatType()) {
returnValue = ConstantValue::get(0.0f);
}
builder.createReturnInst(returnValue);
} else {
builder.createReturnInst();
}
}
module->leaveScope(); module->leaveScope();
return std::any(); return std::any();
@@ -310,7 +323,7 @@ std::any SysYIRGenerator::visitIfStmt(SysYParser::IfStmtContext *ctx) {
builder.popTrueBlock(); builder.popTrueBlock();
builder.popFalseBlock(); builder.popFalseBlock();
labelstring << "then.L" << builder.getLabelIndex(); labelstring << "if_then.L" << builder.getLabelIndex();
thenBlock->setName(labelstring.str()); thenBlock->setName(labelstring.str());
labelstring.str(""); labelstring.str("");
function->addBasicBlock(thenBlock); function->addBasicBlock(thenBlock);
@@ -329,7 +342,7 @@ std::any SysYIRGenerator::visitIfStmt(SysYParser::IfStmtContext *ctx) {
builder.createUncondBrInst(exitBlock, {}); builder.createUncondBrInst(exitBlock, {});
BasicBlock::conectBlocks(builder.getBasicBlock(), exitBlock); BasicBlock::conectBlocks(builder.getBasicBlock(), exitBlock);
labelstring << "else.L" << builder.getLabelIndex(); labelstring << "if_else.L" << builder.getLabelIndex();
elseBlock->setName(labelstring.str()); elseBlock->setName(labelstring.str());
labelstring.str(""); labelstring.str("");
function->addBasicBlock(elseBlock); function->addBasicBlock(elseBlock);
@@ -343,9 +356,10 @@ std::any SysYIRGenerator::visitIfStmt(SysYParser::IfStmtContext *ctx) {
ctx->stmt(1)->accept(this); ctx->stmt(1)->accept(this);
module->leaveScope(); module->leaveScope();
} }
builder.createUncondBrInst(exitBlock, {});
BasicBlock::conectBlocks(builder.getBasicBlock(), exitBlock); BasicBlock::conectBlocks(builder.getBasicBlock(), exitBlock);
labelstring << "exit.L" << builder.getLabelIndex(); labelstring << "if_exit.L" << builder.getLabelIndex();
exitBlock->setName(labelstring.str()); exitBlock->setName(labelstring.str());
labelstring.str(""); labelstring.str("");
function->addBasicBlock(exitBlock); function->addBasicBlock(exitBlock);
@@ -358,7 +372,7 @@ std::any SysYIRGenerator::visitIfStmt(SysYParser::IfStmtContext *ctx) {
builder.popTrueBlock(); builder.popTrueBlock();
builder.popFalseBlock(); builder.popFalseBlock();
labelstring << "then.L" << builder.getLabelIndex(); labelstring << "if_then.L" << builder.getLabelIndex();
thenBlock->setName(labelstring.str()); thenBlock->setName(labelstring.str());
labelstring.str(""); labelstring.str("");
function->addBasicBlock(thenBlock); function->addBasicBlock(thenBlock);
@@ -374,7 +388,7 @@ std::any SysYIRGenerator::visitIfStmt(SysYParser::IfStmtContext *ctx) {
} }
BasicBlock::conectBlocks(builder.getBasicBlock(), exitBlock); BasicBlock::conectBlocks(builder.getBasicBlock(), exitBlock);
labelstring << "exit.L" << builder.getLabelIndex(); labelstring << "if_exit.L" << builder.getLabelIndex();
exitBlock->setName(labelstring.str()); exitBlock->setName(labelstring.str());
labelstring.str(""); labelstring.str("");
function->addBasicBlock(exitBlock); function->addBasicBlock(exitBlock);
@@ -390,7 +404,7 @@ std::any SysYIRGenerator::visitWhileStmt(SysYParser::WhileStmtContext *ctx) {
Function* function = builder.getBasicBlock()->getParent(); Function* function = builder.getBasicBlock()->getParent();
std::stringstream labelstring; std::stringstream labelstring;
labelstring << "head.L" << builder.getLabelIndex(); labelstring << "while_head.L" << builder.getLabelIndex();
BasicBlock *headBlock = function->addBasicBlock(labelstring.str()); BasicBlock *headBlock = function->addBasicBlock(labelstring.str());
labelstring.str(""); labelstring.str("");
BasicBlock::conectBlocks(curBlock, headBlock); BasicBlock::conectBlocks(curBlock, headBlock);
@@ -406,7 +420,7 @@ std::any SysYIRGenerator::visitWhileStmt(SysYParser::WhileStmtContext *ctx) {
builder.popTrueBlock(); builder.popTrueBlock();
builder.popFalseBlock(); builder.popFalseBlock();
labelstring << "body.L" << builder.getLabelIndex(); labelstring << "while_body.L" << builder.getLabelIndex();
bodyBlock->setName(labelstring.str()); bodyBlock->setName(labelstring.str());
labelstring.str(""); labelstring.str("");
function->addBasicBlock(bodyBlock); function->addBasicBlock(bodyBlock);
@@ -430,7 +444,7 @@ std::any SysYIRGenerator::visitWhileStmt(SysYParser::WhileStmtContext *ctx) {
builder.popBreakBlock(); builder.popBreakBlock();
builder.popContinueBlock(); builder.popContinueBlock();
labelstring << "exit.L" << builder.getLabelIndex(); labelstring << "while_exit.L" << builder.getLabelIndex();
exitBlock->setName(labelstring.str()); exitBlock->setName(labelstring.str());
labelstring.str(""); labelstring.str("");
function->addBasicBlock(exitBlock); function->addBasicBlock(exitBlock);
@@ -441,7 +455,7 @@ std::any SysYIRGenerator::visitWhileStmt(SysYParser::WhileStmtContext *ctx) {
std::any SysYIRGenerator::visitBreakStmt(SysYParser::BreakStmtContext *ctx) { std::any SysYIRGenerator::visitBreakStmt(SysYParser::BreakStmtContext *ctx) {
BasicBlock* breakBlock = builder.getBreakBlock(); BasicBlock* breakBlock = builder.getBreakBlock();
builder.pushBreakBlock(breakBlock); builder.createUncondBrInst(breakBlock, {});
BasicBlock::conectBlocks(builder.getBasicBlock(), breakBlock); BasicBlock::conectBlocks(builder.getBasicBlock(), breakBlock);
return std::any(); return std::any();
} }
@@ -449,6 +463,7 @@ std::any SysYIRGenerator::visitBreakStmt(SysYParser::BreakStmtContext *ctx) {
std::any SysYIRGenerator::visitContinueStmt(SysYParser::ContinueStmtContext *ctx) { std::any SysYIRGenerator::visitContinueStmt(SysYParser::ContinueStmtContext *ctx) {
BasicBlock* continueBlock = builder.getContinueBlock(); BasicBlock* continueBlock = builder.getContinueBlock();
builder.createUncondBrInst(continueBlock, {}); builder.createUncondBrInst(continueBlock, {});
BasicBlock::conectBlocks(builder.getBasicBlock(), continueBlock);
return std::any(); return std::any();
} }
@@ -476,6 +491,7 @@ std::any SysYIRGenerator::visitReturnStmt(SysYParser::ReturnStmtContext *ctx) {
} }
} }
builder.createReturnInst(returnValue); builder.createReturnInst(returnValue);
HasReturnInst = true;
return std::any(); return std::any();
} }

View File

@@ -4,6 +4,7 @@
#include <map> #include <map>
#include <memory> #include <memory>
#include <string> #include <string>
#include <iostream>
#include "IR.h" #include "IR.h"
#include "IRBuilder.h" #include "IRBuilder.h"
@@ -458,11 +459,13 @@ void SysYOptPre::SysYAddReturn() {
// 如果基本块没有后继块,则添加一个返回指令 // 如果基本块没有后继块,则添加一个返回指令
if (block->getNumInstructions() == 0) { if (block->getNumInstructions() == 0) {
pBuilder->setPosition(block.get(), block->end()); pBuilder->setPosition(block.get(), block->end());
pBuilder->createReturnInst({}); pBuilder->createReturnInst();
} }
auto thelastinst = block->getInstructions().end(); auto thelastinst = block->getInstructions().end();
--thelastinst; --thelastinst;
if (thelastinst->get()->getKind() != Instruction::kReturn) { if (thelastinst->get()->getKind() != Instruction::kReturn) {
// std::cout << "Warning: Function " << func->getName() << " has no return instruction, adding default return." << std::endl;
pBuilder->setPosition(block.get(), block->end()); pBuilder->setPosition(block.get(), block->end());
// TODO: 如果int float函数缺少返回值是否需要报错 // TODO: 如果int float函数缺少返回值是否需要报错
if (func->getReturnType()->isInt()) { if (func->getReturnType()->isInt()) {
@@ -470,7 +473,7 @@ void SysYOptPre::SysYAddReturn() {
} else if (func->getReturnType()->isFloat()) { } else if (func->getReturnType()->isFloat()) {
pBuilder->createReturnInst(ConstantValue::get(0.0F)); pBuilder->createReturnInst(ConstantValue::get(0.0F));
} else { } else {
pBuilder->createReturnInst({}); pBuilder->createReturnInst();
} }
} }
} }

View File

@@ -30,9 +30,9 @@ void SysYPrinter::printIR() {
} }
std::string SysYPrinter::getTypeString(Type *type) { std::string SysYPrinter::getTypeString(Type *type) {
if (type->isVoid()) { if (type->isVoid()) {
return "void"; return "void";
} else if (type->isInt()) { } else if (type->isInt()) {
return "i32"; return "i32";
} else if (type->isFloat()) { } else if (type->isFloat()) {
return "float"; return "float";
@@ -251,7 +251,7 @@ void SysYPrinter::printInst(Instruction *pInst) {
switch (pInst->getKind()) { switch (pInst->getKind()) {
case Kind::kNeg: std::cout << "sub "; break; case Kind::kNeg: std::cout << "sub "; break;
case Kind::kNot: std::cout << "xor "; break; case Kind::kNot: std::cout << "not "; break;
case Kind::kFNeg: std::cout << "fneg "; break; case Kind::kFNeg: std::cout << "fneg "; break;
case Kind::kFNot: std::cout << "fneg "; break; // FNot not standard, map to fneg case Kind::kFNot: std::cout << "fneg "; break; // FNot not standard, map to fneg
case Kind::kFtoI: std::cout << "fptosi "; break; case Kind::kFtoI: std::cout << "fptosi "; break;

View File

@@ -2,6 +2,8 @@
#include "IR.h" #include "IR.h"
#include "SysYIRAnalyser.h" #include "SysYIRAnalyser.h"
#include "SysYIRPrinter.h"
namespace sysy { namespace sysy {
class DeadCodeElimination { class DeadCodeElimination {

View File

@@ -883,6 +883,10 @@ public:
assert(false); assert(false);
} }
} ///< 根据指令类型进行二元计算eval template模板实现 } ///< 根据指令类型进行二元计算eval template模板实现
static BinaryInst* create(Kind kind, Type *type, Value *lhs, Value *rhs, BasicBlock *parent, const std::string &name = "") {
// 后端处理数组访存操作时需要创建计算地址的指令,需要在外部构造 BinaryInst 对象所以写了个public的方法。
return new BinaryInst(kind, type, lhs, rhs, parent, name);
}
}; // class BinaryInst }; // class BinaryInst
//! The return statement //! The return statement

View File

@@ -1,78 +0,0 @@
#pragma once
#include "SysYBaseVisitor.h"
#include "SysYParser.h"
#include "IR.h"
#include "IRBuilder.h"
#include <sstream>
#include <map>
#include <vector>
#include <stack>
class LLVMIRGenerator : public SysYBaseVisitor {
public:
sysy::Module* getIRModule() const { return irModule.get(); }
std::string generateIR(SysYParser::CompUnitContext* unit);
std::string getIR() const { return irStream.str(); }
private:
std::unique_ptr<sysy::Module> irModule; // IR数据结构
std::stringstream irStream; // 文本输出流
sysy::IRBuilder irBuilder; // IR构建器
int tempCounter = 0;
std::string currentVarType;
// std::map<std::string, sysy::Value*> symbolTable;
std::map<std::string, std::pair<std::string, std::string>> symbolTable;
std::map<std::string, std::string> tmpTable;
std::vector<std::string> globalVars;
std::string currentFunction;
std::string currentReturnType;
std::vector<std::string> breakStack;
std::vector<std::string> continueStack;
bool hasReturn = false;
struct LoopLabels {
std::string breakLabel; // break跳转的目标标签
std::string continueLabel; // continue跳转的目标标签
};
std::stack<LoopLabels> loopStack; // 用于管理循环的break和continue标签
std::string getNextTemp();
std::string getLLVMType(const std::string&);
sysy::Type* getSysYType(const std::string&);
bool inFunction = false; // 标识当前是否处于函数内部
// 访问方法
std::any visitCompUnit(SysYParser::CompUnitContext* ctx);
std::any visitConstDecl(SysYParser::ConstDeclContext* ctx);
std::any visitVarDecl(SysYParser::VarDeclContext* ctx);
std::any visitVarDef(SysYParser::VarDefContext* ctx);
std::any visitFuncDef(SysYParser::FuncDefContext* ctx);
std::any visitBlockStmt(SysYParser::BlockStmtContext* ctx);
// std::any visitStmt(SysYParser::StmtContext* ctx);
std::any visitLValue(SysYParser::LValueContext* ctx);
std::any visitPrimaryExp(SysYParser::PrimaryExpContext* ctx);
std::any visitPrimExp(SysYParser::PrimExpContext* ctx);
std::any visitParenExp(SysYParser::ParenExpContext* ctx);
std::any visitNumber(SysYParser::NumberContext* ctx);
std::any visitString(SysYParser::StringContext* ctx);
std::any visitCall(SysYParser::CallContext *ctx);
std::any visitUnExp(SysYParser::UnExpContext* ctx);
std::any visitMulExp(SysYParser::MulExpContext* ctx);
std::any visitAddExp(SysYParser::AddExpContext* ctx);
std::any visitRelExp(SysYParser::RelExpContext* ctx);
std::any visitEqExp(SysYParser::EqExpContext* ctx);
std::any visitLAndExp(SysYParser::LAndExpContext* ctx);
std::any visitLOrExp(SysYParser::LOrExpContext* ctx);
std::any visitAssignStmt(SysYParser::AssignStmtContext *ctx) override;
std::any visitIfStmt(SysYParser::IfStmtContext *ctx) override;
std::any visitWhileStmt(SysYParser::WhileStmtContext *ctx) override;
std::any visitBreakStmt(SysYParser::BreakStmtContext *ctx) override;
std::any visitContinueStmt(SysYParser::ContinueStmtContext *ctx) override;
std::any visitReturnStmt(SysYParser::ReturnStmtContext *ctx) override;
// 统一创建二元操作(同时生成数据结构和文本)
sysy::Value* createBinaryOp(SysYParser::ExpContext* lhs,
SysYParser::ExpContext* rhs,
sysy::Instruction::Kind opKind);
};

View File

@@ -62,6 +62,8 @@ private:
public: public:
SysYIRGenerator() = default; SysYIRGenerator() = default;
bool HasReturnInst;
public: public:
Module *get() const { return module.get(); } Module *get() const { return module.get(); }
IRBuilder *getBuilder(){ return &builder; } IRBuilder *getBuilder(){ return &builder; }

View File

@@ -15,15 +15,16 @@ public:
public: public:
void printIR(); void printIR();
void printGlobalVariable(); void printGlobalVariable();
void printFunction(Function *function);
void printInst(Instruction *pInst);
void printType(Type *type);
void printValue(Value *value);
public: public:
static void printFunction(Function *function);
static void printInst(Instruction *pInst);
static void printType(Type *type);
static void printValue(Value *value);
static std::string getOperandName(Value *operand); static std::string getOperandName(Value *operand);
std::string getTypeString(Type *type); static std::string getTypeString(Type *type);
std::string getValueName(Value *value); static std::string getValueName(Value *value);
}; };
} // namespace sysy } // namespace sysy

View File

@@ -10,6 +10,7 @@ using namespace antlr4;
#include "SysYIRGenerator.h" #include "SysYIRGenerator.h"
#include "SysYIRPrinter.h" #include "SysYIRPrinter.h"
#include "SysYIROptPre.h" #include "SysYIROptPre.h"
#include "RISCv64Backend.h"
#include "SysYIRAnalyser.h" #include "SysYIRAnalyser.h"
#include "DeadCodeElimination.h" #include "DeadCodeElimination.h"
#include "Mem2Reg.h" #include "Mem2Reg.h"
@@ -17,6 +18,9 @@ using namespace antlr4;
// #include "LLVMIRGenerator.h" // #include "LLVMIRGenerator.h"
using namespace sysy; using namespace sysy;
int DEBUG = 0;
int DEEPDEBUG = 0;
static string argStopAfter; static string argStopAfter;
static string argInputFile; static string argInputFile;
static bool argFormat = false; static bool argFormat = false;
@@ -26,7 +30,7 @@ void usage(int code = EXIT_FAILURE) {
"Supported options:\n" "Supported options:\n"
" -h \tprint help message and exit\n"; " -h \tprint help message and exit\n";
" -f \tpretty-format the input file\n"; " -f \tpretty-format the input file\n";
" -s {ast,ir,asm,llvmir}\tstop after generating AST/IR/Assembly\n"; " -s {ast,ir,asm,llvmir,asmd,ird}\tstop after generating AST/IR/Assembly\n";
cerr << msg; cerr << msg;
exit(code); exit(code);
} }
@@ -77,13 +81,18 @@ int main(int argc, char **argv) {
// visit AST to generate IR // visit AST to generate IR
SysYIRGenerator generator;
if (argStopAfter == "ir") { generator.visitCompUnit(moduleAST);
SysYIRGenerator generator; if (argStopAfter == "ir" || argStopAfter == "ird") {
generator.visitCompUnit(moduleAST); if (argStopAfter == "ird") {
DEBUG = 1;
}
auto moduleIR = generator.get(); auto moduleIR = generator.get();
SysYPrinter printer(moduleIR); SysYPrinter printer(moduleIR);
printer.printIR(); if (DEBUG) {
cout << "=== Original IR ===\n";
printer.printIR();
}
auto builder = generator.getBuilder(); auto builder = generator.getBuilder();
SysYOptPre optPre(moduleIR, builder); SysYOptPre optPre(moduleIR, builder);
optPre.SysYOptimizateAfterIR(); optPre.SysYOptimizateAfterIR();
@@ -91,21 +100,50 @@ int main(int argc, char **argv) {
cfa.init(); cfa.init();
ActiveVarAnalysis ava; ActiveVarAnalysis ava;
ava.init(moduleIR); ava.init(moduleIR);
printer.printIR(); if (DEBUG) {
cout << "=== After CFA & AVA ===\n";
printer.printIR();
}
DeadCodeElimination dce(moduleIR, &cfa, &ava); DeadCodeElimination dce(moduleIR, &cfa, &ava);
dce.runDCEPipeline(); dce.runDCEPipeline();
if (DEBUG) {
cout << "=== After 1st DCE ===\n";
printer.printIR();
}
Mem2Reg mem2reg(moduleIR, builder, &cfa, &ava); Mem2Reg mem2reg(moduleIR, builder, &cfa, &ava);
mem2reg.mem2regPipeline(); mem2reg.mem2regPipeline();
printer.printIR(); if (DEBUG) {
cout << "=== After Mem2Reg ===\n";
printer.printIR();
}
Reg2Mem reg2mem(moduleIR, builder); Reg2Mem reg2mem(moduleIR, builder);
reg2mem.DeletePhiInst(); reg2mem.DeletePhiInst();
printer.printIR(); if (DEBUG) {
cout << "=== After Reg2Mem ===\n";
printer.printIR();
}
dce.runDCEPipeline(); dce.runDCEPipeline();
if (DEBUG) {
cout << "=== After 2nd DCE ===\n";
printer.printIR();
}
cout << "=== Final IR ===\n";
printer.printIR(); printer.printIR();
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }
// generate assembly
auto module = generator.get();
sysy::RISCv64CodeGen codegen(module);
string asmCode = codegen.code_gen();
if (argStopAfter == "asm" || argStopAfter == "asmd") {
if (argStopAfter == "asmd") {
DEBUG = 1;
DEEPDEBUG = 1;
}
cout << asmCode << endl;
return EXIT_SUCCESS;
}
return EXIT_SUCCESS; return EXIT_SUCCESS;
} }

View File

@@ -1,12 +1,8 @@
//test add //test add
int main(){ int main(){
int a, b; int a, b;
float d;
a = 10; a = 10;
b = 2; b = 2;
int c = a; return a + b;
d = 1.1 ;
return a + b + c;
} }

View File

@@ -5,10 +5,10 @@ int main() {
const int b = 2; const int b = 2;
int c; int c;
if (a == b) if (a != b)
c = a + b; c = b - a + 20; // 21 <- this
else else
c = a * b; c = a * b + b + b + 10; // 16
return c; return c;
} }

View File

@@ -7,7 +7,7 @@ int mul(int x, int y) {
int main(){ int main(){
int a, b; int a, b;
a = 10; a = 10;
b = 0; b = 3;
a = mul(a, b); a = mul(a, b); //60
return a + b; return a + b; //66
} }

3
test_script/clean.sh Normal file
View File

@@ -0,0 +1,3 @@
rm -rf tmp/*
rm -rf *.s *.ll *clang *sysyc
rm -rf *_riscv32

View File

@@ -0,0 +1,49 @@
#!/bin/bash
# 定义输入目录
input_dir="./tmp"
# 获取tmp目录下的所有符合条件的可执行文件并按前缀数字升序排序
executable_files=$(ls "$input_dir" | grep -E '^[0-9]+_.*' | grep -E '_gcc_riscv32$|_sysyc_riscv32$' | sort -t '_' -k1,1n)
# 用于存储前缀数字和返回值
declare -A gcc_results
declare -A sysyc_results
# 遍历所有符合条件的可执行文件
for file in $executable_files; do
# 提取文件名前缀和后缀
prefix=$(echo "$file" | cut -d '_' -f 1)
suffix=$(echo "$file" | cut -d '_' -f 2)
# 检查是否已经处理过该前缀的两个文件
if [[ ${gcc_results["$prefix"]} && ${sysyc_results["$prefix"]} ]]; then
continue
fi
# 执行可执行文件并捕获返回值
echo "Executing: $file"
qemu-riscv32 "$input_dir/$file"
ret_code=$?
# 明确记录返回值
echo "Return code for $file: $ret_code"
# 根据后缀存储返回值
if [[ "$suffix" == "gcc" ]]; then
gcc_results["$prefix"]=$ret_code
elif [[ "$suffix" == "sysyc" ]]; then
sysyc_results["$prefix"]=$ret_code
fi
# 如果同一个前缀的两个文件都已执行,比较它们的返回值
if [[ ${gcc_results["$prefix"]} && ${sysyc_results["$prefix"]} ]]; then
gcc_ret=${gcc_results["$prefix"]}
sysyc_ret=${sysyc_results["$prefix"]}
if [[ "$gcc_ret" -ne "$sysyc_ret" ]]; then
echo -e "\e[31mWARNING: Return codes differ for prefix $prefix: _gcc=$gcc_ret, _sysyc=$sysyc_ret\e[0m"
else
echo "Return codes match for prefix $prefix: $gcc_ret"
fi
fi
done

49
test_script/exe.sh Normal file
View File

@@ -0,0 +1,49 @@
#!/bin/bash
# 定义输入目录
input_dir="."
# 获取当前目录下的所有符合条件的可执行文件,并按前缀数字升序排序
executable_files=$(ls "$input_dir" | grep -E '^[0-9]+_.*' | grep -E '_clang$|_sysyc$' | sort -t '_' -k1,1n)
# 用于存储前缀数字和返回值
declare -A clang_results
declare -A sysyc_results
# 遍历所有符合条件的可执行文件
for file in $executable_files; do
# 提取文件名前缀和后缀
prefix=$(echo "$file" | cut -d '_' -f 1)
suffix=$(echo "$file" | cut -d '_' -f 2)
# 检查是否已经处理过该前缀的两个文件
if [[ ${clang_results["$prefix"]} && ${sysyc_results["$prefix"]} ]]; then
continue
fi
# 执行可执行文件并捕获返回值
echo "Executing: $file"
"./$file"
ret_code=$?
# 明确记录返回值
echo "Return code for $file: $ret_code"
# 根据后缀存储返回值
if [[ "$suffix" == "clang" ]]; then
clang_results["$prefix"]=$ret_code
elif [[ "$suffix" == "sysyc" ]]; then
sysyc_results["$prefix"]=$ret_code
fi
# 如果同一个前缀的两个文件都已执行,比较它们的返回值
if [[ ${clang_results["$prefix"]} && ${sysyc_results["$prefix"]} ]]; then
clang_ret=${clang_results["$prefix"]}
sysyc_ret=${sysyc_results["$prefix"]}
if [[ "$clang_ret" -ne "$sysyc_ret" ]]; then
echo -e "\e[31mWARNING: Return codes differ for prefix $prefix: _clang=$clang_ret, _sysyc=$sysyc_ret\e[0m"
else
echo "Return codes match for prefix $prefix: $clang_ret"
fi
fi
done

View File

@@ -0,0 +1,57 @@
#!/bin/bash
# 定义输入和输出路径
input_dir="../test/"
output_dir="./tmp"
# 默认不生成可执行文件
generate_executable=false
# 解析命令行参数
while [[ "$#" -gt 0 ]]; do
case $1 in
--executable|-e)
generate_executable=true
shift
;;
*)
echo "Unknown parameter: $1"
exit 1
;;
esac
done
# 确保输出目录存在
mkdir -p "$output_dir"
# 遍历输入路径中的所有 .sy 文件
for sy_file in "$input_dir"*.sy; do
# 获取文件名(不带路径和扩展名)
base_name=$(basename "$sy_file" .sy)
# 定义输出文件路径
output_file="${output_dir}/${base_name}_gcc_riscv32.s"
# 使用 gcc 编译 .sy 文件为 .ll 文件
riscv32-unknown-elf-gcc -x c -S "$sy_file" -o "$output_file"
# 检查是否成功
if [ $? -eq 0 ]; then
echo "Compiled $sy_file -> $output_file"
else
echo "Failed to compile $sy_file"
continue
fi
# 如果指定了 --executable 或 -e 参数,则进一步编译为可执行文件
if $generate_executable; then
executable_file="${output_dir}/${base_name}_gcc_riscv32"
riscv32-unknown-elf-gcc "$output_file" -o "$executable_file"
if [ $? -eq 0 ]; then
echo "Generated executable: $executable_file"
else
echo "Failed to generate executable from $output_file"
fi
fi
done

57
test_script/ll.sh Normal file
View File

@@ -0,0 +1,57 @@
#!/bin/bash
# 定义输入和输出路径
input_dir="../test/"
output_dir="./"
# 默认不生成可执行文件
generate_executable=false
# 解析命令行参数
while [[ "$#" -gt 0 ]]; do
case $1 in
--executable|-e)
generate_executable=true
shift
;;
*)
echo "Unknown parameter: $1"
exit 1
;;
esac
done
# 确保输出目录存在
mkdir -p "$output_dir"
# 遍历输入路径中的所有 .sy 文件
for sy_file in "$input_dir"*.sy; do
# 获取文件名(不带路径和扩展名)
base_name=$(basename "$sy_file" .sy)
# 定义输出文件路径
output_file="${base_name}_clang.ll"
# 使用 clang 编译 .sy 文件为 .ll 文件
clang -x c -S -emit-llvm "$sy_file" -o "$output_file"
# 检查是否成功
if [ $? -eq 0 ]; then
echo "Compiled $sy_file -> $output_file"
else
echo "Failed to compile $sy_file"
continue
fi
# 如果指定了 --executable 或 -e 参数,则进一步编译为可执行文件
if $generate_executable; then
executable_file="${base_name}_clang"
clang "$output_file" -o "$executable_file"
if [ $? -eq 0 ]; then
echo "Generated executable: $executable_file"
else
echo "Failed to generate executable from $output_file"
fi
fi
done

View File

@@ -0,0 +1,208 @@
#!/bin/bash
# run_vm_tests.sh - 用于在 RISC-V 虚拟机内部汇编、链接和测试 SysY 程序的脚本
# 此脚本应该在Riscv64架构的机器上运行依赖gcc。
# 脚本的目录结构应该为:
# .
# ├── runit.sh
# ├── lib
# │ └── libsysy_riscv.a
# └── testdata
# ├── functional
# └── performance
# 定义相对于脚本位置的目录
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
TMP_DIR="${SCRIPT_DIR}/tmp"
LIB_DIR="${SCRIPT_DIR}/lib"
TESTDATA_DIR="${SCRIPT_DIR}/testdata"
# 定义编译器
GCC_NATIVE="gcc" # VM 内部的 gcc
# 显示帮助信息的函数
show_help() {
echo "用法: $0 [选项]"
echo "此脚本用于在 RISC-V 虚拟机内部,对之前生成的 .s 汇编文件进行汇编、链接和测试。"
echo "假设当前运行环境已经是 RISC-V 64 位架构,可以直接执行编译后的程序。"
echo ""
echo "选项:"
echo " -c, --clean 清理 'tmp' 目录下的所有生成文件。"
echo " -h, --help 显示此帮助信息并退出。"
echo ""
echo "执行步骤:"
echo "1. 遍历 'tmp/' 目录下的所有 .s 汇编文件。"
echo "2. 使用 VM 内部的 gcc 将 .s 文件汇编并链接为可执行文件 (链接 -L./lib -lsysy_riscv -static)。"
echo "3. 直接运行编译后的可执行文件 (使用 ./ 方式)。"
echo "4. 根据对应的 testdata/*.out 文件内容(最后一行是否为整数)决定是进行返回值比较、标准输出比较,或两者都进行。"
echo "5. 如果没有对应的 .in/.out 文件,则打印可执行文件的返回值。"
echo "6. 输出比较时会忽略行尾多余的换行符。"
}
# 清理临时文件的函数
clean_tmp() {
echo "正在清理临时目录: ${TMP_DIR}"
# 清理所有由本脚本和 runit.sh 生成的文件
rm -rf "${TMP_DIR}"/*.s \
"${TMP_DIR}"/*_sysyc_riscv64 \
"${TMP_DIR}"/*_sysyc_riscv64.actual_out \
"${TMP_DIR}"/*_sysyc_riscv64.expected_stdout \
"${TMP_DIR}"/*_sysyc_riscv64.o # 以防生成了 .o 文件
echo "清理完成。"
}
# 如果临时目录不存在,则创建它 (尽管 runit.sh 应该已经创建了)
mkdir -p "${TMP_DIR}"
# 解析命令行参数
while [[ "$#" -gt 0 ]]; do
case "$1" in
-c|--clean)
clean_tmp
exit 0
;;
-h|--help)
show_help
exit 0
;;
*)
echo "未知选项: $1"
show_help
exit 1
;;
esac
done
echo "SysY VM 内部测试运行器启动..."
echo "汇编文件目录: ${TMP_DIR}"
echo "库文件目录: ${LIB_DIR}"
echo "测试数据目录: ${TESTDATA_DIR}"
echo ""
# 查找 tmp 目录下的所有 .s 汇编文件
# 遍历找到的每个 .s 文件
find "${TMP_DIR}" -maxdepth 1 -name "*.s" | while read s_file; do
# 从 .s 文件名中提取原始的测试用例名称部分
# 例如:从 functional_21_if_test2_sysyc_riscv64.s 提取 functional_21_if_test2
base_name_from_s_file=$(basename "$s_file" .s)
original_test_name_underscored=$(echo "$base_name_from_s_file" | sed 's/_sysyc_riscv64$//')
# 将下划线转换回斜杠以构建原始的相对路径例如functional/21_if_test2
original_relative_path=$(echo "$original_test_name_underscored" | tr '_' '/')
# 定义可执行文件、输入文件、参考输出文件和实际输出文件的路径
executable_file="${TMP_DIR}/${base_name_from_s_file}"
input_file="${TESTDATA_DIR}/${original_relative_path}.in"
output_reference_file="${TESTDATA_DIR}/${original_relative_path}.out"
output_actual_file="${TMP_DIR}/${base_name_from_s_file}.actual_out"
echo "正在处理汇编文件: $(basename "$s_file")"
echo " 对应的测试用例路径: ${original_relative_path}"
# 步骤 1: 使用 VM 内部的 gcc 编译 .s 到可执行文件
# 注意:这里假设 gcc 在 VM 环境中可用,且 ./lib 是相对于当前脚本运行目录
echo " 使用 gcc 汇编并链接: ${GCC_NATIVE} \"${s_file}\" -o \"${executable_file}\" -L\"${LIB_DIR}\" -lsysy_riscv -static -g"
"${GCC_NATIVE}" "${s_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static -g
if [ $? -ne 0 ]; then
echo -e "\e[31m错误: GCC 汇编/链接 ${s_file} 失败\e[0m"
continue
fi
echo " 生成的可执行文件: ${executable_file}"
# 步骤 2: 执行编译后的文件并比较/报告结果
# 直接执行可执行文件,不再通过 qemu-riscv64
echo " 正在执行: ./\"${executable_file}\""
# 检查是否存在 .out 文件
if [ -f "${output_reference_file}" ]; then
# 尝试从 .out 文件中提取期望的返回码和期望的标准输出
# 获取 .out 文件的最后一行,去除空白字符
LAST_LINE_TRIMMED=$(tail -n 1 "${output_reference_file}" | tr -d '[:space:]')
# 检查最后一行是否为纯整数 (允许正负号)
if [[ "$LAST_LINE_TRIMMED" =~ ^[-+]?[0-9]+$ ]]; then
# 假设最后一行是期望的返回码
EXPECTED_RETURN_CODE="$LAST_LINE_TRIMMED"
# 创建一个只包含期望标准输出的临时文件 (所有行除了最后一行)
EXPECTED_STDOUT_FILE="${TMP_DIR}/${base_name_from_s_file}.expected_stdout"
# 使用 head -n -1 来获取除了最后一行之外的所有行。如果文件只有一行,则生成一个空文件。
head -n -1 "${output_reference_file}" > "${EXPECTED_STDOUT_FILE}"
echo " 检测到 .out 文件同时包含标准输出和期望的返回码。"
echo " 期望返回码: ${EXPECTED_RETURN_CODE}"
if [ -s "${EXPECTED_STDOUT_FILE}" ]; then # -s 检查文件是否非空
echo " 期望标准输出文件: ${EXPECTED_STDOUT_FILE}"
else
echo " 期望标准输出为空。"
fi
# 执行程序,捕获实际返回码和实际标准输出
if [ -f "${input_file}" ]; then
echo " 使用输入文件: ${input_file}"
"./${executable_file}" < "${input_file}" > "${output_actual_file}"
else
"./${executable_file}" > "${output_actual_file}"
fi
ACTUAL_RETURN_CODE=$? # 捕获执行状态
# 比较实际返回码与期望返回码
if [ "$ACTUAL_RETURN_CODE" -eq "$EXPECTED_RETURN_CODE" ]; then
echo -e "\e[32m 返回码测试成功: ${original_relative_path}.sy 的返回码 (${ACTUAL_RETURN_CODE}) 与期望值 (${EXPECTED_RETURN_CODE}) 匹配\e[0m"
else
echo -e "\e[31m 返回码测试失败: ${original_relative_path}.sy 的返回码不匹配。期望: ${EXPECTED_RETURN_CODE}, 实际: ${ACTUAL_RETURN_CODE}\e[0m"
fi
# 比较实际标准输出与期望标准输出,忽略文件末尾的换行符差异
if diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
echo -e "\e[32m 标准输出测试成功: 输出与 ${original_relative_path}.sy 的参考输出匹配 (忽略行尾换行符差异)\e[0m"
else
echo -e "\e[31m 标准输出测试失败: ${original_relative_path}.sy 的输出不匹配\e[0m"
echo " 差异 (可能包含行尾换行符差异):"
diff "${output_actual_file}" "${EXPECTED_STDOUT_FILE}" # 显示原始差异以便调试
fi
else
# 最后一行不是纯整数,将整个 .out 文件视为纯标准输出
echo " 检测到 .out 文件为纯标准输出参考。正在与输出文件比较: ${output_reference_file}"
# 执行程序,并将输出重定向到临时文件
if [ -f "${input_file}" ]; then
echo " 使用输入文件: ${input_file}"
"./${executable_file}" < "${input_file}" > "${output_actual_file}"
else
"./${executable_file}" > "${output_actual_file}"
fi
EXEC_STATUS=$? # 捕获执行状态
if [ $EXEC_STATUS -ne 0 ]; then
echo -e "\e[33m警告: 可执行文件 ${original_relative_path}.sy 以非零状态 ${EXEC_STATUS} 退出 (纯输出比较模式)。请检查程序逻辑或其是否应返回此状态。\e[0m"
fi
# 比较实际输出与参考输出,忽略文件末尾的换行符差异
if diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${output_reference_file}") >/dev/null 2>&1; then
echo -e "\e[32m 成功: 输出与 ${original_relative_path}.sy 的参考输出匹配 (忽略行尾换行符差异)\e[0m"
else
echo -e "\e[31m 失败: ${original_relative_path}.sy 的输出不匹配\e[0m"
echo " 差异 (可能包含行尾换行符差异):"
diff "${output_actual_file}" "${output_reference_file}" # 显示原始差异以便调试
fi
fi
elif [ -f "${input_file}" ]; then
# 只有 .in 文件存在,使用输入运行并报告退出码(无参考输出)
echo " 使用输入文件: ${input_file}"
echo " 没有 .out 文件进行比较。正在运行并报告返回码。"
"./${executable_file}" < "${input_file}"
EXEC_STATUS=$?
echo " ${original_relative_path}.sy 的返回码: ${EXEC_STATUS}"
else
# .in 和 .out 文件都不存在,只运行并报告退出码
echo " 未找到 .in 或 .out 文件。正在运行并报告返回码。"
"./${executable_file}"
EXEC_STATUS=$?
echo " ${original_relative_path}.sy 的返回码: ${EXEC_STATUS}"
fi
echo "" # 为测试用例之间添加一个空行,以提高可读性
done
echo "脚本完成。"

223
test_script/runit.sh Normal file
View File

@@ -0,0 +1,223 @@
#!/bin/bash
# runit.sh - 用于编译和测试 SysY 程序的脚本
# 此脚本应该位于 mysysy/test_script/
# 定义相对于脚本位置的目录
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" &>/dev/null && pwd)"
TESTDATA_DIR="${SCRIPT_DIR}/../testdata"
BUILD_BIN_DIR="${SCRIPT_DIR}/../build/bin"
LIB_DIR="${SCRIPT_DIR}/../lib"
# TMP_DIR="${SCRIPT_DIR}/tmp"
TMP_DIR="/home/ladev987/paraComp/debug/share_folder/tmp"
# 定义编译器和模拟器
SYSYC="${BUILD_BIN_DIR}/sysyc"
GCC_RISCV64="riscv64-linux-gnu-gcc"
QEMU_RISCV64="qemu-riscv64"
# 标志,用于确定是否应该生成和运行可执行文件
EXECUTE_MODE=false
# 显示帮助信息的函数
show_help() {
echo "用法: $0 [选项]"
echo "此脚本用于编译 .sy 文件,并可选择性地运行它们进行测试。"
echo ""
echo "选项:"
echo " -e, --executable 编译为可执行文件,运行可执行文件,并比较输出(如果存在 .in/.out 文件)。"
echo " 如果 .out 文件的最后一行是整数,则将其视为期望的返回值进行比较,其余内容视为期望的标准输出。"
echo " 如果 .out 文件的最后一行不是整数,则将整个 .out 文件视为期望的标准输出进行比较。"
echo " 输出比较时会忽略行尾多余的换行符。"
echo " 如果不存在 .in/.out 文件,则打印返回码。"
echo " -c, --clean 清理 'tmp' 目录下的所有生成文件。"
echo " -h, --help 显示此帮助信息并退出。"
echo ""
echo "编译步骤:"
echo "1. 调用 sysyc 将 .sy 编译为 .s (RISC-V 汇编)。"
echo "2. 调用 riscv64-linux-gnu-gcc 将 .s 编译为可执行文件,并链接 -L../lib/ -lsysy_riscv -static。"
echo "3. 调用 qemu-riscv64 执行编译后的文件。"
echo "4. 根据 .out 文件内容(最后一行是否为整数)决定是进行返回值比较、标准输出比较,或两者都进行。"
echo "5. 如果没有 .in/.out 文件,则打印可执行文件的返回值。"
}
# 清理临时文件的函数
clean_tmp() {
echo "正在清理临时目录: ${TMP_DIR}"
rm -rf "${TMP_DIR}"/*
# 如果需要,也可以根据 clean.sh 示例清理其他特定文件
# rm -rf "${SCRIPT_DIR}"/*.s "${SCRIPT_DIR}"/*.ll "${SCRIPT_DIR}"/*clang "${SCRIPT_DIR}"/*sysyc
# rm -rf "${SCRIPT_DIR}"/*_riscv64
}
# 如果临时目录不存在,则创建它
mkdir -p "${TMP_DIR}"
# 解析命令行参数
while [[ "$#" -gt 0 ]]; do
case "$1" in
-e|--executable)
EXECUTE_MODE=true
shift
;;
-c|--clean)
clean_tmp
exit 0
;;
-h|--help)
show_help
exit 0
;;
*)
echo "未知选项: $1"
show_help
exit 1
;;
esac
done
echo "SysY 测试运行器启动..."
echo "输入目录: ${TESTDATA_DIR}"
echo "临时目录: ${TMP_DIR}"
echo "执行模式已启用: ${EXECUTE_MODE}"
echo ""
# 查找 testdata 目录及其子目录中的所有 .sy 文件
# 遍历找到的每个 .sy 文件
find "${TESTDATA_DIR}" -name "*.sy" | while read sy_file; do
# 获取 .sy 文件的基本名称例如21_if_test2
# 这也处理了文件位于子目录中的情况例如functional/21_if_test2.sy
relative_path_no_ext=$(realpath --relative-to="${TESTDATA_DIR}" "${sy_file%.*}")
# 将斜杠替换为下划线,用于输出文件名,以避免冲突并保持结构
output_base_name=$(echo "${relative_path_no_ext}" | tr '/' '_')
# 定义汇编文件、可执行文件、输入文件和输出文件的路径
assembly_file="${TMP_DIR}/${output_base_name}_sysyc_riscv64.s"
executable_file="${TMP_DIR}/${output_base_name}_sysyc_riscv64"
input_file="${sy_file%.*}.in"
output_reference_file="${sy_file%.*}.out"
output_actual_file="${TMP_DIR}/${output_base_name}_sysyc_riscv64.actual_out"
echo "正在处理: $(basename "$sy_file")"
echo " SY 文件: ${sy_file}"
# 步骤 1: 使用 sysyc 编译 .sy 到 .s
echo " 使用 sysyc 编译: ${SYSYC} -s asm \"${sy_file}\" > \"${assembly_file}\""
"${SYSYC}" -s asm "${sy_file}" > "${assembly_file}"
if [ $? -ne 0 ]; then
echo -e "\e[31m错误: SysY 编译 ${sy_file} 失败\e[0m"
continue
fi
echo " 生成的汇编文件: ${assembly_file}"
# 只有当 EXECUTE_MODE 为 true 时才继续生成和执行可执行文件
if ${EXECUTE_MODE}; then
# 步骤 2: 使用 riscv64-linux-gnu-gcc 编译 .s 到可执行文件
echo " 使用 gcc 编译: ${GCC_RISCV64} \"${assembly_file}\" -o \"${executable_file}\" -L\"${LIB_DIR}\" -lsysy_riscv -static"
"${GCC_RISCV64}" "${assembly_file}" -o "${executable_file}" -L"${LIB_DIR}" -lsysy_riscv -static
if [ $? -ne 0 ]; then
echo -e "\e[31m错误: GCC 编译 ${assembly_file} 失败\e[0m"
continue
fi
echo " 生成的可执行文件: ${executable_file}"
# 步骤 3, 4, 5: 执行编译后的文件并比较/报告结果
echo " 正在执行: ${QEMU_RISCV664} \"${executable_file}\""
# 检查是否存在 .out 文件
if [ -f "${output_reference_file}" ]; then
# 尝试从 .out 文件中提取期望的返回码和期望的标准输出
# 获取 .out 文件的最后一行,去除空白字符
LAST_LINE_TRIMMED=$(tail -n 1 "${output_reference_file}" | tr -d '[:space:]')
# 检查最后一行是否为纯整数 (允许正负号)
if [[ "$LAST_LINE_TRIMMED" =~ ^[-+]?[0-9]+$ ]]; then
# 假设最后一行是期望的返回码
EXPECTED_RETURN_CODE="$LAST_LINE_TRIMMED"
# 创建一个只包含期望标准输出的临时文件 (所有行除了最后一行)
EXPECTED_STDOUT_FILE="${TMP_DIR}/${output_base_name}_sysyc_riscv64.expected_stdout"
# 使用 head -n -1 来获取除了最后一行之外的所有行。如果文件只有一行,则生成一个空文件。
head -n -1 "${output_reference_file}" > "${EXPECTED_STDOUT_FILE}"
echo " 检测到 .out 文件同时包含标准输出和期望的返回码。"
echo " 期望返回码: ${EXPECTED_RETURN_CODE}"
if [ -s "${EXPECTED_STDOUT_FILE}" ]; then # -s 检查文件是否非空
echo " 期望标准输出文件: ${EXPECTED_STDOUT_FILE}"
else
echo " 期望标准输出为空。"
fi
# 执行程序,捕获实际返回码和实际标准输出
if [ -f "${input_file}" ]; then
echo " 使用输入文件: ${input_file}"
"${QEMU_RISCV64}" "${executable_file}" < "${input_file}" > "${output_actual_file}"
else
"${QEMU_RISCV64}" "${executable_file}" > "${output_actual_file}"
fi
ACTUAL_RETURN_CODE=$? # 捕获执行状态
# 比较实际返回码与期望返回码
if [ "$ACTUAL_RETURN_CODE" -eq "$EXPECTED_RETURN_CODE" ]; then
echo -e "\e[32m 返回码测试成功: ${sy_file} 的返回码 (${ACTUAL_RETURN_CODE}) 与期望值 (${EXPECTED_RETURN_CODE}) 匹配\e[0m"
else
echo -e "\e[31m 返回码测试失败: ${sy_file} 的返回码不匹配。期望: ${EXPECTED_RETURN_CODE}, 实际: ${ACTUAL_RETURN_CODE}\e[0m"
fi
# 比较实际标准输出与期望标准输出,忽略文件末尾的换行符差异
# 使用 sed 命令去除文件末尾的所有换行符,再通过 diff 进行比较
if diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${EXPECTED_STDOUT_FILE}") >/dev/null 2>&1; then
echo -e "\e[32m 标准输出测试成功: 输出与 ${sy_file} 的参考输出匹配 (忽略行尾换行符差异)\e[0m"
else
echo -e "\e[31m 标准输出测试失败: ${sy_file} 的输出不匹配\e[0m"
echo " 差异 (可能包含行尾换行符差异):"
diff "${output_actual_file}" "${EXPECTED_STDOUT_FILE}" # 显示原始差异以便调试
fi
else
# 最后一行不是纯整数,将整个 .out 文件视为纯标准输出
echo " 检测到 .out 文件为纯标准输出参考。正在与输出文件比较: ${output_reference_file}"
# 使用输入文件(如果存在)运行可执行文件,并将输出重定向到临时文件
if [ -f "${input_file}" ]; then
echo " 使用输入文件: ${input_file}"
"${QEMU_RISCV64}" "${executable_file}" < "${input_file}" > "${output_actual_file}"
else
"${QEMU_RISCV64}" "${executable_file}" > "${output_actual_file}"
fi
EXEC_STATUS=$? # 捕获执行状态
if [ $EXEC_STATUS -ne 0 ]; then
echo -e "\e[33m警告: 可执行文件 ${sy_file} 以非零状态 ${EXEC_STATUS} 退出 (纯输出比较模式)。请检查程序逻辑或其是否应返回此状态。\e[0m"
fi
# 比较实际输出与参考输出,忽略文件末尾的换行符差异
if diff -q <(sed ':a;N;$!ba;s/\n*$//' "${output_actual_file}") <(sed ':a;N;$!ba;s/\n*$//' "${output_reference_file}") >/dev/null 2>&1; then
echo -e "\e[32m 成功: 输出与 ${sy_file} 的参考输出匹配 (忽略行尾换行符差异)\e[0m"
else
echo -e "\e[31m 失败: ${sy_file} 的输出不匹配\e[0m"
echo " 差异 (可能包含行尾换行符差异):"
diff "${output_actual_file}" "${output_reference_file}" # 显示原始差异以便调试
fi
fi
elif [ -f "${input_file}" ]; then
# 只有 .in 文件存在,使用输入运行并报告退出码(无参考输出)
echo " 使用输入文件: ${input_file}"
echo " 没有 .out 文件进行比较。正在运行并报告返回码。"
"${QEMU_RISCV64}" "${executable_file}" < "${input_file}"
EXEC_STATUS=$?
echo " ${sy_file} 的返回码: ${EXEC_STATUS}"
else
# .in 和 .out 文件都不存在,只运行并报告退出码
echo " 未找到 .in 或 .out 文件。正在运行并报告返回码。"
"${QEMU_RISCV64}" "${executable_file}"
EXEC_STATUS=$?
echo " ${sy_file} 的返回码: ${EXEC_STATUS}"
fi
else
echo " 跳过执行模式。仅生成汇编文件。"
fi
echo "" # 为测试用例之间添加一个空行,以提高可读性
done
echo "脚本完成。"

View File

@@ -0,0 +1,57 @@
#!/bin/bash
# 定义输入和输出路径
input_dir="../test/"
output_dir="./tmp"
# 默认不生成可执行文件
generate_executable=false
# 解析命令行参数
while [[ "$#" -gt 0 ]]; do
case $1 in
--executable|-e)
generate_executable=true
shift
;;
*)
echo "Unknown parameter: $1"
exit 1
;;
esac
done
# 确保输出目录存在
mkdir -p "$output_dir"
# 遍历输入路径中的所有 .sy 文件
for sy_file in "$input_dir"*.sy; do
# 获取文件名(不带路径和扩展名)
base_name=$(basename "$sy_file" .sy)
# 定义输出文件路径
output_file="${output_dir}/${base_name}_sysyc_riscv32.s"
# 使用 sysyc 编译 .sy 文件为 .s 文件
../build/bin/sysyc -s asm "$sy_file" > "$output_file"
# 检查是否成功
if [ $? -eq 0 ]; then
echo "Compiled $sy_file -> $output_file"
else
echo "Failed to compile $sy_file"
continue
fi
# 如果指定了 --executable 或 -e 参数,则进一步编译为可执行文件
if $generate_executable; then
executable_file="${output_dir}/${base_name}_sysyc_riscv32"
riscv32-unknown-elf-gcc "$output_file" -o "$executable_file"
if [ $? -eq 0 ]; then
echo "Generated executable: $executable_file"
else
echo "Failed to generate executable from $output_file"
fi
fi
done

57
test_script/sysyll.sh Normal file
View File

@@ -0,0 +1,57 @@
#!/bin/bash
# 定义输入和输出路径
input_dir="../test/"
output_dir="./"
# 默认不生成可执行文件
generate_executable=false
# 解析命令行参数
while [[ "$#" -gt 0 ]]; do
case $1 in
--executable|-e)
generate_executable=true
shift
;;
*)
echo "Unknown parameter: $1"
exit 1
;;
esac
done
# 确保输出目录存在
mkdir -p "$output_dir"
# 遍历输入路径中的所有 .sy 文件
for sy_file in "$input_dir"*.sy; do
# 获取文件名(不带路径和扩展名)
base_name=$(basename "$sy_file" .sy)
# 定义输出文件路径
output_file="${base_name}_sysyc.ll"
# 使用 sysyc 编译 .sy 文件为 .ll 文件
../build/bin/sysyc -s ir "$sy_file" > "$output_file"
# 检查是否成功
if [ $? -eq 0 ]; then
echo "Compiled $sy_file -> $output_file"
else
echo "Failed to compile $sy_file"
continue
fi
# 如果指定了 --executable 或 -e 参数,则进一步编译为可执行文件
if $generate_executable; then
executable_file="${base_name}_sysyc"
clang "$output_file" -o "$executable_file"
if [ $? -eq 0 ]; then
echo "Generated executable: $executable_file"
else
echo "Failed to generate executable from $output_file"
fi
fi
done

3
test_script/wrapper.sh Normal file
View File

@@ -0,0 +1,3 @@
sh ./gcc-riscv32.sh -e
sh ./sysy-riscv32.sh -e
sh ./exe-riscv32.sh