diff --git a/include/olc/ir/IR.h b/include/olc/ir/IR.h index 3bdc1ba32519194ece391934ab5f9ee82b7a6d04..86b2cf93ab01de406950c6b7ad6272fd4eaa08ad 100644 --- a/include/olc/ir/IR.h +++ b/include/olc/ir/IR.h @@ -113,6 +113,7 @@ struct User : public Value { void setOperand(unsigned i, Value *v); void addOperand(Value *v); size_t getNumOperands() const { return operands.size(); } + void removeOperands(unsigned i1, unsigned i2); private: void setOperandWithoutRemoveUse(unsigned i, Value *v); @@ -151,6 +152,8 @@ struct BasicBlock : Value { instructions.push_back(inst); return inst; } + + void remove_phi_from(BasicBlock *); }; struct Argument : Value { @@ -412,9 +415,7 @@ struct PhiInst : Instruction { return cast<BasicBlock>(getOperand(i * 2 + 1)); } - Value *getIncomingValue(unsigned i) const { - return getOperand(i * 2); - } + Value *getIncomingValue(unsigned i) const { return getOperand(i * 2); } unsigned getNumIncomingValues() const { return operands.size() / 2; } }; diff --git a/include/olc/passes/SCCPPass.h b/include/olc/passes/SCCPPass.h index 52db562338ffc061e274299bed7f21821323604c..7cfcdb67996a7954b30eba9ef7a9ef0be1f0067b 100644 --- a/include/olc/passes/SCCPPass.h +++ b/include/olc/passes/SCCPPass.h @@ -219,9 +219,14 @@ private: block->instructions.push_back(jmpInst); block->instructions.remove(branchInst); block->successors.remove(falseBlock); + for (auto *succBlock : falseBlock->successors) { + succBlock->remove_phi_from(falseBlock); + } falseBlock->predecessors.remove(block); } + + static const void *ID; }; diff --git a/src/ir/IR.cpp b/src/ir/IR.cpp index 5dae38d53e215cf9ea7a3b0a74db335775b323b9..d887ff54dfc5681d72cf7474402d6f1334672c12 100644 --- a/src/ir/IR.cpp +++ b/src/ir/IR.cpp @@ -54,4 +54,41 @@ void User::addOperand(Value *v) { } } +void User::removeOperands(unsigned i1, unsigned i2) { + auto backup = std::vector<Value *>{}; + for (auto i = i2 + 1; i < operands.size(); i++) { + backup.push_back(operands[i]); + } + for (auto i = i1; i < operands.size(); i++) { + operands[i]->removeUse(this, i); + } + operands.erase(operands.begin() + i1, operands.begin() + operands.size()); + for (auto *op : backup) { + addOperand(op); + } +} + +void BasicBlock::remove_phi_from(BasicBlock *block) { + auto to_remove = std::vector<Instruction *>{}; + for (auto *inst : instructions) { + if (!inst->isPHI()) + break; + for (unsigned i = 1; i < inst->getNumOperands();) { + auto *op = inst->getOperand(i); + if (op == block) { + inst->removeOperands(i - 1, i); + } else { + i += 2; + } + if (inst->getNumOperands() == 2) { + inst->replaceAllUseWith(inst->getOperand(0)); + to_remove.push_back(inst); + } + } + } + for (auto *inst : to_remove) { + instructions.remove(inst); + } +} + } // namespace olc