[midend-mem2reg]目前reg2mem仅将函数参数和phi指令及其对应指令进行reg2mem,旨在消除phi指令。
This commit is contained in:
@ -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());
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user