| //===- ReplaceConstant.cpp - Replace LLVM constant expression--------------===// | |
| // | |
| // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | |
| // See https://llvm.org/LICENSE.txt for license information. | |
| // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | |
| // | |
| //===----------------------------------------------------------------------===// | |
| // | |
| // This file implements a utility function for replacing LLVM constant | |
| // expressions by instructions. | |
| // | |
| //===----------------------------------------------------------------------===// | |
| #include "llvm/IR/ReplaceConstant.h" | |
| #include "llvm/ADT/SmallPtrSet.h" | |
| #include "llvm/IR/Constants.h" | |
| #include "llvm/IR/Instructions.h" | |
| #include "llvm/IR/ValueMap.h" | |
| namespace llvm { | |
| void convertConstantExprsToInstructions(Instruction *I, ConstantExpr *CE, | |
| SmallPtrSetImpl<Instruction *> *Insts) { | |
| // Collect all reachable paths to CE from constant exprssion operands of I. | |
| std::map<Use *, std::vector<std::vector<ConstantExpr *>>> CEPaths; | |
| collectConstantExprPaths(I, CE, CEPaths); | |
| // Convert all constant expressions to instructions which are collected at | |
| // CEPaths. | |
| convertConstantExprsToInstructions(I, CEPaths, Insts); | |
| } | |
| void convertConstantExprsToInstructions( | |
| Instruction *I, | |
| std::map<Use *, std::vector<std::vector<ConstantExpr *>>> &CEPaths, | |
| SmallPtrSetImpl<Instruction *> *Insts) { | |
| ValueMap<ConstantExpr *, Instruction *> Visited; | |
| for (Use &U : I->operands()) { | |
| // The operand U is either not a constant expression operand or the | |
| // constant expression paths do not belong to U, ignore U. | |
| if (!CEPaths.count(&U)) | |
| continue; | |
| // If the instruction I is a PHI instruction, then fix the instruction | |
| // insertion point to the entry of the incoming basic block for operand U. | |
| auto *BI = I; | |
| if (auto *Phi = dyn_cast<PHINode>(I)) { | |
| BasicBlock *BB = Phi->getIncomingBlock(U); | |
| BI = &(*(BB->getFirstInsertionPt())); | |
| } | |
| // Go through all the paths associated with operand U, and convert all the | |
| // constant expressions along all the paths to corresponding instructions. | |
| auto *II = I; | |
| auto &Paths = CEPaths[&U]; | |
| for (auto &Path : Paths) { | |
| for (auto *CE : Path) { | |
| // Instruction which is equivalent to CE. | |
| Instruction *NI = nullptr; | |
| if (!Visited.count(CE)) { | |
| // CE is encountered first time, convert it into a corresponding | |
| // instruction NI, and appropriately insert NI before the parent | |
| // instruction. | |
| NI = CE->getAsInstruction(BI); | |
| // Mark CE as visited by mapping CE to NI. | |
| Visited[CE] = NI; | |
| // If required collect NI. | |
| if (Insts) | |
| Insts->insert(NI); | |
| } else { | |
| // We had already encountered CE, the correponding instruction already | |
| // exist, use it to replace CE. | |
| NI = Visited[CE]; | |
| } | |
| assert(NI && "Expected an instruction corresponding to constant " | |
| "expression."); | |
| // Replace all uses of constant expression CE by the corresponding | |
| // instruction NI within the current parent instruction. | |
| II->replaceUsesOfWith(CE, NI); | |
| BI = II = NI; | |
| } | |
| } | |
| } | |
| // Remove all converted constant expressions which are dead by now. | |
| for (auto Item : Visited) | |
| Item.first->removeDeadConstantUsers(); | |
| } | |
| void collectConstantExprPaths( | |
| Instruction *I, ConstantExpr *CE, | |
| std::map<Use *, std::vector<std::vector<ConstantExpr *>>> &CEPaths) { | |
| for (Use &U : I->operands()) { | |
| // If the operand U is not a constant expression operand, then ignore it. | |
| auto *CE2 = dyn_cast<ConstantExpr>(U.get()); | |
| if (!CE2) | |
| continue; | |
| // Holds all reachable paths from CE2 to CE. | |
| std::vector<std::vector<ConstantExpr *>> Paths; | |
| // Collect all reachable paths from CE2 to CE. | |
| std::vector<ConstantExpr *> Path{CE2}; | |
| std::vector<std::vector<ConstantExpr *>> Stack{Path}; | |
| while (!Stack.empty()) { | |
| std::vector<ConstantExpr *> TPath = Stack.back(); | |
| Stack.pop_back(); | |
| auto *CE3 = TPath.back(); | |
| if (CE3 == CE) { | |
| Paths.push_back(TPath); | |
| continue; | |
| } | |
| for (auto &UU : CE3->operands()) { | |
| if (auto *CE4 = dyn_cast<ConstantExpr>(UU.get())) { | |
| std::vector<ConstantExpr *> NPath(TPath.begin(), TPath.end()); | |
| NPath.push_back(CE4); | |
| Stack.push_back(NPath); | |
| } | |
| } | |
| } | |
| // Associate all the collected paths with U, and save it. | |
| if (!Paths.empty()) | |
| CEPaths[&U] = Paths; | |
| } | |
| } | |
| } // namespace llvm |