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