1 | //===-- ConstantsContext.h - Constants-related Context Interals -*- C++ -*-===// |
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 defines various helper methods and classes used by |
10 | // LLVMContextImpl for creating and managing constants. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #ifndef LLVM_LIB_IR_CONSTANTSCONTEXT_H |
15 | #define LLVM_LIB_IR_CONSTANTSCONTEXT_H |
16 | |
17 | #include "llvm/ADT/ArrayRef.h" |
18 | #include "llvm/ADT/DenseMapInfo.h" |
19 | #include "llvm/ADT/DenseSet.h" |
20 | #include "llvm/ADT/Hashing.h" |
21 | #include "llvm/ADT/SmallVector.h" |
22 | #include "llvm/ADT/StringRef.h" |
23 | #include "llvm/IR/Constant.h" |
24 | #include "llvm/IR/Constants.h" |
25 | #include "llvm/IR/DerivedTypes.h" |
26 | #include "llvm/IR/InlineAsm.h" |
27 | #include "llvm/IR/Instruction.h" |
28 | #include "llvm/IR/Instructions.h" |
29 | #include "llvm/IR/OperandTraits.h" |
30 | #include "llvm/Support/Casting.h" |
31 | #include "llvm/Support/Debug.h" |
32 | #include "llvm/Support/ErrorHandling.h" |
33 | #include "llvm/Support/raw_ostream.h" |
34 | #include <cassert> |
35 | #include <cstddef> |
36 | #include <cstdint> |
37 | #include <utility> |
38 | |
39 | #define DEBUG_TYPE "ir" |
40 | |
41 | namespace llvm { |
42 | |
43 | /// CastConstantExpr - This class is private to Constants.cpp, and is used |
44 | /// behind the scenes to implement cast constant exprs. |
45 | class CastConstantExpr final : public ConstantExpr { |
46 | public: |
47 | CastConstantExpr(unsigned Opcode, Constant *C, Type *Ty) |
48 | : ConstantExpr(Ty, Opcode, &Op<0>(), 1) { |
49 | Op<0>() = C; |
50 | } |
51 | |
52 | // allocate space for exactly one operand |
53 | void *operator new(size_t S) { return User::operator new(Size: S, Us: 1); } |
54 | void operator delete(void *Ptr) { User::operator delete(Usr: Ptr); } |
55 | |
56 | DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); |
57 | |
58 | static bool classof(const ConstantExpr *CE) { |
59 | return Instruction::isCast(Opcode: CE->getOpcode()); |
60 | } |
61 | static bool classof(const Value *V) { |
62 | return isa<ConstantExpr>(Val: V) && classof(CE: cast<ConstantExpr>(Val: V)); |
63 | } |
64 | }; |
65 | |
66 | /// BinaryConstantExpr - This class is private to Constants.cpp, and is used |
67 | /// behind the scenes to implement binary constant exprs. |
68 | class BinaryConstantExpr final : public ConstantExpr { |
69 | public: |
70 | BinaryConstantExpr(unsigned Opcode, Constant *C1, Constant *C2, |
71 | unsigned Flags) |
72 | : ConstantExpr(C1->getType(), Opcode, &Op<0>(), 2) { |
73 | Op<0>() = C1; |
74 | Op<1>() = C2; |
75 | SubclassOptionalData = Flags; |
76 | } |
77 | |
78 | // allocate space for exactly two operands |
79 | void *operator new(size_t S) { return User::operator new(Size: S, Us: 2); } |
80 | void operator delete(void *Ptr) { User::operator delete(Usr: Ptr); } |
81 | |
82 | /// Transparently provide more efficient getOperand methods. |
83 | DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); |
84 | |
85 | static bool classof(const ConstantExpr *CE) { |
86 | return Instruction::isBinaryOp(Opcode: CE->getOpcode()); |
87 | } |
88 | static bool classof(const Value *V) { |
89 | return isa<ConstantExpr>(Val: V) && classof(CE: cast<ConstantExpr>(Val: V)); |
90 | } |
91 | }; |
92 | |
93 | /// ExtractElementConstantExpr - This class is private to |
94 | /// Constants.cpp, and is used behind the scenes to implement |
95 | /// extractelement constant exprs. |
96 | class final : public ConstantExpr { |
97 | public: |
98 | (Constant *C1, Constant *C2) |
99 | : ConstantExpr(cast<VectorType>(Val: C1->getType())->getElementType(), |
100 | Instruction::ExtractElement, &Op<0>(), 2) { |
101 | Op<0>() = C1; |
102 | Op<1>() = C2; |
103 | } |
104 | |
105 | // allocate space for exactly two operands |
106 | void *(size_t S) { return User::operator new(Size: S, Us: 2); } |
107 | void (void *Ptr) { User::operator delete(Usr: Ptr); } |
108 | |
109 | /// Transparently provide more efficient getOperand methods. |
110 | DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); |
111 | |
112 | static bool (const ConstantExpr *CE) { |
113 | return CE->getOpcode() == Instruction::ExtractElement; |
114 | } |
115 | static bool (const Value *V) { |
116 | return isa<ConstantExpr>(Val: V) && classof(CE: cast<ConstantExpr>(Val: V)); |
117 | } |
118 | }; |
119 | |
120 | /// InsertElementConstantExpr - This class is private to |
121 | /// Constants.cpp, and is used behind the scenes to implement |
122 | /// insertelement constant exprs. |
123 | class InsertElementConstantExpr final : public ConstantExpr { |
124 | public: |
125 | InsertElementConstantExpr(Constant *C1, Constant *C2, Constant *C3) |
126 | : ConstantExpr(C1->getType(), Instruction::InsertElement, |
127 | &Op<0>(), 3) { |
128 | Op<0>() = C1; |
129 | Op<1>() = C2; |
130 | Op<2>() = C3; |
131 | } |
132 | |
133 | // allocate space for exactly three operands |
134 | void *operator new(size_t S) { return User::operator new(Size: S, Us: 3); } |
135 | void operator delete(void *Ptr) { User::operator delete(Usr: Ptr); } |
136 | |
137 | /// Transparently provide more efficient getOperand methods. |
138 | DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); |
139 | |
140 | static bool classof(const ConstantExpr *CE) { |
141 | return CE->getOpcode() == Instruction::InsertElement; |
142 | } |
143 | static bool classof(const Value *V) { |
144 | return isa<ConstantExpr>(Val: V) && classof(CE: cast<ConstantExpr>(Val: V)); |
145 | } |
146 | }; |
147 | |
148 | /// ShuffleVectorConstantExpr - This class is private to |
149 | /// Constants.cpp, and is used behind the scenes to implement |
150 | /// shufflevector constant exprs. |
151 | class ShuffleVectorConstantExpr final : public ConstantExpr { |
152 | public: |
153 | ShuffleVectorConstantExpr(Constant *C1, Constant *C2, ArrayRef<int> Mask) |
154 | : ConstantExpr(VectorType::get( |
155 | ElementType: cast<VectorType>(Val: C1->getType())->getElementType(), |
156 | NumElements: Mask.size(), Scalable: isa<ScalableVectorType>(Val: C1->getType())), |
157 | Instruction::ShuffleVector, &Op<0>(), 2) { |
158 | assert(ShuffleVectorInst::isValidOperands(C1, C2, Mask) && |
159 | "Invalid shuffle vector instruction operands!" ); |
160 | Op<0>() = C1; |
161 | Op<1>() = C2; |
162 | ShuffleMask.assign(in_start: Mask.begin(), in_end: Mask.end()); |
163 | ShuffleMaskForBitcode = |
164 | ShuffleVectorInst::convertShuffleMaskForBitcode(Mask, ResultTy: getType()); |
165 | } |
166 | |
167 | SmallVector<int, 4> ShuffleMask; |
168 | Constant *ShuffleMaskForBitcode; |
169 | |
170 | void *operator new(size_t S) { return User::operator new(Size: S, Us: 2); } |
171 | void operator delete(void *Ptr) { return User::operator delete(Usr: Ptr); } |
172 | |
173 | /// Transparently provide more efficient getOperand methods. |
174 | DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); |
175 | |
176 | static bool classof(const ConstantExpr *CE) { |
177 | return CE->getOpcode() == Instruction::ShuffleVector; |
178 | } |
179 | static bool classof(const Value *V) { |
180 | return isa<ConstantExpr>(Val: V) && classof(CE: cast<ConstantExpr>(Val: V)); |
181 | } |
182 | }; |
183 | |
184 | /// GetElementPtrConstantExpr - This class is private to Constants.cpp, and is |
185 | /// used behind the scenes to implement getelementptr constant exprs. |
186 | class GetElementPtrConstantExpr : public ConstantExpr { |
187 | Type *SrcElementTy; |
188 | Type *ResElementTy; |
189 | std::optional<ConstantRange> InRange; |
190 | |
191 | GetElementPtrConstantExpr(Type *SrcElementTy, Constant *C, |
192 | ArrayRef<Constant *> IdxList, Type *DestTy, |
193 | std::optional<ConstantRange> InRange); |
194 | |
195 | public: |
196 | static GetElementPtrConstantExpr * |
197 | Create(Type *SrcElementTy, Constant *C, ArrayRef<Constant *> IdxList, |
198 | Type *DestTy, unsigned Flags, std::optional<ConstantRange> InRange) { |
199 | GetElementPtrConstantExpr *Result = new (IdxList.size() + 1) |
200 | GetElementPtrConstantExpr(SrcElementTy, C, IdxList, DestTy, |
201 | std::move(InRange)); |
202 | Result->SubclassOptionalData = Flags; |
203 | return Result; |
204 | } |
205 | |
206 | Type *getSourceElementType() const; |
207 | Type *getResultElementType() const; |
208 | std::optional<ConstantRange> getInRange() const; |
209 | |
210 | /// Transparently provide more efficient getOperand methods. |
211 | DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); |
212 | |
213 | static bool classof(const ConstantExpr *CE) { |
214 | return CE->getOpcode() == Instruction::GetElementPtr; |
215 | } |
216 | static bool classof(const Value *V) { |
217 | return isa<ConstantExpr>(Val: V) && classof(CE: cast<ConstantExpr>(Val: V)); |
218 | } |
219 | }; |
220 | |
221 | // CompareConstantExpr - This class is private to Constants.cpp, and is used |
222 | // behind the scenes to implement ICmp and FCmp constant expressions. This is |
223 | // needed in order to store the predicate value for these instructions. |
224 | class CompareConstantExpr final : public ConstantExpr { |
225 | public: |
226 | unsigned short predicate; |
227 | CompareConstantExpr(Type *ty, Instruction::OtherOps opc, |
228 | unsigned short pred, Constant* LHS, Constant* RHS) |
229 | : ConstantExpr(ty, opc, &Op<0>(), 2), predicate(pred) { |
230 | Op<0>() = LHS; |
231 | Op<1>() = RHS; |
232 | } |
233 | |
234 | // allocate space for exactly two operands |
235 | void *operator new(size_t S) { return User::operator new(Size: S, Us: 2); } |
236 | void operator delete(void *Ptr) { return User::operator delete(Usr: Ptr); } |
237 | |
238 | /// Transparently provide more efficient getOperand methods. |
239 | DECLARE_TRANSPARENT_OPERAND_ACCESSORS(Value); |
240 | |
241 | static bool classof(const ConstantExpr *CE) { |
242 | return CE->getOpcode() == Instruction::ICmp || |
243 | CE->getOpcode() == Instruction::FCmp; |
244 | } |
245 | static bool classof(const Value *V) { |
246 | return isa<ConstantExpr>(Val: V) && classof(CE: cast<ConstantExpr>(Val: V)); |
247 | } |
248 | }; |
249 | |
250 | template <> |
251 | struct OperandTraits<CastConstantExpr> |
252 | : public FixedNumOperandTraits<CastConstantExpr, 1> {}; |
253 | DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CastConstantExpr, Value) |
254 | |
255 | template <> |
256 | struct OperandTraits<BinaryConstantExpr> |
257 | : public FixedNumOperandTraits<BinaryConstantExpr, 2> {}; |
258 | DEFINE_TRANSPARENT_OPERAND_ACCESSORS(BinaryConstantExpr, Value) |
259 | |
260 | template <> |
261 | struct OperandTraits<ExtractElementConstantExpr> |
262 | : public FixedNumOperandTraits<ExtractElementConstantExpr, 2> {}; |
263 | DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ExtractElementConstantExpr, Value) |
264 | |
265 | template <> |
266 | struct OperandTraits<InsertElementConstantExpr> |
267 | : public FixedNumOperandTraits<InsertElementConstantExpr, 3> {}; |
268 | DEFINE_TRANSPARENT_OPERAND_ACCESSORS(InsertElementConstantExpr, Value) |
269 | |
270 | template <> |
271 | struct OperandTraits<ShuffleVectorConstantExpr> |
272 | : public FixedNumOperandTraits<ShuffleVectorConstantExpr, 2> {}; |
273 | DEFINE_TRANSPARENT_OPERAND_ACCESSORS(ShuffleVectorConstantExpr, Value) |
274 | |
275 | template <> |
276 | struct OperandTraits<GetElementPtrConstantExpr> |
277 | : public VariadicOperandTraits<GetElementPtrConstantExpr, 1> {}; |
278 | |
279 | DEFINE_TRANSPARENT_OPERAND_ACCESSORS(GetElementPtrConstantExpr, Value) |
280 | |
281 | template <> |
282 | struct OperandTraits<CompareConstantExpr> |
283 | : public FixedNumOperandTraits<CompareConstantExpr, 2> {}; |
284 | DEFINE_TRANSPARENT_OPERAND_ACCESSORS(CompareConstantExpr, Value) |
285 | |
286 | template <class ConstantClass> struct ConstantAggrKeyType; |
287 | struct InlineAsmKeyType; |
288 | struct ConstantExprKeyType; |
289 | |
290 | template <class ConstantClass> struct ConstantInfo; |
291 | template <> struct ConstantInfo<ConstantExpr> { |
292 | using ValType = ConstantExprKeyType; |
293 | using TypeClass = Type; |
294 | }; |
295 | template <> struct ConstantInfo<InlineAsm> { |
296 | using ValType = InlineAsmKeyType; |
297 | using TypeClass = PointerType; |
298 | }; |
299 | template <> struct ConstantInfo<ConstantArray> { |
300 | using ValType = ConstantAggrKeyType<ConstantArray>; |
301 | using TypeClass = ArrayType; |
302 | }; |
303 | template <> struct ConstantInfo<ConstantStruct> { |
304 | using ValType = ConstantAggrKeyType<ConstantStruct>; |
305 | using TypeClass = StructType; |
306 | }; |
307 | template <> struct ConstantInfo<ConstantVector> { |
308 | using ValType = ConstantAggrKeyType<ConstantVector>; |
309 | using TypeClass = VectorType; |
310 | }; |
311 | |
312 | template <class ConstantClass> struct ConstantAggrKeyType { |
313 | ArrayRef<Constant *> Operands; |
314 | |
315 | ConstantAggrKeyType(ArrayRef<Constant *> Operands) : Operands(Operands) {} |
316 | |
317 | ConstantAggrKeyType(ArrayRef<Constant *> Operands, const ConstantClass *) |
318 | : Operands(Operands) {} |
319 | |
320 | ConstantAggrKeyType(const ConstantClass *C, |
321 | SmallVectorImpl<Constant *> &Storage) { |
322 | assert(Storage.empty() && "Expected empty storage" ); |
323 | for (unsigned I = 0, E = C->getNumOperands(); I != E; ++I) |
324 | Storage.push_back(Elt: C->getOperand(I)); |
325 | Operands = Storage; |
326 | } |
327 | |
328 | bool operator==(const ConstantAggrKeyType &X) const { |
329 | return Operands == X.Operands; |
330 | } |
331 | |
332 | bool operator==(const ConstantClass *C) const { |
333 | if (Operands.size() != C->getNumOperands()) |
334 | return false; |
335 | for (unsigned I = 0, E = Operands.size(); I != E; ++I) |
336 | if (Operands[I] != C->getOperand(I)) |
337 | return false; |
338 | return true; |
339 | } |
340 | |
341 | unsigned getHash() const { |
342 | return hash_combine_range(first: Operands.begin(), last: Operands.end()); |
343 | } |
344 | |
345 | using TypeClass = typename ConstantInfo<ConstantClass>::TypeClass; |
346 | |
347 | ConstantClass *create(TypeClass *Ty) const { |
348 | return new (Operands.size()) ConstantClass(Ty, Operands); |
349 | } |
350 | }; |
351 | |
352 | struct InlineAsmKeyType { |
353 | StringRef AsmString; |
354 | StringRef Constraints; |
355 | FunctionType *FTy; |
356 | bool HasSideEffects; |
357 | bool IsAlignStack; |
358 | InlineAsm::AsmDialect AsmDialect; |
359 | bool CanThrow; |
360 | |
361 | InlineAsmKeyType(StringRef AsmString, StringRef Constraints, |
362 | FunctionType *FTy, bool HasSideEffects, bool IsAlignStack, |
363 | InlineAsm::AsmDialect AsmDialect, bool canThrow) |
364 | : AsmString(AsmString), Constraints(Constraints), FTy(FTy), |
365 | HasSideEffects(HasSideEffects), IsAlignStack(IsAlignStack), |
366 | AsmDialect(AsmDialect), CanThrow(canThrow) {} |
367 | |
368 | InlineAsmKeyType(const InlineAsm *Asm, SmallVectorImpl<Constant *> &) |
369 | : AsmString(Asm->getAsmString()), Constraints(Asm->getConstraintString()), |
370 | FTy(Asm->getFunctionType()), HasSideEffects(Asm->hasSideEffects()), |
371 | IsAlignStack(Asm->isAlignStack()), AsmDialect(Asm->getDialect()), |
372 | CanThrow(Asm->canThrow()) {} |
373 | |
374 | bool operator==(const InlineAsmKeyType &X) const { |
375 | return HasSideEffects == X.HasSideEffects && |
376 | IsAlignStack == X.IsAlignStack && AsmDialect == X.AsmDialect && |
377 | AsmString == X.AsmString && Constraints == X.Constraints && |
378 | FTy == X.FTy && CanThrow == X.CanThrow; |
379 | } |
380 | |
381 | bool operator==(const InlineAsm *Asm) const { |
382 | return HasSideEffects == Asm->hasSideEffects() && |
383 | IsAlignStack == Asm->isAlignStack() && |
384 | AsmDialect == Asm->getDialect() && |
385 | AsmString == Asm->getAsmString() && |
386 | Constraints == Asm->getConstraintString() && |
387 | FTy == Asm->getFunctionType() && CanThrow == Asm->canThrow(); |
388 | } |
389 | |
390 | unsigned getHash() const { |
391 | return hash_combine(args: AsmString, args: Constraints, args: HasSideEffects, args: IsAlignStack, |
392 | args: AsmDialect, args: FTy, args: CanThrow); |
393 | } |
394 | |
395 | using TypeClass = ConstantInfo<InlineAsm>::TypeClass; |
396 | |
397 | InlineAsm *create(TypeClass *Ty) const { |
398 | assert(PointerType::getUnqual(FTy) == Ty); |
399 | return new InlineAsm(FTy, std::string(AsmString), std::string(Constraints), |
400 | HasSideEffects, IsAlignStack, AsmDialect, CanThrow); |
401 | } |
402 | }; |
403 | |
404 | struct ConstantExprKeyType { |
405 | private: |
406 | uint8_t Opcode; |
407 | uint8_t SubclassOptionalData; |
408 | uint16_t SubclassData; |
409 | ArrayRef<Constant *> Ops; |
410 | ArrayRef<int> ShuffleMask; |
411 | Type *ExplicitTy; |
412 | std::optional<ConstantRange> InRange; |
413 | |
414 | static ArrayRef<int> getShuffleMaskIfValid(const ConstantExpr *CE) { |
415 | if (CE->getOpcode() == Instruction::ShuffleVector) |
416 | return CE->getShuffleMask(); |
417 | return std::nullopt; |
418 | } |
419 | |
420 | static Type *getSourceElementTypeIfValid(const ConstantExpr *CE) { |
421 | if (auto *GEPCE = dyn_cast<GetElementPtrConstantExpr>(Val: CE)) |
422 | return GEPCE->getSourceElementType(); |
423 | return nullptr; |
424 | } |
425 | |
426 | static std::optional<ConstantRange> |
427 | getInRangeIfValid(const ConstantExpr *CE) { |
428 | if (auto *GEPCE = dyn_cast<GetElementPtrConstantExpr>(Val: CE)) |
429 | return GEPCE->getInRange(); |
430 | return std::nullopt; |
431 | } |
432 | |
433 | public: |
434 | ConstantExprKeyType(unsigned Opcode, ArrayRef<Constant *> Ops, |
435 | unsigned short SubclassData = 0, |
436 | unsigned short SubclassOptionalData = 0, |
437 | ArrayRef<int> ShuffleMask = std::nullopt, |
438 | Type *ExplicitTy = nullptr, |
439 | std::optional<ConstantRange> InRange = std::nullopt) |
440 | : Opcode(Opcode), SubclassOptionalData(SubclassOptionalData), |
441 | SubclassData(SubclassData), Ops(Ops), ShuffleMask(ShuffleMask), |
442 | ExplicitTy(ExplicitTy), InRange(std::move(InRange)) {} |
443 | |
444 | ConstantExprKeyType(ArrayRef<Constant *> Operands, const ConstantExpr *CE) |
445 | : Opcode(CE->getOpcode()), |
446 | SubclassOptionalData(CE->getRawSubclassOptionalData()), |
447 | SubclassData(CE->isCompare() ? CE->getPredicate() : 0), Ops(Operands), |
448 | ShuffleMask(getShuffleMaskIfValid(CE)), |
449 | ExplicitTy(getSourceElementTypeIfValid(CE)), |
450 | InRange(getInRangeIfValid(CE)) {} |
451 | |
452 | ConstantExprKeyType(const ConstantExpr *CE, |
453 | SmallVectorImpl<Constant *> &Storage) |
454 | : Opcode(CE->getOpcode()), |
455 | SubclassOptionalData(CE->getRawSubclassOptionalData()), |
456 | SubclassData(CE->isCompare() ? CE->getPredicate() : 0), |
457 | ShuffleMask(getShuffleMaskIfValid(CE)), |
458 | ExplicitTy(getSourceElementTypeIfValid(CE)), |
459 | InRange(getInRangeIfValid(CE)) { |
460 | assert(Storage.empty() && "Expected empty storage" ); |
461 | for (unsigned I = 0, E = CE->getNumOperands(); I != E; ++I) |
462 | Storage.push_back(Elt: CE->getOperand(i_nocapture: I)); |
463 | Ops = Storage; |
464 | } |
465 | |
466 | static bool rangesEqual(const std::optional<ConstantRange> &A, |
467 | const std::optional<ConstantRange> &B) { |
468 | if (!A.has_value() || !B.has_value()) |
469 | return A.has_value() == B.has_value(); |
470 | return A->getBitWidth() == B->getBitWidth() && A == B; |
471 | } |
472 | |
473 | bool operator==(const ConstantExprKeyType &X) const { |
474 | return Opcode == X.Opcode && SubclassData == X.SubclassData && |
475 | SubclassOptionalData == X.SubclassOptionalData && Ops == X.Ops && |
476 | ShuffleMask == X.ShuffleMask && ExplicitTy == X.ExplicitTy && |
477 | rangesEqual(A: InRange, B: X.InRange); |
478 | } |
479 | |
480 | bool operator==(const ConstantExpr *CE) const { |
481 | if (Opcode != CE->getOpcode()) |
482 | return false; |
483 | if (SubclassOptionalData != CE->getRawSubclassOptionalData()) |
484 | return false; |
485 | if (Ops.size() != CE->getNumOperands()) |
486 | return false; |
487 | if (SubclassData != (CE->isCompare() ? CE->getPredicate() : 0)) |
488 | return false; |
489 | for (unsigned I = 0, E = Ops.size(); I != E; ++I) |
490 | if (Ops[I] != CE->getOperand(i_nocapture: I)) |
491 | return false; |
492 | if (ShuffleMask != getShuffleMaskIfValid(CE)) |
493 | return false; |
494 | if (ExplicitTy != getSourceElementTypeIfValid(CE)) |
495 | return false; |
496 | if (!rangesEqual(A: InRange, B: getInRangeIfValid(CE))) |
497 | return false; |
498 | return true; |
499 | } |
500 | |
501 | unsigned getHash() const { |
502 | return hash_combine( |
503 | args: Opcode, args: SubclassOptionalData, args: SubclassData, |
504 | args: hash_combine_range(first: Ops.begin(), last: Ops.end()), |
505 | args: hash_combine_range(first: ShuffleMask.begin(), last: ShuffleMask.end()), args: ExplicitTy); |
506 | } |
507 | |
508 | using TypeClass = ConstantInfo<ConstantExpr>::TypeClass; |
509 | |
510 | ConstantExpr *create(TypeClass *Ty) const { |
511 | switch (Opcode) { |
512 | default: |
513 | if (Instruction::isCast(Opcode)) |
514 | return new CastConstantExpr(Opcode, Ops[0], Ty); |
515 | if ((Opcode >= Instruction::BinaryOpsBegin && |
516 | Opcode < Instruction::BinaryOpsEnd)) |
517 | return new BinaryConstantExpr(Opcode, Ops[0], Ops[1], |
518 | SubclassOptionalData); |
519 | llvm_unreachable("Invalid ConstantExpr!" ); |
520 | case Instruction::ExtractElement: |
521 | return new ExtractElementConstantExpr(Ops[0], Ops[1]); |
522 | case Instruction::InsertElement: |
523 | return new InsertElementConstantExpr(Ops[0], Ops[1], Ops[2]); |
524 | case Instruction::ShuffleVector: |
525 | return new ShuffleVectorConstantExpr(Ops[0], Ops[1], ShuffleMask); |
526 | case Instruction::GetElementPtr: |
527 | return GetElementPtrConstantExpr::Create( |
528 | SrcElementTy: ExplicitTy, C: Ops[0], IdxList: Ops.slice(N: 1), DestTy: Ty, Flags: SubclassOptionalData, InRange); |
529 | case Instruction::ICmp: |
530 | return new CompareConstantExpr(Ty, Instruction::ICmp, SubclassData, |
531 | Ops[0], Ops[1]); |
532 | case Instruction::FCmp: |
533 | return new CompareConstantExpr(Ty, Instruction::FCmp, SubclassData, |
534 | Ops[0], Ops[1]); |
535 | } |
536 | } |
537 | }; |
538 | |
539 | // Free memory for a given constant. Assumes the constant has already been |
540 | // removed from all relevant maps. |
541 | void deleteConstant(Constant *C); |
542 | |
543 | template <class ConstantClass> class ConstantUniqueMap { |
544 | public: |
545 | using ValType = typename ConstantInfo<ConstantClass>::ValType; |
546 | using TypeClass = typename ConstantInfo<ConstantClass>::TypeClass; |
547 | using LookupKey = std::pair<TypeClass *, ValType>; |
548 | |
549 | /// Key and hash together, so that we compute the hash only once and reuse it. |
550 | using LookupKeyHashed = std::pair<unsigned, LookupKey>; |
551 | |
552 | private: |
553 | struct MapInfo { |
554 | using ConstantClassInfo = DenseMapInfo<ConstantClass *>; |
555 | |
556 | static inline ConstantClass *getEmptyKey() { |
557 | return ConstantClassInfo::getEmptyKey(); |
558 | } |
559 | |
560 | static inline ConstantClass *getTombstoneKey() { |
561 | return ConstantClassInfo::getTombstoneKey(); |
562 | } |
563 | |
564 | static unsigned getHashValue(const ConstantClass *CP) { |
565 | SmallVector<Constant *, 32> Storage; |
566 | return getHashValue(LookupKey(CP->getType(), ValType(CP, Storage))); |
567 | } |
568 | |
569 | static bool isEqual(const ConstantClass *LHS, const ConstantClass *RHS) { |
570 | return LHS == RHS; |
571 | } |
572 | |
573 | static unsigned getHashValue(const LookupKey &Val) { |
574 | return hash_combine(Val.first, Val.second.getHash()); |
575 | } |
576 | |
577 | static unsigned getHashValue(const LookupKeyHashed &Val) { |
578 | return Val.first; |
579 | } |
580 | |
581 | static bool isEqual(const LookupKey &LHS, const ConstantClass *RHS) { |
582 | if (RHS == getEmptyKey() || RHS == getTombstoneKey()) |
583 | return false; |
584 | if (LHS.first != RHS->getType()) |
585 | return false; |
586 | return LHS.second == RHS; |
587 | } |
588 | |
589 | static bool isEqual(const LookupKeyHashed &LHS, const ConstantClass *RHS) { |
590 | return isEqual(LHS.second, RHS); |
591 | } |
592 | }; |
593 | |
594 | public: |
595 | using MapTy = DenseSet<ConstantClass *, MapInfo>; |
596 | |
597 | private: |
598 | MapTy Map; |
599 | |
600 | public: |
601 | typename MapTy::iterator begin() { return Map.begin(); } |
602 | typename MapTy::iterator end() { return Map.end(); } |
603 | |
604 | void freeConstants() { |
605 | for (auto &I : Map) |
606 | deleteConstant(I); |
607 | } |
608 | |
609 | private: |
610 | ConstantClass *create(TypeClass *Ty, ValType V, LookupKeyHashed &HashKey) { |
611 | ConstantClass *Result = V.create(Ty); |
612 | |
613 | assert(Result->getType() == Ty && "Type specified is not correct!" ); |
614 | Map.insert_as(Result, HashKey); |
615 | |
616 | return Result; |
617 | } |
618 | |
619 | public: |
620 | /// Return the specified constant from the map, creating it if necessary. |
621 | ConstantClass *getOrCreate(TypeClass *Ty, ValType V) { |
622 | LookupKey Key(Ty, V); |
623 | /// Hash once, and reuse it for the lookup and the insertion if needed. |
624 | LookupKeyHashed Lookup(MapInfo::getHashValue(Key), Key); |
625 | |
626 | ConstantClass *Result = nullptr; |
627 | |
628 | auto I = Map.find_as(Lookup); |
629 | if (I == Map.end()) |
630 | Result = create(Ty, V, HashKey&: Lookup); |
631 | else |
632 | Result = *I; |
633 | assert(Result && "Unexpected nullptr" ); |
634 | |
635 | return Result; |
636 | } |
637 | |
638 | /// Remove this constant from the map |
639 | void remove(ConstantClass *CP) { |
640 | typename MapTy::iterator I = Map.find(CP); |
641 | assert(I != Map.end() && "Constant not found in constant table!" ); |
642 | assert(*I == CP && "Didn't find correct element?" ); |
643 | Map.erase(I); |
644 | } |
645 | |
646 | ConstantClass *replaceOperandsInPlace(ArrayRef<Constant *> Operands, |
647 | ConstantClass *CP, Value *From, |
648 | Constant *To, unsigned NumUpdated = 0, |
649 | unsigned OperandNo = ~0u) { |
650 | LookupKey Key(CP->getType(), ValType(Operands, CP)); |
651 | /// Hash once, and reuse it for the lookup and the insertion if needed. |
652 | LookupKeyHashed Lookup(MapInfo::getHashValue(Key), Key); |
653 | |
654 | auto ItMap = Map.find_as(Lookup); |
655 | if (ItMap != Map.end()) |
656 | return *ItMap; |
657 | |
658 | // Update to the new value. Optimize for the case when we have a single |
659 | // operand that we're changing, but handle bulk updates efficiently. |
660 | remove(CP); |
661 | if (NumUpdated == 1) { |
662 | assert(OperandNo < CP->getNumOperands() && "Invalid index" ); |
663 | assert(CP->getOperand(OperandNo) != To && "I didn't contain From!" ); |
664 | CP->setOperand(OperandNo, To); |
665 | } else { |
666 | for (unsigned I = 0, E = CP->getNumOperands(); I != E; ++I) |
667 | if (CP->getOperand(I) == From) |
668 | CP->setOperand(I, To); |
669 | } |
670 | Map.insert_as(CP, Lookup); |
671 | return nullptr; |
672 | } |
673 | |
674 | void dump() const { |
675 | LLVM_DEBUG(dbgs() << "Constant.cpp: ConstantUniqueMap\n" ); |
676 | } |
677 | }; |
678 | |
679 | template <> inline void ConstantUniqueMap<InlineAsm>::freeConstants() { |
680 | for (auto &I : Map) |
681 | delete I; |
682 | } |
683 | |
684 | } // end namespace llvm |
685 | |
686 | #endif // LLVM_LIB_IR_CONSTANTSCONTEXT_H |
687 | |