[midend-mem2reg]Reg2Mem建立完成runit测试127/140,reg2mem基本思路:函数参数默认降级到内存,有结果的指令被降级的内存

This commit is contained in:
rain2133
2025-07-29 14:34:16 +08:00
parent 3dc4b28c92
commit fff19ca1ea
3 changed files with 18 additions and 13 deletions

View File

@ -1,5 +1,6 @@
#include "Reg2Mem.h"
#include "SysYIROptUtils.h" // 如果有的话
#include "SysYIROptUtils.h"
#include "SysYIRPrinter.h"
extern int DEBUG; // 全局调试标志
@ -33,15 +34,15 @@ void Reg2MemContext::run(Function *func) {
bool Reg2MemContext::isPromotableToMemory(Value *val) {
// 参数和指令结果是 SSA 值
if(DEBUG){
if(val->getName() == ""){
assert(false && "Value name should not be empty in Reg2MemContext::isPromotableToMemory");
}
std::cout << "Checking if value is promotable to memory: " << val->getName() << std::endl;
// if(val->getName() == ""){
// assert(false && "Value name should not be empty in Reg2MemContext::isPromotableToMemory");
// }
// std::cout << "Checking if value is promotable to memory: " << val->getName() << std::endl;
}
if (dynamic_cast<Argument *>(val) || dynamic_cast<Instruction *>(val)) {
// 如果值已经是指针类型,则通常不为其分配额外的内存,因为它已经是一个地址。
// (除非我们想将其值也存储起来,这通常不用于 Reg2Mem
// Reg2Mem 关注的是将非指针值从寄存器语义转换为内存语义。
// // Reg2Mem 关注的是将非指针值从寄存器语义转换为内存语义。
if (val->getType()->isPointer()) {
return false;
}
@ -60,9 +61,10 @@ void Reg2MemContext::allocateMemoryForSSAValues(Function *func) {
// 1. 为函数参数分配内存
builder->setPosition(entryBlock, entryBlock->begin()); // 确保在入口块的开始位置插入
for (auto arg : func->getArguments()) {
if (isPromotableToMemory(arg)) {
// 默认情况下,将所有参数是提升到内存
// if (isPromotableToMemory(arg)) {
// 参数的类型就是 AllocaInst 需要分配的类型
AllocaInst *alloca = builder->createAllocaInst(arg->getType(), {});
AllocaInst *alloca = builder->createAllocaInst(Type::getPointerType(arg->getType()), {}, arg->getName() + ".reg2mem");
// 将参数值 store 到 alloca 中 (这是 Mem2Reg 逆转的关键一步)
builder->createStoreInst(arg, alloca);
valueToAllocaMap[arg] = alloca;
@ -71,17 +73,19 @@ void Reg2MemContext::allocateMemoryForSSAValues(Function *func) {
// 通常 alloca 都在 entry block 的最开始
// 这里我们只是创建,并让 builder 决定插入位置 (通常在当前插入点)
// 如果需要严格控制顺序,可能需要手动 insert 到 instruction list
}
// }
}
// 2. 为指令结果分配内存
// 遍历所有基本块和指令,找出所有需要分配 Alloca 的指令结果
for (auto &bb : func->getBasicBlocks()) {
for (auto &inst : bb->getInstructions_Range()) {
// SysYPrinter::printInst(inst.get());
// 只有有结果的指令才可能需要分配内存
// (例如 BinaryInst, CallInst, LoadInst, PhiInst 等)
// StoreInst, BranchInst, ReturnInst 等没有结果的指令不需要
if (inst.get()->getType()->isVoid()) { // 没有返回值的指令
if (dynamic_cast<AllocaInst*>(inst.get()) || inst.get()->getType()->isVoid()) {
continue;
}
@ -90,7 +94,7 @@ void Reg2MemContext::allocateMemoryForSSAValues(Function *func) {
// AllocaInst 应该在入口块,而不是当前指令所在块
// 这里我们只是创建,并稍后调整其位置
// 通常的做法是在循环结束后统一将 alloca 放到 entryBlock 的顶部
AllocaInst *alloca = builder->createAllocaInst(inst.get()->getType(), {});
AllocaInst *alloca = builder->createAllocaInst(Type::getPointerType(inst.get()->getType()), {}, inst.get()->getName() + ".reg2mem");
valueToAllocaMap[inst.get()] = alloca;
}
}

View File

@ -712,7 +712,7 @@ std::any SysYIRGenerator::visitReturnStmt(SysYParser::ReturnStmtContext *ctx) {
}
Type* funcType = builder.getBasicBlock()->getParent()->getReturnType();
if (funcType!= returnValue->getType() && returnValue != nullptr) {
if (returnValue != nullptr && funcType!= returnValue->getType()) {
ConstantValue * constValue = dynamic_cast<ConstantValue *>(returnValue);
if (constValue != nullptr) {
if (funcType == Type::getFloatType()) {

View File

@ -364,7 +364,8 @@ void SysYPrinter::printInst(Instruction *pInst) {
// AllocaInst 的类型现在应该是一个 PointerType指向正确的 ArrayType 或 ScalarType
// 例如alloca i32, align 4 或者 alloca [10 x i32], align 4
auto allocatedType = dynamic_cast<PointerType *>(allocaInst->getType())->getBaseType();
// auto allocatedType = dynamic_cast<PointerType *>(allocaInst->getType())->getBaseType();
auto allocatedType = allocaInst->getAllocatedType();
printType(allocatedType);
// 仍然打印维度信息,如果存在的话