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" 15*06c3fb27SDimitry 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 21*06c3fb27SDimitry Andric static bool isExpandableUser(User *U) { 22*06c3fb27SDimitry Andric return isa<ConstantExpr>(U) || isa<ConstantAggregate>(U); 23fe6060f1SDimitry Andric } 24fe6060f1SDimitry Andric 25*06c3fb27SDimitry Andric static Instruction *expandUser(Instruction *InsertPt, Constant *C) { 26*06c3fb27SDimitry Andric if (auto *CE = dyn_cast<ConstantExpr>(C)) { 27*06c3fb27SDimitry Andric return CE->getAsInstruction(InsertPt); 28*06c3fb27SDimitry Andric } else if (isa<ConstantStruct>(C) || isa<ConstantArray>(C)) { 29*06c3fb27SDimitry Andric Value *V = PoisonValue::get(C->getType()); 30*06c3fb27SDimitry Andric for (auto [Idx, Op] : enumerate(C->operands())) 31*06c3fb27SDimitry Andric V = InsertValueInst::Create(V, Op, Idx, "", InsertPt); 32*06c3fb27SDimitry Andric return cast<Instruction>(V); 33*06c3fb27SDimitry Andric } else if (isa<ConstantVector>(C)) { 34*06c3fb27SDimitry Andric Type *IdxTy = Type::getInt32Ty(C->getContext()); 35*06c3fb27SDimitry Andric Value *V = PoisonValue::get(C->getType()); 36*06c3fb27SDimitry Andric for (auto [Idx, Op] : enumerate(C->operands())) 37*06c3fb27SDimitry Andric V = InsertElementInst::Create(V, Op, ConstantInt::get(IdxTy, Idx), "", 38*06c3fb27SDimitry Andric InsertPt); 39*06c3fb27SDimitry Andric return cast<Instruction>(V); 40*06c3fb27SDimitry Andric } else { 41*06c3fb27SDimitry Andric llvm_unreachable("Not an expandable user"); 42*06c3fb27SDimitry Andric } 43*06c3fb27SDimitry Andric } 44349cc55cSDimitry Andric 45*06c3fb27SDimitry Andric bool convertUsersOfConstantsToInstructions(ArrayRef<Constant *> Consts) { 46*06c3fb27SDimitry Andric // Find all expandable direct users of Consts. 47*06c3fb27SDimitry Andric SmallVector<Constant *> Stack; 48*06c3fb27SDimitry Andric for (Constant *C : Consts) 49*06c3fb27SDimitry Andric for (User *U : C->users()) 50*06c3fb27SDimitry Andric if (isExpandableUser(U)) 51*06c3fb27SDimitry Andric Stack.push_back(cast<Constant>(U)); 52*06c3fb27SDimitry Andric 53*06c3fb27SDimitry Andric // Include transitive users. 54*06c3fb27SDimitry Andric SetVector<Constant *> ExpandableUsers; 55*06c3fb27SDimitry Andric while (!Stack.empty()) { 56*06c3fb27SDimitry Andric Constant *C = Stack.pop_back_val(); 57*06c3fb27SDimitry Andric if (!ExpandableUsers.insert(C)) 58fe6060f1SDimitry Andric continue; 59fe6060f1SDimitry Andric 60*06c3fb27SDimitry Andric for (auto *Nested : C->users()) 61*06c3fb27SDimitry Andric if (isExpandableUser(Nested)) 62*06c3fb27SDimitry Andric Stack.push_back(cast<Constant>(Nested)); 63*06c3fb27SDimitry Andric } 64*06c3fb27SDimitry Andric 65*06c3fb27SDimitry Andric // Find all instructions that use any of the expandable users 66*06c3fb27SDimitry Andric SetVector<Instruction *> InstructionWorklist; 67*06c3fb27SDimitry Andric for (Constant *C : ExpandableUsers) 68*06c3fb27SDimitry Andric for (User *U : C->users()) 69*06c3fb27SDimitry Andric if (auto *I = dyn_cast<Instruction>(U)) 70*06c3fb27SDimitry Andric InstructionWorklist.insert(I); 71*06c3fb27SDimitry Andric 72*06c3fb27SDimitry Andric // Replace those expandable operands with instructions 73*06c3fb27SDimitry Andric bool Changed = false; 74*06c3fb27SDimitry Andric while (!InstructionWorklist.empty()) { 75*06c3fb27SDimitry Andric Instruction *I = InstructionWorklist.pop_back_val(); 76*06c3fb27SDimitry Andric for (Use &U : I->operands()) { 77fe6060f1SDimitry Andric auto *BI = I; 78fe6060f1SDimitry Andric if (auto *Phi = dyn_cast<PHINode>(I)) { 79fe6060f1SDimitry Andric BasicBlock *BB = Phi->getIncomingBlock(U); 80*06c3fb27SDimitry Andric BasicBlock::iterator It = BB->getFirstInsertionPt(); 81*06c3fb27SDimitry Andric assert(It != BB->end() && "Unexpected empty basic block"); 82*06c3fb27SDimitry Andric BI = &*It; 83fe6060f1SDimitry Andric } 84fe6060f1SDimitry Andric 85*06c3fb27SDimitry Andric if (auto *C = dyn_cast<Constant>(U.get())) { 86*06c3fb27SDimitry Andric if (ExpandableUsers.contains(C)) { 87*06c3fb27SDimitry Andric Changed = true; 88*06c3fb27SDimitry Andric Instruction *NI = expandUser(BI, C); 89*06c3fb27SDimitry Andric InstructionWorklist.insert(NI); 90*06c3fb27SDimitry Andric U.set(NI); 91349cc55cSDimitry Andric } 92e8d8bef9SDimitry Andric } 93e8d8bef9SDimitry Andric } 94fe6060f1SDimitry Andric } 95349cc55cSDimitry Andric 96*06c3fb27SDimitry Andric for (Constant *C : Consts) 97*06c3fb27SDimitry Andric C->removeDeadConstantUsers(); 98fe6060f1SDimitry Andric 99*06c3fb27SDimitry Andric return Changed; 100fe6060f1SDimitry Andric } 101fe6060f1SDimitry Andric 102e8d8bef9SDimitry Andric } // namespace llvm 103