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" 15e8d8bef9SDimitry Andric #include "llvm/IR/IRBuilder.h" 16e8d8bef9SDimitry Andric #include "llvm/IR/Instructions.h" 17e8d8bef9SDimitry Andric #include "llvm/IR/NoFolder.h" 18e8d8bef9SDimitry Andric 19e8d8bef9SDimitry Andric namespace llvm { 20e8d8bef9SDimitry Andric // Replace a constant expression by instructions with equivalent operations at 21e8d8bef9SDimitry Andric // a specified location. 22e8d8bef9SDimitry Andric Instruction *createReplacementInstr(ConstantExpr *CE, Instruction *Instr) { 23*fe6060f1SDimitry Andric auto *CEInstr = CE->getAsInstruction(); 24*fe6060f1SDimitry Andric CEInstr->insertBefore(Instr); 25*fe6060f1SDimitry Andric return CEInstr; 26e8d8bef9SDimitry Andric } 27*fe6060f1SDimitry Andric 28*fe6060f1SDimitry Andric void convertConstantExprsToInstructions(Instruction *I, ConstantExpr *CE, 29*fe6060f1SDimitry Andric SmallPtrSetImpl<Instruction *> *Insts) { 30*fe6060f1SDimitry Andric // Collect all reachable paths to CE from constant exprssion operands of I. 31*fe6060f1SDimitry Andric std::map<Use *, std::vector<std::vector<ConstantExpr *>>> CEPaths; 32*fe6060f1SDimitry Andric collectConstantExprPaths(I, CE, CEPaths); 33*fe6060f1SDimitry Andric 34*fe6060f1SDimitry Andric // Convert all constant expressions to instructions which are collected at 35*fe6060f1SDimitry Andric // CEPaths. 36*fe6060f1SDimitry Andric convertConstantExprsToInstructions(I, CEPaths, Insts); 37*fe6060f1SDimitry Andric } 38*fe6060f1SDimitry Andric 39*fe6060f1SDimitry Andric void convertConstantExprsToInstructions( 40*fe6060f1SDimitry Andric Instruction *I, 41*fe6060f1SDimitry Andric std::map<Use *, std::vector<std::vector<ConstantExpr *>>> &CEPaths, 42*fe6060f1SDimitry Andric SmallPtrSetImpl<Instruction *> *Insts) { 43*fe6060f1SDimitry Andric SmallPtrSet<ConstantExpr *, 8> Visited; 44*fe6060f1SDimitry Andric for (Use &U : I->operands()) { 45*fe6060f1SDimitry Andric // The operand U is either not a constant expression operand or the 46*fe6060f1SDimitry Andric // constant expression paths do not belong to U, ignore U. 47*fe6060f1SDimitry Andric if (!CEPaths.count(&U)) 48*fe6060f1SDimitry Andric continue; 49*fe6060f1SDimitry Andric 50*fe6060f1SDimitry Andric // If the instruction I is a PHI instruction, then fix the instruction 51*fe6060f1SDimitry Andric // insertion point to the entry of the incoming basic block for operand U. 52*fe6060f1SDimitry Andric auto *BI = I; 53*fe6060f1SDimitry Andric if (auto *Phi = dyn_cast<PHINode>(I)) { 54*fe6060f1SDimitry Andric BasicBlock *BB = Phi->getIncomingBlock(U); 55*fe6060f1SDimitry Andric BI = &(*(BB->getFirstInsertionPt())); 56*fe6060f1SDimitry Andric } 57*fe6060f1SDimitry Andric 58*fe6060f1SDimitry Andric // Go through the paths associated with operand U, and convert all the 59*fe6060f1SDimitry Andric // constant expressions along all paths to corresponding instructions. 60*fe6060f1SDimitry Andric auto *II = I; 61*fe6060f1SDimitry Andric auto &Paths = CEPaths[&U]; 62*fe6060f1SDimitry Andric for (auto &Path : Paths) { 63*fe6060f1SDimitry Andric for (auto *CE : Path) { 64*fe6060f1SDimitry Andric if (!Visited.insert(CE).second) 65*fe6060f1SDimitry Andric continue; 66*fe6060f1SDimitry Andric auto *NI = CE->getAsInstruction(); 67*fe6060f1SDimitry Andric NI->insertBefore(BI); 68*fe6060f1SDimitry Andric II->replaceUsesOfWith(CE, NI); 69*fe6060f1SDimitry Andric CE->removeDeadConstantUsers(); 70*fe6060f1SDimitry Andric BI = II = NI; 71*fe6060f1SDimitry Andric if (Insts) 72*fe6060f1SDimitry Andric Insts->insert(NI); 73e8d8bef9SDimitry Andric } 74e8d8bef9SDimitry Andric } 75*fe6060f1SDimitry Andric } 76*fe6060f1SDimitry Andric } 77*fe6060f1SDimitry Andric 78*fe6060f1SDimitry Andric void collectConstantExprPaths( 79*fe6060f1SDimitry Andric Instruction *I, ConstantExpr *CE, 80*fe6060f1SDimitry Andric std::map<Use *, std::vector<std::vector<ConstantExpr *>>> &CEPaths) { 81*fe6060f1SDimitry Andric for (Use &U : I->operands()) { 82*fe6060f1SDimitry Andric // If the operand U is not a constant expression operand, then ignore it. 83*fe6060f1SDimitry Andric auto *CE2 = dyn_cast<ConstantExpr>(U.get()); 84*fe6060f1SDimitry Andric if (!CE2) 85*fe6060f1SDimitry Andric continue; 86*fe6060f1SDimitry Andric 87*fe6060f1SDimitry Andric // Holds all reachable paths from CE2 to CE. 88*fe6060f1SDimitry Andric std::vector<std::vector<ConstantExpr *>> Paths; 89*fe6060f1SDimitry Andric 90*fe6060f1SDimitry Andric // Collect all reachable paths from CE2 to CE. 91*fe6060f1SDimitry Andric std::vector<ConstantExpr *> Path{CE2}; 92*fe6060f1SDimitry Andric std::vector<std::vector<ConstantExpr *>> Stack{Path}; 93*fe6060f1SDimitry Andric while (!Stack.empty()) { 94*fe6060f1SDimitry Andric std::vector<ConstantExpr *> TPath = Stack.back(); 95*fe6060f1SDimitry Andric Stack.pop_back(); 96*fe6060f1SDimitry Andric auto *CE3 = TPath.back(); 97*fe6060f1SDimitry Andric 98*fe6060f1SDimitry Andric if (CE3 == CE) { 99*fe6060f1SDimitry Andric Paths.push_back(TPath); 100*fe6060f1SDimitry Andric continue; 101*fe6060f1SDimitry Andric } 102*fe6060f1SDimitry Andric 103*fe6060f1SDimitry Andric for (auto &UU : CE3->operands()) { 104*fe6060f1SDimitry Andric if (auto *CE4 = dyn_cast<ConstantExpr>(UU.get())) { 105*fe6060f1SDimitry Andric std::vector<ConstantExpr *> NPath(TPath.begin(), TPath.end()); 106*fe6060f1SDimitry Andric NPath.push_back(CE4); 107*fe6060f1SDimitry Andric Stack.push_back(NPath); 108*fe6060f1SDimitry Andric } 109*fe6060f1SDimitry Andric } 110*fe6060f1SDimitry Andric } 111*fe6060f1SDimitry Andric 112*fe6060f1SDimitry Andric // Associate all the collected paths with U, and save it. 113*fe6060f1SDimitry Andric if (!Paths.empty()) 114*fe6060f1SDimitry Andric CEPaths[&U] = Paths; 115*fe6060f1SDimitry Andric } 116*fe6060f1SDimitry Andric } 117*fe6060f1SDimitry Andric 118e8d8bef9SDimitry Andric } // namespace llvm 119