LLVM  15.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  bool Changed = false;
23  if (From == To) return Changed; // Duh what?
24 
25  assert((!isa<Constant>(this) || isa<GlobalValue>(this)) &&
26  "Cannot call User::replaceUsesOfWith on a constant!");
27 
28  for (unsigned i = 0, E = getNumOperands(); i != E; ++i)
29  if (getOperand(i) == From) { // Is This operand is pointing to oldval?
30  // The side effects of this setOperand call include linking to
31  // "To", adding "this" to the uses list of To, and
32  // most importantly, removing "this" from the use list of "From".
33  setOperand(i, To);
34  Changed = true;
35  }
36  if (auto DVI = dyn_cast_or_null<DbgVariableIntrinsic>(this)) {
37  if (is_contained(DVI->location_ops(), From)) {
38  DVI->replaceVariableLocationOp(From, To);
39  Changed = true;
40  }
41  }
42 
43  return Changed;
44 }
45 
46 //===----------------------------------------------------------------------===//
47 // User allocHungoffUses Implementation
48 //===----------------------------------------------------------------------===//
49 
50 void User::allocHungoffUses(unsigned N, bool IsPhi) {
51  assert(HasHungOffUses && "alloc must have hung off uses");
52 
53  static_assert(alignof(Use) >= alignof(BasicBlock *),
54  "Alignment is insufficient for 'hung-off-uses' pieces");
55 
56  // Allocate the array of Uses
57  size_t size = N * sizeof(Use);
58  if (IsPhi)
59  size += N * sizeof(BasicBlock *);
60  Use *Begin = static_cast<Use*>(::operator new(size));
61  Use *End = Begin + N;
62  setOperandList(Begin);
63  for (; Begin != End; Begin++)
64  new (Begin) Use(this);
65 }
66 
67 void User::growHungoffUses(unsigned NewNumUses, bool IsPhi) {
68  assert(HasHungOffUses && "realloc must have hung off uses");
69 
70  unsigned OldNumUses = getNumOperands();
71 
72  // We don't support shrinking the number of uses. We wouldn't have enough
73  // space to copy the old uses in to the new space.
74  assert(NewNumUses > OldNumUses && "realloc must grow num uses");
75 
76  Use *OldOps = getOperandList();
77  allocHungoffUses(NewNumUses, IsPhi);
78  Use *NewOps = getOperandList();
79 
80  // Now copy from the old operands list to the new one.
81  std::copy(OldOps, OldOps + OldNumUses, NewOps);
82 
83  // If this is a Phi, then we need to copy the BB pointers too.
84  if (IsPhi) {
85  auto *OldPtr = reinterpret_cast<char *>(OldOps + OldNumUses);
86  auto *NewPtr = reinterpret_cast<char *>(NewOps + NewNumUses);
87  std::copy(OldPtr, OldPtr + (OldNumUses * sizeof(BasicBlock *)), NewPtr);
88  }
89  Use::zap(OldOps, OldOps + OldNumUses, true);
90 }
91 
92 
93 // This is a private struct used by `User` to track the co-allocated descriptor
94 // section.
97 };
98 
100  auto MutableARef = const_cast<User *>(this)->getDescriptor();
101  return {MutableARef.begin(), MutableARef.end()};
102 }
103 
105  assert(HasDescriptor && "Don't call otherwise!");
106  assert(!HasHungOffUses && "Invariant!");
107 
108  auto *DI = reinterpret_cast<DescriptorInfo *>(getIntrusiveOperands()) - 1;
109  assert(DI->SizeInBytes != 0 && "Should not have had a descriptor otherwise!");
110 
112  reinterpret_cast<uint8_t *>(DI) - DI->SizeInBytes, DI->SizeInBytes);
113 }
114 
115 bool User::isDroppable() const {
116  return isa<AssumeInst>(this) || isa<PseudoProbeInst>(this);
117 }
118 
119 //===----------------------------------------------------------------------===//
120 // User operator new Implementations
121 //===----------------------------------------------------------------------===//
122 
123 void *User::allocateFixedOperandUser(size_t Size, unsigned Us,
124  unsigned DescBytes) {
125  assert(Us < (1u << NumUserOperandsBits) && "Too many operands");
126 
127  static_assert(sizeof(DescriptorInfo) % sizeof(void *) == 0, "Required below");
128 
129  unsigned DescBytesToAllocate =
130  DescBytes == 0 ? 0 : (DescBytes + sizeof(DescriptorInfo));
131  assert(DescBytesToAllocate % sizeof(void *) == 0 &&
132  "We need this to satisfy alignment constraints for Uses");
133 
134  uint8_t *Storage = static_cast<uint8_t *>(
135  ::operator new(Size + sizeof(Use) * Us + DescBytesToAllocate));
136  Use *Start = reinterpret_cast<Use *>(Storage + DescBytesToAllocate);
137  Use *End = Start + Us;
138  User *Obj = reinterpret_cast<User*>(End);
139  Obj->NumUserOperands = Us;
140  Obj->HasHungOffUses = false;
141  Obj->HasDescriptor = DescBytes != 0;
142  for (; Start != End; Start++)
143  new (Start) Use(Obj);
144 
145  if (DescBytes != 0) {
146  auto *DescInfo = reinterpret_cast<DescriptorInfo *>(Storage + DescBytes);
147  DescInfo->SizeInBytes = DescBytes;
148  }
149 
150  return Obj;
151 }
152 
153 void *User::operator new(size_t Size, unsigned Us) {
154  return allocateFixedOperandUser(Size, Us, 0);
155 }
156 
157 void *User::operator new(size_t Size, unsigned Us, unsigned DescBytes) {
158  return allocateFixedOperandUser(Size, Us, DescBytes);
159 }
160 
161 void *User::operator new(size_t Size) {
162  // Allocate space for a single Use*
163  void *Storage = ::operator new(Size + sizeof(Use *));
164  Use **HungOffOperandList = static_cast<Use **>(Storage);
165  User *Obj = reinterpret_cast<User *>(HungOffOperandList + 1);
166  Obj->NumUserOperands = 0;
167  Obj->HasHungOffUses = true;
168  Obj->HasDescriptor = false;
169  *HungOffOperandList = nullptr;
170  return Obj;
171 }
172 
173 //===----------------------------------------------------------------------===//
174 // User operator delete Implementation
175 //===----------------------------------------------------------------------===//
176 
177 // Repress memory sanitization, due to use-after-destroy by operator
178 // delete. Bug report 24578 identifies this issue.
179 LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE void User::operator delete(void *Usr) {
180  // Hung off uses use a single Use* before the User, while other subclasses
181  // use a Use[] allocated prior to the user.
182  User *Obj = static_cast<User *>(Usr);
183  if (Obj->HasHungOffUses) {
184  assert(!Obj->HasDescriptor && "not supported!");
185 
186  Use **HungOffOperandList = static_cast<Use **>(Usr) - 1;
187  // drop the hung off uses.
188  Use::zap(*HungOffOperandList, *HungOffOperandList + Obj->NumUserOperands,
189  /* Delete */ true);
190  ::operator delete(HungOffOperandList);
191  } else if (Obj->HasDescriptor) {
192  Use *UseBegin = static_cast<Use *>(Usr) - Obj->NumUserOperands;
193  Use::zap(UseBegin, UseBegin + Obj->NumUserOperands, /* Delete */ false);
194 
195  auto *DI = reinterpret_cast<DescriptorInfo *>(UseBegin) - 1;
196  uint8_t *Storage = reinterpret_cast<uint8_t *>(DI) - DI->SizeInBytes;
197  ::operator delete(Storage);
198  } else {
199  Use *Storage = static_cast<Use *>(Usr) - Obj->NumUserOperands;
200  Use::zap(Storage, Storage + Obj->NumUserOperands,
201  /* Delete */ false);
202  ::operator delete(Storage);
203  }
204 }
205 
206 } // namespace llvm
i
i
Definition: README.txt:29
llvm
This is an optimization pass for GlobalISel generic memory operations.
Definition: AddressRanges.h:17
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:35
llvm::Value::HasHungOffUses
unsigned HasHungOffUses
Definition: Value.h:120
llvm::Value::NumUserOperands
unsigned NumUserOperands
Definition: Value.h:114
llvm::User::growHungoffUses
void growHungoffUses(unsigned N, bool IsPhi=false)
Grow the number of hung off uses.
Definition: User.cpp:67
llvm::BasicBlock
LLVM Basic Block Representation.
Definition: BasicBlock.h:55
GlobalValue.h
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:99
llvm::DescriptorInfo::SizeInBytes
intptr_t SizeInBytes
Definition: User.cpp:96
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:50
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:1672
assert
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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:115
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:1588
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:95
llvm::Value::NumUserOperandsBits
@ NumUserOperandsBits
Definition: Value.h:113
llvm::User::replaceUsesOfWith
bool replaceUsesOfWith(Value *From, Value *To)
Replace uses of one Value with another.
Definition: User.cpp:21
Constant.h
llvm::Value::HasDescriptor
unsigned HasDescriptor
Definition: Value.h:121
LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE
#define LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE
Definition: Compiler.h:409
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:74
llvm::Use
A Use represents the edge between a Value definition and its users.
Definition: Use.h:43