xref: /freebsd-src/contrib/llvm-project/llvm/lib/IR/ReplaceConstant.cpp (revision fe6060f10f634930ff71b7c50291ddc610da2475)
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