1e8d8bef9SDimitry Andric //===- ReplaceConstant.cpp - Replace LLVM constant expression--------------===// 2e8d8bef9SDimitry Andric // 3e8d8bef9SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4e8d8bef9SDimitry Andric // See https://llvm.org/LICENSE.txt for license information. 5e8d8bef9SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6e8d8bef9SDimitry Andric // 7e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 8e8d8bef9SDimitry Andric // 9e8d8bef9SDimitry Andric // This file implements a utility function for replacing LLVM constant 10e8d8bef9SDimitry Andric // expressions by instructions. 11e8d8bef9SDimitry Andric // 12e8d8bef9SDimitry Andric //===----------------------------------------------------------------------===// 13e8d8bef9SDimitry Andric 14e8d8bef9SDimitry Andric #include "llvm/IR/ReplaceConstant.h" 151fd87a68SDimitry Andric #include "llvm/ADT/SmallPtrSet.h" 16*81ad6265SDimitry Andric #include "llvm/IR/Constants.h" 17e8d8bef9SDimitry Andric #include "llvm/IR/Instructions.h" 18349cc55cSDimitry Andric #include "llvm/IR/ValueMap.h" 19e8d8bef9SDimitry Andric 20e8d8bef9SDimitry Andric namespace llvm { 21fe6060f1SDimitry Andric 22fe6060f1SDimitry Andric void convertConstantExprsToInstructions(Instruction *I, ConstantExpr *CE, 23fe6060f1SDimitry Andric SmallPtrSetImpl<Instruction *> *Insts) { 24fe6060f1SDimitry Andric // Collect all reachable paths to CE from constant exprssion operands of I. 25fe6060f1SDimitry Andric std::map<Use *, std::vector<std::vector<ConstantExpr *>>> CEPaths; 26fe6060f1SDimitry Andric collectConstantExprPaths(I, CE, CEPaths); 27fe6060f1SDimitry Andric 28fe6060f1SDimitry Andric // Convert all constant expressions to instructions which are collected at 29fe6060f1SDimitry Andric // CEPaths. 30fe6060f1SDimitry Andric convertConstantExprsToInstructions(I, CEPaths, Insts); 31fe6060f1SDimitry Andric } 32fe6060f1SDimitry Andric 33fe6060f1SDimitry Andric void convertConstantExprsToInstructions( 34fe6060f1SDimitry Andric Instruction *I, 35fe6060f1SDimitry Andric std::map<Use *, std::vector<std::vector<ConstantExpr *>>> &CEPaths, 36fe6060f1SDimitry Andric SmallPtrSetImpl<Instruction *> *Insts) { 37349cc55cSDimitry Andric ValueMap<ConstantExpr *, Instruction *> Visited; 38349cc55cSDimitry Andric 39fe6060f1SDimitry Andric for (Use &U : I->operands()) { 40fe6060f1SDimitry Andric // The operand U is either not a constant expression operand or the 41fe6060f1SDimitry Andric // constant expression paths do not belong to U, ignore U. 42fe6060f1SDimitry Andric if (!CEPaths.count(&U)) 43fe6060f1SDimitry Andric continue; 44fe6060f1SDimitry Andric 45fe6060f1SDimitry Andric // If the instruction I is a PHI instruction, then fix the instruction 46fe6060f1SDimitry Andric // insertion point to the entry of the incoming basic block for operand U. 47fe6060f1SDimitry Andric auto *BI = I; 48fe6060f1SDimitry Andric if (auto *Phi = dyn_cast<PHINode>(I)) { 49fe6060f1SDimitry Andric BasicBlock *BB = Phi->getIncomingBlock(U); 50fe6060f1SDimitry Andric BI = &(*(BB->getFirstInsertionPt())); 51fe6060f1SDimitry Andric } 52fe6060f1SDimitry Andric 53349cc55cSDimitry Andric // Go through all the paths associated with operand U, and convert all the 54349cc55cSDimitry Andric // constant expressions along all the paths to corresponding instructions. 55fe6060f1SDimitry Andric auto *II = I; 56fe6060f1SDimitry Andric auto &Paths = CEPaths[&U]; 57fe6060f1SDimitry Andric for (auto &Path : Paths) { 58fe6060f1SDimitry Andric for (auto *CE : Path) { 59349cc55cSDimitry Andric // Instruction which is equivalent to CE. 60349cc55cSDimitry Andric Instruction *NI = nullptr; 61349cc55cSDimitry Andric 62349cc55cSDimitry Andric if (!Visited.count(CE)) { 63349cc55cSDimitry Andric // CE is encountered first time, convert it into a corresponding 64349cc55cSDimitry Andric // instruction NI, and appropriately insert NI before the parent 65349cc55cSDimitry Andric // instruction. 66349cc55cSDimitry Andric NI = CE->getAsInstruction(BI); 67349cc55cSDimitry Andric 68349cc55cSDimitry Andric // Mark CE as visited by mapping CE to NI. 69349cc55cSDimitry Andric Visited[CE] = NI; 70349cc55cSDimitry Andric 71349cc55cSDimitry Andric // If required collect NI. 72fe6060f1SDimitry Andric if (Insts) 73fe6060f1SDimitry Andric Insts->insert(NI); 74349cc55cSDimitry Andric } else { 75349cc55cSDimitry Andric // We had already encountered CE, the correponding instruction already 76349cc55cSDimitry Andric // exist, use it to replace CE. 77349cc55cSDimitry Andric NI = Visited[CE]; 78349cc55cSDimitry Andric } 79349cc55cSDimitry Andric 80349cc55cSDimitry Andric assert(NI && "Expected an instruction corresponding to constant " 81349cc55cSDimitry Andric "expression."); 82349cc55cSDimitry Andric 83349cc55cSDimitry Andric // Replace all uses of constant expression CE by the corresponding 84349cc55cSDimitry Andric // instruction NI within the current parent instruction. 85349cc55cSDimitry Andric II->replaceUsesOfWith(CE, NI); 86349cc55cSDimitry Andric BI = II = NI; 87e8d8bef9SDimitry Andric } 88e8d8bef9SDimitry Andric } 89fe6060f1SDimitry Andric } 90349cc55cSDimitry Andric 91349cc55cSDimitry Andric // Remove all converted constant expressions which are dead by now. 92349cc55cSDimitry Andric for (auto Item : Visited) 93349cc55cSDimitry Andric Item.first->removeDeadConstantUsers(); 94fe6060f1SDimitry Andric } 95fe6060f1SDimitry Andric 96fe6060f1SDimitry Andric void collectConstantExprPaths( 97fe6060f1SDimitry Andric Instruction *I, ConstantExpr *CE, 98fe6060f1SDimitry Andric std::map<Use *, std::vector<std::vector<ConstantExpr *>>> &CEPaths) { 99fe6060f1SDimitry Andric for (Use &U : I->operands()) { 100fe6060f1SDimitry Andric // If the operand U is not a constant expression operand, then ignore it. 101fe6060f1SDimitry Andric auto *CE2 = dyn_cast<ConstantExpr>(U.get()); 102fe6060f1SDimitry Andric if (!CE2) 103fe6060f1SDimitry Andric continue; 104fe6060f1SDimitry Andric 105fe6060f1SDimitry Andric // Holds all reachable paths from CE2 to CE. 106fe6060f1SDimitry Andric std::vector<std::vector<ConstantExpr *>> Paths; 107fe6060f1SDimitry Andric 108fe6060f1SDimitry Andric // Collect all reachable paths from CE2 to CE. 109fe6060f1SDimitry Andric std::vector<ConstantExpr *> Path{CE2}; 110fe6060f1SDimitry Andric std::vector<std::vector<ConstantExpr *>> Stack{Path}; 111fe6060f1SDimitry Andric while (!Stack.empty()) { 112fe6060f1SDimitry Andric std::vector<ConstantExpr *> TPath = Stack.back(); 113fe6060f1SDimitry Andric Stack.pop_back(); 114fe6060f1SDimitry Andric auto *CE3 = TPath.back(); 115fe6060f1SDimitry Andric 116fe6060f1SDimitry Andric if (CE3 == CE) { 117fe6060f1SDimitry Andric Paths.push_back(TPath); 118fe6060f1SDimitry Andric continue; 119fe6060f1SDimitry Andric } 120fe6060f1SDimitry Andric 121fe6060f1SDimitry Andric for (auto &UU : CE3->operands()) { 122fe6060f1SDimitry Andric if (auto *CE4 = dyn_cast<ConstantExpr>(UU.get())) { 123fe6060f1SDimitry Andric std::vector<ConstantExpr *> NPath(TPath.begin(), TPath.end()); 124fe6060f1SDimitry Andric NPath.push_back(CE4); 125fe6060f1SDimitry Andric Stack.push_back(NPath); 126fe6060f1SDimitry Andric } 127fe6060f1SDimitry Andric } 128fe6060f1SDimitry Andric } 129fe6060f1SDimitry Andric 130fe6060f1SDimitry Andric // Associate all the collected paths with U, and save it. 131fe6060f1SDimitry Andric if (!Paths.empty()) 132fe6060f1SDimitry Andric CEPaths[&U] = Paths; 133fe6060f1SDimitry Andric } 134fe6060f1SDimitry Andric } 135fe6060f1SDimitry Andric 136e8d8bef9SDimitry Andric } // namespace llvm 137