LLVM  14.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/GlobalValue.h"
12 #include "llvm/IR/IntrinsicInst.h"
13 
14 namespace llvm {
15 class BasicBlock;
16 
17 //===----------------------------------------------------------------------===//
18 // User Class
19 //===----------------------------------------------------------------------===//
20 
22  if (From == To) return; // Duh what?
23 
24  assert((!isa<Constant>(this) || isa<GlobalValue>(this)) &&
25  "Cannot call User::replaceUsesOfWith on a constant!");
26 
27  for (unsigned i = 0, E = getNumOperands(); i != E; ++i)
28  if (getOperand(i) == From) { // Is This operand is pointing to oldval?
29  // The side effects of this setOperand call include linking to
30  // "To", adding "this" to the uses list of To, and
31  // most importantly, removing "this" from the use list of "From".
32  setOperand(i, To);
33  }
34  if (auto DVI = dyn_cast_or_null<DbgVariableIntrinsic>(this)) {
35  if (is_contained(DVI->location_ops(), From))
36  DVI->replaceVariableLocationOp(From, To);
37  }
38 }
39 
40 //===----------------------------------------------------------------------===//
41 // User allocHungoffUses Implementation
42 //===----------------------------------------------------------------------===//
43 
44 void User::allocHungoffUses(unsigned N, bool IsPhi) {
45  assert(HasHungOffUses && "alloc must have hung off uses");
46 
47  static_assert(alignof(Use) >= alignof(BasicBlock *),
48  "Alignment is insufficient for 'hung-off-uses' pieces");
49 
50  // Allocate the array of Uses
51  size_t size = N * sizeof(Use);
52  if (IsPhi)
53  size += N * sizeof(BasicBlock *);
54  Use *Begin = static_cast<Use*>(::operator new(size));
55  Use *End = Begin + N;
56  setOperandList(Begin);
57  for (; Begin != End; Begin++)
58  new (Begin) Use(this);
59 }
60 
61 void User::growHungoffUses(unsigned NewNumUses, bool IsPhi) {
62  assert(HasHungOffUses && "realloc must have hung off uses");
63 
64  unsigned OldNumUses = getNumOperands();
65 
66  // We don't support shrinking the number of uses. We wouldn't have enough
67  // space to copy the old uses in to the new space.
68  assert(NewNumUses > OldNumUses && "realloc must grow num uses");
69 
70  Use *OldOps = getOperandList();
71  allocHungoffUses(NewNumUses, IsPhi);
72  Use *NewOps = getOperandList();
73 
74  // Now copy from the old operands list to the new one.
75  std::copy(OldOps, OldOps + OldNumUses, NewOps);
76 
77  // If this is a Phi, then we need to copy the BB pointers too.
78  if (IsPhi) {
79  auto *OldPtr = reinterpret_cast<char *>(OldOps + OldNumUses);
80  auto *NewPtr = reinterpret_cast<char *>(NewOps + NewNumUses);
81  std::copy(OldPtr, OldPtr + (OldNumUses * sizeof(BasicBlock *)), NewPtr);
82  }
83  Use::zap(OldOps, OldOps + OldNumUses, true);
84 }
85 
86 
87 // This is a private struct used by `User` to track the co-allocated descriptor
88 // section.
91 };
92 
94  auto MutableARef = const_cast<User *>(this)->getDescriptor();
95  return {MutableARef.begin(), MutableARef.end()};
96 }
97 
99  assert(HasDescriptor && "Don't call otherwise!");
100  assert(!HasHungOffUses && "Invariant!");
101 
102  auto *DI = reinterpret_cast<DescriptorInfo *>(getIntrusiveOperands()) - 1;
103  assert(DI->SizeInBytes != 0 && "Should not have had a descriptor otherwise!");
104 
106  reinterpret_cast<uint8_t *>(DI) - DI->SizeInBytes, DI->SizeInBytes);
107 }
108 
109 bool User::isDroppable() const {
110  return isa<AssumeInst>(this);
111 }
112 
113 //===----------------------------------------------------------------------===//
114 // User operator new Implementations
115 //===----------------------------------------------------------------------===//
116 
117 void *User::allocateFixedOperandUser(size_t Size, unsigned Us,
118  unsigned DescBytes) {
119  assert(Us < (1u << NumUserOperandsBits) && "Too many operands");
120 
121  static_assert(sizeof(DescriptorInfo) % sizeof(void *) == 0, "Required below");
122 
123  unsigned DescBytesToAllocate =
124  DescBytes == 0 ? 0 : (DescBytes + sizeof(DescriptorInfo));
125  assert(DescBytesToAllocate % sizeof(void *) == 0 &&
126  "We need this to satisfy alignment constraints for Uses");
127 
128  uint8_t *Storage = static_cast<uint8_t *>(
129  ::operator new(Size + sizeof(Use) * Us + DescBytesToAllocate));
130  Use *Start = reinterpret_cast<Use *>(Storage + DescBytesToAllocate);
131  Use *End = Start + Us;
132  User *Obj = reinterpret_cast<User*>(End);
133  Obj->NumUserOperands = Us;
134  Obj->HasHungOffUses = false;
135  Obj->HasDescriptor = DescBytes != 0;
136  for (; Start != End; Start++)
137  new (Start) Use(Obj);
138 
139  if (DescBytes != 0) {
140  auto *DescInfo = reinterpret_cast<DescriptorInfo *>(Storage + DescBytes);
141  DescInfo->SizeInBytes = DescBytes;
142  }
143 
144  return Obj;
145 }
146 
147 void *User::operator new(size_t Size, unsigned Us) {
148  return allocateFixedOperandUser(Size, Us, 0);
149 }
150 
151 void *User::operator new(size_t Size, unsigned Us, unsigned DescBytes) {
152  return allocateFixedOperandUser(Size, Us, DescBytes);
153 }
154 
155 void *User::operator new(size_t Size) {
156  // Allocate space for a single Use*
157  void *Storage = ::operator new(Size + sizeof(Use *));
158  Use **HungOffOperandList = static_cast<Use **>(Storage);
159  User *Obj = reinterpret_cast<User *>(HungOffOperandList + 1);
160  Obj->NumUserOperands = 0;
161  Obj->HasHungOffUses = true;
162  Obj->HasDescriptor = false;
163  *HungOffOperandList = nullptr;
164  return Obj;
165 }
166 
167 //===----------------------------------------------------------------------===//
168 // User operator delete Implementation
169 //===----------------------------------------------------------------------===//
170 
171 // Repress memory sanitization, due to use-after-destroy by operator
172 // delete. Bug report 24578 identifies this issue.
173 LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE void User::operator delete(void *Usr) {
174  // Hung off uses use a single Use* before the User, while other subclasses
175  // use a Use[] allocated prior to the user.
176  User *Obj = static_cast<User *>(Usr);
177  if (Obj->HasHungOffUses) {
178  assert(!Obj->HasDescriptor && "not supported!");
179 
180  Use **HungOffOperandList = static_cast<Use **>(Usr) - 1;
181  // drop the hung off uses.
182  Use::zap(*HungOffOperandList, *HungOffOperandList + Obj->NumUserOperands,
183  /* Delete */ true);
184  ::operator delete(HungOffOperandList);
185  } else if (Obj->HasDescriptor) {
186  Use *UseBegin = static_cast<Use *>(Usr) - Obj->NumUserOperands;
187  Use::zap(UseBegin, UseBegin + Obj->NumUserOperands, /* Delete */ false);
188 
189  auto *DI = reinterpret_cast<DescriptorInfo *>(UseBegin) - 1;
190  uint8_t *Storage = reinterpret_cast<uint8_t *>(DI) - DI->SizeInBytes;
191  ::operator delete(Storage);
192  } else {
193  Use *Storage = static_cast<Use *>(Usr) - Obj->NumUserOperands;
194  Use::zap(Storage, Storage + Obj->NumUserOperands,
195  /* Delete */ false);
196  ::operator delete(Storage);
197  }
198 }
199 
200 } // namespace llvm
llvm::Check::Size
@ Size
Definition: FileCheck.h:73
i
i
Definition: README.txt:29
llvm
---------------------— PointerInfo ------------------------------------—
Definition: AllocatorList.h:23
intptr_t
IntrinsicInst.h
llvm::Use::zap
static 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:37
llvm::Value::HasHungOffUses
unsigned HasHungOffUses
Definition: Value.h:121
llvm::Value::NumUserOperands
unsigned NumUserOperands
Definition: Value.h:115
llvm::User::growHungoffUses
void growHungoffUses(unsigned N, bool IsPhi=false)
Grow the number of hung off uses.
Definition: User.cpp:61
llvm::BasicBlock
LLVM Basic Block Representation.
Definition: BasicBlock.h:58
GlobalValue.h
llvm::Value::NumUserOperandsBits
@ NumUserOperandsBits
Definition: Value.h:114
llvm::MutableArrayRef< uint8_t >
E
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
llvm::User
Definition: User.h:44
llvm::User::getDescriptor
ArrayRef< const uint8_t > getDescriptor() const
Returns the descriptor co-allocated with this User instance.
Definition: User.cpp:93
llvm::DescriptorInfo::SizeInBytes
intptr_t SizeInBytes
Definition: User.cpp:90
llvm::User::allocHungoffUses
void allocHungoffUses(unsigned N, bool IsPhi=false)
Allocate the array of Uses, followed by a pointer (with bottom bit set) to the User.
Definition: User.cpp:44
llvm::is_contained
bool is_contained(R &&Range, const E &Element)
Wrapper function around std::find to detect if an element exists in a container.
Definition: STLExtras.h:1612
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
llvm::User::replaceUsesOfWith
void replaceUsesOfWith(Value *From, Value *To)
Replace uses of one Value with another.
Definition: User.cpp:21
llvm::ISD::BasicBlock
@ BasicBlock
Various leaf nodes.
Definition: ISDOpcodes.h:71
llvm::User::isDroppable
bool isDroppable() const
A droppable user is a user for which uses can be dropped without affecting correctness and should be ...
Definition: User.cpp:109
llvm::User::setOperand
void setOperand(unsigned i, Value *Val)
Definition: User.h:174
llvm::size
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:1528
llvm::ArrayRef
ArrayRef - Represent a constant reference to an array (0 or more elements consecutively in memory),...
Definition: APInt.h:32
llvm::User::getOperandList
const Use * getOperandList() const
Definition: User.h:162
llvm::DescriptorInfo
Definition: User.cpp:89
Constant.h
llvm::Value::HasDescriptor
unsigned HasDescriptor
Definition: Value.h:122
LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE
#define LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE
Definition: Compiler.h:419
llvm::User::getNumOperands
unsigned getNumOperands() const
Definition: User.h:191
User.h
N
#define N
From
BlockVerifier::State From
Definition: BlockVerifier.cpp:55
llvm::User::getOperand
Value * getOperand(unsigned i) const
Definition: User.h:169
copy
we should consider alternate ways to model stack dependencies Lots of things could be done in WebAssemblyTargetTransformInfo cpp there are numerous optimization related hooks that can be overridden in WebAssemblyTargetLowering Instead of the OptimizeReturned which should consider preserving the returned attribute through to MachineInstrs and extending the MemIntrinsicResults pass to do this optimization on calls too That would also let the WebAssemblyPeephole pass clean up dead defs for such as it does for stores Consider implementing and or getMachineCombinerPatterns Find a clean way to fix the problem which leads to the Shrink Wrapping pass being run after the WebAssembly PEI pass When setting multiple variables to the same we currently get code like const It could be done with a smaller encoding like local tee $pop5 local copy
Definition: README.txt:101
llvm::Value
LLVM Value Representation.
Definition: Value.h:75
llvm::Use
A Use represents the edge between a Value definition and its users.
Definition: Use.h:44