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"
1506c3fb27SDimitry 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
isExpandableUser(User * U)2106c3fb27SDimitry Andric static bool isExpandableUser(User *U) {
2206c3fb27SDimitry Andric return isa<ConstantExpr>(U) || isa<ConstantAggregate>(U);
23fe6060f1SDimitry Andric }
24fe6060f1SDimitry Andric
expandUser(BasicBlock::iterator InsertPt,Constant * C)25*0fca6ea1SDimitry Andric static SmallVector<Instruction *, 4> expandUser(BasicBlock::iterator InsertPt,
265f757f3fSDimitry Andric Constant *C) {
275f757f3fSDimitry Andric SmallVector<Instruction *, 4> NewInsts;
2806c3fb27SDimitry Andric if (auto *CE = dyn_cast<ConstantExpr>(C)) {
29*0fca6ea1SDimitry Andric Instruction *ConstInst = CE->getAsInstruction();
30*0fca6ea1SDimitry Andric ConstInst->insertBefore(*InsertPt->getParent(), InsertPt);
31*0fca6ea1SDimitry Andric NewInsts.push_back(ConstInst);
3206c3fb27SDimitry Andric } else if (isa<ConstantStruct>(C) || isa<ConstantArray>(C)) {
3306c3fb27SDimitry Andric Value *V = PoisonValue::get(C->getType());
345f757f3fSDimitry Andric for (auto [Idx, Op] : enumerate(C->operands())) {
3506c3fb27SDimitry Andric V = InsertValueInst::Create(V, Op, Idx, "", InsertPt);
365f757f3fSDimitry Andric NewInsts.push_back(cast<Instruction>(V));
375f757f3fSDimitry Andric }
3806c3fb27SDimitry Andric } else if (isa<ConstantVector>(C)) {
3906c3fb27SDimitry Andric Type *IdxTy = Type::getInt32Ty(C->getContext());
4006c3fb27SDimitry Andric Value *V = PoisonValue::get(C->getType());
415f757f3fSDimitry Andric for (auto [Idx, Op] : enumerate(C->operands())) {
4206c3fb27SDimitry Andric V = InsertElementInst::Create(V, Op, ConstantInt::get(IdxTy, Idx), "",
4306c3fb27SDimitry Andric InsertPt);
445f757f3fSDimitry Andric NewInsts.push_back(cast<Instruction>(V));
455f757f3fSDimitry Andric }
4606c3fb27SDimitry Andric } else {
4706c3fb27SDimitry Andric llvm_unreachable("Not an expandable user");
4806c3fb27SDimitry Andric }
495f757f3fSDimitry Andric return NewInsts;
5006c3fb27SDimitry Andric }
51349cc55cSDimitry Andric
convertUsersOfConstantsToInstructions(ArrayRef<Constant * > Consts,Function * RestrictToFunc,bool RemoveDeadConstants,bool IncludeSelf)52*0fca6ea1SDimitry Andric bool convertUsersOfConstantsToInstructions(ArrayRef<Constant *> Consts,
53*0fca6ea1SDimitry Andric Function *RestrictToFunc,
54*0fca6ea1SDimitry Andric bool RemoveDeadConstants,
55*0fca6ea1SDimitry Andric bool IncludeSelf) {
5606c3fb27SDimitry Andric // Find all expandable direct users of Consts.
5706c3fb27SDimitry Andric SmallVector<Constant *> Stack;
58*0fca6ea1SDimitry Andric for (Constant *C : Consts) {
59*0fca6ea1SDimitry Andric if (IncludeSelf) {
60*0fca6ea1SDimitry Andric assert(isExpandableUser(C) && "One of the constants is not expandable");
61*0fca6ea1SDimitry Andric Stack.push_back(C);
62*0fca6ea1SDimitry Andric } else {
6306c3fb27SDimitry Andric for (User *U : C->users())
6406c3fb27SDimitry Andric if (isExpandableUser(U))
6506c3fb27SDimitry Andric Stack.push_back(cast<Constant>(U));
66*0fca6ea1SDimitry Andric }
67*0fca6ea1SDimitry Andric }
6806c3fb27SDimitry Andric
6906c3fb27SDimitry Andric // Include transitive users.
7006c3fb27SDimitry Andric SetVector<Constant *> ExpandableUsers;
7106c3fb27SDimitry Andric while (!Stack.empty()) {
7206c3fb27SDimitry Andric Constant *C = Stack.pop_back_val();
7306c3fb27SDimitry Andric if (!ExpandableUsers.insert(C))
74fe6060f1SDimitry Andric continue;
75fe6060f1SDimitry Andric
7606c3fb27SDimitry Andric for (auto *Nested : C->users())
7706c3fb27SDimitry Andric if (isExpandableUser(Nested))
7806c3fb27SDimitry Andric Stack.push_back(cast<Constant>(Nested));
7906c3fb27SDimitry Andric }
8006c3fb27SDimitry Andric
8106c3fb27SDimitry Andric // Find all instructions that use any of the expandable users
8206c3fb27SDimitry Andric SetVector<Instruction *> InstructionWorklist;
8306c3fb27SDimitry Andric for (Constant *C : ExpandableUsers)
8406c3fb27SDimitry Andric for (User *U : C->users())
8506c3fb27SDimitry Andric if (auto *I = dyn_cast<Instruction>(U))
86*0fca6ea1SDimitry Andric if (!RestrictToFunc || I->getFunction() == RestrictToFunc)
8706c3fb27SDimitry Andric InstructionWorklist.insert(I);
8806c3fb27SDimitry Andric
8906c3fb27SDimitry Andric // Replace those expandable operands with instructions
9006c3fb27SDimitry Andric bool Changed = false;
9106c3fb27SDimitry Andric while (!InstructionWorklist.empty()) {
9206c3fb27SDimitry Andric Instruction *I = InstructionWorklist.pop_back_val();
935f757f3fSDimitry Andric DebugLoc Loc = I->getDebugLoc();
9406c3fb27SDimitry Andric for (Use &U : I->operands()) {
95*0fca6ea1SDimitry Andric BasicBlock::iterator BI = I->getIterator();
96fe6060f1SDimitry Andric if (auto *Phi = dyn_cast<PHINode>(I)) {
97fe6060f1SDimitry Andric BasicBlock *BB = Phi->getIncomingBlock(U);
98*0fca6ea1SDimitry Andric BI = BB->getFirstInsertionPt();
99*0fca6ea1SDimitry Andric assert(BI != BB->end() && "Unexpected empty basic block");
100fe6060f1SDimitry Andric }
101fe6060f1SDimitry Andric
10206c3fb27SDimitry Andric if (auto *C = dyn_cast<Constant>(U.get())) {
10306c3fb27SDimitry Andric if (ExpandableUsers.contains(C)) {
10406c3fb27SDimitry Andric Changed = true;
1055f757f3fSDimitry Andric auto NewInsts = expandUser(BI, C);
1065f757f3fSDimitry Andric for (auto *NI : NewInsts)
1075f757f3fSDimitry Andric NI->setDebugLoc(Loc);
1085f757f3fSDimitry Andric InstructionWorklist.insert(NewInsts.begin(), NewInsts.end());
1095f757f3fSDimitry Andric U.set(NewInsts.back());
110349cc55cSDimitry Andric }
111e8d8bef9SDimitry Andric }
112e8d8bef9SDimitry Andric }
113fe6060f1SDimitry Andric }
114349cc55cSDimitry Andric
115*0fca6ea1SDimitry Andric if (RemoveDeadConstants)
11606c3fb27SDimitry Andric for (Constant *C : Consts)
11706c3fb27SDimitry Andric C->removeDeadConstantUsers();
118fe6060f1SDimitry Andric
11906c3fb27SDimitry Andric return Changed;
120fe6060f1SDimitry Andric }
121fe6060f1SDimitry Andric
122e8d8bef9SDimitry Andric } // namespace llvm
123