xref: /freebsd/contrib/llvm-project/llvm/lib/IR/ReplaceConstant.cpp (revision 5f757f3ff9144b609b3c433dfd370cc6bdc191ad)
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 
2106c3fb27SDimitry Andric static bool isExpandableUser(User *U) {
2206c3fb27SDimitry Andric   return isa<ConstantExpr>(U) || isa<ConstantAggregate>(U);
23fe6060f1SDimitry Andric }
24fe6060f1SDimitry Andric 
25*5f757f3fSDimitry Andric static SmallVector<Instruction *, 4> expandUser(Instruction *InsertPt,
26*5f757f3fSDimitry Andric                                                 Constant *C) {
27*5f757f3fSDimitry Andric   SmallVector<Instruction *, 4> NewInsts;
2806c3fb27SDimitry Andric   if (auto *CE = dyn_cast<ConstantExpr>(C)) {
29*5f757f3fSDimitry Andric     NewInsts.push_back(CE->getAsInstruction(InsertPt));
3006c3fb27SDimitry Andric   } else if (isa<ConstantStruct>(C) || isa<ConstantArray>(C)) {
3106c3fb27SDimitry Andric     Value *V = PoisonValue::get(C->getType());
32*5f757f3fSDimitry Andric     for (auto [Idx, Op] : enumerate(C->operands())) {
3306c3fb27SDimitry Andric       V = InsertValueInst::Create(V, Op, Idx, "", InsertPt);
34*5f757f3fSDimitry Andric       NewInsts.push_back(cast<Instruction>(V));
35*5f757f3fSDimitry Andric     }
3606c3fb27SDimitry Andric   } else if (isa<ConstantVector>(C)) {
3706c3fb27SDimitry Andric     Type *IdxTy = Type::getInt32Ty(C->getContext());
3806c3fb27SDimitry Andric     Value *V = PoisonValue::get(C->getType());
39*5f757f3fSDimitry Andric     for (auto [Idx, Op] : enumerate(C->operands())) {
4006c3fb27SDimitry Andric       V = InsertElementInst::Create(V, Op, ConstantInt::get(IdxTy, Idx), "",
4106c3fb27SDimitry Andric                                     InsertPt);
42*5f757f3fSDimitry Andric       NewInsts.push_back(cast<Instruction>(V));
43*5f757f3fSDimitry Andric     }
4406c3fb27SDimitry Andric   } else {
4506c3fb27SDimitry Andric     llvm_unreachable("Not an expandable user");
4606c3fb27SDimitry Andric   }
47*5f757f3fSDimitry Andric   return NewInsts;
4806c3fb27SDimitry Andric }
49349cc55cSDimitry Andric 
5006c3fb27SDimitry Andric bool convertUsersOfConstantsToInstructions(ArrayRef<Constant *> Consts) {
5106c3fb27SDimitry Andric   // Find all expandable direct users of Consts.
5206c3fb27SDimitry Andric   SmallVector<Constant *> Stack;
5306c3fb27SDimitry Andric   for (Constant *C : Consts)
5406c3fb27SDimitry Andric     for (User *U : C->users())
5506c3fb27SDimitry Andric       if (isExpandableUser(U))
5606c3fb27SDimitry Andric         Stack.push_back(cast<Constant>(U));
5706c3fb27SDimitry Andric 
5806c3fb27SDimitry Andric   // Include transitive users.
5906c3fb27SDimitry Andric   SetVector<Constant *> ExpandableUsers;
6006c3fb27SDimitry Andric   while (!Stack.empty()) {
6106c3fb27SDimitry Andric     Constant *C = Stack.pop_back_val();
6206c3fb27SDimitry Andric     if (!ExpandableUsers.insert(C))
63fe6060f1SDimitry Andric       continue;
64fe6060f1SDimitry Andric 
6506c3fb27SDimitry Andric     for (auto *Nested : C->users())
6606c3fb27SDimitry Andric       if (isExpandableUser(Nested))
6706c3fb27SDimitry Andric         Stack.push_back(cast<Constant>(Nested));
6806c3fb27SDimitry Andric   }
6906c3fb27SDimitry Andric 
7006c3fb27SDimitry Andric   // Find all instructions that use any of the expandable users
7106c3fb27SDimitry Andric   SetVector<Instruction *> InstructionWorklist;
7206c3fb27SDimitry Andric   for (Constant *C : ExpandableUsers)
7306c3fb27SDimitry Andric     for (User *U : C->users())
7406c3fb27SDimitry Andric       if (auto *I = dyn_cast<Instruction>(U))
7506c3fb27SDimitry Andric         InstructionWorklist.insert(I);
7606c3fb27SDimitry Andric 
7706c3fb27SDimitry Andric   // Replace those expandable operands with instructions
7806c3fb27SDimitry Andric   bool Changed = false;
7906c3fb27SDimitry Andric   while (!InstructionWorklist.empty()) {
8006c3fb27SDimitry Andric     Instruction *I = InstructionWorklist.pop_back_val();
81*5f757f3fSDimitry Andric     DebugLoc Loc = I->getDebugLoc();
8206c3fb27SDimitry Andric     for (Use &U : I->operands()) {
83fe6060f1SDimitry Andric       auto *BI = I;
84fe6060f1SDimitry Andric       if (auto *Phi = dyn_cast<PHINode>(I)) {
85fe6060f1SDimitry Andric         BasicBlock *BB = Phi->getIncomingBlock(U);
8606c3fb27SDimitry Andric         BasicBlock::iterator It = BB->getFirstInsertionPt();
8706c3fb27SDimitry Andric         assert(It != BB->end() && "Unexpected empty basic block");
8806c3fb27SDimitry Andric         BI = &*It;
89fe6060f1SDimitry Andric       }
90fe6060f1SDimitry Andric 
9106c3fb27SDimitry Andric       if (auto *C = dyn_cast<Constant>(U.get())) {
9206c3fb27SDimitry Andric         if (ExpandableUsers.contains(C)) {
9306c3fb27SDimitry Andric           Changed = true;
94*5f757f3fSDimitry Andric           auto NewInsts = expandUser(BI, C);
95*5f757f3fSDimitry Andric           for (auto *NI : NewInsts)
96*5f757f3fSDimitry Andric             NI->setDebugLoc(Loc);
97*5f757f3fSDimitry Andric           InstructionWorklist.insert(NewInsts.begin(), NewInsts.end());
98*5f757f3fSDimitry Andric           U.set(NewInsts.back());
99349cc55cSDimitry Andric         }
100e8d8bef9SDimitry Andric       }
101e8d8bef9SDimitry Andric     }
102fe6060f1SDimitry Andric   }
103349cc55cSDimitry Andric 
10406c3fb27SDimitry Andric   for (Constant *C : Consts)
10506c3fb27SDimitry Andric     C->removeDeadConstantUsers();
106fe6060f1SDimitry Andric 
10706c3fb27SDimitry Andric   return Changed;
108fe6060f1SDimitry Andric }
109fe6060f1SDimitry Andric 
110e8d8bef9SDimitry Andric } // namespace llvm
111