1 //===- ReplaceConstant.cpp - Replace LLVM constant expression--------------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // This file implements a utility function for replacing LLVM constant
10 // expressions by instructions.
11 //
12 //===----------------------------------------------------------------------===//
13
14 #include "llvm/IR/ReplaceConstant.h"
15 #include "llvm/ADT/SetVector.h"
16 #include "llvm/IR/Constants.h"
17 #include "llvm/IR/Instructions.h"
18
19 namespace llvm {
20
isExpandableUser(User * U)21 static bool isExpandableUser(User *U) {
22 return isa<ConstantExpr>(U) || isa<ConstantAggregate>(U);
23 }
24
expandUser(BasicBlock::iterator InsertPt,Constant * C)25 static SmallVector<Instruction *, 4> expandUser(BasicBlock::iterator InsertPt,
26 Constant *C) {
27 SmallVector<Instruction *, 4> NewInsts;
28 if (auto *CE = dyn_cast<ConstantExpr>(C)) {
29 Instruction *ConstInst = CE->getAsInstruction();
30 ConstInst->insertBefore(*InsertPt->getParent(), InsertPt);
31 NewInsts.push_back(ConstInst);
32 } else if (isa<ConstantStruct>(C) || isa<ConstantArray>(C)) {
33 Value *V = PoisonValue::get(C->getType());
34 for (auto [Idx, Op] : enumerate(C->operands())) {
35 V = InsertValueInst::Create(V, Op, Idx, "", InsertPt);
36 NewInsts.push_back(cast<Instruction>(V));
37 }
38 } else if (isa<ConstantVector>(C)) {
39 Type *IdxTy = Type::getInt32Ty(C->getContext());
40 Value *V = PoisonValue::get(C->getType());
41 for (auto [Idx, Op] : enumerate(C->operands())) {
42 V = InsertElementInst::Create(V, Op, ConstantInt::get(IdxTy, Idx), "",
43 InsertPt);
44 NewInsts.push_back(cast<Instruction>(V));
45 }
46 } else {
47 llvm_unreachable("Not an expandable user");
48 }
49 return NewInsts;
50 }
51
convertUsersOfConstantsToInstructions(ArrayRef<Constant * > Consts,Function * RestrictToFunc,bool RemoveDeadConstants,bool IncludeSelf)52 bool convertUsersOfConstantsToInstructions(ArrayRef<Constant *> Consts,
53 Function *RestrictToFunc,
54 bool RemoveDeadConstants,
55 bool IncludeSelf) {
56 // Find all expandable direct users of Consts.
57 SmallVector<Constant *> Stack;
58 for (Constant *C : Consts) {
59 if (IncludeSelf) {
60 assert(isExpandableUser(C) && "One of the constants is not expandable");
61 Stack.push_back(C);
62 } else {
63 for (User *U : C->users())
64 if (isExpandableUser(U))
65 Stack.push_back(cast<Constant>(U));
66 }
67 }
68
69 // Include transitive users.
70 SetVector<Constant *> ExpandableUsers;
71 while (!Stack.empty()) {
72 Constant *C = Stack.pop_back_val();
73 if (!ExpandableUsers.insert(C))
74 continue;
75
76 for (auto *Nested : C->users())
77 if (isExpandableUser(Nested))
78 Stack.push_back(cast<Constant>(Nested));
79 }
80
81 // Find all instructions that use any of the expandable users
82 SetVector<Instruction *> InstructionWorklist;
83 for (Constant *C : ExpandableUsers)
84 for (User *U : C->users())
85 if (auto *I = dyn_cast<Instruction>(U))
86 if (!RestrictToFunc || I->getFunction() == RestrictToFunc)
87 InstructionWorklist.insert(I);
88
89 // Replace those expandable operands with instructions
90 bool Changed = false;
91 while (!InstructionWorklist.empty()) {
92 Instruction *I = InstructionWorklist.pop_back_val();
93 DebugLoc Loc = I->getDebugLoc();
94 for (Use &U : I->operands()) {
95 BasicBlock::iterator BI = I->getIterator();
96 if (auto *Phi = dyn_cast<PHINode>(I)) {
97 BasicBlock *BB = Phi->getIncomingBlock(U);
98 BI = BB->getFirstInsertionPt();
99 assert(BI != BB->end() && "Unexpected empty basic block");
100 }
101
102 if (auto *C = dyn_cast<Constant>(U.get())) {
103 if (ExpandableUsers.contains(C)) {
104 Changed = true;
105 auto NewInsts = expandUser(BI, C);
106 for (auto *NI : NewInsts)
107 NI->setDebugLoc(Loc);
108 InstructionWorklist.insert(NewInsts.begin(), NewInsts.end());
109 U.set(NewInsts.back());
110 }
111 }
112 }
113 }
114
115 if (RemoveDeadConstants)
116 for (Constant *C : Consts)
117 C->removeDeadConstantUsers();
118
119 return Changed;
120 }
121
122 } // namespace llvm
123