xref: /freebsd/contrib/llvm-project/llvm/lib/IR/ReplaceConstant.cpp (revision 06c3fb2749bda94cb5201f81ffdb8fa6c3161b2e)
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*06c3fb27SDimitry Andric #include "llvm/ADT/SetVector.h"
1681ad6265SDimitry Andric #include "llvm/IR/Constants.h"
17e8d8bef9SDimitry Andric #include "llvm/IR/Instructions.h"
18e8d8bef9SDimitry Andric 
19e8d8bef9SDimitry Andric namespace llvm {
20fe6060f1SDimitry Andric 
21*06c3fb27SDimitry Andric static bool isExpandableUser(User *U) {
22*06c3fb27SDimitry Andric   return isa<ConstantExpr>(U) || isa<ConstantAggregate>(U);
23fe6060f1SDimitry Andric }
24fe6060f1SDimitry Andric 
25*06c3fb27SDimitry Andric static Instruction *expandUser(Instruction *InsertPt, Constant *C) {
26*06c3fb27SDimitry Andric   if (auto *CE = dyn_cast<ConstantExpr>(C)) {
27*06c3fb27SDimitry Andric     return CE->getAsInstruction(InsertPt);
28*06c3fb27SDimitry Andric   } else if (isa<ConstantStruct>(C) || isa<ConstantArray>(C)) {
29*06c3fb27SDimitry Andric     Value *V = PoisonValue::get(C->getType());
30*06c3fb27SDimitry Andric     for (auto [Idx, Op] : enumerate(C->operands()))
31*06c3fb27SDimitry Andric       V = InsertValueInst::Create(V, Op, Idx, "", InsertPt);
32*06c3fb27SDimitry Andric     return cast<Instruction>(V);
33*06c3fb27SDimitry Andric   } else if (isa<ConstantVector>(C)) {
34*06c3fb27SDimitry Andric     Type *IdxTy = Type::getInt32Ty(C->getContext());
35*06c3fb27SDimitry Andric     Value *V = PoisonValue::get(C->getType());
36*06c3fb27SDimitry Andric     for (auto [Idx, Op] : enumerate(C->operands()))
37*06c3fb27SDimitry Andric       V = InsertElementInst::Create(V, Op, ConstantInt::get(IdxTy, Idx), "",
38*06c3fb27SDimitry Andric                                     InsertPt);
39*06c3fb27SDimitry Andric     return cast<Instruction>(V);
40*06c3fb27SDimitry Andric   } else {
41*06c3fb27SDimitry Andric     llvm_unreachable("Not an expandable user");
42*06c3fb27SDimitry Andric   }
43*06c3fb27SDimitry Andric }
44349cc55cSDimitry Andric 
45*06c3fb27SDimitry Andric bool convertUsersOfConstantsToInstructions(ArrayRef<Constant *> Consts) {
46*06c3fb27SDimitry Andric   // Find all expandable direct users of Consts.
47*06c3fb27SDimitry Andric   SmallVector<Constant *> Stack;
48*06c3fb27SDimitry Andric   for (Constant *C : Consts)
49*06c3fb27SDimitry Andric     for (User *U : C->users())
50*06c3fb27SDimitry Andric       if (isExpandableUser(U))
51*06c3fb27SDimitry Andric         Stack.push_back(cast<Constant>(U));
52*06c3fb27SDimitry Andric 
53*06c3fb27SDimitry Andric   // Include transitive users.
54*06c3fb27SDimitry Andric   SetVector<Constant *> ExpandableUsers;
55*06c3fb27SDimitry Andric   while (!Stack.empty()) {
56*06c3fb27SDimitry Andric     Constant *C = Stack.pop_back_val();
57*06c3fb27SDimitry Andric     if (!ExpandableUsers.insert(C))
58fe6060f1SDimitry Andric       continue;
59fe6060f1SDimitry Andric 
60*06c3fb27SDimitry Andric     for (auto *Nested : C->users())
61*06c3fb27SDimitry Andric       if (isExpandableUser(Nested))
62*06c3fb27SDimitry Andric         Stack.push_back(cast<Constant>(Nested));
63*06c3fb27SDimitry Andric   }
64*06c3fb27SDimitry Andric 
65*06c3fb27SDimitry Andric   // Find all instructions that use any of the expandable users
66*06c3fb27SDimitry Andric   SetVector<Instruction *> InstructionWorklist;
67*06c3fb27SDimitry Andric   for (Constant *C : ExpandableUsers)
68*06c3fb27SDimitry Andric     for (User *U : C->users())
69*06c3fb27SDimitry Andric       if (auto *I = dyn_cast<Instruction>(U))
70*06c3fb27SDimitry Andric         InstructionWorklist.insert(I);
71*06c3fb27SDimitry Andric 
72*06c3fb27SDimitry Andric   // Replace those expandable operands with instructions
73*06c3fb27SDimitry Andric   bool Changed = false;
74*06c3fb27SDimitry Andric   while (!InstructionWorklist.empty()) {
75*06c3fb27SDimitry Andric     Instruction *I = InstructionWorklist.pop_back_val();
76*06c3fb27SDimitry Andric     for (Use &U : I->operands()) {
77fe6060f1SDimitry Andric       auto *BI = I;
78fe6060f1SDimitry Andric       if (auto *Phi = dyn_cast<PHINode>(I)) {
79fe6060f1SDimitry Andric         BasicBlock *BB = Phi->getIncomingBlock(U);
80*06c3fb27SDimitry Andric         BasicBlock::iterator It = BB->getFirstInsertionPt();
81*06c3fb27SDimitry Andric         assert(It != BB->end() && "Unexpected empty basic block");
82*06c3fb27SDimitry Andric         BI = &*It;
83fe6060f1SDimitry Andric       }
84fe6060f1SDimitry Andric 
85*06c3fb27SDimitry Andric       if (auto *C = dyn_cast<Constant>(U.get())) {
86*06c3fb27SDimitry Andric         if (ExpandableUsers.contains(C)) {
87*06c3fb27SDimitry Andric           Changed = true;
88*06c3fb27SDimitry Andric           Instruction *NI = expandUser(BI, C);
89*06c3fb27SDimitry Andric           InstructionWorklist.insert(NI);
90*06c3fb27SDimitry Andric           U.set(NI);
91349cc55cSDimitry Andric         }
92e8d8bef9SDimitry Andric       }
93e8d8bef9SDimitry Andric     }
94fe6060f1SDimitry Andric   }
95349cc55cSDimitry Andric 
96*06c3fb27SDimitry Andric   for (Constant *C : Consts)
97*06c3fb27SDimitry Andric     C->removeDeadConstantUsers();
98fe6060f1SDimitry Andric 
99*06c3fb27SDimitry Andric   return Changed;
100fe6060f1SDimitry Andric }
101fe6060f1SDimitry Andric 
102e8d8bef9SDimitry Andric } // namespace llvm
103