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