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
19namespace llvm {
20
21static bool isExpandableUser(User *U) {
22 return isa<ConstantExpr>(Val: U) || isa<ConstantAggregate>(Val: U);
23}
24
25static SmallVector<Instruction *, 4> expandUser(BasicBlock::iterator InsertPt,
26 Constant *C) {
27 SmallVector<Instruction *, 4> NewInsts;
28 if (auto *CE = dyn_cast<ConstantExpr>(Val: C)) {
29 Instruction *ConstInst = CE->getAsInstruction();
30 ConstInst->insertBefore(BB&: *InsertPt->getParent(), InsertPos: InsertPt);
31 NewInsts.push_back(Elt: ConstInst);
32 } else if (isa<ConstantStruct>(Val: C) || isa<ConstantArray>(Val: C)) {
33 Value *V = PoisonValue::get(T: C->getType());
34 for (auto [Idx, Op] : enumerate(First: C->operands())) {
35 V = InsertValueInst::Create(Agg: V, Val: Op, Idxs: Idx, NameStr: "", InsertBefore: InsertPt);
36 NewInsts.push_back(Elt: cast<Instruction>(Val: V));
37 }
38 } else if (isa<ConstantVector>(Val: C)) {
39 Type *IdxTy = Type::getInt32Ty(C&: C->getContext());
40 Value *V = PoisonValue::get(T: C->getType());
41 for (auto [Idx, Op] : enumerate(First: C->operands())) {
42 V = InsertElementInst::Create(Vec: V, NewElt: Op, Idx: ConstantInt::get(Ty: IdxTy, V: Idx), NameStr: "",
43 InsertBefore: InsertPt);
44 NewInsts.push_back(Elt: cast<Instruction>(Val: V));
45 }
46 } else {
47 llvm_unreachable("Not an expandable user");
48 }
49 return NewInsts;
50}
51
52bool 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 assert(!isa<ConstantData>(C) &&
60 "should not be expanding trivial constant users");
61
62 if (IncludeSelf) {
63 assert(isExpandableUser(C) && "One of the constants is not expandable");
64 Stack.push_back(Elt: C);
65 } else {
66 for (User *U : C->users())
67 if (isExpandableUser(U))
68 Stack.push_back(Elt: cast<Constant>(Val: U));
69 }
70 }
71
72 // Include transitive users.
73 SetVector<Constant *> ExpandableUsers;
74 while (!Stack.empty()) {
75 Constant *C = Stack.pop_back_val();
76 if (!ExpandableUsers.insert(X: C))
77 continue;
78
79 for (auto *Nested : C->users())
80 if (isExpandableUser(U: Nested))
81 Stack.push_back(Elt: cast<Constant>(Val: Nested));
82 }
83
84 // Find all instructions that use any of the expandable users
85 SetVector<Instruction *> InstructionWorklist;
86 for (Constant *C : ExpandableUsers)
87 for (User *U : C->users())
88 if (auto *I = dyn_cast<Instruction>(Val: U))
89 if (!RestrictToFunc || I->getFunction() == RestrictToFunc)
90 InstructionWorklist.insert(X: I);
91
92 // Replace those expandable operands with instructions
93 bool Changed = false;
94 while (!InstructionWorklist.empty()) {
95 Instruction *I = InstructionWorklist.pop_back_val();
96 DebugLoc Loc = I->getDebugLoc();
97 for (Use &U : I->operands()) {
98 BasicBlock::iterator BI = I->getIterator();
99 if (auto *Phi = dyn_cast<PHINode>(Val: I)) {
100 BasicBlock *BB = Phi->getIncomingBlock(U);
101 BI = BB->getFirstInsertionPt();
102 assert(BI != BB->end() && "Unexpected empty basic block");
103 }
104
105 if (auto *C = dyn_cast<Constant>(Val: U.get())) {
106 if (ExpandableUsers.contains(key: C)) {
107 Changed = true;
108 auto NewInsts = expandUser(InsertPt: BI, C);
109 for (auto *NI : NewInsts)
110 NI->setDebugLoc(Loc);
111 InstructionWorklist.insert_range(R&: NewInsts);
112 U.set(NewInsts.back());
113 }
114 }
115 }
116 }
117
118 if (RemoveDeadConstants)
119 for (Constant *C : Consts)
120 C->removeDeadConstantUsers();
121
122 return Changed;
123}
124
125} // namespace llvm
126