[midend-mem2reg]目前reg2mem仅将函数参数和phi指令及其对应指令进行reg2mem,旨在消除phi指令。

This commit is contained in:
rain2133
2025-07-29 15:30:28 +08:00
parent fff19ca1ea
commit 15fe69187a

View File

@ -39,13 +39,23 @@ bool Reg2MemContext::isPromotableToMemory(Value *val) {
// }
// std::cout << "Checking if value is promotable to memory: " << val->getName() << std::endl;
}
if (dynamic_cast<Argument *>(val) || dynamic_cast<Instruction *>(val)) {
// 如果值已经是指针类型,则通常不为其分配额外的内存,因为它已经是一个地址。
// (除非我们想将其值也存储起来,这通常不用于 Reg2Mem
// // Reg2Mem 关注的是将非指针值从寄存器语义转换为内存语义。
if (val->getType()->isPointer()) {
return false;
}
// if (dynamic_cast<Argument *>(val) || dynamic_cast<Instruction *>(val)) {
// // 如果值已经是指针类型,则通常不为其分配额外的内存,因为它已经是一个地址。
// // (除非我们想将其值也存储起来,这通常不用于 Reg2Mem
// // // Reg2Mem 关注的是将非指针值从寄存器语义转换为内存语义。
// if (val->getType()->isPointer()) {
// return false;
// }
// return true;
// }
// 1. 如果是 Argument则可以提升到内存
if (dynamic_cast<Argument *>(val)) {
// 参数类型i32, i32* 等)都可以为其分配内存
// 因为它们在 Mem2Reg 逆操作中,被认为是从寄存器分配到内存
return true;
}
if (dynamic_cast<PhiInst *>(val)) {
// Phi 指令的结果也是一个 SSA 值,需要将其转换为 Load/Store
return true;
}
return false;
@ -62,18 +72,17 @@ void Reg2MemContext::allocateMemoryForSSAValues(Function *func) {
builder->setPosition(entryBlock, entryBlock->begin()); // 确保在入口块的开始位置插入
for (auto arg : func->getArguments()) {
// 默认情况下,将所有参数是提升到内存
// if (isPromotableToMemory(arg)) {
if (isPromotableToMemory(arg)) {
// 参数的类型就是 AllocaInst 需要分配的类型
AllocaInst *alloca = builder->createAllocaInst(Type::getPointerType(arg->getType()), {}, arg->getName() + ".reg2mem");
// 将参数值 store 到 alloca 中 (这是 Mem2Reg 逆转的关键一步)
builder->createStoreInst(arg, alloca);
valueToAllocaMap[arg] = alloca;
// 确保 alloca 位于入口块的顶部,但在所有参数的 store 指令之前
// 通常 alloca 都在 entry block 的最开始
// 这里我们只是创建,并让 builder 决定插入位置 (通常在当前插入点)
// 如果需要严格控制顺序,可能需要手动 insert 到 instruction list
// }
}
}
// 2. 为指令结果分配内存
@ -99,25 +108,27 @@ void Reg2MemContext::allocateMemoryForSSAValues(Function *func) {
}
}
}
// 统一将所有新创建的 AllocaInst 移到入口块的最前面,
// 在参数的 AllocaInst 和 Store 指令之后。
// 这部分可能需要根据你的 IR 结构来调整。
// 假设 builder.createAllocaInst 默认在当前 builder position 插入。
// 如果 builder 只能在当前位置插入,可能需要收集这些 alloca然后在最后手动移动。
// 更简单的方式是:在 builder 创建 alloca 时,将 position 设置到 entryBlock 的开头。
builder->setPosition(entryBlock, entryBlock->begin());
// 再次循环 valueToAllocaMap如果 alloca 是新创建的,确保它在正确位置
// 对于已经创建的 alloca这里不需要重新创建
for (auto const &[val, alloca_inst] : valueToAllocaMap) {
// 假设 alloca_inst 还没有被插入或者需要移动到开头
// 你的 builder 可能需要一个方法来将指令移动到特定位置
// 如果 builder.createAllocaInst 总是插入到当前位置,那么需要在循环之前设置好 builder 的位置
Instruction *firstNonAlloca = nullptr;
for (auto instIter = entryBlock->getInstructions().begin(); instIter != entryBlock->getInstructions().end(); instIter++) {
if (!dynamic_cast<AllocaInst*>(instIter->get())) {
firstNonAlloca = instIter->get();
break;
}
}
// 再次设置 builder 位置到入口块的末尾,以便后续插入 Store 等指令
// 由于消除了fallthrough所有入口块的末尾一定是一个 terminator
// 所以可以安全地将位置设置到末尾的terminator。
// 这将确保后续的 Store 指令插入到入口块的末尾。
if (firstNonAlloca) {
builder->setPosition(entryBlock, entryBlock->findInstIterator(firstNonAlloca));
} else { // 如果 entryBlock 只有 AllocaInst 或为空,则设置到 terminator 前
builder->setPosition(entryBlock, entryBlock->terminator());
}
// 插入所有参数的初始 Store 指令
for (auto arg : func->getArguments()) {
if (valueToAllocaMap.count(arg)) { // 检查是否为其分配了 alloca
builder->createStoreInst(arg, valueToAllocaMap[arg]);
}
}
builder->setPosition(entryBlock, entryBlock->terminator());
}