brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.0 KiB · b1864c3 Raw
135 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements a utility function for replacing LLVM constant10// 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 19using namespace llvm;20 21static bool isExpandableUser(User *U) {22  return isa<ConstantExpr>(U) || isa<ConstantAggregate>(U);23}24 25static void expandUser(BasicBlock::iterator InsertPt, Constant *C,26                       SmallVector<Instruction *, 4> &NewInsts) {27  NewInsts.clear();28  if (auto *CE = dyn_cast<ConstantExpr>(C)) {29    Instruction *ConstInst = CE->getAsInstruction();30    ConstInst->insertBefore(*InsertPt->getParent(), InsertPt);31    NewInsts.push_back(ConstInst);32  } else if (isa<ConstantStruct>(C) || isa<ConstantArray>(C)) {33    Value *V = PoisonValue::get(C->getType());34    for (auto [Idx, Op] : enumerate(C->operands())) {35      V = InsertValueInst::Create(V, Op, Idx, "", InsertPt);36      NewInsts.push_back(cast<Instruction>(V));37    }38  } else if (isa<ConstantVector>(C)) {39    Type *IdxTy = Type::getInt32Ty(C->getContext());40    Value *V = PoisonValue::get(C->getType());41    for (auto [Idx, Op] : enumerate(C->operands())) {42      V = InsertElementInst::Create(V, Op, ConstantInt::get(IdxTy, Idx), "",43                                    InsertPt);44      NewInsts.push_back(cast<Instruction>(V));45    }46  } else {47    llvm_unreachable("Not an expandable user");48  }49}50 51bool llvm::convertUsersOfConstantsToInstructions(ArrayRef<Constant *> Consts,52                                                 Function *RestrictToFunc,53                                                 bool RemoveDeadConstants,54                                                 bool IncludeSelf) {55  // Find all expandable direct users of Consts.56  SmallVector<Constant *> Stack;57  for (Constant *C : Consts) {58    assert(!isa<ConstantData>(C) &&59           "should not be expanding trivial constant users");60 61    if (IncludeSelf) {62      assert(isExpandableUser(C) && "One of the constants is not expandable");63      Stack.push_back(C);64    } else {65      for (User *U : C->users())66        if (isExpandableUser(U))67          Stack.push_back(cast<Constant>(U));68    }69  }70 71  // Include transitive users.72  SetVector<Constant *> ExpandableUsers;73  while (!Stack.empty()) {74    Constant *C = Stack.pop_back_val();75    if (!ExpandableUsers.insert(C))76      continue;77 78    for (auto *Nested : C->users())79      if (isExpandableUser(Nested))80        Stack.push_back(cast<Constant>(Nested));81  }82 83  // Find all instructions that use any of the expandable users84  SetVector<Instruction *> InstructionWorklist;85  for (Constant *C : ExpandableUsers)86    for (User *U : C->users())87      if (auto *I = dyn_cast<Instruction>(U))88        if (!RestrictToFunc || I->getFunction() == RestrictToFunc)89          InstructionWorklist.insert(I);90 91  // Replace those expandable operands with instructions92  bool Changed = false;93  // We need to cache the instructions we've already expanded to avoid expanding94  // the same constant multiple times in the same basic block, which is95  // problematic when the same constant is used in a phi node multiple times.96  DenseMap<std::pair<Constant *, BasicBlock *>, SmallVector<Instruction *, 4>>97      ConstantToInstructionMap;98  while (!InstructionWorklist.empty()) {99    Instruction *I = InstructionWorklist.pop_back_val();100    DebugLoc Loc = I->getDebugLoc();101    for (Use &U : I->operands()) {102      BasicBlock::iterator BI = I->getIterator();103      if (auto *Phi = dyn_cast<PHINode>(I)) {104        BasicBlock *BB = Phi->getIncomingBlock(U);105        BI = BB->getFirstInsertionPt();106        assert(BI != BB->end() && "Unexpected empty basic block");107      }108 109      if (auto *C = dyn_cast<Constant>(U.get())) {110        if (ExpandableUsers.contains(C)) {111          Changed = true;112          SmallVector<Instruction *, 4> &NewInsts =113              ConstantToInstructionMap[std::make_pair(C, BI->getParent())];114          // If the cached instruction is after the insertion point, we need to115          // create a new one. We can't simply move the cached instruction116          // because its operands (also expanded instructions) might not117          // dominate the new position.118          if (NewInsts.empty() || BI->comesBefore(NewInsts.front()))119            expandUser(BI, C, NewInsts);120          for (auto *NI : NewInsts)121            NI->setDebugLoc(Loc);122          InstructionWorklist.insert_range(NewInsts);123          U.set(NewInsts.back());124        }125      }126    }127  }128 129  if (RemoveDeadConstants)130    for (Constant *C : Consts)131      C->removeDeadConstantUsers();132 133  return Changed;134}135