LLVM 24.0.0git
User.cpp
Go to the documentation of this file.
1//===-- User.cpp - Implement the User class -------------------------------===//
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#include "llvm/IR/User.h"
10#include "llvm/IR/Constant.h"
11#include "llvm/IR/Constants.h"
12#include "llvm/IR/GlobalValue.h"
14
15using namespace llvm;
16
17namespace llvm {
18class BasicBlock;
19}
20
21//===----------------------------------------------------------------------===//
22// User Class
23//===----------------------------------------------------------------------===//
24
25bool User::replaceUsesOfWith(Value *From, Value *To) {
26 bool Changed = false;
27 if (From == To) return Changed; // Duh what?
28
29 assert((!isa<Constant>(this) || isa<GlobalValue>(this)) &&
30 "Cannot call User::replaceUsesOfWith on a constant!");
31
32 for (unsigned i = 0, E = getNumOperands(); i != E; ++i)
33 if (getOperand(i) == From) { // Is This operand is pointing to oldval?
34 // The side effects of this setOperand call include linking to
35 // "To", adding "this" to the uses list of To, and
36 // most importantly, removing "this" from the use list of "From".
37 setOperand(i, To);
38 Changed = true;
39 }
40
41 return Changed;
42}
43
44//===----------------------------------------------------------------------===//
45// User allocHungoffUses Implementation
46//===----------------------------------------------------------------------===//
47
48void User::allocHungoffUses(unsigned N, bool WithExtraValues) {
49 assert(HasHungOffUses && "alloc must have hung off uses");
50
51 static_assert(alignof(Use) >= alignof(Value *),
52 "Alignment is insufficient for 'hung-off-uses' pieces");
53
54 // Allocate the array of Uses
55 size_t size = N * sizeof(Use);
56 if (WithExtraValues)
57 size += N * sizeof(Value *);
58 Use *Begin = static_cast<Use*>(::operator new(size));
59 Use *End = Begin + N;
60 setOperandList(Begin);
61 for (; Begin != End; Begin++)
62 new (Begin) Use(this);
63}
64
65void User::growHungoffUses(unsigned NewNumUses, bool WithExtraValues) {
66 assert(HasHungOffUses && "realloc must have hung off uses");
67
68 unsigned OldNumUses = getNumOperands();
69
70 // We don't support shrinking the number of uses. We wouldn't have enough
71 // space to copy the old uses in to the new space.
72 assert(NewNumUses > OldNumUses && "realloc must grow num uses");
73
74 Use *OldOps = getOperandList();
75 allocHungoffUses(NewNumUses, WithExtraValues);
76 Use *NewOps = getOperandList();
77
78 // Now copy from the old operands list to the new one.
79 std::copy(OldOps, OldOps + OldNumUses, NewOps);
80
81 // If the User has extra values (phi basic blocks, switch case values), then
82 // we need to copy these, too.
83 if (WithExtraValues) {
84 auto *OldPtr = reinterpret_cast<char *>(OldOps + OldNumUses);
85 auto *NewPtr = reinterpret_cast<char *>(NewOps + NewNumUses);
86 std::copy(OldPtr, OldPtr + (OldNumUses * sizeof(Value *)), NewPtr);
87 }
88 Use::zap(OldOps, OldOps + OldNumUses, true);
89}
90
91// This is a private struct used by `User` to track the co-allocated descriptor
92// section.
93struct DescriptorInfo {
94 intptr_t SizeInBytes;
95};
96
98 auto MutableARef = const_cast<User *>(this)->getDescriptor();
99 return {MutableARef.begin(), MutableARef.end()};
100}
101
103 assert(HasDescriptor && "Don't call otherwise!");
104 assert(!HasHungOffUses && "Invariant!");
105
106 auto *DI = reinterpret_cast<DescriptorInfo *>(getIntrusiveOperands()) - 1;
107 assert(DI->SizeInBytes != 0 && "Should not have had a descriptor otherwise!");
108
110 reinterpret_cast<uint8_t *>(DI) - DI->SizeInBytes, DI->SizeInBytes);
111}
112
113bool User::isDroppable() const {
114 if (auto *II = dyn_cast<IntrinsicInst>(this)) {
115 switch (II->getIntrinsicID()) {
116 default:
117 return false;
118 case Intrinsic::assume:
119 case Intrinsic::pseudoprobe:
120 case Intrinsic::experimental_noalias_scope_decl:
121 return true;
122 }
123 }
124 return false;
125}
126
127//===----------------------------------------------------------------------===//
128// User operator new Implementations
129//===----------------------------------------------------------------------===//
130
131void *User::allocateFixedOperandUser(size_t Size, unsigned Us,
132 unsigned DescBytes) {
133 assert(Us < (1u << NumUserOperandsBits) && "Too many operands");
134
135 static_assert(sizeof(DescriptorInfo) % sizeof(void *) == 0, "Required below");
136
137 unsigned DescBytesToAllocate =
138 DescBytes == 0 ? 0 : (DescBytes + sizeof(DescriptorInfo));
139 assert(DescBytesToAllocate % sizeof(void *) == 0 &&
140 "We need this to satisfy alignment constraints for Uses");
141
142 size_t LeadingSize = DescBytesToAllocate + sizeof(Use) * Us;
143
144 // Ensure we allocate at least one pointer's worth of space before the main
145 // user allocation. We use this memory to pass information from the destructor
146 // to the deletion operator, so it can recover the true allocation start.
147 LeadingSize = std::max(LeadingSize, sizeof(void *));
148
149 uint8_t *Storage = static_cast<uint8_t *>(::operator new(LeadingSize + Size));
150 User *Obj = reinterpret_cast<User *>(Storage + LeadingSize);
151 Use *Operands = reinterpret_cast<Use *>(Obj) - Us;
152 Obj->NumUserOperands = Us;
153 Obj->HasHungOffUses = false;
154 Obj->HasDescriptor = DescBytes != 0;
155
156 if (DescBytes != 0) {
157 auto *DescInfo = reinterpret_cast<DescriptorInfo *>(Operands) - 1;
158 DescInfo->SizeInBytes = DescBytes;
159 }
160
161 return Obj;
162}
163
164void *User::operator new(size_t Size, IntrusiveOperandsAllocMarker allocTrait) {
165 return allocateFixedOperandUser(Size, allocTrait.NumOps, 0);
166}
167
168void *User::operator new(size_t Size,
169 IntrusiveOperandsAndDescriptorAllocMarker allocTrait) {
170 return allocateFixedOperandUser(Size, allocTrait.NumOps,
171 allocTrait.DescBytes);
172}
173
174void *User::operator new(size_t Size, HungOffOperandsAllocMarker) {
175 // Allocate space for a single Use*
176 void *Storage = ::operator new(Size + sizeof(Use *));
177 Use **HungOffOperandList = static_cast<Use **>(Storage);
178 User *Obj = reinterpret_cast<User *>(HungOffOperandList + 1);
179 Obj->NumUserOperands = 0;
180 Obj->HasHungOffUses = true;
181 Obj->HasDescriptor = false;
182 *HungOffOperandList = nullptr;
183 return Obj;
184}
185
186//===----------------------------------------------------------------------===//
187// User operator delete Implementation
188//===----------------------------------------------------------------------===//
189
190User::~User() {
191 // Hung off uses use a single Use* before the User, while other subclasses
192 // use a Use[] allocated prior to the user.
193 void *AllocStart = nullptr;
194 if (HasHungOffUses) {
195 assert(!HasDescriptor && "not supported!");
196
197 Use **HungOffOperandList = reinterpret_cast<Use **>(this) - 1;
198 // drop the hung off uses.
199 Use::zap(*HungOffOperandList, *HungOffOperandList + NumUserOperands,
200 /* Delete */ true);
201 AllocStart = HungOffOperandList;
202 } else if (HasDescriptor) {
203 Use *UseBegin = reinterpret_cast<Use *>(this) - NumUserOperands;
204 Use::zap(UseBegin, UseBegin + NumUserOperands, /* Delete */ false);
205
206 auto *DI = reinterpret_cast<DescriptorInfo *>(UseBegin) - 1;
207 AllocStart = reinterpret_cast<uint8_t *>(DI) - DI->SizeInBytes;
208 } else if (NumUserOperands > 0) {
209 Use *Storage = reinterpret_cast<Use *>(this) - NumUserOperands;
210 Use::zap(Storage, Storage + NumUserOperands,
211 /* Delete */ false);
212 AllocStart = Storage;
213 } else {
214 // Handle the edge case where there are no operands and no descriptor.
215 AllocStart = (void **)(this) - 1;
216 }
217
218 // Operator delete needs to know where the allocation started. To avoid
219 // use-after-destroy, we have to store the allocation start outside the User
220 // object memory. The `User` new operator always allocates least one pointer
221 // before the User, so we can use that to store the allocation start. As a
222 // special case, we avoid this extra prefix allocation for ConstantData
223 // instances, since those are extremely common.
224 if (!isa<ConstantData>(this))
225 ((void **)this)[-1] = AllocStart;
226}
227
228void User::operator delete(void *Usr) { ::operator delete(((void **)Usr)[-1]); }
229
230void User::operator delete(void *Usr, HungOffOperandsAllocMarker) {
231 Use **HungOffOperandList = static_cast<Use **>(Usr) - 1;
232 ::operator delete(HungOffOperandList);
233}
234
235void User::operator delete(void *Usr,
236 IntrusiveOperandsAndDescriptorAllocMarker Marker) {
237 unsigned NumOps = Marker.NumOps;
238 Use *UseBegin = static_cast<Use *>(Usr) - NumOps;
239 auto *DI = reinterpret_cast<DescriptorInfo *>(UseBegin) - 1;
240 uint8_t *Storage = reinterpret_cast<uint8_t *>(DI) - DI->SizeInBytes;
241 ::operator delete(Storage);
242}
243
244void User::operator delete(void *Usr, IntrusiveOperandsAllocMarker Marker) {
245 unsigned NumOps = Marker.NumOps;
246 size_t LeadingSize = sizeof(Use) * NumOps;
247 // Handle the edge case where there are no operands and no descriptor.
248 LeadingSize = std::max(LeadingSize, sizeof(void *));
249 uint8_t *Storage = static_cast<uint8_t *>(Usr) - LeadingSize;
250 ::operator delete(Storage);
251}
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file contains the declarations for the subclasses of Constant, which represent the different fla...
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
const size_t AbstractManglingParser< Derived, Alloc >::NumOps
uint64_t IntrinsicInst * II
SI Fold Operands
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:40
LLVM Basic Block Representation.
Definition BasicBlock.h:62
Represent a mutable reference to an array (0 or more elements consecutively in memory),...
Definition ArrayRef.h:294
A Use represents the edge between a Value definition and its users.
Definition Use.h:35
static LLVM_ABI void zap(Use *Start, const Use *Stop, bool del=false)
Destroys Use operands when the number of operands of a User changes.
Definition Use.cpp:39
LLVM_ABI void allocHungoffUses(unsigned N, bool WithExtraValues=false)
Allocate the array of Uses, followed by a pointer (with bottom bit set) to the User.
Definition User.cpp:48
LLVM_ABI ArrayRef< const uint8_t > getDescriptor() const
Returns the descriptor co-allocated with this User instance.
Definition User.cpp:97
LLVM_ABI bool isDroppable() const
A droppable user is a user for which uses can be dropped without affecting correctness and should be ...
Definition User.cpp:113
LLVM_ABI bool replaceUsesOfWith(Value *From, Value *To)
Replace uses of one Value with another.
Definition User.cpp:25
LLVM_ABI void growHungoffUses(unsigned N, bool WithExtraValues=false)
Grow the number of hung off uses.
Definition User.cpp:65
LLVM_ABI ~User()
Definition User.cpp:190
Changed
LLVM_ABI const descriptor::Clause & getDescriptor(Clause C)
This is an optimization pass for GlobalISel generic memory operations.
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
Definition STLExtras.h:1685
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
Definition Casting.h:547
@ End
Run the machine verifier once, at the end of the pipeline.
Definition CodeGen.h:267
#define N
intptr_t SizeInBytes
Definition User.cpp:94