LLVM 22.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 if (auto DVI = dyn_cast_or_null<DbgVariableIntrinsic>(this)) {
41 if (is_contained(DVI->location_ops(), From)) {
42 DVI->replaceVariableLocationOp(From, To);
43 Changed = true;
44 }
45 }
46
47 return Changed;
48}
49
50//===----------------------------------------------------------------------===//
51// User allocHungoffUses Implementation
52//===----------------------------------------------------------------------===//
53
54void User::allocHungoffUses(unsigned N, bool WithExtraValues) {
55 assert(HasHungOffUses && "alloc must have hung off uses");
56
57 static_assert(alignof(Use) >= alignof(Value *),
58 "Alignment is insufficient for 'hung-off-uses' pieces");
59
60 // Allocate the array of Uses
61 size_t size = N * sizeof(Use);
62 if (WithExtraValues)
63 size += N * sizeof(Value *);
64 Use *Begin = static_cast<Use*>(::operator new(size));
65 Use *End = Begin + N;
66 setOperandList(Begin);
67 for (; Begin != End; Begin++)
68 new (Begin) Use(this);
69}
70
71void User::growHungoffUses(unsigned NewNumUses, bool WithExtraValues) {
72 assert(HasHungOffUses && "realloc must have hung off uses");
73
74 unsigned OldNumUses = getNumOperands();
75
76 // We don't support shrinking the number of uses. We wouldn't have enough
77 // space to copy the old uses in to the new space.
78 assert(NewNumUses > OldNumUses && "realloc must grow num uses");
79
80 Use *OldOps = getOperandList();
81 allocHungoffUses(NewNumUses, WithExtraValues);
82 Use *NewOps = getOperandList();
83
84 // Now copy from the old operands list to the new one.
85 std::copy(OldOps, OldOps + OldNumUses, NewOps);
86
87 // If the User has extra values (phi basic blocks, switch case values), then
88 // we need to copy these, too.
89 if (WithExtraValues) {
90 auto *OldPtr = reinterpret_cast<char *>(OldOps + OldNumUses);
91 auto *NewPtr = reinterpret_cast<char *>(NewOps + NewNumUses);
92 std::copy(OldPtr, OldPtr + (OldNumUses * sizeof(Value *)), NewPtr);
93 }
94 Use::zap(OldOps, OldOps + OldNumUses, true);
95}
96
97// This is a private struct used by `User` to track the co-allocated descriptor
98// section.
99struct DescriptorInfo {
100 intptr_t SizeInBytes;
101};
102
104 auto MutableARef = const_cast<User *>(this)->getDescriptor();
105 return {MutableARef.begin(), MutableARef.end()};
106}
107
109 assert(HasDescriptor && "Don't call otherwise!");
110 assert(!HasHungOffUses && "Invariant!");
111
112 auto *DI = reinterpret_cast<DescriptorInfo *>(getIntrusiveOperands()) - 1;
113 assert(DI->SizeInBytes != 0 && "Should not have had a descriptor otherwise!");
114
116 reinterpret_cast<uint8_t *>(DI) - DI->SizeInBytes, DI->SizeInBytes);
117}
118
119bool User::isDroppable() const {
120 if (auto *II = dyn_cast<IntrinsicInst>(this)) {
121 switch (II->getIntrinsicID()) {
122 default:
123 return false;
124 case Intrinsic::assume:
125 case Intrinsic::pseudoprobe:
126 case Intrinsic::experimental_noalias_scope_decl:
127 return true;
128 }
129 }
130 return false;
131}
132
133//===----------------------------------------------------------------------===//
134// User operator new Implementations
135//===----------------------------------------------------------------------===//
136
137void *User::allocateFixedOperandUser(size_t Size, unsigned Us,
138 unsigned DescBytes) {
139 assert(Us < (1u << NumUserOperandsBits) && "Too many operands");
140
141 static_assert(sizeof(DescriptorInfo) % sizeof(void *) == 0, "Required below");
142
143 unsigned DescBytesToAllocate =
144 DescBytes == 0 ? 0 : (DescBytes + sizeof(DescriptorInfo));
145 assert(DescBytesToAllocate % sizeof(void *) == 0 &&
146 "We need this to satisfy alignment constraints for Uses");
147
148 size_t LeadingSize = DescBytesToAllocate + sizeof(Use) * Us;
149
150 // Ensure we allocate at least one pointer's worth of space before the main
151 // user allocation. We use this memory to pass information from the destructor
152 // to the deletion operator, so it can recover the true allocation start.
153 LeadingSize = std::max(LeadingSize, sizeof(void *));
154
155 uint8_t *Storage = static_cast<uint8_t *>(::operator new(LeadingSize + Size));
156 User *Obj = reinterpret_cast<User *>(Storage + LeadingSize);
157 Use *Operands = reinterpret_cast<Use *>(Obj) - Us;
158 Obj->NumUserOperands = Us;
159 Obj->HasHungOffUses = false;
160 Obj->HasDescriptor = DescBytes != 0;
161 for (unsigned I = 0; I < Us; ++I)
162 new (&Operands[I]) Use(Obj);
163
164 if (DescBytes != 0) {
165 auto *DescInfo = reinterpret_cast<DescriptorInfo *>(Operands) - 1;
166 DescInfo->SizeInBytes = DescBytes;
167 }
168
169 return Obj;
170}
171
172void *User::operator new(size_t Size, IntrusiveOperandsAllocMarker allocTrait) {
173 return allocateFixedOperandUser(Size, allocTrait.NumOps, 0);
174}
175
176void *User::operator new(size_t Size,
177 IntrusiveOperandsAndDescriptorAllocMarker allocTrait) {
178 return allocateFixedOperandUser(Size, allocTrait.NumOps,
179 allocTrait.DescBytes);
180}
181
182void *User::operator new(size_t Size, HungOffOperandsAllocMarker) {
183 // Allocate space for a single Use*
184 void *Storage = ::operator new(Size + sizeof(Use *));
185 Use **HungOffOperandList = static_cast<Use **>(Storage);
186 User *Obj = reinterpret_cast<User *>(HungOffOperandList + 1);
187 Obj->NumUserOperands = 0;
188 Obj->HasHungOffUses = true;
189 Obj->HasDescriptor = false;
190 *HungOffOperandList = nullptr;
191 return Obj;
192}
193
194//===----------------------------------------------------------------------===//
195// User operator delete Implementation
196//===----------------------------------------------------------------------===//
197
198User::~User() {
199 // Hung off uses use a single Use* before the User, while other subclasses
200 // use a Use[] allocated prior to the user.
201 void *AllocStart = nullptr;
202 if (HasHungOffUses) {
203 assert(!HasDescriptor && "not supported!");
204
205 Use **HungOffOperandList = reinterpret_cast<Use **>(this) - 1;
206 // drop the hung off uses.
207 Use::zap(*HungOffOperandList, *HungOffOperandList + NumUserOperands,
208 /* Delete */ true);
209 AllocStart = HungOffOperandList;
210 } else if (HasDescriptor) {
211 Use *UseBegin = reinterpret_cast<Use *>(this) - NumUserOperands;
212 Use::zap(UseBegin, UseBegin + NumUserOperands, /* Delete */ false);
213
214 auto *DI = reinterpret_cast<DescriptorInfo *>(UseBegin) - 1;
215 AllocStart = reinterpret_cast<uint8_t *>(DI) - DI->SizeInBytes;
216 } else if (NumUserOperands > 0) {
217 Use *Storage = reinterpret_cast<Use *>(this) - NumUserOperands;
218 Use::zap(Storage, Storage + NumUserOperands,
219 /* Delete */ false);
220 AllocStart = Storage;
221 } else {
222 // Handle the edge case where there are no operands and no descriptor.
223 AllocStart = (void **)(this) - 1;
224 }
225
226 // Operator delete needs to know where the allocation started. To avoid
227 // use-after-destroy, we have to store the allocation start outside the User
228 // object memory. The `User` new operator always allocates least one pointer
229 // before the User, so we can use that to store the allocation start. As a
230 // special case, we avoid this extra prefix allocation for ConstantData
231 // instances, since those are extremely common.
232 if (!isa<ConstantData>(this))
233 ((void **)this)[-1] = AllocStart;
234}
235
236void User::operator delete(void *Usr) { ::operator delete(((void **)Usr)[-1]); }
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...
#define I(x, y, z)
Definition MD5.cpp:57
uint64_t IntrinsicInst * II
ArrayRef - 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
MutableArrayRef - Represent a mutable reference to an array (0 or more elements consecutively in memo...
Definition ArrayRef.h:298
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:54
LLVM_ABI ArrayRef< const uint8_t > getDescriptor() const
Returns the descriptor co-allocated with this User instance.
Definition User.cpp:103
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:119
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:71
Changed
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:1667
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
Definition Casting.h:643
auto dyn_cast_or_null(const Y &Val)
Definition Casting.h:753
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
bool is_contained(R &&Range, const E &Element)
Returns true if Element is found in Range.
Definition STLExtras.h:1945
#define N
intptr_t SizeInBytes
Definition User.cpp:100