llvm.org GIT mirror llvm / 8820ca4
Merging r277625: ------------------------------------------------------------------------ r277625 | dexonsmith | 2016-08-03 11:19:43 -0700 (Wed, 03 Aug 2016) | 42 lines IR: Drop uniquing when an MDNode Value operand is deleted This is a fix for PR28697. An MDNode can indirectly refer to a GlobalValue, through a ConstantAsMetadata. When the GlobalValue is deleted, the MDNode operand is reset to `nullptr`. If the node is uniqued, this can lead to a hard-to-detect cache invalidation in a Metadata map that's shared across an LLVMContext. Consider: 1. A map from Metadata* to `T` called RemappedMDs. 2. A node that references a global variable, `!{i1* @GV}`. 3. Insert `!{i1* @GV} -> SomeT` in the map. 4. Delete `@GV`, leaving behind `!{null} -> SomeT`. Looking up the generic and uninteresting `!{null}` gives you `SomeT`, which is likely related to `@GV`. Worse, `SomeT`'s lifetime may be tied to the deleted `@GV`. This occurs in practice in the shared ValueMap used since r266579 in the IRMover. Other code that handles more than one Module (with different lifetimes) in the same LLVMContext could hit it too. The fix here is a partial revert of r225223: in the rare case that an MDNode operand is a ConstantAsMetadata (i.e., wrapping a node from the Value hierarchy), drop uniquing if it gets replaced with `nullptr`. This changes step #4 above to leave behind `distinct !{null} -> SomeT`, which can't be confused with the generic `!{null}`. In theory, this can cause some churn in the LLVMContext's MDNode uniquing map when Values are being deleted. However: - The number of GlobalValues referenced from uniqued MDNodes is expected to be quite small. E.g., the debug info metadata schema only references GlobalValues from distinct nodes. - Other Constants have the lifetime of the LLVMContext, whose teardown is careful to drop references before deleting the constants. As a result, I don't expect a compile time regression from this change. ------------------------------------------------------------------------ git-svn-id: https://llvm.org/svn/llvm-project/llvm/branches/release_39@277639 91177308-0d34-0410-b5e6-96231b3b80d8 Hans Wennborg 4 years ago
5 changed file(s) with 81 addition(s) and 5 deletion(s). Raw diff Collapse all Expand all
674674 Metadata *Old = getOperand(Op);
675675 setOperand(Op, New);
676676
677 // Drop uniquing for self-reference cycles.
678 if (New == this) {
677 // Drop uniquing for self-reference cycles and deleted constants.
678 if (New == this || (!New && Old && isa(Old))) {
679679 if (!isResolved())
680680 resolve();
681681 storeDistinctInContext();
0 ; RUN: llvm-link -S -o - %s %S/Inputs/metadata-with-global-value-operand.ll | FileCheck %s
1 ; This test confirms that the !{null} from the second module doesn't get mapped
2 ; onto the abandoned !{i1* @var} node from this module.
3
4 ; CHECK: @var = global
5 @var = global i1 false
6
7 ; CHECK: !named.vars = !{!0}
8 ; CHECK: !named.null = !{!1}
9 !named.vars = !{!0}
10
11 ; CHECK: !0 = !{i1* @var}
12 ; CHECK: !1 = !{null}
13 !0 = !{i1* @var}
2727 ; CHECK: !named = !{![[NULL:[0-9]+]]}
2828
2929 !0 = !{i8*** @G}
30 ; CHECK-DAG: ![[NULL]] = !{null}
30 ; CHECK-DAG: ![[NULL]] = distinct !{null}
3131 ; CHECK-DAG: ![[EMPTY]] = !{}
448448 EXPECT_FALSE(Wrapped1->isDistinct());
449449 }
450450
451 TEST_F(MDNodeTest, UniquedOnDeletedOperand) {
452 // temp !{}
453 TempMDTuple T = MDTuple::getTemporary(Context, None);
454
455 // !{temp !{}}
456 Metadata *Ops[] = {T.get()};
457 MDTuple *N = MDTuple::get(Context, Ops);
458
459 // !{temp !{}} => !{null}
460 T.reset();
461 ASSERT_TRUE(N->isUniqued());
462 Metadata *NullOps[] = {nullptr};
463 ASSERT_EQ(N, MDTuple::get(Context, NullOps));
464 }
465
466 TEST_F(MDNodeTest, DistinctOnDeletedValueOperand) {
467 // i1* @GV
468 Type *Ty = Type::getInt1PtrTy(Context);
469 std::unique_ptr GV(
470 new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage));
471 ConstantAsMetadata *Op = ConstantAsMetadata::get(GV.get());
472
473 // !{i1* @GV}
474 Metadata *Ops[] = {Op};
475 MDTuple *N = MDTuple::get(Context, Ops);
476
477 // !{i1* @GV} => !{null}
478 GV.reset();
479 ASSERT_TRUE(N->isDistinct());
480 ASSERT_EQ(nullptr, N->getOperand(0));
481 Metadata *NullOps[] = {nullptr};
482 ASSERT_NE(N, MDTuple::get(Context, NullOps));
483 }
484
451485 TEST_F(MDNodeTest, getDistinct) {
452486 // !{}
453487 MDNode *Empty = MDNode::get(Context, None);
668702 EXPECT_TRUE(N->isResolved());
669703 }
670704
671 TEST_F(MDNodeTest, replaceWithUniquedChangingOperand) {
705 TEST_F(MDNodeTest, replaceWithUniquedDeletedOperand) {
672706 // i1* @GV
673707 Type *Ty = Type::getInt1PtrTy(Context);
674708 std::unique_ptr GV(
685719
686720 // !{i1* @GV} => !{null}
687721 GV.reset();
722 ASSERT_TRUE(N->isDistinct());
723 ASSERT_EQ(nullptr, N->getOperand(0));
724 Metadata *NullOps[] = {nullptr};
725 ASSERT_NE(N, MDTuple::get(Context, NullOps));
726 }
727
728 TEST_F(MDNodeTest, replaceWithUniquedChangedOperand) {
729 // i1* @GV
730 Type *Ty = Type::getInt1PtrTy(Context);
731 std::unique_ptr GV(
732 new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage));
733 ConstantAsMetadata *Op = ConstantAsMetadata::get(GV.get());
734
735 // temp !{i1* @GV}
736 Metadata *Ops[] = {Op};
737 MDTuple *N = MDTuple::getTemporary(Context, Ops).release();
738
739 // temp !{i1* @GV} => !{i1* @GV}
740 ASSERT_EQ(N, MDNode::replaceWithUniqued(TempMDTuple(N)));
688741 ASSERT_TRUE(N->isUniqued());
689 Metadata *NullOps[] = {nullptr};
742
743 // !{i1* @GV} => !{i1* @GV2}
744 std::unique_ptr GV2(
745 new GlobalVariable(Ty, false, GlobalValue::ExternalLinkage));
746 GV->replaceAllUsesWith(GV2.get());
747 ASSERT_TRUE(N->isUniqued());
748 Metadata *NullOps[] = {ConstantAsMetadata::get(GV2.get())};
690749 ASSERT_EQ(N, MDTuple::get(Context, NullOps));
691750 }
692751