Skip to content

Commit e01e363

Browse files
committed
Assert that we have all use/users in the getters.
An error that is pretty easy to make is to use the lazy bitcode reader and then do something like if (V.use_empty()) The problem is that uses in unmaterialized functions are not accounted for. This patch adds asserts that all uses are known. llvm-svn: 256105
1 parent 0334a04 commit e01e363

File tree

7 files changed

+96
-23
lines changed

7 files changed

+96
-23
lines changed

llvm/include/llvm/IR/Module.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -439,14 +439,14 @@ class Module {
439439
void setMaterializer(GVMaterializer *GVM);
440440
/// Retrieves the GVMaterializer, if any, for this Module.
441441
GVMaterializer *getMaterializer() const { return Materializer.get(); }
442+
bool isMaterialized() const { return !getMaterializer(); }
442443

443444
/// Make sure the GlobalValue is fully read. If the module is corrupt, this
444445
/// returns true and fills in the optional string with information about the
445446
/// problem. If successful, this returns false.
446447
std::error_code materialize(GlobalValue *GV);
447448

448449
/// Make sure all GlobalValues in this Module are fully read and clear the
449-
/// Materializer. If the module is corrupt, this DOES NOT clear the old
450450
/// Materializer.
451451
std::error_code materializeAll();
452452

llvm/include/llvm/IR/Value.h

Lines changed: 65 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -273,38 +273,91 @@ class Value {
273273
//----------------------------------------------------------------------
274274
// Methods for handling the chain of uses of this Value.
275275
//
276-
bool use_empty() const { return UseList == nullptr; }
276+
// Materializing a function can introduce new uses, so these methods come in
277+
// two variants:
278+
// The methods that start with materialized_ check the uses that are
279+
// currently known given which functions are materialized. Be very careful
280+
// when using them since you might not get all uses.
281+
// The methods that don't start with materialized_ assert that modules is
282+
// fully materialized.
283+
#ifdef NDEBUG
284+
void assertModuleIsMaterialized() const {}
285+
#else
286+
void assertModuleIsMaterialized() const;
287+
#endif
288+
289+
bool use_empty() const {
290+
assertModuleIsMaterialized();
291+
return UseList == nullptr;
292+
}
277293

278294
typedef use_iterator_impl<Use> use_iterator;
279295
typedef use_iterator_impl<const Use> const_use_iterator;
280-
use_iterator use_begin() { return use_iterator(UseList); }
281-
const_use_iterator use_begin() const { return const_use_iterator(UseList); }
296+
use_iterator materialized_use_begin() { return use_iterator(UseList); }
297+
const_use_iterator materialized_use_begin() const {
298+
return const_use_iterator(UseList);
299+
}
300+
use_iterator use_begin() {
301+
assertModuleIsMaterialized();
302+
return materialized_use_begin();
303+
}
304+
const_use_iterator use_begin() const {
305+
assertModuleIsMaterialized();
306+
return materialized_use_begin();
307+
}
282308
use_iterator use_end() { return use_iterator(); }
283309
const_use_iterator use_end() const { return const_use_iterator(); }
310+
iterator_range<use_iterator> materialized_uses() {
311+
return make_range(materialized_use_begin(), use_end());
312+
}
313+
iterator_range<const_use_iterator> materialized_uses() const {
314+
return make_range(materialized_use_begin(), use_end());
315+
}
284316
iterator_range<use_iterator> uses() {
285-
return make_range(use_begin(), use_end());
317+
assertModuleIsMaterialized();
318+
return materialized_uses();
286319
}
287320
iterator_range<const_use_iterator> uses() const {
288-
return make_range(use_begin(), use_end());
321+
assertModuleIsMaterialized();
322+
return materialized_uses();
289323
}
290324

291-
bool user_empty() const { return UseList == nullptr; }
325+
bool user_empty() const {
326+
assertModuleIsMaterialized();
327+
return UseList == nullptr;
328+
}
292329

293330
typedef user_iterator_impl<User> user_iterator;
294331
typedef user_iterator_impl<const User> const_user_iterator;
295-
user_iterator user_begin() { return user_iterator(UseList); }
296-
const_user_iterator user_begin() const {
332+
user_iterator materialized_user_begin() { return user_iterator(UseList); }
333+
const_user_iterator materialized_user_begin() const {
297334
return const_user_iterator(UseList);
298335
}
336+
user_iterator user_begin() {
337+
assertModuleIsMaterialized();
338+
return materialized_user_begin();
339+
}
340+
const_user_iterator user_begin() const {
341+
assertModuleIsMaterialized();
342+
return materialized_user_begin();
343+
}
299344
user_iterator user_end() { return user_iterator(); }
300345
const_user_iterator user_end() const { return const_user_iterator(); }
301-
User *user_back() { return *user_begin(); }
302-
const User *user_back() const { return *user_begin(); }
346+
User *user_back() {
347+
assertModuleIsMaterialized();
348+
return *materialized_user_begin();
349+
}
350+
const User *user_back() const {
351+
assertModuleIsMaterialized();
352+
return *materialized_user_begin();
353+
}
303354
iterator_range<user_iterator> users() {
304-
return make_range(user_begin(), user_end());
355+
assertModuleIsMaterialized();
356+
return make_range(materialized_user_begin(), user_end());
305357
}
306358
iterator_range<const_user_iterator> users() const {
307-
return make_range(user_begin(), user_end());
359+
assertModuleIsMaterialized();
360+
return make_range(materialized_user_begin(), user_end());
308361
}
309362

310363
/// \brief Return true if there is exactly one user of this value.

llvm/lib/Bitcode/Reader/BitcodeReader.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3028,7 +3028,7 @@ std::error_code BitcodeReader::parseUseLists() {
30283028
V = ValueList[ID];
30293029
unsigned NumUses = 0;
30303030
SmallDenseMap<const Use *, unsigned, 16> Order;
3031-
for (const Use &U : V->uses()) {
3031+
for (const Use &U : V->materialized_uses()) {
30323032
if (++NumUses > Record.size())
30333033
break;
30343034
Order[&U] = Record[NumUses - 1];
@@ -5266,7 +5266,8 @@ std::error_code BitcodeReader::materialize(GlobalValue *GV) {
52665266

52675267
// Upgrade any old intrinsic calls in the function.
52685268
for (auto &I : UpgradedIntrinsics) {
5269-
for (auto UI = I.first->user_begin(), UE = I.first->user_end(); UI != UE;) {
5269+
for (auto UI = I.first->materialized_user_begin(), UE = I.first->user_end();
5270+
UI != UE;) {
52705271
User *U = *UI;
52715272
++UI;
52725273
if (CallInst *CI = dyn_cast<CallInst>(U))

llvm/lib/IR/Module.cpp

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -394,10 +394,8 @@ std::error_code Module::materialize(GlobalValue *GV) {
394394
std::error_code Module::materializeAll() {
395395
if (!Materializer)
396396
return std::error_code();
397-
if (std::error_code EC = Materializer->materializeModule())
398-
return EC;
399-
Materializer.reset();
400-
return std::error_code();
397+
std::unique_ptr<GVMaterializer> M = std::move(Materializer);
398+
return M->materializeModule();
401399
}
402400

403401
std::error_code Module::materializeMetadata() {

llvm/lib/IR/Value.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -314,6 +314,16 @@ void Value::takeName(Value *V) {
314314
}
315315

316316
#ifndef NDEBUG
317+
void Value::assertModuleIsMaterialized() const {
318+
const GlobalValue *GV = dyn_cast<GlobalValue>(this);
319+
if (!GV)
320+
return;
321+
const Module *M = GV->getParent();
322+
if (!M)
323+
return;
324+
assert(M->isMaterialized());
325+
}
326+
317327
static bool contains(SmallPtrSetImpl<ConstantExpr *> &Cache, ConstantExpr *Expr,
318328
Constant *C) {
319329
if (!Cache.insert(Expr).second)

llvm/lib/IR/Verifier.cpp

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1831,7 +1831,9 @@ void Verifier::visitFunction(const Function &F) {
18311831

18321832
// If this function is actually an intrinsic, verify that it is only used in
18331833
// direct call/invokes, never having its "address taken".
1834-
if (F.getIntrinsicID()) {
1834+
// Only do this if the module is materialized, otherwise we don't have all the
1835+
// uses.
1836+
if (F.getIntrinsicID() && F.getParent()->isMaterialized()) {
18351837
const User *U;
18361838
if (F.hasAddressTaken(&U))
18371839
Assert(0, "Invalid user of intrinsic instruction!", U);

llvm/tools/llvm-extract/llvm-extract.cpp

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -242,13 +242,22 @@ int main(int argc, char **argv) {
242242
}
243243
}
244244

245+
{
246+
std::vector<GlobalValue *> Gvs(GVs.begin(), GVs.end());
247+
legacy::PassManager Extract;
248+
Extract.add(createGVExtractionPass(Gvs, DeleteFn));
249+
Extract.run(*M);
250+
251+
// Now that we have all the GVs we want, mark the module as fully
252+
// materialized.
253+
// FIXME: should the GVExtractionPass handle this?
254+
M->materializeAll();
255+
}
256+
245257
// In addition to deleting all other functions, we also want to spiff it
246258
// up a little bit. Do this now.
247259
legacy::PassManager Passes;
248260

249-
std::vector<GlobalValue*> Gvs(GVs.begin(), GVs.end());
250-
251-
Passes.add(createGVExtractionPass(Gvs, DeleteFn));
252261
if (!DeleteFn)
253262
Passes.add(createGlobalDCEPass()); // Delete unreachable globals
254263
Passes.add(createStripDeadDebugInfoPass()); // Remove dead debug info

0 commit comments

Comments
 (0)