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