Compare commits

...

41 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
rain2133
d9fa9e787a 删除注释 2025-06-25 16:33:43 +08:00
rain2133
97410d9417 删除调试信息输出 2025-06-25 16:07:29 +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
rain2133
0d23475aa1 [死代码删除]:保证扩展性、模块化构建死代码删除,包括消除无用store,alloca,load,globalval,mem2reg引入的无用alloca以及reg2mem导致的store-load-store冗余存储 2025-06-25 15:33:25 +08:00
rain2133
b12732f10d 修复分析器逻辑,保证优化遍共享一个分析器(主要是在mem2reg) 2025-06-25 15:30:28 +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
rain2133
1e06c5a446 debugging 2025-06-25 14:00:27 +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
34 changed files with 4194 additions and 1987 deletions

View File

@@ -19,9 +19,10 @@ add_executable(sysyc
SysYIRPrinter.cpp
SysYIROptPre.cpp
SysYIRAnalyser.cpp
DeadCodeElimination.cpp
Mem2Reg.cpp
Reg2Mem.cpp
RISCv32Backend.cpp
RISCv64Backend.cpp
)
target_include_directories(sysyc PRIVATE ${CMAKE_CURRENT_BINARY_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/include)
target_compile_options(sysyc PRIVATE -frtti)

276
src/DeadCodeElimination.cpp Normal file
View File

@@ -0,0 +1,276 @@
#include "DeadCodeElimination.h"
#include <iostream>
extern int DEBUG;
namespace sysy {
void DeadCodeElimination::runDCEPipeline() {
const auto& functions = pModule->getFunctions();
for (const auto& function : functions) {
const auto& func = function.second;
bool changed = true;
while (changed) {
changed = false;
eliminateDeadStores(func.get(), changed);
eliminateDeadLoads(func.get(), changed);
eliminateDeadAllocas(func.get(), changed);
eliminateDeadRedundantLoadStore(func.get(), changed);
eliminateDeadGlobals(changed);
}
}
}
// 消除无用存储 消除条件:
// 存储的目标指针pointer不是全局变量!isGlobal(pointer))。
// 存储的目标指针不是数组参数(!isArr(pointer) 或不在函数参数列表里)。
// 该指针的所有使用者uses仅限 alloca 或 store即没有 load 或其他指令使用它)。
void DeadCodeElimination::eliminateDeadStores(Function* func, bool& changed) {
for (const auto& block : func->getBasicBlocks()) {
auto& instrs = block->getInstructions();
for (auto iter = instrs.begin(); iter != instrs.end();) {
auto inst = iter->get();
if (!inst->isStore()) {
++iter;
continue;
}
auto storeInst = dynamic_cast<StoreInst*>(inst);
auto pointer = storeInst->getPointer();
// 如果是全局变量或者是函数的数组参数
if (isGlobal(pointer) || (isArr(pointer) &&
std::find(func->getEntryBlock()->getArguments().begin(),
func->getEntryBlock()->getArguments().end(),
pointer) != func->getEntryBlock()->getArguments().end())) {
++iter;
continue;
}
bool changetag = true;
for (auto& use : pointer->getUses()) {
// 依次判断store的指针是否被其他指令使用
auto user = use->getUser();
auto userInst = dynamic_cast<Instruction*>(user);
// 如果使用store的指针的指令不是Alloca或Store则不删除
if (userInst != nullptr && !userInst->isAlloca() && !userInst->isStore()) {
changetag = false;
break;
}
}
if (changetag) {
changed = true;
if(DEBUG){
std::cout << "=== Dead Store Found ===\n";
SysYPrinter::printInst(storeInst);
}
usedelete(storeInst);
iter = instrs.erase(iter);
} else {
++iter;
}
}
}
}
// 消除无用加载 消除条件:
// 该指令的结果未被使用inst->getUses().empty())。
void DeadCodeElimination::eliminateDeadLoads(Function* func, bool& changed) {
for (const auto& block : func->getBasicBlocks()) {
auto& instrs = block->getInstructions();
for (auto iter = instrs.begin(); iter != instrs.end();) {
auto inst = iter->get();
if (inst->isBinary() || inst->isUnary() || inst->isLoad()) {
if (inst->getUses().empty()) {
changed = true;
if(DEBUG){
std::cout << "=== Dead Load Binary Unary Found ===\n";
SysYPrinter::printInst(inst);
}
usedelete(inst);
iter = instrs.erase(iter);
continue;
}
}
++iter;
}
}
}
// 消除无用加载 消除条件:
// 该 alloca 未被任何指令使用allocaInst->getUses().empty())。
// 该 alloca 不是函数的参数(不在 entry 块的参数列表里)。
void DeadCodeElimination::eliminateDeadAllocas(Function* func, bool& changed) {
for (const auto& block : func->getBasicBlocks()) {
auto& instrs = block->getInstructions();
for (auto iter = instrs.begin(); iter != instrs.end();) {
auto inst = iter->get();
if (inst->isAlloca()) {
auto allocaInst = dynamic_cast<AllocaInst*>(inst);
if (allocaInst->getUses().empty() &&
std::find(func->getEntryBlock()->getArguments().begin(),
func->getEntryBlock()->getArguments().end(),
allocaInst) == func->getEntryBlock()->getArguments().end()) {
changed = true;
if(DEBUG){
std::cout << "=== Dead Alloca Found ===\n";
SysYPrinter::printInst(inst);
}
usedelete(inst);
iter = instrs.erase(iter);
continue;
}
}
++iter;
}
}
}
void DeadCodeElimination::eliminateDeadIndirectiveAllocas(Function* func, bool& changed) {
// 删除mem2reg时引入的且现在已经没有value使用了的隐式alloca
FunctionAnalysisInfo* funcInfo = pCFA->getFunctionAnalysisInfo(func);
for (auto it = funcInfo->getIndirectAllocas().begin(); it != funcInfo->getIndirectAllocas().end();) {
auto &allocaInst = *it;
if (allocaInst->getUses().empty()) {
changed = true;
if(DEBUG){
std::cout << "=== Dead Indirect Alloca Found ===\n";
SysYPrinter::printInst(allocaInst.get());
}
it = funcInfo->getIndirectAllocas().erase(it);
} else {
++it;
}
}
}
// 该全局变量未被任何指令使用global->getUses().empty())。
void DeadCodeElimination::eliminateDeadGlobals(bool& changed) {
auto& globals = pModule->getGlobals();
for (auto it = globals.begin(); it != globals.end();) {
auto& global = *it;
if (global->getUses().empty()) {
changed = true;
if(DEBUG){
std::cout << "=== Dead Global Found ===\n";
SysYPrinter::printValue(global.get());
}
it = globals.erase(it);
} else {
++it;
}
}
}
// 消除冗余加载和存储 消除条件:
// phi 指令的目标指针仅被该 phi 使用(无其他 store/load 使用)。
// memset 指令的目标指针未被使用pointer->getUses().empty()
// store -> load -> store 模式
void DeadCodeElimination::eliminateDeadRedundantLoadStore(Function* func, bool& changed) {
for (const auto& block : func->getBasicBlocks()) {
auto& instrs = block->getInstructions();
for (auto iter = instrs.begin(); iter != instrs.end();) {
auto inst = iter->get();
if (inst->isPhi()) {
auto phiInst = dynamic_cast<PhiInst*>(inst);
auto pointer = phiInst->getPointer();
bool tag = true;
for (const auto& use : pointer->getUses()) {
auto user = use->getUser();
if (user != inst) {
tag = false;
break;
}
}
/// 如果 pointer 仅被该 phi 使用,可以删除 ph
if (tag) {
changed = true;
usedelete(inst);
iter = instrs.erase(iter);
continue;
}
// 数组指令还不完善不保证memset优化效果
} else if (inst->isMemset()) {
auto memsetInst = dynamic_cast<MemsetInst*>(inst);
auto pointer = memsetInst->getPointer();
if (pointer->getUses().empty()) {
changed = true;
usedelete(inst);
iter = instrs.erase(iter);
continue;
}
}else if(inst->isLoad()) {
if (iter != instrs.begin()) {
auto loadInst = dynamic_cast<LoadInst*>(inst);
auto loadPointer = loadInst->getPointer();
// TODO:store -> load -> store 模式
auto prevIter = std::prev(iter);
auto prevInst = prevIter->get();
if (prevInst->isStore()) {
auto prevStore = dynamic_cast<StoreInst*>(prevInst);
auto prevStorePointer = prevStore->getPointer();
auto prevStoreValue = prevStore->getOperand(0);
// 确保前一个 store 不是数组操作
if (prevStore->getIndices().empty()) {
// 检查后一条指令是否是 store 同一个值
auto nextIter = std::next(iter);
if (nextIter != instrs.end()) {
auto nextInst = nextIter->get();
if (nextInst->isStore()) {
auto nextStore = dynamic_cast<StoreInst*>(nextInst);
auto nextStorePointer = nextStore->getPointer();
auto nextStoreValue = nextStore->getOperand(0);
// 确保后一个 store 不是数组操作
if (nextStore->getIndices().empty()) {
// 判断优化条件:
// 1. prevStore 的指针操作数 == load 的指针操作数
// 2. nextStore 的值操作数 == load 指令本身
if (prevStorePointer == loadPointer &&
nextStoreValue == loadInst) {
// 可以优化直接把prevStorePointer的值存到nextStorePointer
changed = true;
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);
iter = instrs.erase(iter);
// 删除 prevStore 这里是不是可以留给删除无用store处理
// if (prevStore->getUses().empty()) {
// usedelete(prevStore);
// instrs.erase(prevIter); // 删除 prevStore
// }
continue; // 跳过 ++iter因为已经移动迭代器
}
}
}
}
}
}
}
}
++iter;
}
}
}
bool DeadCodeElimination::isGlobal(Value *val){
auto gval = dynamic_cast<GlobalValue *>(val);
return gval != nullptr;
}
bool DeadCodeElimination::isArr(Value *val){
auto aval = dynamic_cast<AllocaInst *>(val);
return aval != nullptr && aval->getNumDims() != 0;
}
void DeadCodeElimination::usedelete(Instruction *instr){
for (auto &use1 : instr->getOperands()) {
auto val1 = use1->getValue();
val1->removeUse(use1);
}
}
} // namespace sysy

View File

@@ -135,7 +135,7 @@ auto Function::getCalleesWithNoExternalAndSelf() -> std::set<Function *> {
}
return result;
}
// 函数克隆,后续函数级优化(内联等)需要用到
Function * Function::clone(const std::string &suffix) const {
std::stringstream ss;
std::map<BasicBlock *, BasicBlock *> oldNewBlockMap;
@@ -527,11 +527,7 @@ Function * Function::clone(const std::string &suffix) const {
return newFunction;
}
/**
* @brief 设置操作数
*
* @param [in] index 所要设置的操作数的位置
* @param [in] value 所要设置成的value
* @return 无返回值
* 设置操作数
*/
void User::setOperand(unsigned index, Value *value) {
assert(index < getNumOperands());
@@ -539,11 +535,7 @@ void User::setOperand(unsigned index, Value *value) {
value->addUse(operands[index]);
}
/**
* @brief 替换操作数
*
* @param [in] index 所要替换的操作数的位置
* @param [in] value 所要替换成的value
* @return 无返回值
* 替换操作数
*/
void User::replaceOperand(unsigned index, Value *value) {
assert(index < getNumOperands());
@@ -561,17 +553,12 @@ CallInst::CallInst(Function *callee, const std::vector<Value *> &args, BasicBloc
}
}
/**
* @brief 获取被调用函数的指针
*
* @return 被调用函数的指针
* 获取被调用函数的指针
*/
Function * CallInst::getCallee() const { return dynamic_cast<Function *>(getOperand(0)); }
/**
* @brief 获取变量指针
*
* @param [in] name 变量名字
* @return 变量指针
* 获取变量指针
*/
auto SymbolTable::getVariable(const std::string &name) const -> User * {
auto node = curNode;
@@ -586,11 +573,7 @@ auto SymbolTable::getVariable(const std::string &name) const -> User * {
return nullptr;
}
/**
* @brief 添加变量
*
* @param [in] name 变量名字
* @param [in] variable 变量指针
* @return 变量指针
* 添加变量到符号表
*/
auto SymbolTable::addVariable(const std::string &name, User *variable) -> User * {
User *result = nullptr;
@@ -621,21 +604,15 @@ auto SymbolTable::addVariable(const std::string &name, User *variable) -> User *
return result;
}
/**
* @brief 获取全局变量
*
* @return 全局变量列表
* 获取全局变量
*/
auto SymbolTable::getGlobals() -> std::vector<std::unique_ptr<GlobalValue>> & { return globals; }
/**
* @brief 获取常量
*
* @return 常量列表
* 获取常量
*/
auto SymbolTable::getConsts() const -> const std::vector<std::unique_ptr<ConstantVariable>> & { return consts; }
/**
* @brief 进入新的作用域
*
* @return 无返回值
* 进入新的作用域
*/
void SymbolTable::enterNewScope() {
auto newNode = new SymbolTableNode;
@@ -647,31 +624,20 @@ void SymbolTable::enterNewScope() {
curNode = newNode;
}
/**
* @brief 进入全局作用域
*
* @return 无返回值
* 进入全局作用域
*/
void SymbolTable::enterGlobalScope() { curNode = nodeList.front().get(); }
/**
* @brief 离开作用域
*
* @return 无返回值
* 离开作用域
*/
void SymbolTable::leaveScope() { curNode = curNode->pNode; }
/**
* @brief 是否位于全局作用域
*
* @return 布尔值
* 是否位于全局作用域
*/
auto SymbolTable::isInGlobalScope() const -> bool { return curNode->pNode == nullptr; }
/**
* @brief 移动指令
*
* @param [in] sourcePos 源指令列表位置
* @param [in] targetPos 目的指令列表位置
* @param [in] block 目标基本块
* @return 无返回值
*移动指令
*/
auto BasicBlock::moveInst(iterator sourcePos, iterator targetPos, BasicBlock *block) -> iterator {
auto inst = sourcePos->release();

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

View File

@@ -47,12 +47,12 @@ std::unordered_set<BasicBlock *> Mem2Reg::computeIterDf(const std::unordered_set
*/
auto Mem2Reg::computeValue2Blocks() -> void {
SysYPrinter printer(pModule); // 初始化打印机
std::cout << "===== Start computeValue2Blocks =====" << std::endl;
// std::cout << "===== Start computeValue2Blocks =====" << std::endl;
auto &functions = pModule->getFunctions();
for (const auto &function : functions) {
auto func = function.second.get();
std::cout << "\nProcessing function: " << func->getName() << std::endl;
// std::cout << "\nProcessing function: " << func->getName() << std::endl;
FunctionAnalysisInfo* funcInfo = controlFlowAnalysis->getFunctionAnalysisInfo(func);
if (!funcInfo) {
@@ -61,98 +61,98 @@ auto Mem2Reg::computeValue2Blocks() -> void {
}
auto basicBlocks = func->getBasicBlocks();
std::cout << "BasicBlocks count: " << basicBlocks.size() << std::endl;
// std::cout << "BasicBlocks count: " << basicBlocks.size() << std::endl;
for (auto &it : basicBlocks) {
auto basicBlock = it.get();
std::cout << "\nProcessing BB: " << basicBlock->getName() << std::endl;
// std::cout << "\nProcessing BB: " << basicBlock->getName() << std::endl;
// printer.printBlock(basicBlock); // 打印基本块内容
auto &instrs = basicBlock->getInstructions();
for (auto &instr : instrs) {
std::cout << " Analyzing instruction: ";
printer.printInst(instr.get());
std::cout << std::endl;
// std::cout << " Analyzing instruction: ";
// printer.printInst(instr.get());
// std::cout << std::endl;
if (instr->isAlloca()) {
if (!(isArr(instr.get()) || isGlobal(instr.get()))) {
std::cout << " Found alloca: ";
printer.printInst(instr.get());
std::cout << " -> Adding to allocBlocks" << std::endl;
// std::cout << " Found alloca: ";
// printer.printInst(instr.get());
// std::cout << " -> Adding to allocBlocks" << std::endl;
funcInfo->addValue2AllocBlocks(instr.get(), basicBlock);
} else {
std::cout << " Skip array/global alloca: ";
printer.printInst(instr.get());
std::cout << std::endl;
// std::cout << " Skip array/global alloca: ";
// printer.printInst(instr.get());
// std::cout << std::endl;
}
}
else if (instr->isStore()) {
auto val = instr->getOperand(1);
std::cout << " Store target: ";
printer.printInst(dynamic_cast<Instruction *>(val));
// std::cout << " Store target: ";
// printer.printInst(dynamic_cast<Instruction *>(val));
if (!(isArr(val) || isGlobal(val))) {
std::cout << " Adding store to defBlocks for value: ";
printer.printInst(dynamic_cast<Instruction *>(instr.get()));
std::cout << std::endl;
// std::cout << " Adding store to defBlocks for value: ";
// printer.printInst(dynamic_cast<Instruction *>(instr.get()));
// std::cout << std::endl;
// 将store的目标值添加到defBlocks中
funcInfo->addValue2DefBlocks(val, basicBlock);
} else {
std::cout << " Skip array/global store" << std::endl;
// std::cout << " Skip array/global store" << std::endl;
}
}
else if (instr->isLoad()) {
auto val = instr->getOperand(0);
std::cout << " Load source: ";
printer.printInst(dynamic_cast<Instruction *>(val));
std::cout << std::endl;
// std::cout << " Load source: ";
// printer.printInst(dynamic_cast<Instruction *>(val));
// std::cout << std::endl;
if (!(isArr(val) || isGlobal(val))) {
std::cout << " Adding load to useBlocks for value: ";
printer.printInst(dynamic_cast<Instruction *>(val));
std::cout << std::endl;
// std::cout << " Adding load to useBlocks for value: ";
// printer.printInst(dynamic_cast<Instruction *>(val));
// std::cout << std::endl;
funcInfo->addValue2UseBlocks(val, basicBlock);
} else {
std::cout << " Skip array/global load" << std::endl;
// std::cout << " Skip array/global load" << std::endl;
}
}
}
}
// 打印分析结果
std::cout << "\nAnalysis results for function " << func->getName() << ":" << std::endl;
// std::cout << "\nAnalysis results for function " << func->getName() << ":" << std::endl;
auto &allocMap = funcInfo->getValue2AllocBlocks();
std::cout << "AllocBlocks (" << allocMap.size() << "):" << std::endl;
for (auto &[val, bb] : allocMap) {
std::cout << " ";
printer.printInst(dynamic_cast<Instruction *>(val));
std::cout << " in BB: " << bb->getName() << std::endl;
}
// auto &allocMap = funcInfo->getValue2AllocBlocks();
// std::cout << "AllocBlocks (" << allocMap.size() << "):" << std::endl;
// for (auto &[val, bb] : allocMap) {
// std::cout << " ";
// printer.printInst(dynamic_cast<Instruction *>(val));
// std::cout << " in BB: " << bb->getName() << std::endl;
// }
auto &defMap = funcInfo->getValue2DefBlocks();
std::cout << "DefBlocks (" << defMap.size() << "):" << std::endl;
for (auto &[val, bbs] : defMap) {
std::cout << " ";
printer.printInst(dynamic_cast<Instruction *>(val));
for (const auto &[bb, count] : bbs) {
std::cout << " in BB: " << bb->getName() << " (count: " << count << ")";
}
}
// auto &defMap = funcInfo->getValue2DefBlocks();
// std::cout << "DefBlocks (" << defMap.size() << "):" << std::endl;
// for (auto &[val, bbs] : defMap) {
// std::cout << " ";
// printer.printInst(dynamic_cast<Instruction *>(val));
// for (const auto &[bb, count] : bbs) {
// std::cout << " in BB: " << bb->getName() << " (count: " << count << ")";
// }
// }
auto &useMap = funcInfo->getValue2UseBlocks();
std::cout << "UseBlocks (" << useMap.size() << "):" << std::endl;
for (auto &[val, bbs] : useMap) {
std::cout << " ";
printer.printInst(dynamic_cast<Instruction *>(val));
for (const auto &[bb, count] : bbs) {
std::cout << " in BB: " << bb->getName() << " (count: " << count << ")";
}
}
// auto &useMap = funcInfo->getValue2UseBlocks();
// std::cout << "UseBlocks (" << useMap.size() << "):" << std::endl;
// for (auto &[val, bbs] : useMap) {
// std::cout << " ";
// printer.printInst(dynamic_cast<Instruction *>(val));
// for (const auto &[bb, count] : bbs) {
// std::cout << " in BB: " << bb->getName() << " (count: " << count << ")";
// }
// }
}
std::cout << "===== End computeValue2Blocks =====" << std::endl;
// std::cout << "===== End computeValue2Blocks =====" << std::endl;
}
@@ -207,33 +207,31 @@ auto Mem2Reg::cascade(Instruction *instr, bool &changed, Function *func, BasicBl
}
/**
* @brief llvm mem2reg预优化1: 删除不含load的alloc和store
* llvm mem2reg预优化1: 删除不含load的alloc和store
*
* 1. 删除不含load的alloc和store
* 2. 删除store指令之前的用于作store指令第0个操作数的那些级联指令就冗余了也要删除
* 3. 删除之后可能有些变量的load使用恰好又没有了因此再次从第一步开始循环这里使用不动点法
*
* @note 额外说明:由于删除了级联关系,所以这里的方法有点儿激进;
* 由于删除了级联关系,所以这里的方法有点儿激进;
* 同时也考虑了级联关系时如果调用了函数可能会有side effect所以没有删除调用函数的级联关系
* 而且关于函数参数的alloca不会在指令中删除也不会在value2Alloca中删除;
* 同样地我们不考虑数组和global不过这里的代码是基于value2blocks的在value2blocks中已经考虑了所以不用显式指明
*
* @param [in] void
* @return 无返回值,但满足条件的情况下会对指令进行删除
*=
*/
auto Mem2Reg::preOptimize1() -> void {
SysYPrinter printer(pModule); // 初始化打印机
auto &functions = pModule->getFunctions();
std::cout << "===== Start preOptimize1 =====" << std::endl;
// std::cout << "===== Start preOptimize1 =====" << std::endl;
for (const auto &function : functions) {
auto func = function.second.get();
std::cout << "\nProcessing function: " << func->getName() << std::endl;
// std::cout << "\nProcessing function: " << func->getName() << std::endl;
FunctionAnalysisInfo* funcInfo = controlFlowAnalysis->getFunctionAnalysisInfo(func);
if (!funcInfo) {
std::cerr << "ERROR: No analysis info for function " << func->getName() << std::endl;
// std::cerr << "ERROR: No analysis info for function " << func->getName() << std::endl;
continue;
}
@@ -242,48 +240,45 @@ auto Mem2Reg::preOptimize1() -> void {
auto &vToAllocB = funcInfo->getValue2AllocBlocks();
// 打印初始状态
std::cout << "Initial allocas: " << vToAllocB.size() << std::endl;
for (auto &[val, bb] : vToAllocB) {
std::cout << " Alloca: ";
printer.printInst(dynamic_cast<Instruction *>(val));
std::cout << " in BB: " << bb->getName() << std::endl;
}
// std::cout << "Initial allocas: " << vToAllocB.size() << std::endl;
// for (auto &[val, bb] : vToAllocB) {
// std::cout << " Alloca: ";
// printer.printInst(dynamic_cast<Instruction *>(val));
// std::cout << " in BB: " << bb->getName() << std::endl;
// }
// 阶段1删除无store的alloca
std::cout << "\nPhase 1: Remove unused allocas" << std::endl;
// std::cout << "\nPhase 1: Remove unused allocas" << std::endl;
for (auto iter = vToAllocB.begin(); iter != vToAllocB.end();) {
auto val = iter->first;
auto bb = iter->second;
std::cout << "Checking alloca: ";
printer.printInst(dynamic_cast<Instruction *>(val));
std::cout << " in BB: " << bb->getName() << std::endl;
// std::cout << "Checking alloca: ";
// printer.printInst(dynamic_cast<Instruction *>(val));
// std::cout << " in BB: " << bb->getName() << std::endl;
// 如果该alloca没有对应的store指令且不在函数参数中
// 这里的vToDefB是value2DefBlocksvToUseB是value2UseBlocks
// 打印vToDefB
std::cout << "DefBlocks (" << vToDefB.size() << "):" << std::endl;
for (auto &[val, bbs] : vToDefB) {
std::cout << " ";
printer.printInst(dynamic_cast<Instruction *>(val));
for (const auto &[bb, count] : bbs) {
std::cout << " in BB: " << bb->getName() << " (count: " << count << ")" << std::endl;
}
}
std::cout << vToDefB.count(val) << std::endl;
bool hasStore = false;
// std::cout << "DefBlocks (" << vToDefB.size() << "):" << std::endl;
// for (auto &[val, bbs] : vToDefB) {
// std::cout << " ";
// printer.printInst(dynamic_cast<Instruction *>(val));
// for (const auto &[bb, count] : bbs) {
// std::cout << " in BB: " << bb->getName() << " (count: " << count << ")" << std::endl;
// }
// }
// std::cout << vToDefB.count(val) << std::endl;
if (vToDefB.count(val) == 0U &&
std::find(func->getEntryBlock()->getArguments().begin(),
func->getEntryBlock()->getArguments().end(),
val) == func->getEntryBlock()->getArguments().end()) {
std::cout << " Removing unused alloca: ";
printer.printInst(dynamic_cast<Instruction *>(val));
std::cout << std::endl;
// std::cout << " Removing unused alloca: ";
// printer.printInst(dynamic_cast<Instruction *>(val));
// std::cout << std::endl;
auto tofind = std::find_if(bb->getInstructions().begin(),
bb->getInstructions().end(),
@@ -291,7 +286,7 @@ auto Mem2Reg::preOptimize1() -> void {
return instr.get() == val;
});
if (tofind == bb->getInstructions().end()) {
std::cerr << "ERROR: Alloca not found in BB!" << std::endl;
// std::cerr << "ERROR: Alloca not found in BB!" << std::endl;
++iter;
continue;
}
@@ -305,37 +300,37 @@ auto Mem2Reg::preOptimize1() -> void {
}
// 阶段2删除无load的store
std::cout << "\nPhase 2: Remove dead stores" << std::endl;
// std::cout << "\nPhase 2: Remove dead stores" << std::endl;
bool changed = true;
int iteration = 0;
while (changed) {
changed = false;
iteration++;
std::cout << "\nIteration " << iteration << std::endl;
// std::cout << "\nIteration " << iteration << std::endl;
for (auto iter = vToDefB.begin(); iter != vToDefB.end();) {
auto val = iter->first;
std::cout << "Checking value: ";
printer.printInst(dynamic_cast<Instruction *>(val));
std::cout << std::endl;
// std::cout << "Checking value: ";
// printer.printInst(dynamic_cast<Instruction *>(val));
// std::cout << std::endl;
if (vToUseB.count(val) == 0U) {
std::cout << " Found dead store for value: ";
printer.printInst(dynamic_cast<Instruction *>(val));
std::cout << std::endl;
// std::cout << " Found dead store for value: ";
// printer.printInst(dynamic_cast<Instruction *>(val));
// std::cout << std::endl;
auto blocks = funcInfo->getDefBlocksByValue(val);
for (auto block : blocks) {
std::cout << " Processing BB: " << block->getName() << std::endl;
// std::cout << " Processing BB: " << block->getName() << std::endl;
// printer.printBlock(block); // 打印基本块内容
auto &instrs = block->getInstructions();
for (auto it = instrs.begin(); it != instrs.end();) {
if ((*it)->isStore() && (*it)->getOperand(1) == val) {
std::cout << " Removing store: ";
printer.printInst(it->get());
// std::cout << " Removing store: ";
// printer.printInst(it->get());
std::cout << std::endl;
auto valUsedByStore = dynamic_cast<Instruction *>((*it)->getOperand(0));
@@ -344,9 +339,9 @@ auto Mem2Reg::preOptimize1() -> void {
if (valUsedByStore != nullptr &&
valUsedByStore->getUses().size() == 1 &&
valUsedByStore->getUses().front()->getUser() == (*it).get()) {
std::cout << " Cascade deleting: ";
printer.printInst(valUsedByStore);
std::cout << std::endl;
// std::cout << " Cascade deleting: ";
// printer.printInst(valUsedByStore);
// std::cout << std::endl;
cascade(valUsedByStore, changed, func, block, instrs);
}
@@ -364,9 +359,9 @@ auto Mem2Reg::preOptimize1() -> void {
val) == func->getEntryBlock()->getArguments().end()) {
auto bb = funcInfo->getAllocBlockByValue(val);
if (bb != nullptr) {
std::cout << " Removing alloca: ";
printer.printInst(dynamic_cast<Instruction *>(val));
std::cout << " in BB: " << bb->getName() << std::endl;
// std::cout << " Removing alloca: ";
// printer.printInst(dynamic_cast<Instruction *>(val));
// std::cout << " in BB: " << bb->getName() << std::endl;
funcInfo->removeValue2AllocBlock(val);
auto tofind = std::find_if(bb->getInstructions().begin(),
@@ -389,11 +384,11 @@ auto Mem2Reg::preOptimize1() -> void {
}
}
}
std::cout << "===== End preOptimize1 =====" << std::endl;
// std::cout << "===== End preOptimize1 =====" << std::endl;
}
/**
* @brief llvm mem2reg预优化2: 针对某个变量的Defblocks只有一个块的情况
* llvm mem2reg预优化2: 针对某个变量的Defblocks只有一个块的情况
*
* 1. 该基本块最后一次对该变量的store指令后的所有对该变量的load指令都可以替换为该基本块最后一次store指令的第0个操作数
* 2. 以该基本块为必经结点的结点集合中的对该变量的load指令都可以替换为该基本块最后一次对该变量的store指令的第0个操作数
@@ -402,12 +397,9 @@ auto Mem2Reg::preOptimize1() -> void {
* 4.
* 如果对该value的所有load都替换掉了对于该变量剩下还有store的话就转换成了preOptimize1的情况再调用preOptimize1进行删除
*
* @note 额外说明:同样有点儿激进;
* 同样不考虑数组和全局变量因为这些变量不会被mem2reg优化在value2blocks中已经考虑了所以不用显式指明
* 替换的操作采用了UD链进行简化和效率的提升
*
* @param [in] void
* @return 无返回值,但满足条件的情况下会对指令的操作数进行替换以及对指令进行删除
*/
auto Mem2Reg::preOptimize2() -> void {
auto &functions = pModule->getFunctions();
@@ -570,14 +562,12 @@ auto Mem2Reg::preOptimize3() -> void {
}
/**
* @brief 为所有变量的定义块集合的迭代支配边界插入phi结点
* 为所有变量的定义块集合的迭代支配边界插入phi结点
*
* insertPhi是mem2reg的核心之一这里是对所有变量的迭代支配边界的phi结点插入无参数也无返回值
* 同样跳过对数组和全局变量的处理因为这些变量不会被mem2reg优化刚好这里在计算value2DefBlocks时已经跳过了所以不需要再显式处理了
* 同时我们进行了剪枝处理只有在基本块入口活跃的变量才插入phi函数
*
* @param [in] void
* @return 无返回值但是会在每个变量的迭代支配边界上插入phi结点
*/
auto Mem2Reg::insertPhi() -> void {
auto &functions = pModule->getFunctions();
@@ -604,15 +594,11 @@ auto Mem2Reg::insertPhi() -> void {
}
/**
* @brief 重命名
* 重命名
*
* 重命名是mem2reg的核心之二这里是对单个块的重命名递归实现
* 同样跳过对数组和全局变量的处理因为这些变量不会被mem2reg优化
*
* @param [in] block 一个基本块
* @param [in] count 计数器,用于给变量重命名,地址传递
* @param [in] stacks 用于存储变量的栈,地址传递
* @return 无返回值
*/
auto Mem2Reg::rename(BasicBlock *block, std::unordered_map<Value *, int> &count,
std::unordered_map<Value *, std::stack<Instruction *>> &stacks) -> void {
@@ -712,12 +698,10 @@ auto Mem2Reg::rename(BasicBlock *block, std::unordered_map<Value *, int> &count,
}
/**
* @brief 重命名所有块
* 重命名所有块
*
* 调用rename自上而下实现所有rename
*
* @param [in] void
* @return 无返回值
*/
auto Mem2Reg::renameAll() -> void {
auto &functions = pModule->getFunctions();
@@ -736,20 +720,17 @@ auto Mem2Reg::renameAll() -> void {
}
/**
* @brief mem2reg对外的接口
* mem2reg对外的接口
*
* 静态单一赋值 + mem2reg等pass的逻辑组合
*
* @param [in] void
* @return 无返回值
*/
auto Mem2Reg::mem2regPipeline() -> void {
// 首先进行mem2reg的前置分析
controlFlowAnalysis = new ControlFlowAnalysis(pModule);
activeVarAnalysis = new ActiveVarAnalysis();
// 控制流分析
controlFlowAnalysis->clear();
controlFlowAnalysis->runControlFlowAnalysis();
// 活跃变量分析
activeVarAnalysis->clear();
dataFlowAnalysisUtils.addBackwardAnalyzer(activeVarAnalysis);
dataFlowAnalysisUtils.backwardAnalyze(pModule);
@@ -775,13 +756,10 @@ auto Mem2Reg::mem2regPipeline() -> void {
}
/**
* @brief 计算块n是块s的第几个前驱
* 计算块n是块s的第几个前驱
*
* helperfunction没有返回值但是会将dom和other的交集赋值给dom
*
* @param [in] n 基本块n是s的前驱之一
* @param [in] s 基本块s是n的后继之一
* @return 返回n是s的第几个前驱
*/
auto Mem2Reg::getPredIndex(BasicBlock *n, BasicBlock *s) -> int {
int index = 0;

File diff suppressed because it is too large Load Diff

View File

@@ -6,60 +6,93 @@
#include <vector>
#include <map>
#include <set>
#include <memory>
#include <iostream>
#include <functional> // For std::function
namespace sysy {
class RISCv32CodeGen {
public:
explicit RISCv32CodeGen(Module* mod) : module(mod) {}
std::string code_gen(); // 生成模块的汇编代码
private:
Module* module;
// 物理寄存器
enum class PhysicalReg {
T0, T1, T2, T3, T4, T5, T6, // x5-x7, x28-x31
A0, A1, A2, A3, A4, A5, A6, A7 // x10-x17
};
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) {}
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
};
// RISC-V 指令
struct RISCv32Inst {
std::string opcode;
std::vector<Operand> operands;
RISCv32Inst(const std::string& op, const std::vector<Operand>& ops)
: opcode(op), operands(ops) {}
// 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<Value*, PhysicalReg> reg_map; // 虚拟寄存器到物理寄存器的映射
std::map<Value*, int> stack_map; // 虚拟寄存器到堆栈槽的映射
int stack_size; // 堆栈帧大小
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
};
// 后端方法
RISCv32CodeGen(Module* mod) : module(mod) {}
std::string code_gen();
std::string module_gen();
std::string function_gen(Function* func);
std::string basicBlock_gen(BasicBlock* bb, const RegAllocResult& alloc);
std::vector<RISCv32Inst> instruction_gen(Instruction* inst);
// 修改 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);
std::map<Instruction*, std::set<Value*>> liveness_analysis(Function* func);
std::map<Value*, std::set<Value*>> build_interference_graph(
const std::map<Instruction*, std::set<Value*>>& live_sets);
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_";
};
} // 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){
// 更新作用域
module->enterNewScope();
HasReturnInst = false;
auto name = ctx->Ident()->getText();
std::vector<Type *> paramTypes;
@@ -243,6 +244,18 @@ std::any SysYIRGenerator::visitFuncDef(SysYParser::FuncDefContext *ctx){
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();
return std::any();
@@ -310,7 +323,7 @@ std::any SysYIRGenerator::visitIfStmt(SysYParser::IfStmtContext *ctx) {
builder.popTrueBlock();
builder.popFalseBlock();
labelstring << "then.L" << builder.getLabelIndex();
labelstring << "if_then.L" << builder.getLabelIndex();
thenBlock->setName(labelstring.str());
labelstring.str("");
function->addBasicBlock(thenBlock);
@@ -329,7 +342,7 @@ std::any SysYIRGenerator::visitIfStmt(SysYParser::IfStmtContext *ctx) {
builder.createUncondBrInst(exitBlock, {});
BasicBlock::conectBlocks(builder.getBasicBlock(), exitBlock);
labelstring << "else.L" << builder.getLabelIndex();
labelstring << "if_else.L" << builder.getLabelIndex();
elseBlock->setName(labelstring.str());
labelstring.str("");
function->addBasicBlock(elseBlock);
@@ -343,9 +356,10 @@ std::any SysYIRGenerator::visitIfStmt(SysYParser::IfStmtContext *ctx) {
ctx->stmt(1)->accept(this);
module->leaveScope();
}
builder.createUncondBrInst(exitBlock, {});
BasicBlock::conectBlocks(builder.getBasicBlock(), exitBlock);
labelstring << "exit.L" << builder.getLabelIndex();
labelstring << "if_exit.L" << builder.getLabelIndex();
exitBlock->setName(labelstring.str());
labelstring.str("");
function->addBasicBlock(exitBlock);
@@ -358,7 +372,7 @@ std::any SysYIRGenerator::visitIfStmt(SysYParser::IfStmtContext *ctx) {
builder.popTrueBlock();
builder.popFalseBlock();
labelstring << "then.L" << builder.getLabelIndex();
labelstring << "if_then.L" << builder.getLabelIndex();
thenBlock->setName(labelstring.str());
labelstring.str("");
function->addBasicBlock(thenBlock);
@@ -374,7 +388,7 @@ std::any SysYIRGenerator::visitIfStmt(SysYParser::IfStmtContext *ctx) {
}
BasicBlock::conectBlocks(builder.getBasicBlock(), exitBlock);
labelstring << "exit.L" << builder.getLabelIndex();
labelstring << "if_exit.L" << builder.getLabelIndex();
exitBlock->setName(labelstring.str());
labelstring.str("");
function->addBasicBlock(exitBlock);
@@ -390,7 +404,7 @@ std::any SysYIRGenerator::visitWhileStmt(SysYParser::WhileStmtContext *ctx) {
Function* function = builder.getBasicBlock()->getParent();
std::stringstream labelstring;
labelstring << "head.L" << builder.getLabelIndex();
labelstring << "while_head.L" << builder.getLabelIndex();
BasicBlock *headBlock = function->addBasicBlock(labelstring.str());
labelstring.str("");
BasicBlock::conectBlocks(curBlock, headBlock);
@@ -406,7 +420,7 @@ std::any SysYIRGenerator::visitWhileStmt(SysYParser::WhileStmtContext *ctx) {
builder.popTrueBlock();
builder.popFalseBlock();
labelstring << "body.L" << builder.getLabelIndex();
labelstring << "while_body.L" << builder.getLabelIndex();
bodyBlock->setName(labelstring.str());
labelstring.str("");
function->addBasicBlock(bodyBlock);
@@ -430,7 +444,7 @@ std::any SysYIRGenerator::visitWhileStmt(SysYParser::WhileStmtContext *ctx) {
builder.popBreakBlock();
builder.popContinueBlock();
labelstring << "exit.L" << builder.getLabelIndex();
labelstring << "while_exit.L" << builder.getLabelIndex();
exitBlock->setName(labelstring.str());
labelstring.str("");
function->addBasicBlock(exitBlock);
@@ -441,7 +455,7 @@ std::any SysYIRGenerator::visitWhileStmt(SysYParser::WhileStmtContext *ctx) {
std::any SysYIRGenerator::visitBreakStmt(SysYParser::BreakStmtContext *ctx) {
BasicBlock* breakBlock = builder.getBreakBlock();
builder.pushBreakBlock(breakBlock);
builder.createUncondBrInst(breakBlock, {});
BasicBlock::conectBlocks(builder.getBasicBlock(), breakBlock);
return std::any();
}
@@ -449,6 +463,7 @@ std::any SysYIRGenerator::visitBreakStmt(SysYParser::BreakStmtContext *ctx) {
std::any SysYIRGenerator::visitContinueStmt(SysYParser::ContinueStmtContext *ctx) {
BasicBlock* continueBlock = builder.getContinueBlock();
builder.createUncondBrInst(continueBlock, {});
BasicBlock::conectBlocks(builder.getBasicBlock(), continueBlock);
return std::any();
}
@@ -476,6 +491,7 @@ std::any SysYIRGenerator::visitReturnStmt(SysYParser::ReturnStmtContext *ctx) {
}
}
builder.createReturnInst(returnValue);
HasReturnInst = true;
return std::any();
}

View File

@@ -1,17 +1,10 @@
/**
* @file: Sysyoptimization.cpp
* @brief CFG优化
* @Author : Ixeux email:you@domain.com
* @Version : 1.0
* @Creat Date : 2024-08-10
*
*/
#include "SysYIROptPre.h"
#include <cassert>
#include <list>
#include <map>
#include <memory>
#include <string>
#include <iostream>
#include "IR.h"
#include "IRBuilder.h"
@@ -466,11 +459,13 @@ void SysYOptPre::SysYAddReturn() {
// 如果基本块没有后继块,则添加一个返回指令
if (block->getNumInstructions() == 0) {
pBuilder->setPosition(block.get(), block->end());
pBuilder->createReturnInst({});
pBuilder->createReturnInst();
}
auto thelastinst = block->getInstructions().end();
--thelastinst;
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());
// TODO: 如果int float函数缺少返回值是否需要报错
if (func->getReturnType()->isInt()) {
@@ -478,7 +473,7 @@ void SysYOptPre::SysYAddReturn() {
} else if (func->getReturnType()->isFloat()) {
pBuilder->createReturnInst(ConstantValue::get(0.0F));
} else {
pBuilder->createReturnInst({});
pBuilder->createReturnInst();
}
}
}

View File

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

View File

@@ -0,0 +1,39 @@
#pragma once
#include "IR.h"
#include "SysYIRAnalyser.h"
#include "SysYIRPrinter.h"
namespace sysy {
class DeadCodeElimination {
private:
Module *pModule;
ControlFlowAnalysis *pCFA; // 控制流分析指针
ActiveVarAnalysis *pAVA; // 活跃变量分析指针
DataFlowAnalysisUtils dataFlowAnalysisUtils; // 数据流分析工具类
public:
explicit DeadCodeElimination(Module *pMoudle,
ControlFlowAnalysis *pCFA = nullptr,
ActiveVarAnalysis *pAVA = nullptr)
: pModule(pMoudle), pCFA(pCFA), pAVA(pAVA), dataFlowAnalysisUtils() {} // 构造函数
// TODO根据参数传入的passes来运行不同的死代码删除流程
// void runDCEPipeline(const std::vector<std::string>& passes = {
// "dead-store", "redundant-load-store", "dead-load", "dead-alloca", "dead-global"
// });
void runDCEPipeline(); // 运行死代码删除
void eliminateDeadStores(Function* func, bool& changed); // 消除无用存储
void eliminateDeadLoads(Function* func, bool& changed); // 消除无用加载
void eliminateDeadAllocas(Function* func, bool& changed); // 消除无用内存分配
void eliminateDeadGlobals(bool& changed); // 消除无用全局变量
void eliminateDeadIndirectiveAllocas(Function* func, bool& changed); // 消除无用间接内存分配(phi节点)
void eliminateDeadRedundantLoadStore(Function* func, bool& changed); // 消除冗余加载和存储
bool isGlobal(Value *val);
bool isArr(Value *val);
void usedelete(Instruction *instr);
};
} // namespace sysy

View File

@@ -883,6 +883,10 @@ public:
assert(false);
}
} ///< 根据指令类型进行二元计算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
//! The return statement

View File

@@ -263,7 +263,7 @@ class IRBuilder {
auto inst = new AllocaInst(type, dims, parent, name);
assert(inst);
return inst;
} ///< 创建不插入指令列表的分配指令
} ///< 创建不插入指令列表的分配指令[仅用于phi指令]
LoadInst * createLoadInst(Value *pointer, const std::vector<Value *> &indices = {}, const std::string &name = "") {
std::string newName;
if (name.empty()) {

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

@@ -17,13 +17,14 @@ class Mem2Reg {
private:
Module *pModule;
IRBuilder *pBuilder;
ActiveVarAnalysis *activeVarAnalysis; // 活跃变量分析
ControlFlowAnalysis *controlFlowAnalysis; // 控制流分析
ActiveVarAnalysis *activeVarAnalysis; // 活跃变量分析
DataFlowAnalysisUtils dataFlowAnalysisUtils;
public:
Mem2Reg(Module *pMoudle, IRBuilder *pBuilder) :
pModule(pMoudle), pBuilder(pBuilder), activeVarAnalysis(nullptr), controlFlowAnalysis(nullptr), dataFlowAnalysisUtils()
Mem2Reg(Module *pMoudle, IRBuilder *pBuilder,
ControlFlowAnalysis *pCFA = nullptr, ActiveVarAnalysis *pAVA = nullptr) :
pModule(pMoudle), pBuilder(pBuilder), controlFlowAnalysis(pCFA), activeVarAnalysis(pAVA), dataFlowAnalysisUtils()
{} // 初始化函数
void mem2regPipeline(); ///< mem2reg

View File

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

View File

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

View File

@@ -10,12 +10,17 @@ using namespace antlr4;
#include "SysYIRGenerator.h"
#include "SysYIRPrinter.h"
#include "SysYIROptPre.h"
#include "RISCv64Backend.h"
#include "SysYIRAnalyser.h"
#include "DeadCodeElimination.h"
#include "Mem2Reg.h"
#include "Reg2Mem.h"
// #include "LLVMIRGenerator.h"
using namespace sysy;
int DEBUG = 0;
int DEEPDEBUG = 0;
static string argStopAfter;
static string argInputFile;
static bool argFormat = false;
@@ -25,7 +30,7 @@ void usage(int code = EXIT_FAILURE) {
"Supported options:\n"
" -h \tprint help message and exit\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;
exit(code);
}
@@ -76,23 +81,69 @@ int main(int argc, char **argv) {
// visit AST to generate IR
if (argStopAfter == "ir") {
SysYIRGenerator generator;
generator.visitCompUnit(moduleAST);
SysYIRGenerator generator;
generator.visitCompUnit(moduleAST);
if (argStopAfter == "ir" || argStopAfter == "ird") {
if (argStopAfter == "ird") {
DEBUG = 1;
}
auto moduleIR = generator.get();
SysYPrinter printer(moduleIR);
printer.printIR();
if (DEBUG) {
cout << "=== Original IR ===\n";
printer.printIR();
}
auto builder = generator.getBuilder();
SysYOptPre optPre(moduleIR, builder);
optPre.SysYOptimizateAfterIR();
Mem2Reg mem2reg(moduleIR, builder);
ControlFlowAnalysis cfa(moduleIR);
cfa.init();
ActiveVarAnalysis ava;
ava.init(moduleIR);
if (DEBUG) {
cout << "=== After CFA & AVA ===\n";
printer.printIR();
}
DeadCodeElimination dce(moduleIR, &cfa, &ava);
dce.runDCEPipeline();
if (DEBUG) {
cout << "=== After 1st DCE ===\n";
printer.printIR();
}
Mem2Reg mem2reg(moduleIR, builder, &cfa, &ava);
mem2reg.mem2regPipeline();
printer.printIR();
if (DEBUG) {
cout << "=== After Mem2Reg ===\n";
printer.printIR();
}
Reg2Mem reg2mem(moduleIR, builder);
reg2mem.DeletePhiInst();
if (DEBUG) {
cout << "=== After Reg2Mem ===\n";
printer.printIR();
}
dce.runDCEPipeline();
if (DEBUG) {
cout << "=== After 2nd DCE ===\n";
printer.printIR();
}
cout << "=== Final IR ===\n";
printer.printIR();
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;
}

View File

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

View File

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

View File

@@ -7,7 +7,7 @@ int mul(int x, int y) {
int main(){
int a, b;
a = 10;
b = 0;
a = mul(a, b);
return a + b;
b = 3;
a = mul(a, b); //60
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