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