1ef860a24SChandler Carruth //===-- User.cpp - Implement the User class -------------------------------===//
2ef860a24SChandler Carruth //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6ef860a24SChandler Carruth //
7ef860a24SChandler Carruth //===----------------------------------------------------------------------===//
8ef860a24SChandler Carruth
99fb823bbSChandler Carruth #include "llvm/IR/User.h"
109fb823bbSChandler Carruth #include "llvm/IR/Constant.h"
119fb823bbSChandler Carruth #include "llvm/IR/GlobalValue.h"
12f16f139dSTyker #include "llvm/IR/IntrinsicInst.h"
13ef860a24SChandler Carruth
14ef860a24SChandler Carruth namespace llvm {
1587b925b0SPete Cooper class BasicBlock;
16ef860a24SChandler Carruth
17ef860a24SChandler Carruth //===----------------------------------------------------------------------===//
18ef860a24SChandler Carruth // User Class
19ef860a24SChandler Carruth //===----------------------------------------------------------------------===//
20ef860a24SChandler Carruth
replaceUsesOfWith(Value * From,Value * To)21*e1d47d86SNikita Popov bool User::replaceUsesOfWith(Value *From, Value *To) {
22*e1d47d86SNikita Popov bool Changed = false;
23*e1d47d86SNikita Popov if (From == To) return Changed; // Duh what?
24ef860a24SChandler Carruth
25ef860a24SChandler Carruth assert((!isa<Constant>(this) || isa<GlobalValue>(this)) &&
26ef860a24SChandler Carruth "Cannot call User::replaceUsesOfWith on a constant!");
27ef860a24SChandler Carruth
28ef860a24SChandler Carruth for (unsigned i = 0, E = getNumOperands(); i != E; ++i)
29ef860a24SChandler Carruth if (getOperand(i) == From) { // Is This operand is pointing to oldval?
30ef860a24SChandler Carruth // The side effects of this setOperand call include linking to
31ef860a24SChandler Carruth // "To", adding "this" to the uses list of To, and
32ef860a24SChandler Carruth // most importantly, removing "this" from the use list of "From".
33dd4106d2SChuanqi Xu setOperand(i, To);
34*e1d47d86SNikita Popov Changed = true;
35ef860a24SChandler Carruth }
363bfddc25SStephen Tozer if (auto DVI = dyn_cast_or_null<DbgVariableIntrinsic>(this)) {
37*e1d47d86SNikita Popov if (is_contained(DVI->location_ops(), From)) {
383bfddc25SStephen Tozer DVI->replaceVariableLocationOp(From, To);
39*e1d47d86SNikita Popov Changed = true;
403bfddc25SStephen Tozer }
41ef860a24SChandler Carruth }
42ef860a24SChandler Carruth
43*e1d47d86SNikita Popov return Changed;
44*e1d47d86SNikita Popov }
45*e1d47d86SNikita Popov
46ef860a24SChandler Carruth //===----------------------------------------------------------------------===//
47ef860a24SChandler Carruth // User allocHungoffUses Implementation
48ef860a24SChandler Carruth //===----------------------------------------------------------------------===//
49ef860a24SChandler Carruth
allocHungoffUses(unsigned N,bool IsPhi)503fc30408SPete Cooper void User::allocHungoffUses(unsigned N, bool IsPhi) {
51c91fda3bSPete Cooper assert(HasHungOffUses && "alloc must have hung off uses");
528096d34eSJames Y Knight
53ff9379f4STyker static_assert(alignof(Use) >= alignof(BasicBlock *),
54f27e4413SJames Y Knight "Alignment is insufficient for 'hung-off-uses' pieces");
558096d34eSJames Y Knight
56ff9379f4STyker // Allocate the array of Uses
57ff9379f4STyker size_t size = N * sizeof(Use);
5887b925b0SPete Cooper if (IsPhi)
5987b925b0SPete Cooper size += N * sizeof(BasicBlock *);
60ef860a24SChandler Carruth Use *Begin = static_cast<Use*>(::operator new(size));
61ef860a24SChandler Carruth Use *End = Begin + N;
62ff9379f4STyker setOperandList(Begin);
63ff9379f4STyker for (; Begin != End; Begin++)
64ff9379f4STyker new (Begin) Use(this);
65ef860a24SChandler Carruth }
66ef860a24SChandler Carruth
growHungoffUses(unsigned NewNumUses,bool IsPhi)6793f9ff57SPete Cooper void User::growHungoffUses(unsigned NewNumUses, bool IsPhi) {
6893f9ff57SPete Cooper assert(HasHungOffUses && "realloc must have hung off uses");
6993f9ff57SPete Cooper
7093f9ff57SPete Cooper unsigned OldNumUses = getNumOperands();
7193f9ff57SPete Cooper
7293f9ff57SPete Cooper // We don't support shrinking the number of uses. We wouldn't have enough
7393f9ff57SPete Cooper // space to copy the old uses in to the new space.
7493f9ff57SPete Cooper assert(NewNumUses > OldNumUses && "realloc must grow num uses");
7593f9ff57SPete Cooper
7674510a40SPete Cooper Use *OldOps = getOperandList();
7793f9ff57SPete Cooper allocHungoffUses(NewNumUses, IsPhi);
7874510a40SPete Cooper Use *NewOps = getOperandList();
7993f9ff57SPete Cooper
8093f9ff57SPete Cooper // Now copy from the old operands list to the new one.
8193f9ff57SPete Cooper std::copy(OldOps, OldOps + OldNumUses, NewOps);
8293f9ff57SPete Cooper
8393f9ff57SPete Cooper // If this is a Phi, then we need to copy the BB pointers too.
8493f9ff57SPete Cooper if (IsPhi) {
85ff9379f4STyker auto *OldPtr = reinterpret_cast<char *>(OldOps + OldNumUses);
86ff9379f4STyker auto *NewPtr = reinterpret_cast<char *>(NewOps + NewNumUses);
8793f9ff57SPete Cooper std::copy(OldPtr, OldPtr + (OldNumUses * sizeof(BasicBlock *)), NewPtr);
8893f9ff57SPete Cooper }
8993f9ff57SPete Cooper Use::zap(OldOps, OldOps + OldNumUses, true);
9093f9ff57SPete Cooper }
9193f9ff57SPete Cooper
92b07fc572SSanjoy Das
93b07fc572SSanjoy Das // This is a private struct used by `User` to track the co-allocated descriptor
94b07fc572SSanjoy Das // section.
95b07fc572SSanjoy Das struct DescriptorInfo {
96b07fc572SSanjoy Das intptr_t SizeInBytes;
97b07fc572SSanjoy Das };
98b07fc572SSanjoy Das
getDescriptor() const99b07fc572SSanjoy Das ArrayRef<const uint8_t> User::getDescriptor() const {
100b07fc572SSanjoy Das auto MutableARef = const_cast<User *>(this)->getDescriptor();
101b07fc572SSanjoy Das return {MutableARef.begin(), MutableARef.end()};
102b07fc572SSanjoy Das }
103b07fc572SSanjoy Das
getDescriptor()104b07fc572SSanjoy Das MutableArrayRef<uint8_t> User::getDescriptor() {
105b07fc572SSanjoy Das assert(HasDescriptor && "Don't call otherwise!");
106b07fc572SSanjoy Das assert(!HasHungOffUses && "Invariant!");
107b07fc572SSanjoy Das
108b07fc572SSanjoy Das auto *DI = reinterpret_cast<DescriptorInfo *>(getIntrusiveOperands()) - 1;
109b07fc572SSanjoy Das assert(DI->SizeInBytes != 0 && "Should not have had a descriptor otherwise!");
110b07fc572SSanjoy Das
111b07fc572SSanjoy Das return MutableArrayRef<uint8_t>(
112b07fc572SSanjoy Das reinterpret_cast<uint8_t *>(DI) - DI->SizeInBytes, DI->SizeInBytes);
113b07fc572SSanjoy Das }
114b07fc572SSanjoy Das
isDroppable() const115f16f139dSTyker bool User::isDroppable() const {
116098a0d8fSHongtao Yu return isa<AssumeInst>(this) || isa<PseudoProbeInst>(this);
117f16f139dSTyker }
118f16f139dSTyker
119ef860a24SChandler Carruth //===----------------------------------------------------------------------===//
120ef860a24SChandler Carruth // User operator new Implementations
121ef860a24SChandler Carruth //===----------------------------------------------------------------------===//
122ef860a24SChandler Carruth
allocateFixedOperandUser(size_t Size,unsigned Us,unsigned DescBytes)123b07fc572SSanjoy Das void *User::allocateFixedOperandUser(size_t Size, unsigned Us,
124b07fc572SSanjoy Das unsigned DescBytes) {
125b4eede2cSPete Cooper assert(Us < (1u << NumUserOperandsBits) && "Too many operands");
126b07fc572SSanjoy Das
127b07fc572SSanjoy Das static_assert(sizeof(DescriptorInfo) % sizeof(void *) == 0, "Required below");
128b07fc572SSanjoy Das
129b07fc572SSanjoy Das unsigned DescBytesToAllocate =
130b07fc572SSanjoy Das DescBytes == 0 ? 0 : (DescBytes + sizeof(DescriptorInfo));
131b07fc572SSanjoy Das assert(DescBytesToAllocate % sizeof(void *) == 0 &&
132b07fc572SSanjoy Das "We need this to satisfy alignment constraints for Uses");
133b07fc572SSanjoy Das
134b07fc572SSanjoy Das uint8_t *Storage = static_cast<uint8_t *>(
135b07fc572SSanjoy Das ::operator new(Size + sizeof(Use) * Us + DescBytesToAllocate));
136b07fc572SSanjoy Das Use *Start = reinterpret_cast<Use *>(Storage + DescBytesToAllocate);
137ef860a24SChandler Carruth Use *End = Start + Us;
138ef860a24SChandler Carruth User *Obj = reinterpret_cast<User*>(End);
139b4eede2cSPete Cooper Obj->NumUserOperands = Us;
140b676b01bSPete Cooper Obj->HasHungOffUses = false;
141b07fc572SSanjoy Das Obj->HasDescriptor = DescBytes != 0;
142ff9379f4STyker for (; Start != End; Start++)
143ff9379f4STyker new (Start) Use(Obj);
144b07fc572SSanjoy Das
145b07fc572SSanjoy Das if (DescBytes != 0) {
146b07fc572SSanjoy Das auto *DescInfo = reinterpret_cast<DescriptorInfo *>(Storage + DescBytes);
147b07fc572SSanjoy Das DescInfo->SizeInBytes = DescBytes;
148b07fc572SSanjoy Das }
149b07fc572SSanjoy Das
150ef860a24SChandler Carruth return Obj;
151ef860a24SChandler Carruth }
152ef860a24SChandler Carruth
operator new(size_t Size,unsigned Us)153b07fc572SSanjoy Das void *User::operator new(size_t Size, unsigned Us) {
154b07fc572SSanjoy Das return allocateFixedOperandUser(Size, Us, 0);
155b07fc572SSanjoy Das }
156b07fc572SSanjoy Das
operator new(size_t Size,unsigned Us,unsigned DescBytes)157b07fc572SSanjoy Das void *User::operator new(size_t Size, unsigned Us, unsigned DescBytes) {
158b07fc572SSanjoy Das return allocateFixedOperandUser(Size, Us, DescBytes);
159b07fc572SSanjoy Das }
160b07fc572SSanjoy Das
operator new(size_t Size)161c91fda3bSPete Cooper void *User::operator new(size_t Size) {
162b676b01bSPete Cooper // Allocate space for a single Use*
163b676b01bSPete Cooper void *Storage = ::operator new(Size + sizeof(Use *));
164b676b01bSPete Cooper Use **HungOffOperandList = static_cast<Use **>(Storage);
165b676b01bSPete Cooper User *Obj = reinterpret_cast<User *>(HungOffOperandList + 1);
166c91fda3bSPete Cooper Obj->NumUserOperands = 0;
167b676b01bSPete Cooper Obj->HasHungOffUses = true;
168b07fc572SSanjoy Das Obj->HasDescriptor = false;
169b676b01bSPete Cooper *HungOffOperandList = nullptr;
170c91fda3bSPete Cooper return Obj;
171c91fda3bSPete Cooper }
172c91fda3bSPete Cooper
173ef860a24SChandler Carruth //===----------------------------------------------------------------------===//
174ef860a24SChandler Carruth // User operator delete Implementation
175ef860a24SChandler Carruth //===----------------------------------------------------------------------===//
176ef860a24SChandler Carruth
1778ca7871aSEvgenii Stepanov // Repress memory sanitization, due to use-after-destroy by operator
1788ca7871aSEvgenii Stepanov // delete. Bug report 24578 identifies this issue.
operator delete(void * Usr)1798ca7871aSEvgenii Stepanov LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE void User::operator delete(void *Usr) {
180b676b01bSPete Cooper // Hung off uses use a single Use* before the User, while other subclasses
181b676b01bSPete Cooper // use a Use[] allocated prior to the user.
182b676b01bSPete Cooper User *Obj = static_cast<User *>(Usr);
183b676b01bSPete Cooper if (Obj->HasHungOffUses) {
184b07fc572SSanjoy Das assert(!Obj->HasDescriptor && "not supported!");
185b07fc572SSanjoy Das
186b676b01bSPete Cooper Use **HungOffOperandList = static_cast<Use **>(Usr) - 1;
187b676b01bSPete Cooper // drop the hung off uses.
188b676b01bSPete Cooper Use::zap(*HungOffOperandList, *HungOffOperandList + Obj->NumUserOperands,
189b676b01bSPete Cooper /* Delete */ true);
190b676b01bSPete Cooper ::operator delete(HungOffOperandList);
191b07fc572SSanjoy Das } else if (Obj->HasDescriptor) {
192b07fc572SSanjoy Das Use *UseBegin = static_cast<Use *>(Usr) - Obj->NumUserOperands;
193b07fc572SSanjoy Das Use::zap(UseBegin, UseBegin + Obj->NumUserOperands, /* Delete */ false);
194b07fc572SSanjoy Das
195b07fc572SSanjoy Das auto *DI = reinterpret_cast<DescriptorInfo *>(UseBegin) - 1;
196b07fc572SSanjoy Das uint8_t *Storage = reinterpret_cast<uint8_t *>(DI) - DI->SizeInBytes;
197b07fc572SSanjoy Das ::operator delete(Storage);
198b676b01bSPete Cooper } else {
199b676b01bSPete Cooper Use *Storage = static_cast<Use *>(Usr) - Obj->NumUserOperands;
200b676b01bSPete Cooper Use::zap(Storage, Storage + Obj->NumUserOperands,
201b676b01bSPete Cooper /* Delete */ false);
202ef860a24SChandler Carruth ::operator delete(Storage);
203ef860a24SChandler Carruth }
204b676b01bSPete Cooper }
205ef860a24SChandler Carruth
2068b52037cSSimon Pilgrim } // namespace llvm
207