1 //===- ValueList.cpp - Internal BitcodeReader implementation --------------===//
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
7 //===----------------------------------------------------------------------===//
10 #include "llvm/ADT/SmallVector.h"
11 #include "llvm/IR/Argument.h"
12 #include "llvm/IR/Constant.h"
13 #include "llvm/IR/Constants.h"
14 #include "llvm/IR/GlobalValue.h"
15 #include "llvm/IR/Instruction.h"
16 #include "llvm/IR/Type.h"
17 #include "llvm/IR/User.h"
18 #include "llvm/IR/Value.h"
19 #include "llvm/Support/Casting.h"
20 #include "llvm/Support/ErrorHandling.h"
31 /// A class for maintaining the slot number definition
32 /// as a placeholder for the actual definition for forward constants defs.
33 class ConstantPlaceHolder
: public ConstantExpr
{
35 explicit ConstantPlaceHolder(Type
*Ty
, LLVMContext
&Context
)
36 : ConstantExpr(Ty
, Instruction::UserOp1
, &Op
<0>(), 1) {
37 Op
<0>() = UndefValue::get(Type::getInt32Ty(Context
));
40 ConstantPlaceHolder
&operator=(const ConstantPlaceHolder
&) = delete;
42 // allocate space for exactly one operand
43 void *operator new(size_t s
) { return User::operator new(s
, 1); }
45 /// Methods to support type inquiry through isa, cast, and dyn_cast.
46 static bool classof(const Value
*V
) {
47 return isa
<ConstantExpr
>(V
) &&
48 cast
<ConstantExpr
>(V
)->getOpcode() == Instruction::UserOp1
;
51 /// Provide fast operand accessors
52 DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value
);
55 } // end anonymous namespace
57 // FIXME: can we inherit this from ConstantExpr?
59 struct OperandTraits
<ConstantPlaceHolder
>
60 : public FixedNumOperandTraits
<ConstantPlaceHolder
, 1> {};
61 DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ConstantPlaceHolder
, Value
)
63 } // end namespace llvm
65 void BitcodeReaderValueList::assignValue(Value
*V
, unsigned Idx
) {
74 WeakTrackingVH
&OldV
= ValuePtrs
[Idx
];
80 // Handle constants and non-constants (e.g. instrs) differently for
82 if (Constant
*PHC
= dyn_cast
<Constant
>(&*OldV
)) {
83 ResolveConstants
.push_back(std::make_pair(PHC
, Idx
));
86 // If there was a forward reference to this value, replace it.
87 Value
*PrevVal
= OldV
;
88 OldV
->replaceAllUsesWith(V
);
89 PrevVal
->deleteValue();
93 Constant
*BitcodeReaderValueList::getConstantFwdRef(unsigned Idx
, Type
*Ty
) {
94 // Bail out for a clearly invalid value.
95 if (Idx
>= RefsUpperBound
)
101 if (Value
*V
= ValuePtrs
[Idx
]) {
102 if (Ty
!= V
->getType())
103 report_fatal_error("Type mismatch in constant table!");
104 return cast
<Constant
>(V
);
107 // Create and return a placeholder, which will later be RAUW'd.
108 Constant
*C
= new ConstantPlaceHolder(Ty
, Context
);
113 Value
*BitcodeReaderValueList::getValueFwdRef(unsigned Idx
, Type
*Ty
) {
114 // Bail out for a clearly invalid value.
115 if (Idx
>= RefsUpperBound
)
121 if (Value
*V
= ValuePtrs
[Idx
]) {
122 // If the types don't match, it's invalid.
123 if (Ty
&& Ty
!= V
->getType())
128 // No type specified, must be invalid reference.
132 // Create and return a placeholder, which will later be RAUW'd.
133 Value
*V
= new Argument(Ty
);
138 /// Once all constants are read, this method bulk resolves any forward
139 /// references. The idea behind this is that we sometimes get constants (such
140 /// as large arrays) which reference *many* forward ref constants. Replacing
141 /// each of these causes a lot of thrashing when building/reuniquing the
142 /// constant. Instead of doing this, we look at all the uses and rewrite all
143 /// the place holders at once for any constant that uses a placeholder.
144 void BitcodeReaderValueList::resolveConstantForwardRefs() {
145 // Sort the values by-pointer so that they are efficient to look up with a
147 llvm::sort(ResolveConstants
);
149 SmallVector
<Constant
*, 64> NewOps
;
151 while (!ResolveConstants
.empty()) {
152 Value
*RealVal
= operator[](ResolveConstants
.back().second
);
153 Constant
*Placeholder
= ResolveConstants
.back().first
;
154 ResolveConstants
.pop_back();
156 // Loop over all users of the placeholder, updating them to reference the
157 // new value. If they reference more than one placeholder, update them all
159 while (!Placeholder
->use_empty()) {
160 auto UI
= Placeholder
->user_begin();
163 // If the using object isn't uniqued, just update the operands. This
164 // handles instructions and initializers for global variables.
165 if (!isa
<Constant
>(U
) || isa
<GlobalValue
>(U
)) {
166 UI
.getUse().set(RealVal
);
170 // Otherwise, we have a constant that uses the placeholder. Replace that
171 // constant with a new constant that has *all* placeholder uses updated.
172 Constant
*UserC
= cast
<Constant
>(U
);
173 for (User::op_iterator I
= UserC
->op_begin(), E
= UserC
->op_end(); I
!= E
;
176 if (!isa
<ConstantPlaceHolder
>(*I
)) {
177 // Not a placeholder reference.
179 } else if (*I
== Placeholder
) {
180 // Common case is that it just references this one placeholder.
183 // Otherwise, look up the placeholder in ResolveConstants.
184 ResolveConstantsTy::iterator It
= llvm::lower_bound(
186 std::pair
<Constant
*, unsigned>(cast
<Constant
>(*I
), 0));
187 assert(It
!= ResolveConstants
.end() && It
->first
== *I
);
188 NewOp
= operator[](It
->second
);
191 NewOps
.push_back(cast
<Constant
>(NewOp
));
194 // Make the new constant.
196 if (ConstantArray
*UserCA
= dyn_cast
<ConstantArray
>(UserC
)) {
197 NewC
= ConstantArray::get(UserCA
->getType(), NewOps
);
198 } else if (ConstantStruct
*UserCS
= dyn_cast
<ConstantStruct
>(UserC
)) {
199 NewC
= ConstantStruct::get(UserCS
->getType(), NewOps
);
200 } else if (isa
<ConstantVector
>(UserC
)) {
201 NewC
= ConstantVector::get(NewOps
);
203 assert(isa
<ConstantExpr
>(UserC
) && "Must be a ConstantExpr.");
204 NewC
= cast
<ConstantExpr
>(UserC
)->getWithOperands(NewOps
);
207 UserC
->replaceAllUsesWith(NewC
);
208 UserC
->destroyConstant();
212 // Update all ValueHandles, they should be the only users at this point.
213 Placeholder
->replaceAllUsesWith(RealVal
);
214 delete cast
<ConstantPlaceHolder
>(Placeholder
);