[midend]修改了removeinst方法,应对不同的使用情况,增加user析构函数使得user对象销毁顺带销毁其use关系销毁,重构usedelete方法封装指令删除和use关系删除

This commit is contained in:
rain2133
2025-07-31 21:10:20 +08:00
parent aed4577490
commit ef09bc70d4
2 changed files with 86 additions and 14 deletions

View File

@ -599,7 +599,7 @@ public:
prev->addSuccessor(next);
next->addPredecessor(prev);
}
void removeInst(iterator pos) { instructions.erase(pos); }
iterator removeInst(iterator pos) { return instructions.erase(pos); }
void removeInst(Instruction *inst) {
auto pos = std::find_if(instructions.begin(), instructions.end(),
[inst](const std::unique_ptr<Instruction> &i) { return i.get() == inst; });
@ -626,6 +626,21 @@ class User : public Value {
explicit User(Type *type, const std::string &name = "") : Value(type, name) {}
public:
~User() override {
// 当 User 对象被销毁时例如LoadInst 或 StoreInst 被删除时),
// 它必须通知它所使用的所有 Value将对应的 Use 关系从它们的 uses 列表中移除。
// 这样可以防止 Value 的 uses 列表中出现悬空的 Use 对象。
for (const auto &use_ptr : operands) {
// 确保 use_ptr 非空,并且其内部指向的 Value* 也非空
// (虽然通常情况下不会为空,但为了健壮性考虑)
if (use_ptr && use_ptr->getValue()) {
use_ptr->getValue()->removeUse(use_ptr);
}
}
// operands 向量本身是 std::vector<std::shared_ptr<Use>>
// 在此析构函数结束后operands 向量会被销毁,其内部的 shared_ptr 也会被释放,
// 如果 shared_ptr 引用计数降为0Use 对象本身也会被销毁。
}
unsigned getNumOperands() const { return operands.size(); } ///< 获取操作数数量
auto operand_begin() const { return operands.begin(); } ///< 返回操作数列表的开头迭代器
auto operand_end() const { return operands.end(); } ///< 返回操作数列表的结尾迭代器

View File

@ -22,23 +22,70 @@ public:
}
};
// 仅仅删除use关系
static void usedelete(Instruction *instr) {
for (auto &use : instr->getOperands()) {
Value* val = use->getValue();
val->removeUse(use);
static void __internal_handle_instruction_deletion_uses(Instruction *inst_to_delete) {
assert(inst_to_delete && "Instruction to delete cannot be null.");
// 确保指令有一个父基本块,才能进行后续的物理删除
BasicBlock *parentBlock = inst_to_delete->getParent();
assert(parentBlock && "Instruction must have a parent BasicBlock to be deleted.");
// 如果指令定义了一个值并且仍然有使用者(即它的 getUses() 不为空),
// 那么将其所有用途替换为对应类型的 UndefinedValue。
// 这是一种安全的做法,避免悬空指针,同时表示这些值是未定义的。
// 如果指令本身不产生值(如 StoreInst, BranchInst 等),或者没有用户,
// getUses().empty() 会为 truereplaceAllUsesWith 将是一个空操作,这也是正确的。
if (!inst_to_delete->getUses().empty()) {
// UndefinedValue::get(Type*) 需要一个 Type* 参数,确保类型匹配。
// 例如,如果 inst_to_delete 是 alloca i32那么它的类型是 PointerType (i32*)。
// UndefinedValue::get 的参数应是 i32* 类型。
std::cout << "Replacing uses of instruction " << inst_to_delete->getName()
<< " with UndefinedValue." << std::endl;
inst_to_delete->replaceAllUsesWith(UndefinedValue::get(inst_to_delete->getType()));
}
// 至此inst_to_delete 在语义上已不再被其他活跃指令使用。
}
// 删除use关系并删除指令
static void usedelete_withinstdelte(Instruction *instr) {
for (auto &use : instr->getOperands()) {
Value* val = use->getValue();
val->removeUse(use);
}
instr->getParent()->removeInst(instr);
// 版本1: 传入 Instruction*
static void usedelete(Instruction *inst) {
__internal_handle_instruction_deletion_uses(inst);
// 物理删除指令。BasicBlock::removeInst(Instruction*) 会在内部查找指令。
// 这行调用会触发 inst 指针所指向的 Instruction 对象的析构。
inst->getParent()->removeInst(inst);
}
// 版本2: 传入 BasicBlock::iterator
static BasicBlock::iterator usedelete(BasicBlock::iterator inst_it) {
// 获取 unique_ptr 中的原始 Instruction 指针。
// 必须在物理删除操作之前获取因为物理删除后迭代器和unique_ptr可能失效。
Instruction *inst_to_delete = inst_it->get();
__internal_handle_instruction_deletion_uses(inst_to_delete);
// 物理删除指令。BasicBlock::removeInst(iterator pos) 更适合 std::list
// 并且会返回一个新的迭代器,指向被删除元素之后的位置。
// 这行调用会触发 inst_to_delete 指向的 Instruction 对象的析构。
BasicBlock *parentBlock = inst_to_delete->getParent(); // 再次获取父块,以防万一
// 这里调用的是 BasicBlock 中修改后的 removeInst(iterator pos) 版本
return parentBlock->removeInst(inst_it);
}
// 仅仅删除use关系
// static void usedelete(Instruction *instr) {
// for (auto &use : instr->getOperands()) {
// Value* val = use->getValue();
// val->removeUse(use);
// }
// }
// // 删除use关系并删除指令
// static void usedelete_withinstdelte(Instruction *instr) {
// for (auto &use : instr->getOperands()) {
// Value* val = use->getValue();
// val->removeUse(use);
// }
// instr->getParent()->removeInst(instr);
// }
// 判断是否是全局变量
static bool isGlobal(Value *val) {
auto gval = dynamic_cast<GlobalValue *>(val);
@ -47,7 +94,17 @@ public:
// 判断是否是数组
static bool isArr(Value *val) {
auto aval = dynamic_cast<AllocaInst *>(val);
return aval != nullptr && aval->getNumDims() != 0;
// 如果是 AllocaInst 且通过Type::isArray()判断为数组类型
return aval && aval->getType()->as<PointerType>()->getBaseType()->isArray();
}
// 判断是否是指向数组的指针
static bool isArrPointer(Value *val) {
auto aval = dynamic_cast<AllocaInst *>(val);
// 如果是 AllocaInst 且通过Type::isPointer()判断为指针;
auto baseType = aval->getType()->as<PointerType>()->getBaseType();
// 在sysy中函数的数组参数会退化成指针
// 所以当AllocaInst的basetype是PointerType时一维数组或者是指向ArrayType的PointerType多位数组返回true
return aval && (baseType->isPointer() || baseType->as<PointerType>()->getBaseType()->isArray());
}
};