Coverage Report

Created: 2024-01-17 10:31

/src/llvm-project/llvm/lib/IR/ReplaceConstant.cpp
Line
Count
Source (jump to first uncovered line)
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-exception
6
//
7
//===----------------------------------------------------------------------===//
8
//
9
// This file implements a utility function for replacing LLVM constant
10
// 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
19
namespace llvm {
20
21
0
static bool isExpandableUser(User *U) {
22
0
  return isa<ConstantExpr>(U) || isa<ConstantAggregate>(U);
23
0
}
24
25
static SmallVector<Instruction *, 4> expandUser(Instruction *InsertPt,
26
0
                                                Constant *C) {
27
0
  SmallVector<Instruction *, 4> NewInsts;
28
0
  if (auto *CE = dyn_cast<ConstantExpr>(C)) {
29
0
    NewInsts.push_back(CE->getAsInstruction(InsertPt));
30
0
  } else if (isa<ConstantStruct>(C) || isa<ConstantArray>(C)) {
31
0
    Value *V = PoisonValue::get(C->getType());
32
0
    for (auto [Idx, Op] : enumerate(C->operands())) {
33
0
      V = InsertValueInst::Create(V, Op, Idx, "", InsertPt);
34
0
      NewInsts.push_back(cast<Instruction>(V));
35
0
    }
36
0
  } else if (isa<ConstantVector>(C)) {
37
0
    Type *IdxTy = Type::getInt32Ty(C->getContext());
38
0
    Value *V = PoisonValue::get(C->getType());
39
0
    for (auto [Idx, Op] : enumerate(C->operands())) {
40
0
      V = InsertElementInst::Create(V, Op, ConstantInt::get(IdxTy, Idx), "",
41
0
                                    InsertPt);
42
0
      NewInsts.push_back(cast<Instruction>(V));
43
0
    }
44
0
  } else {
45
0
    llvm_unreachable("Not an expandable user");
46
0
  }
47
0
  return NewInsts;
48
0
}
49
50
0
bool convertUsersOfConstantsToInstructions(ArrayRef<Constant *> Consts) {
51
  // Find all expandable direct users of Consts.
52
0
  SmallVector<Constant *> Stack;
53
0
  for (Constant *C : Consts)
54
0
    for (User *U : C->users())
55
0
      if (isExpandableUser(U))
56
0
        Stack.push_back(cast<Constant>(U));
57
58
  // Include transitive users.
59
0
  SetVector<Constant *> ExpandableUsers;
60
0
  while (!Stack.empty()) {
61
0
    Constant *C = Stack.pop_back_val();
62
0
    if (!ExpandableUsers.insert(C))
63
0
      continue;
64
65
0
    for (auto *Nested : C->users())
66
0
      if (isExpandableUser(Nested))
67
0
        Stack.push_back(cast<Constant>(Nested));
68
0
  }
69
70
  // Find all instructions that use any of the expandable users
71
0
  SetVector<Instruction *> InstructionWorklist;
72
0
  for (Constant *C : ExpandableUsers)
73
0
    for (User *U : C->users())
74
0
      if (auto *I = dyn_cast<Instruction>(U))
75
0
        InstructionWorklist.insert(I);
76
77
  // Replace those expandable operands with instructions
78
0
  bool Changed = false;
79
0
  while (!InstructionWorklist.empty()) {
80
0
    Instruction *I = InstructionWorklist.pop_back_val();
81
0
    DebugLoc Loc = I->getDebugLoc();
82
0
    for (Use &U : I->operands()) {
83
0
      auto *BI = I;
84
0
      if (auto *Phi = dyn_cast<PHINode>(I)) {
85
0
        BasicBlock *BB = Phi->getIncomingBlock(U);
86
0
        BasicBlock::iterator It = BB->getFirstInsertionPt();
87
0
        assert(It != BB->end() && "Unexpected empty basic block");
88
0
        BI = &*It;
89
0
      }
90
91
0
      if (auto *C = dyn_cast<Constant>(U.get())) {
92
0
        if (ExpandableUsers.contains(C)) {
93
0
          Changed = true;
94
0
          auto NewInsts = expandUser(BI, C);
95
0
          for (auto *NI : NewInsts)
96
0
            NI->setDebugLoc(Loc);
97
0
          InstructionWorklist.insert(NewInsts.begin(), NewInsts.end());
98
0
          U.set(NewInsts.back());
99
0
        }
100
0
      }
101
0
    }
102
0
  }
103
104
0
  for (Constant *C : Consts)
105
0
    C->removeDeadConstantUsers();
106
107
0
  return Changed;
108
0
}
109
110
} // namespace llvm