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"
13#include "llvm/IR/IntrinsicInst.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, Val: To);
38 Changed = true;
39 }
40 if (auto DVI = dyn_cast_or_null<DbgVariableIntrinsic>(Val: this)) {
41 if (is_contained(Range: DVI->location_ops(), Element: From)) {
42 DVI->replaceVariableLocationOp(OldValue: From, NewValue: 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(N: NewNumUses, WithExtraValues);
82 Use *NewOps = getOperandList();
83
84 // Now copy from the old operands list to the new one.
85 std::copy(first: OldOps, last: OldOps + OldNumUses, result: 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(first: OldPtr, last: OldPtr + (OldNumUses * sizeof(Value *)), result: NewPtr);
93 }
94 Use::zap(Start: OldOps, Stop: OldOps + OldNumUses, del: 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
103ArrayRef<const uint8_t> User::getDescriptor() const {
104 auto MutableARef = const_cast<User *>(this)->getDescriptor();
105 return {MutableARef.begin(), MutableARef.end()};
106}
107
108MutableArrayRef<uint8_t> User::getDescriptor() {
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
115 return MutableArrayRef<uint8_t>(
116 reinterpret_cast<uint8_t *>(DI) - DI->SizeInBytes, DI->SizeInBytes);
117}
118
119bool User::isDroppable() const {
120 if (auto *II = dyn_cast<IntrinsicInst>(Val: 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(a: LeadingSize, b: 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
162 if (DescBytes != 0) {
163 auto *DescInfo = reinterpret_cast<DescriptorInfo *>(Operands) - 1;
164 DescInfo->SizeInBytes = DescBytes;
165 }
166
167 return Obj;
168}
169
170void *User::operator new(size_t Size, IntrusiveOperandsAllocMarker allocTrait) {
171 return allocateFixedOperandUser(Size, Us: allocTrait.NumOps, DescBytes: 0);
172}
173
174void *User::operator new(size_t Size,
175 IntrusiveOperandsAndDescriptorAllocMarker allocTrait) {
176 return allocateFixedOperandUser(Size, Us: allocTrait.NumOps,
177 DescBytes: allocTrait.DescBytes);
178}
179
180void *User::operator new(size_t Size, HungOffOperandsAllocMarker) {
181 // Allocate space for a single Use*
182 void *Storage = ::operator new(Size + sizeof(Use *));
183 Use **HungOffOperandList = static_cast<Use **>(Storage);
184 User *Obj = reinterpret_cast<User *>(HungOffOperandList + 1);
185 Obj->NumUserOperands = 0;
186 Obj->HasHungOffUses = true;
187 Obj->HasDescriptor = false;
188 *HungOffOperandList = nullptr;
189 return Obj;
190}
191
192//===----------------------------------------------------------------------===//
193// User operator delete Implementation
194//===----------------------------------------------------------------------===//
195
196User::~User() {
197 // Hung off uses use a single Use* before the User, while other subclasses
198 // use a Use[] allocated prior to the user.
199 void *AllocStart = nullptr;
200 if (HasHungOffUses) {
201 assert(!HasDescriptor && "not supported!");
202
203 Use **HungOffOperandList = reinterpret_cast<Use **>(this) - 1;
204 // drop the hung off uses.
205 Use::zap(Start: *HungOffOperandList, Stop: *HungOffOperandList + NumUserOperands,
206 /* Delete */ del: true);
207 AllocStart = HungOffOperandList;
208 } else if (HasDescriptor) {
209 Use *UseBegin = reinterpret_cast<Use *>(this) - NumUserOperands;
210 Use::zap(Start: UseBegin, Stop: UseBegin + NumUserOperands, /* Delete */ del: false);
211
212 auto *DI = reinterpret_cast<DescriptorInfo *>(UseBegin) - 1;
213 AllocStart = reinterpret_cast<uint8_t *>(DI) - DI->SizeInBytes;
214 } else if (NumUserOperands > 0) {
215 Use *Storage = reinterpret_cast<Use *>(this) - NumUserOperands;
216 Use::zap(Start: Storage, Stop: Storage + NumUserOperands,
217 /* Delete */ del: false);
218 AllocStart = Storage;
219 } else {
220 // Handle the edge case where there are no operands and no descriptor.
221 AllocStart = (void **)(this) - 1;
222 }
223
224 // Operator delete needs to know where the allocation started. To avoid
225 // use-after-destroy, we have to store the allocation start outside the User
226 // object memory. The `User` new operator always allocates least one pointer
227 // before the User, so we can use that to store the allocation start. As a
228 // special case, we avoid this extra prefix allocation for ConstantData
229 // instances, since those are extremely common.
230 if (!isa<ConstantData>(Val: this))
231 ((void **)this)[-1] = AllocStart;
232}
233
234void User::operator delete(void *Usr) { ::operator delete(((void **)Usr)[-1]); }
235
236void User::operator delete(void *Usr, HungOffOperandsAllocMarker) {
237 Use **HungOffOperandList = static_cast<Use **>(Usr) - 1;
238 ::operator delete(HungOffOperandList);
239}
240
241void User::operator delete(void *Usr,
242 IntrusiveOperandsAndDescriptorAllocMarker Marker) {
243 unsigned NumOps = Marker.NumOps;
244 Use *UseBegin = static_cast<Use *>(Usr) - NumOps;
245 auto *DI = reinterpret_cast<DescriptorInfo *>(UseBegin) - 1;
246 uint8_t *Storage = reinterpret_cast<uint8_t *>(DI) - DI->SizeInBytes;
247 ::operator delete(Storage);
248}
249
250void User::operator delete(void *Usr, IntrusiveOperandsAllocMarker Marker) {
251 unsigned NumOps = Marker.NumOps;
252 size_t LeadingSize = sizeof(Use) * NumOps;
253 // Handle the edge case where there are no operands and no descriptor.
254 LeadingSize = std::max(a: LeadingSize, b: sizeof(void *));
255 uint8_t *Storage = static_cast<uint8_t *>(Usr) - LeadingSize;
256 ::operator delete(Storage);
257}
258