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" 15*1fd87a68SDimitry Andric #include "llvm/ADT/SmallPtrSet.h" 16e8d8bef9SDimitry Andric #include "llvm/IR/Instructions.h" 17349cc55cSDimitry Andric #include "llvm/IR/ValueMap.h" 18e8d8bef9SDimitry Andric 19e8d8bef9SDimitry Andric namespace llvm { 20fe6060f1SDimitry Andric 21fe6060f1SDimitry Andric void convertConstantExprsToInstructions(Instruction *I, ConstantExpr *CE, 22fe6060f1SDimitry Andric SmallPtrSetImpl<Instruction *> *Insts) { 23fe6060f1SDimitry Andric // Collect all reachable paths to CE from constant exprssion operands of I. 24fe6060f1SDimitry Andric std::map<Use *, std::vector<std::vector<ConstantExpr *>>> CEPaths; 25fe6060f1SDimitry Andric collectConstantExprPaths(I, CE, CEPaths); 26fe6060f1SDimitry Andric 27fe6060f1SDimitry Andric // Convert all constant expressions to instructions which are collected at 28fe6060f1SDimitry Andric // CEPaths. 29fe6060f1SDimitry Andric convertConstantExprsToInstructions(I, CEPaths, Insts); 30fe6060f1SDimitry Andric } 31fe6060f1SDimitry Andric 32fe6060f1SDimitry Andric void convertConstantExprsToInstructions( 33fe6060f1SDimitry Andric Instruction *I, 34fe6060f1SDimitry Andric std::map<Use *, std::vector<std::vector<ConstantExpr *>>> &CEPaths, 35fe6060f1SDimitry Andric SmallPtrSetImpl<Instruction *> *Insts) { 36349cc55cSDimitry Andric ValueMap<ConstantExpr *, Instruction *> Visited; 37349cc55cSDimitry Andric 38fe6060f1SDimitry Andric for (Use &U : I->operands()) { 39fe6060f1SDimitry Andric // The operand U is either not a constant expression operand or the 40fe6060f1SDimitry Andric // constant expression paths do not belong to U, ignore U. 41fe6060f1SDimitry Andric if (!CEPaths.count(&U)) 42fe6060f1SDimitry Andric continue; 43fe6060f1SDimitry Andric 44fe6060f1SDimitry Andric // If the instruction I is a PHI instruction, then fix the instruction 45fe6060f1SDimitry Andric // insertion point to the entry of the incoming basic block for operand U. 46fe6060f1SDimitry Andric auto *BI = I; 47fe6060f1SDimitry Andric if (auto *Phi = dyn_cast<PHINode>(I)) { 48fe6060f1SDimitry Andric BasicBlock *BB = Phi->getIncomingBlock(U); 49fe6060f1SDimitry Andric BI = &(*(BB->getFirstInsertionPt())); 50fe6060f1SDimitry Andric } 51fe6060f1SDimitry Andric 52349cc55cSDimitry Andric // Go through all the paths associated with operand U, and convert all the 53349cc55cSDimitry Andric // constant expressions along all the paths to corresponding instructions. 54fe6060f1SDimitry Andric auto *II = I; 55fe6060f1SDimitry Andric auto &Paths = CEPaths[&U]; 56fe6060f1SDimitry Andric for (auto &Path : Paths) { 57fe6060f1SDimitry Andric for (auto *CE : Path) { 58349cc55cSDimitry Andric // Instruction which is equivalent to CE. 59349cc55cSDimitry Andric Instruction *NI = nullptr; 60349cc55cSDimitry Andric 61349cc55cSDimitry Andric if (!Visited.count(CE)) { 62349cc55cSDimitry Andric // CE is encountered first time, convert it into a corresponding 63349cc55cSDimitry Andric // instruction NI, and appropriately insert NI before the parent 64349cc55cSDimitry Andric // instruction. 65349cc55cSDimitry Andric NI = CE->getAsInstruction(BI); 66349cc55cSDimitry Andric 67349cc55cSDimitry Andric // Mark CE as visited by mapping CE to NI. 68349cc55cSDimitry Andric Visited[CE] = NI; 69349cc55cSDimitry Andric 70349cc55cSDimitry Andric // If required collect NI. 71fe6060f1SDimitry Andric if (Insts) 72fe6060f1SDimitry Andric Insts->insert(NI); 73349cc55cSDimitry Andric } else { 74349cc55cSDimitry Andric // We had already encountered CE, the correponding instruction already 75349cc55cSDimitry Andric // exist, use it to replace CE. 76349cc55cSDimitry Andric NI = Visited[CE]; 77349cc55cSDimitry Andric } 78349cc55cSDimitry Andric 79349cc55cSDimitry Andric assert(NI && "Expected an instruction corresponding to constant " 80349cc55cSDimitry Andric "expression."); 81349cc55cSDimitry Andric 82349cc55cSDimitry Andric // Replace all uses of constant expression CE by the corresponding 83349cc55cSDimitry Andric // instruction NI within the current parent instruction. 84349cc55cSDimitry Andric II->replaceUsesOfWith(CE, NI); 85349cc55cSDimitry Andric BI = II = NI; 86e8d8bef9SDimitry Andric } 87e8d8bef9SDimitry Andric } 88fe6060f1SDimitry Andric } 89349cc55cSDimitry Andric 90349cc55cSDimitry Andric // Remove all converted constant expressions which are dead by now. 91349cc55cSDimitry Andric for (auto Item : Visited) 92349cc55cSDimitry Andric Item.first->removeDeadConstantUsers(); 93fe6060f1SDimitry Andric } 94fe6060f1SDimitry Andric 95fe6060f1SDimitry Andric void collectConstantExprPaths( 96fe6060f1SDimitry Andric Instruction *I, ConstantExpr *CE, 97fe6060f1SDimitry Andric std::map<Use *, std::vector<std::vector<ConstantExpr *>>> &CEPaths) { 98fe6060f1SDimitry Andric for (Use &U : I->operands()) { 99fe6060f1SDimitry Andric // If the operand U is not a constant expression operand, then ignore it. 100fe6060f1SDimitry Andric auto *CE2 = dyn_cast<ConstantExpr>(U.get()); 101fe6060f1SDimitry Andric if (!CE2) 102fe6060f1SDimitry Andric continue; 103fe6060f1SDimitry Andric 104fe6060f1SDimitry Andric // Holds all reachable paths from CE2 to CE. 105fe6060f1SDimitry Andric std::vector<std::vector<ConstantExpr *>> Paths; 106fe6060f1SDimitry Andric 107fe6060f1SDimitry Andric // Collect all reachable paths from CE2 to CE. 108fe6060f1SDimitry Andric std::vector<ConstantExpr *> Path{CE2}; 109fe6060f1SDimitry Andric std::vector<std::vector<ConstantExpr *>> Stack{Path}; 110fe6060f1SDimitry Andric while (!Stack.empty()) { 111fe6060f1SDimitry Andric std::vector<ConstantExpr *> TPath = Stack.back(); 112fe6060f1SDimitry Andric Stack.pop_back(); 113fe6060f1SDimitry Andric auto *CE3 = TPath.back(); 114fe6060f1SDimitry Andric 115fe6060f1SDimitry Andric if (CE3 == CE) { 116fe6060f1SDimitry Andric Paths.push_back(TPath); 117fe6060f1SDimitry Andric continue; 118fe6060f1SDimitry Andric } 119fe6060f1SDimitry Andric 120fe6060f1SDimitry Andric for (auto &UU : CE3->operands()) { 121fe6060f1SDimitry Andric if (auto *CE4 = dyn_cast<ConstantExpr>(UU.get())) { 122fe6060f1SDimitry Andric std::vector<ConstantExpr *> NPath(TPath.begin(), TPath.end()); 123fe6060f1SDimitry Andric NPath.push_back(CE4); 124fe6060f1SDimitry Andric Stack.push_back(NPath); 125fe6060f1SDimitry Andric } 126fe6060f1SDimitry Andric } 127fe6060f1SDimitry Andric } 128fe6060f1SDimitry Andric 129fe6060f1SDimitry Andric // Associate all the collected paths with U, and save it. 130fe6060f1SDimitry Andric if (!Paths.empty()) 131fe6060f1SDimitry Andric CEPaths[&U] = Paths; 132fe6060f1SDimitry Andric } 133fe6060f1SDimitry Andric } 134fe6060f1SDimitry Andric 135e8d8bef9SDimitry Andric } // namespace llvm 136