// User allocHungoffUses Implementation
//===----------------------------------------------------------------------===//
-Use *User::allocHungoffUses(unsigned N, bool IsPhi) {
+void User::allocHungoffUses(unsigned N, bool IsPhi) {
+ assert(HasHungOffUses && "alloc must have hung off uses");
+
+ static_assert(AlignOf<Use>::Alignment >= AlignOf<Use::UserRef>::Alignment,
+ "Alignment is insufficient for 'hung-off-uses' pieces");
+ static_assert(AlignOf<Use::UserRef>::Alignment >=
+ AlignOf<BasicBlock *>::Alignment,
+ "Alignment is insufficient for 'hung-off-uses' pieces");
+
// Allocate the array of Uses, followed by a pointer (with bottom bit set) to
// the User.
size_t size = N * sizeof(Use) + sizeof(Use::UserRef);
Use *Begin = static_cast<Use*>(::operator new(size));
Use *End = Begin + N;
(void) new(End) Use::UserRef(const_cast<User*>(this), 1);
- Use *Uses = Use::initTags(Begin, End);
- OperandList = Uses;
- // Tag this operand list as being a hung off.
- HasHungOffUses = true;
- return Uses;
+ setOperandList(Use::initTags(Begin, End));
}
void User::growHungoffUses(unsigned NewNumUses, bool IsPhi) {
// space to copy the old uses in to the new space.
assert(NewNumUses > OldNumUses && "realloc must grow num uses");
- Use *OldOps = OperandList;
+ Use *OldOps = getOperandList();
allocHungoffUses(NewNumUses, IsPhi);
- Use *NewOps = OperandList;
+ Use *NewOps = getOperandList();
// Now copy from the old operands list to the new one.
std::copy(OldOps, OldOps + OldNumUses, NewOps);
// User operator new Implementations
//===----------------------------------------------------------------------===//
-void *User::operator new(size_t s, unsigned Us) {
- void *Storage = ::operator new(s + sizeof(Use) * Us);
+void *User::operator new(size_t Size, unsigned Us) {
+ assert(Us < (1u << NumUserOperandsBits) && "Too many operands");
+ void *Storage = ::operator new(Size + sizeof(Use) * Us);
Use *Start = static_cast<Use*>(Storage);
Use *End = Start + Us;
User *Obj = reinterpret_cast<User*>(End);
- Obj->OperandList = Start;
+ Obj->NumUserOperands = Us;
Obj->HasHungOffUses = false;
- Obj->NumOperands = Us;
Use::initTags(Start, End);
return Obj;
}
+void *User::operator new(size_t Size) {
+ // Allocate space for a single Use*
+ void *Storage = ::operator new(Size + sizeof(Use *));
+ Use **HungOffOperandList = static_cast<Use **>(Storage);
+ User *Obj = reinterpret_cast<User *>(HungOffOperandList + 1);
+ Obj->NumUserOperands = 0;
+ Obj->HasHungOffUses = true;
+ *HungOffOperandList = nullptr;
+ return Obj;
+}
+
//===----------------------------------------------------------------------===//
// User operator delete Implementation
//===----------------------------------------------------------------------===//
void User::operator delete(void *Usr) {
- User *Start = static_cast<User*>(Usr);
- Use *Storage = static_cast<Use*>(Usr) - Start->NumOperands;
- // If there were hung-off uses, they will have been freed already and
- // NumOperands reset to 0, so here we just free the User itself.
- ::operator delete(Storage);
+ // Hung off uses use a single Use* before the User, while other subclasses
+ // use a Use[] allocated prior to the user.
+ User *Obj = static_cast<User *>(Usr);
+ if (Obj->HasHungOffUses) {
+ Use **HungOffOperandList = static_cast<Use **>(Usr) - 1;
+ // drop the hung off uses.
+ Use::zap(*HungOffOperandList, *HungOffOperandList + Obj->NumUserOperands,
+ /* Delete */ true);
+ ::operator delete(HungOffOperandList);
+ } else {
+ Use *Storage = static_cast<Use *>(Usr) - Obj->NumUserOperands;
+ Use::zap(Storage, Storage + Obj->NumUserOperands,
+ /* Delete */ false);
+ ::operator delete(Storage);
+ }
}
//===----------------------------------------------------------------------===//