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*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 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