/Users/buildslave/jenkins/sharedspace/clang-stage2-coverage-R@2/llvm/lib/IR/User.cpp
Line | Count | Source (jump to first uncovered line) |
1 | | //===-- User.cpp - Implement the User class -------------------------------===// |
2 | | // |
3 | | // The LLVM Compiler Infrastructure |
4 | | // |
5 | | // This file is distributed under the University of Illinois Open Source |
6 | | // License. See LICENSE.TXT for details. |
7 | | // |
8 | | //===----------------------------------------------------------------------===// |
9 | | |
10 | | #include "llvm/IR/User.h" |
11 | | #include "llvm/IR/Constant.h" |
12 | | #include "llvm/IR/GlobalValue.h" |
13 | | #include "llvm/IR/Operator.h" |
14 | | |
15 | | namespace llvm { |
16 | | class BasicBlock; |
17 | | |
18 | | //===----------------------------------------------------------------------===// |
19 | | // User Class |
20 | | //===----------------------------------------------------------------------===// |
21 | | |
22 | 2.90M | void User::replaceUsesOfWith(Value *From, Value *To) { |
23 | 2.90M | if (From == To2.90M ) return105k ; // Duh what? |
24 | 2.79M | |
25 | 2.90M | assert((!isa<Constant>(this) || isa<GlobalValue>(this)) && |
26 | 2.79M | "Cannot call User::replaceUsesOfWith on a constant!"); |
27 | 2.79M | |
28 | 9.89M | for (unsigned i = 0, E = getNumOperands(); i != E9.89M ; ++i7.09M ) |
29 | 7.09M | if (7.09M getOperand(i) == From7.09M ) { // Is This operand is pointing to oldval? |
30 | 2.79M | // The side effects of this setOperand call include linking to |
31 | 2.79M | // "To", adding "this" to the uses list of To, and |
32 | 2.79M | // most importantly, removing "this" from the use list of "From". |
33 | 2.79M | setOperand(i, To); // Fix it now... |
34 | 2.79M | } |
35 | 2.90M | } |
36 | | |
37 | | //===----------------------------------------------------------------------===// |
38 | | // User allocHungoffUses Implementation |
39 | | //===----------------------------------------------------------------------===// |
40 | | |
41 | 6.32M | void User::allocHungoffUses(unsigned N, bool IsPhi) { |
42 | 6.32M | assert(HasHungOffUses && "alloc must have hung off uses"); |
43 | 6.32M | |
44 | 6.32M | static_assert(alignof(Use) >= alignof(Use::UserRef), |
45 | 6.32M | "Alignment is insufficient for 'hung-off-uses' pieces"); |
46 | 6.32M | static_assert(alignof(Use::UserRef) >= alignof(BasicBlock *), |
47 | 6.32M | "Alignment is insufficient for 'hung-off-uses' pieces"); |
48 | 6.32M | |
49 | 6.32M | // Allocate the array of Uses, followed by a pointer (with bottom bit set) to |
50 | 6.32M | // the User. |
51 | 6.32M | size_t size = N * sizeof(Use) + sizeof(Use::UserRef); |
52 | 6.32M | if (IsPhi) |
53 | 6.22M | size += N * sizeof(BasicBlock *); |
54 | 6.32M | Use *Begin = static_cast<Use*>(::operator new(size)); |
55 | 6.32M | Use *End = Begin + N; |
56 | 6.32M | (void) new(End) Use::UserRef(const_cast<User*>(this), 1); |
57 | 6.32M | setOperandList(Use::initTags(Begin, End)); |
58 | 6.32M | } |
59 | | |
60 | 1.55M | void User::growHungoffUses(unsigned NewNumUses, bool IsPhi) { |
61 | 1.55M | assert(HasHungOffUses && "realloc must have hung off uses"); |
62 | 1.55M | |
63 | 1.55M | unsigned OldNumUses = getNumOperands(); |
64 | 1.55M | |
65 | 1.55M | // We don't support shrinking the number of uses. We wouldn't have enough |
66 | 1.55M | // space to copy the old uses in to the new space. |
67 | 1.55M | assert(NewNumUses > OldNumUses && "realloc must grow num uses"); |
68 | 1.55M | |
69 | 1.55M | Use *OldOps = getOperandList(); |
70 | 1.55M | allocHungoffUses(NewNumUses, IsPhi); |
71 | 1.55M | Use *NewOps = getOperandList(); |
72 | 1.55M | |
73 | 1.55M | // Now copy from the old operands list to the new one. |
74 | 1.55M | std::copy(OldOps, OldOps + OldNumUses, NewOps); |
75 | 1.55M | |
76 | 1.55M | // If this is a Phi, then we need to copy the BB pointers too. |
77 | 1.55M | if (IsPhi1.55M ) { |
78 | 1.55M | auto *OldPtr = |
79 | 1.55M | reinterpret_cast<char *>(OldOps + OldNumUses) + sizeof(Use::UserRef); |
80 | 1.55M | auto *NewPtr = |
81 | 1.55M | reinterpret_cast<char *>(NewOps + NewNumUses) + sizeof(Use::UserRef); |
82 | 1.55M | std::copy(OldPtr, OldPtr + (OldNumUses * sizeof(BasicBlock *)), NewPtr); |
83 | 1.55M | } |
84 | 1.55M | Use::zap(OldOps, OldOps + OldNumUses, true); |
85 | 1.55M | } |
86 | | |
87 | | |
88 | | // This is a private struct used by `User` to track the co-allocated descriptor |
89 | | // section. |
90 | | struct DescriptorInfo { |
91 | | intptr_t SizeInBytes; |
92 | | }; |
93 | | |
94 | 0 | ArrayRef<const uint8_t> User::getDescriptor() const { |
95 | 0 | auto MutableARef = const_cast<User *>(this)->getDescriptor(); |
96 | 0 | return {MutableARef.begin(), MutableARef.end()}; |
97 | 0 | } |
98 | | |
99 | 62.4k | MutableArrayRef<uint8_t> User::getDescriptor() { |
100 | 62.4k | assert(HasDescriptor && "Don't call otherwise!"); |
101 | 62.4k | assert(!HasHungOffUses && "Invariant!"); |
102 | 62.4k | |
103 | 62.4k | auto *DI = reinterpret_cast<DescriptorInfo *>(getIntrusiveOperands()) - 1; |
104 | 62.4k | assert(DI->SizeInBytes != 0 && "Should not have had a descriptor otherwise!"); |
105 | 62.4k | |
106 | 62.4k | return MutableArrayRef<uint8_t>( |
107 | 62.4k | reinterpret_cast<uint8_t *>(DI) - DI->SizeInBytes, DI->SizeInBytes); |
108 | 62.4k | } |
109 | | |
110 | | //===----------------------------------------------------------------------===// |
111 | | // User operator new Implementations |
112 | | //===----------------------------------------------------------------------===// |
113 | | |
114 | | void *User::allocateFixedOperandUser(size_t Size, unsigned Us, |
115 | 66.9M | unsigned DescBytes) { |
116 | 66.9M | assert(Us < (1u << NumUserOperandsBits) && "Too many operands"); |
117 | 66.9M | |
118 | 66.9M | static_assert(sizeof(DescriptorInfo) % sizeof(void *) == 0, "Required below"); |
119 | 66.9M | |
120 | 66.9M | unsigned DescBytesToAllocate = |
121 | 66.9M | DescBytes == 0 ? 066.9M : (DescBytes + sizeof(DescriptorInfo))1.24k ; |
122 | 66.9M | assert(DescBytesToAllocate % sizeof(void *) == 0 && |
123 | 66.9M | "We need this to satisfy alignment constraints for Uses"); |
124 | 66.9M | |
125 | 66.9M | uint8_t *Storage = static_cast<uint8_t *>( |
126 | 66.9M | ::operator new(Size + sizeof(Use) * Us + DescBytesToAllocate)); |
127 | 66.9M | Use *Start = reinterpret_cast<Use *>(Storage + DescBytesToAllocate); |
128 | 66.9M | Use *End = Start + Us; |
129 | 66.9M | User *Obj = reinterpret_cast<User*>(End); |
130 | 66.9M | Obj->NumUserOperands = Us; |
131 | 66.9M | Obj->HasHungOffUses = false; |
132 | 66.9M | Obj->HasDescriptor = DescBytes != 0; |
133 | 66.9M | Use::initTags(Start, End); |
134 | 66.9M | |
135 | 66.9M | if (DescBytes != 066.9M ) { |
136 | 1.24k | auto *DescInfo = reinterpret_cast<DescriptorInfo *>(Storage + DescBytes); |
137 | 1.24k | DescInfo->SizeInBytes = DescBytes; |
138 | 1.24k | } |
139 | 66.9M | |
140 | 66.9M | return Obj; |
141 | 66.9M | } |
142 | | |
143 | 62.4M | void *User::operator new(size_t Size, unsigned Us) { |
144 | 62.4M | return allocateFixedOperandUser(Size, Us, 0); |
145 | 62.4M | } |
146 | | |
147 | 4.48M | void *User::operator new(size_t Size, unsigned Us, unsigned DescBytes) { |
148 | 4.48M | return allocateFixedOperandUser(Size, Us, DescBytes); |
149 | 4.48M | } |
150 | | |
151 | 7.61M | void *User::operator new(size_t Size) { |
152 | 7.61M | // Allocate space for a single Use* |
153 | 7.61M | void *Storage = ::operator new(Size + sizeof(Use *)); |
154 | 7.61M | Use **HungOffOperandList = static_cast<Use **>(Storage); |
155 | 7.61M | User *Obj = reinterpret_cast<User *>(HungOffOperandList + 1); |
156 | 7.61M | Obj->NumUserOperands = 0; |
157 | 7.61M | Obj->HasHungOffUses = true; |
158 | 7.61M | Obj->HasDescriptor = false; |
159 | 7.61M | *HungOffOperandList = nullptr; |
160 | 7.61M | return Obj; |
161 | 7.61M | } |
162 | | |
163 | | //===----------------------------------------------------------------------===// |
164 | | // User operator delete Implementation |
165 | | //===----------------------------------------------------------------------===// |
166 | | |
167 | 46.3M | void User::operator delete(void *Usr) { |
168 | 46.3M | // Hung off uses use a single Use* before the User, while other subclasses |
169 | 46.3M | // use a Use[] allocated prior to the user. |
170 | 46.3M | User *Obj = static_cast<User *>(Usr); |
171 | 46.3M | if (Obj->HasHungOffUses46.3M ) { |
172 | 5.92M | assert(!Obj->HasDescriptor && "not supported!"); |
173 | 5.92M | |
174 | 5.92M | Use **HungOffOperandList = static_cast<Use **>(Usr) - 1; |
175 | 5.92M | // drop the hung off uses. |
176 | 5.92M | Use::zap(*HungOffOperandList, *HungOffOperandList + Obj->NumUserOperands, |
177 | 5.92M | /* Delete */ true); |
178 | 5.92M | ::operator delete(HungOffOperandList); |
179 | 46.3M | } else if (40.4M Obj->HasDescriptor40.4M ) { |
180 | 1.24k | Use *UseBegin = static_cast<Use *>(Usr) - Obj->NumUserOperands; |
181 | 1.24k | Use::zap(UseBegin, UseBegin + Obj->NumUserOperands, /* Delete */ false); |
182 | 1.24k | |
183 | 1.24k | auto *DI = reinterpret_cast<DescriptorInfo *>(UseBegin) - 1; |
184 | 1.24k | uint8_t *Storage = reinterpret_cast<uint8_t *>(DI) - DI->SizeInBytes; |
185 | 1.24k | ::operator delete(Storage); |
186 | 40.4M | } else { |
187 | 40.4M | Use *Storage = static_cast<Use *>(Usr) - Obj->NumUserOperands; |
188 | 40.4M | Use::zap(Storage, Storage + Obj->NumUserOperands, |
189 | 40.4M | /* Delete */ false); |
190 | 40.4M | ::operator delete(Storage); |
191 | 40.4M | } |
192 | 46.3M | } |
193 | | |
194 | | } // End llvm namespace |