xref: /freebsd/contrib/llvm-project/llvm/lib/IR/User.cpp (revision 480093f4440d54b30b3025afeac24b48f2ba7a2e)
10b57cec5SDimitry Andric //===-- User.cpp - Implement the User class -------------------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric 
90b57cec5SDimitry Andric #include "llvm/IR/User.h"
100b57cec5SDimitry Andric #include "llvm/IR/Constant.h"
110b57cec5SDimitry Andric #include "llvm/IR/GlobalValue.h"
120b57cec5SDimitry Andric 
130b57cec5SDimitry Andric namespace llvm {
140b57cec5SDimitry Andric class BasicBlock;
150b57cec5SDimitry Andric 
160b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
170b57cec5SDimitry Andric //                                 User Class
180b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
190b57cec5SDimitry Andric 
200b57cec5SDimitry Andric void User::replaceUsesOfWith(Value *From, Value *To) {
210b57cec5SDimitry Andric   if (From == To) return;   // Duh what?
220b57cec5SDimitry Andric 
230b57cec5SDimitry Andric   assert((!isa<Constant>(this) || isa<GlobalValue>(this)) &&
240b57cec5SDimitry Andric          "Cannot call User::replaceUsesOfWith on a constant!");
250b57cec5SDimitry Andric 
260b57cec5SDimitry Andric   for (unsigned i = 0, E = getNumOperands(); i != E; ++i)
270b57cec5SDimitry Andric     if (getOperand(i) == From) {  // Is This operand is pointing to oldval?
280b57cec5SDimitry Andric       // The side effects of this setOperand call include linking to
290b57cec5SDimitry Andric       // "To", adding "this" to the uses list of To, and
300b57cec5SDimitry Andric       // most importantly, removing "this" from the use list of "From".
310b57cec5SDimitry Andric       setOperand(i, To); // Fix it now...
320b57cec5SDimitry Andric     }
330b57cec5SDimitry Andric }
340b57cec5SDimitry Andric 
350b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
360b57cec5SDimitry Andric //                         User allocHungoffUses Implementation
370b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
380b57cec5SDimitry Andric 
390b57cec5SDimitry Andric void User::allocHungoffUses(unsigned N, bool IsPhi) {
400b57cec5SDimitry Andric   assert(HasHungOffUses && "alloc must have hung off uses");
410b57cec5SDimitry Andric 
420b57cec5SDimitry Andric   static_assert(alignof(Use) >= alignof(Use::UserRef),
430b57cec5SDimitry Andric                 "Alignment is insufficient for 'hung-off-uses' pieces");
440b57cec5SDimitry Andric   static_assert(alignof(Use::UserRef) >= alignof(BasicBlock *),
450b57cec5SDimitry Andric                 "Alignment is insufficient for 'hung-off-uses' pieces");
460b57cec5SDimitry Andric 
470b57cec5SDimitry Andric   // Allocate the array of Uses, followed by a pointer (with bottom bit set) to
480b57cec5SDimitry Andric   // the User.
490b57cec5SDimitry Andric   size_t size = N * sizeof(Use) + sizeof(Use::UserRef);
500b57cec5SDimitry Andric   if (IsPhi)
510b57cec5SDimitry Andric     size += N * sizeof(BasicBlock *);
520b57cec5SDimitry Andric   Use *Begin = static_cast<Use*>(::operator new(size));
530b57cec5SDimitry Andric   Use *End = Begin + N;
540b57cec5SDimitry Andric   (void) new(End) Use::UserRef(const_cast<User*>(this), 1);
550b57cec5SDimitry Andric   setOperandList(Use::initTags(Begin, End));
560b57cec5SDimitry Andric }
570b57cec5SDimitry Andric 
580b57cec5SDimitry Andric void User::growHungoffUses(unsigned NewNumUses, bool IsPhi) {
590b57cec5SDimitry Andric   assert(HasHungOffUses && "realloc must have hung off uses");
600b57cec5SDimitry Andric 
610b57cec5SDimitry Andric   unsigned OldNumUses = getNumOperands();
620b57cec5SDimitry Andric 
630b57cec5SDimitry Andric   // We don't support shrinking the number of uses.  We wouldn't have enough
640b57cec5SDimitry Andric   // space to copy the old uses in to the new space.
650b57cec5SDimitry Andric   assert(NewNumUses > OldNumUses && "realloc must grow num uses");
660b57cec5SDimitry Andric 
670b57cec5SDimitry Andric   Use *OldOps = getOperandList();
680b57cec5SDimitry Andric   allocHungoffUses(NewNumUses, IsPhi);
690b57cec5SDimitry Andric   Use *NewOps = getOperandList();
700b57cec5SDimitry Andric 
710b57cec5SDimitry Andric   // Now copy from the old operands list to the new one.
720b57cec5SDimitry Andric   std::copy(OldOps, OldOps + OldNumUses, NewOps);
730b57cec5SDimitry Andric 
740b57cec5SDimitry Andric   // If this is a Phi, then we need to copy the BB pointers too.
750b57cec5SDimitry Andric   if (IsPhi) {
760b57cec5SDimitry Andric     auto *OldPtr =
770b57cec5SDimitry Andric         reinterpret_cast<char *>(OldOps + OldNumUses) + sizeof(Use::UserRef);
780b57cec5SDimitry Andric     auto *NewPtr =
790b57cec5SDimitry Andric         reinterpret_cast<char *>(NewOps + NewNumUses) + sizeof(Use::UserRef);
800b57cec5SDimitry Andric     std::copy(OldPtr, OldPtr + (OldNumUses * sizeof(BasicBlock *)), NewPtr);
810b57cec5SDimitry Andric   }
820b57cec5SDimitry Andric   Use::zap(OldOps, OldOps + OldNumUses, true);
830b57cec5SDimitry Andric }
840b57cec5SDimitry Andric 
850b57cec5SDimitry Andric 
860b57cec5SDimitry Andric // This is a private struct used by `User` to track the co-allocated descriptor
870b57cec5SDimitry Andric // section.
880b57cec5SDimitry Andric struct DescriptorInfo {
890b57cec5SDimitry Andric   intptr_t SizeInBytes;
900b57cec5SDimitry Andric };
910b57cec5SDimitry Andric 
920b57cec5SDimitry Andric ArrayRef<const uint8_t> User::getDescriptor() const {
930b57cec5SDimitry Andric   auto MutableARef = const_cast<User *>(this)->getDescriptor();
940b57cec5SDimitry Andric   return {MutableARef.begin(), MutableARef.end()};
950b57cec5SDimitry Andric }
960b57cec5SDimitry Andric 
970b57cec5SDimitry Andric MutableArrayRef<uint8_t> User::getDescriptor() {
980b57cec5SDimitry Andric   assert(HasDescriptor && "Don't call otherwise!");
990b57cec5SDimitry Andric   assert(!HasHungOffUses && "Invariant!");
1000b57cec5SDimitry Andric 
1010b57cec5SDimitry Andric   auto *DI = reinterpret_cast<DescriptorInfo *>(getIntrusiveOperands()) - 1;
1020b57cec5SDimitry Andric   assert(DI->SizeInBytes != 0 && "Should not have had a descriptor otherwise!");
1030b57cec5SDimitry Andric 
1040b57cec5SDimitry Andric   return MutableArrayRef<uint8_t>(
1050b57cec5SDimitry Andric       reinterpret_cast<uint8_t *>(DI) - DI->SizeInBytes, DI->SizeInBytes);
1060b57cec5SDimitry Andric }
1070b57cec5SDimitry Andric 
1080b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1090b57cec5SDimitry Andric //                         User operator new Implementations
1100b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1110b57cec5SDimitry Andric 
1120b57cec5SDimitry Andric void *User::allocateFixedOperandUser(size_t Size, unsigned Us,
1130b57cec5SDimitry Andric                                      unsigned DescBytes) {
1140b57cec5SDimitry Andric   assert(Us < (1u << NumUserOperandsBits) && "Too many operands");
1150b57cec5SDimitry Andric 
1160b57cec5SDimitry Andric   static_assert(sizeof(DescriptorInfo) % sizeof(void *) == 0, "Required below");
1170b57cec5SDimitry Andric 
1180b57cec5SDimitry Andric   unsigned DescBytesToAllocate =
1190b57cec5SDimitry Andric       DescBytes == 0 ? 0 : (DescBytes + sizeof(DescriptorInfo));
1200b57cec5SDimitry Andric   assert(DescBytesToAllocate % sizeof(void *) == 0 &&
1210b57cec5SDimitry Andric          "We need this to satisfy alignment constraints for Uses");
1220b57cec5SDimitry Andric 
1230b57cec5SDimitry Andric   uint8_t *Storage = static_cast<uint8_t *>(
1240b57cec5SDimitry Andric       ::operator new(Size + sizeof(Use) * Us + DescBytesToAllocate));
1250b57cec5SDimitry Andric   Use *Start = reinterpret_cast<Use *>(Storage + DescBytesToAllocate);
1260b57cec5SDimitry Andric   Use *End = Start + Us;
1270b57cec5SDimitry Andric   User *Obj = reinterpret_cast<User*>(End);
1280b57cec5SDimitry Andric   Obj->NumUserOperands = Us;
1290b57cec5SDimitry Andric   Obj->HasHungOffUses = false;
1300b57cec5SDimitry Andric   Obj->HasDescriptor = DescBytes != 0;
1310b57cec5SDimitry Andric   Use::initTags(Start, End);
1320b57cec5SDimitry Andric 
1330b57cec5SDimitry Andric   if (DescBytes != 0) {
1340b57cec5SDimitry Andric     auto *DescInfo = reinterpret_cast<DescriptorInfo *>(Storage + DescBytes);
1350b57cec5SDimitry Andric     DescInfo->SizeInBytes = DescBytes;
1360b57cec5SDimitry Andric   }
1370b57cec5SDimitry Andric 
1380b57cec5SDimitry Andric   return Obj;
1390b57cec5SDimitry Andric }
1400b57cec5SDimitry Andric 
1410b57cec5SDimitry Andric void *User::operator new(size_t Size, unsigned Us) {
1420b57cec5SDimitry Andric   return allocateFixedOperandUser(Size, Us, 0);
1430b57cec5SDimitry Andric }
1440b57cec5SDimitry Andric 
1450b57cec5SDimitry Andric void *User::operator new(size_t Size, unsigned Us, unsigned DescBytes) {
1460b57cec5SDimitry Andric   return allocateFixedOperandUser(Size, Us, DescBytes);
1470b57cec5SDimitry Andric }
1480b57cec5SDimitry Andric 
1490b57cec5SDimitry Andric void *User::operator new(size_t Size) {
1500b57cec5SDimitry Andric   // Allocate space for a single Use*
1510b57cec5SDimitry Andric   void *Storage = ::operator new(Size + sizeof(Use *));
1520b57cec5SDimitry Andric   Use **HungOffOperandList = static_cast<Use **>(Storage);
1530b57cec5SDimitry Andric   User *Obj = reinterpret_cast<User *>(HungOffOperandList + 1);
1540b57cec5SDimitry Andric   Obj->NumUserOperands = 0;
1550b57cec5SDimitry Andric   Obj->HasHungOffUses = true;
1560b57cec5SDimitry Andric   Obj->HasDescriptor = false;
1570b57cec5SDimitry Andric   *HungOffOperandList = nullptr;
1580b57cec5SDimitry Andric   return Obj;
1590b57cec5SDimitry Andric }
1600b57cec5SDimitry Andric 
1610b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1620b57cec5SDimitry Andric //                         User operator delete Implementation
1630b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
1640b57cec5SDimitry Andric 
165*480093f4SDimitry Andric // Repress memory sanitization, due to use-after-destroy by operator
166*480093f4SDimitry Andric // delete. Bug report 24578 identifies this issue.
167*480093f4SDimitry Andric LLVM_NO_SANITIZE_MEMORY_ATTRIBUTE void User::operator delete(void *Usr) {
1680b57cec5SDimitry Andric   // Hung off uses use a single Use* before the User, while other subclasses
1690b57cec5SDimitry Andric   // use a Use[] allocated prior to the user.
1700b57cec5SDimitry Andric   User *Obj = static_cast<User *>(Usr);
1710b57cec5SDimitry Andric   if (Obj->HasHungOffUses) {
1720b57cec5SDimitry Andric     assert(!Obj->HasDescriptor && "not supported!");
1730b57cec5SDimitry Andric 
1740b57cec5SDimitry Andric     Use **HungOffOperandList = static_cast<Use **>(Usr) - 1;
1750b57cec5SDimitry Andric     // drop the hung off uses.
1760b57cec5SDimitry Andric     Use::zap(*HungOffOperandList, *HungOffOperandList + Obj->NumUserOperands,
1770b57cec5SDimitry Andric              /* Delete */ true);
1780b57cec5SDimitry Andric     ::operator delete(HungOffOperandList);
1790b57cec5SDimitry Andric   } else if (Obj->HasDescriptor) {
1800b57cec5SDimitry Andric     Use *UseBegin = static_cast<Use *>(Usr) - Obj->NumUserOperands;
1810b57cec5SDimitry Andric     Use::zap(UseBegin, UseBegin + Obj->NumUserOperands, /* Delete */ false);
1820b57cec5SDimitry Andric 
1830b57cec5SDimitry Andric     auto *DI = reinterpret_cast<DescriptorInfo *>(UseBegin) - 1;
1840b57cec5SDimitry Andric     uint8_t *Storage = reinterpret_cast<uint8_t *>(DI) - DI->SizeInBytes;
1850b57cec5SDimitry Andric     ::operator delete(Storage);
1860b57cec5SDimitry Andric   } else {
1870b57cec5SDimitry Andric     Use *Storage = static_cast<Use *>(Usr) - Obj->NumUserOperands;
1880b57cec5SDimitry Andric     Use::zap(Storage, Storage + Obj->NumUserOperands,
1890b57cec5SDimitry Andric              /* Delete */ false);
1900b57cec5SDimitry Andric     ::operator delete(Storage);
1910b57cec5SDimitry Andric   }
1920b57cec5SDimitry Andric }
1930b57cec5SDimitry Andric 
1940b57cec5SDimitry Andric } // End llvm namespace
195