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 // Find all expandable direct users of Consts.
54 SmallVector<Constant *> Stack;
55 for (Constant *C : Consts)
56 for (User *U : C->users())
57 if (isExpandableUser(U))
58 Stack.push_back(Elt: cast<Constant>(Val: U));
59
60 // Include transitive users.
61 SetVector<Constant *> ExpandableUsers;
62 while (!Stack.empty()) {
63 Constant *C = Stack.pop_back_val();
64 if (!ExpandableUsers.insert(X: C))
65 continue;
66
67 for (auto *Nested : C->users())
68 if (isExpandableUser(U: Nested))
69 Stack.push_back(Elt: cast<Constant>(Val: Nested));
70 }
71
72 // Find all instructions that use any of the expandable users
73 SetVector<Instruction *> InstructionWorklist;
74 for (Constant *C : ExpandableUsers)
75 for (User *U : C->users())
76 if (auto *I = dyn_cast<Instruction>(Val: U))
77 InstructionWorklist.insert(X: I);
78
79 // Replace those expandable operands with instructions
80 bool Changed = false;
81 while (!InstructionWorklist.empty()) {
82 Instruction *I = InstructionWorklist.pop_back_val();
83 DebugLoc Loc = I->getDebugLoc();
84 for (Use &U : I->operands()) {
85 BasicBlock::iterator BI = I->getIterator();
86 if (auto *Phi = dyn_cast<PHINode>(Val: I)) {
87 BasicBlock *BB = Phi->getIncomingBlock(U);
88 BI = BB->getFirstInsertionPt();
89 assert(BI != BB->end() && "Unexpected empty basic block");
90 }
91
92 if (auto *C = dyn_cast<Constant>(Val: U.get())) {
93 if (ExpandableUsers.contains(key: C)) {
94 Changed = true;
95 auto NewInsts = expandUser(InsertPt: BI, C);
96 for (auto *NI : NewInsts)
97 NI->setDebugLoc(Loc);
98 InstructionWorklist.insert(Start: NewInsts.begin(), End: NewInsts.end());
99 U.set(NewInsts.back());
100 }
101 }
102 }
103 }
104
105 for (Constant *C : Consts)
106 C->removeDeadConstantUsers();
107
108 return Changed;
109}
110
111} // namespace llvm
112

source code of llvm/lib/IR/ReplaceConstant.cpp