llvm-project
578 строк · 17.8 Кб
1//===- ValueHandleTest.cpp - ValueHandle tests ----------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
9#include "llvm/IR/ValueHandle.h"10#include "llvm/IR/Constants.h"11#include "llvm/IR/Instructions.h"12#include "llvm/IR/LLVMContext.h"13#include "gtest/gtest.h"14#include <memory>15
16using namespace llvm;17
18namespace {19
20class ValueHandle : public testing::Test {21protected:22LLVMContext Context;23Constant *ConstantV;24std::unique_ptr<BitCastInst> BitcastV;25
26ValueHandle()27: ConstantV(ConstantInt::get(Type::getInt32Ty(Context), 0)),28BitcastV(new BitCastInst(ConstantV, Type::getInt32Ty(Context))) {}29};30
31class ConcreteCallbackVH final : public CallbackVH {32public:33ConcreteCallbackVH(Value *V) : CallbackVH(V) {}34};35
36TEST_F(ValueHandle, WeakVH_BasicOperation) {37WeakVH WVH(BitcastV.get());38EXPECT_EQ(BitcastV.get(), WVH);39WVH = ConstantV;40EXPECT_EQ(ConstantV, WVH);41
42// Make sure I can call a method on the underlying Value. It43// doesn't matter which method.44EXPECT_EQ(Type::getInt32Ty(Context), WVH->getType());45EXPECT_EQ(Type::getInt32Ty(Context), (*WVH).getType());46
47WVH = BitcastV.get();48BitcastV->replaceAllUsesWith(ConstantV);49EXPECT_EQ(WVH, BitcastV.get());50BitcastV.reset();51EXPECT_EQ(WVH, nullptr);52}
53
54TEST_F(ValueHandle, WeakTrackingVH_BasicOperation) {55WeakTrackingVH WVH(BitcastV.get());56EXPECT_EQ(BitcastV.get(), WVH);57WVH = ConstantV;58EXPECT_EQ(ConstantV, WVH);59
60// Make sure I can call a method on the underlying Value. It61// doesn't matter which method.62EXPECT_EQ(Type::getInt32Ty(Context), WVH->getType());63EXPECT_EQ(Type::getInt32Ty(Context), (*WVH).getType());64}
65
66TEST_F(ValueHandle, WeakTrackingVH_Comparisons) {67WeakTrackingVH BitcastWVH(BitcastV.get());68WeakTrackingVH ConstantWVH(ConstantV);69
70EXPECT_TRUE(BitcastWVH == BitcastWVH);71EXPECT_TRUE(BitcastV.get() == BitcastWVH);72EXPECT_TRUE(BitcastWVH == BitcastV.get());73EXPECT_FALSE(BitcastWVH == ConstantWVH);74
75EXPECT_TRUE(BitcastWVH != ConstantWVH);76EXPECT_TRUE(BitcastV.get() != ConstantWVH);77EXPECT_TRUE(BitcastWVH != ConstantV);78EXPECT_FALSE(BitcastWVH != BitcastWVH);79
80// Cast to Value* so comparisons work.81Value *BV = BitcastV.get();82Value *CV = ConstantV;83EXPECT_EQ(BV < CV, BitcastWVH < ConstantWVH);84EXPECT_EQ(BV <= CV, BitcastWVH <= ConstantWVH);85EXPECT_EQ(BV > CV, BitcastWVH > ConstantWVH);86EXPECT_EQ(BV >= CV, BitcastWVH >= ConstantWVH);87
88EXPECT_EQ(BV < CV, BitcastV.get() < ConstantWVH);89EXPECT_EQ(BV <= CV, BitcastV.get() <= ConstantWVH);90EXPECT_EQ(BV > CV, BitcastV.get() > ConstantWVH);91EXPECT_EQ(BV >= CV, BitcastV.get() >= ConstantWVH);92
93EXPECT_EQ(BV < CV, BitcastWVH < ConstantV);94EXPECT_EQ(BV <= CV, BitcastWVH <= ConstantV);95EXPECT_EQ(BV > CV, BitcastWVH > ConstantV);96EXPECT_EQ(BV >= CV, BitcastWVH >= ConstantV);97}
98
99TEST_F(ValueHandle, WeakTrackingVH_FollowsRAUW) {100WeakTrackingVH WVH(BitcastV.get());101WeakTrackingVH WVH_Copy(WVH);102WeakTrackingVH WVH_Recreated(BitcastV.get());103BitcastV->replaceAllUsesWith(ConstantV);104EXPECT_EQ(ConstantV, WVH);105EXPECT_EQ(ConstantV, WVH_Copy);106EXPECT_EQ(ConstantV, WVH_Recreated);107}
108
109TEST_F(ValueHandle, WeakTrackingVH_NullOnDeletion) {110WeakTrackingVH WVH(BitcastV.get());111WeakTrackingVH WVH_Copy(WVH);112WeakTrackingVH WVH_Recreated(BitcastV.get());113BitcastV.reset();114Value *null_value = nullptr;115EXPECT_EQ(null_value, WVH);116EXPECT_EQ(null_value, WVH_Copy);117EXPECT_EQ(null_value, WVH_Recreated);118}
119
120
121TEST_F(ValueHandle, AssertingVH_BasicOperation) {122AssertingVH<CastInst> AVH(BitcastV.get());123CastInst *implicit_to_exact_type = AVH;124(void)implicit_to_exact_type; // Avoid warning.125
126AssertingVH<Value> GenericAVH(BitcastV.get());127EXPECT_EQ(BitcastV.get(), GenericAVH);128GenericAVH = ConstantV;129EXPECT_EQ(ConstantV, GenericAVH);130
131// Make sure I can call a method on the underlying CastInst. It132// doesn't matter which method.133EXPECT_FALSE(AVH->mayWriteToMemory());134EXPECT_FALSE((*AVH).mayWriteToMemory());135}
136
137TEST_F(ValueHandle, AssertingVH_Const) {138const CastInst *ConstBitcast = BitcastV.get();139AssertingVH<const CastInst> AVH(ConstBitcast);140const CastInst *implicit_to_exact_type = AVH;141(void)implicit_to_exact_type; // Avoid warning.142}
143
144TEST_F(ValueHandle, AssertingVH_Comparisons) {145AssertingVH<Value> BitcastAVH(BitcastV.get());146AssertingVH<Value> ConstantAVH(ConstantV);147
148EXPECT_TRUE(BitcastAVH == BitcastAVH);149EXPECT_TRUE(BitcastV.get() == BitcastAVH);150EXPECT_TRUE(BitcastAVH == BitcastV.get());151EXPECT_FALSE(BitcastAVH == ConstantAVH);152
153EXPECT_TRUE(BitcastAVH != ConstantAVH);154EXPECT_TRUE(BitcastV.get() != ConstantAVH);155EXPECT_TRUE(BitcastAVH != ConstantV);156EXPECT_FALSE(BitcastAVH != BitcastAVH);157
158// Cast to Value* so comparisons work.159Value *BV = BitcastV.get();160Value *CV = ConstantV;161EXPECT_EQ(BV < CV, BitcastAVH < ConstantAVH);162EXPECT_EQ(BV <= CV, BitcastAVH <= ConstantAVH);163EXPECT_EQ(BV > CV, BitcastAVH > ConstantAVH);164EXPECT_EQ(BV >= CV, BitcastAVH >= ConstantAVH);165
166EXPECT_EQ(BV < CV, BitcastV.get() < ConstantAVH);167EXPECT_EQ(BV <= CV, BitcastV.get() <= ConstantAVH);168EXPECT_EQ(BV > CV, BitcastV.get() > ConstantAVH);169EXPECT_EQ(BV >= CV, BitcastV.get() >= ConstantAVH);170
171EXPECT_EQ(BV < CV, BitcastAVH < ConstantV);172EXPECT_EQ(BV <= CV, BitcastAVH <= ConstantV);173EXPECT_EQ(BV > CV, BitcastAVH > ConstantV);174EXPECT_EQ(BV >= CV, BitcastAVH >= ConstantV);175}
176
177TEST_F(ValueHandle, AssertingVH_DoesNotFollowRAUW) {178AssertingVH<Value> AVH(BitcastV.get());179BitcastV->replaceAllUsesWith(ConstantV);180EXPECT_EQ(BitcastV.get(), AVH);181}
182
183#ifdef NDEBUG184
185TEST_F(ValueHandle, AssertingVH_ReducesToPointer) {186EXPECT_EQ(sizeof(CastInst *), sizeof(AssertingVH<CastInst>));187}
188
189#elif LLVM_ENABLE_ABI_BREAKING_CHECKS // && !NDEBUG190
191#ifdef GTEST_HAS_DEATH_TEST192
193TEST_F(ValueHandle, AssertingVH_Asserts) {194AssertingVH<Value> AVH(BitcastV.get());195EXPECT_DEATH({BitcastV.reset();},196"An asserting value handle still pointed to this value!");197AssertingVH<Value> Copy(AVH);198AVH = nullptr;199EXPECT_DEATH({BitcastV.reset();},200"An asserting value handle still pointed to this value!");201Copy = nullptr;202BitcastV.reset();203}
204
205#endif // GTEST_HAS_DEATH_TEST206
207#endif // NDEBUG208
209TEST_F(ValueHandle, CallbackVH_BasicOperation) {210ConcreteCallbackVH CVH(BitcastV.get());211EXPECT_EQ(BitcastV.get(), CVH);212CVH = ConstantV;213EXPECT_EQ(ConstantV, CVH);214
215// Make sure I can call a method on the underlying Value. It216// doesn't matter which method.217EXPECT_EQ(Type::getInt32Ty(Context), CVH->getType());218EXPECT_EQ(Type::getInt32Ty(Context), (*CVH).getType());219}
220
221TEST_F(ValueHandle, CallbackVH_Comparisons) {222ConcreteCallbackVH BitcastCVH(BitcastV.get());223ConcreteCallbackVH ConstantCVH(ConstantV);224
225EXPECT_TRUE(BitcastCVH == BitcastCVH);226EXPECT_TRUE(BitcastV.get() == BitcastCVH);227EXPECT_TRUE(BitcastCVH == BitcastV.get());228EXPECT_FALSE(BitcastCVH == ConstantCVH);229
230EXPECT_TRUE(BitcastCVH != ConstantCVH);231EXPECT_TRUE(BitcastV.get() != ConstantCVH);232EXPECT_TRUE(BitcastCVH != ConstantV);233EXPECT_FALSE(BitcastCVH != BitcastCVH);234
235// Cast to Value* so comparisons work.236Value *BV = BitcastV.get();237Value *CV = ConstantV;238EXPECT_EQ(BV < CV, BitcastCVH < ConstantCVH);239EXPECT_EQ(BV <= CV, BitcastCVH <= ConstantCVH);240EXPECT_EQ(BV > CV, BitcastCVH > ConstantCVH);241EXPECT_EQ(BV >= CV, BitcastCVH >= ConstantCVH);242
243EXPECT_EQ(BV < CV, BitcastV.get() < ConstantCVH);244EXPECT_EQ(BV <= CV, BitcastV.get() <= ConstantCVH);245EXPECT_EQ(BV > CV, BitcastV.get() > ConstantCVH);246EXPECT_EQ(BV >= CV, BitcastV.get() >= ConstantCVH);247
248EXPECT_EQ(BV < CV, BitcastCVH < ConstantV);249EXPECT_EQ(BV <= CV, BitcastCVH <= ConstantV);250EXPECT_EQ(BV > CV, BitcastCVH > ConstantV);251EXPECT_EQ(BV >= CV, BitcastCVH >= ConstantV);252}
253
254TEST_F(ValueHandle, CallbackVH_CallbackOnDeletion) {255class RecordingVH final : public CallbackVH {256public:257int DeletedCalls;258int AURWCalls;259
260RecordingVH() : DeletedCalls(0), AURWCalls(0) {}261RecordingVH(Value *V) : CallbackVH(V), DeletedCalls(0), AURWCalls(0) {}262
263private:264void deleted() override {265DeletedCalls++;266CallbackVH::deleted();267}268void allUsesReplacedWith(Value *) override { AURWCalls++; }269};270
271RecordingVH RVH;272RVH = BitcastV.get();273EXPECT_EQ(0, RVH.DeletedCalls);274EXPECT_EQ(0, RVH.AURWCalls);275BitcastV.reset();276EXPECT_EQ(1, RVH.DeletedCalls);277EXPECT_EQ(0, RVH.AURWCalls);278}
279
280TEST_F(ValueHandle, CallbackVH_CallbackOnRAUW) {281class RecordingVH final : public CallbackVH {282public:283int DeletedCalls;284Value *AURWArgument;285
286RecordingVH() : DeletedCalls(0), AURWArgument(nullptr) {}287RecordingVH(Value *V)288: CallbackVH(V), DeletedCalls(0), AURWArgument(nullptr) {}289
290private:291void deleted() override {292DeletedCalls++;293CallbackVH::deleted();294}295void allUsesReplacedWith(Value *new_value) override {296EXPECT_EQ(nullptr, AURWArgument);297AURWArgument = new_value;298}299};300
301RecordingVH RVH;302RVH = BitcastV.get();303EXPECT_EQ(0, RVH.DeletedCalls);304EXPECT_EQ(nullptr, RVH.AURWArgument);305BitcastV->replaceAllUsesWith(ConstantV);306EXPECT_EQ(0, RVH.DeletedCalls);307EXPECT_EQ(ConstantV, RVH.AURWArgument);308}
309
310TEST_F(ValueHandle, CallbackVH_DeletionCanRAUW) {311class RecoveringVH final : public CallbackVH {312public:313int DeletedCalls;314Value *AURWArgument;315LLVMContext *Context;316
317RecoveringVH(LLVMContext &TheContext)318: DeletedCalls(0), AURWArgument(nullptr), Context(&TheContext) {}319
320RecoveringVH(LLVMContext &TheContext, Value *V)321: CallbackVH(V), DeletedCalls(0), AURWArgument(nullptr),322Context(&TheContext) {}323
324private:325void deleted() override {326getValPtr()->replaceAllUsesWith(327Constant::getNullValue(Type::getInt32Ty(*Context)));328setValPtr(nullptr);329}330void allUsesReplacedWith(Value *new_value) override {331ASSERT_TRUE(nullptr != getValPtr());332EXPECT_EQ(1U, getValPtr()->getNumUses());333EXPECT_EQ(nullptr, AURWArgument);334AURWArgument = new_value;335}336};337
338// Normally, if a value has uses, deleting it will crash. However, we can use339// a CallbackVH to remove the uses before the check for no uses.340RecoveringVH RVH(Context);341RVH = RecoveringVH(Context, BitcastV.get());342std::unique_ptr<BinaryOperator> BitcastUser(BinaryOperator::CreateAdd(343RVH, Constant::getNullValue(Type::getInt32Ty(Context))));344EXPECT_EQ(BitcastV.get(), BitcastUser->getOperand(0));345BitcastV.reset(); // Would crash without the ValueHandler.346EXPECT_EQ(Constant::getNullValue(Type::getInt32Ty(Context)),347RVH.AURWArgument);348EXPECT_EQ(Constant::getNullValue(Type::getInt32Ty(Context)),349BitcastUser->getOperand(0));350}
351
352TEST_F(ValueHandle, DestroyingOtherVHOnSameValueDoesntBreakIteration) {353// When a CallbackVH modifies other ValueHandles in its callbacks,354// that shouldn't interfere with non-modified ValueHandles receiving355// their appropriate callbacks.356//357// We create the active CallbackVH in the middle of a palindromic358// arrangement of other VHs so that the bad behavior would be359// triggered in whichever order callbacks run.360
361class DestroyingVH final : public CallbackVH {362public:363std::unique_ptr<WeakTrackingVH> ToClear[2];364DestroyingVH(Value *V) {365ToClear[0].reset(new WeakTrackingVH(V));366setValPtr(V);367ToClear[1].reset(new WeakTrackingVH(V));368}369void deleted() override {370ToClear[0].reset();371ToClear[1].reset();372CallbackVH::deleted();373}374void allUsesReplacedWith(Value *) override {375ToClear[0].reset();376ToClear[1].reset();377}378};379
380{381WeakTrackingVH ShouldBeVisited1(BitcastV.get());382DestroyingVH C(BitcastV.get());383WeakTrackingVH ShouldBeVisited2(BitcastV.get());384
385BitcastV->replaceAllUsesWith(ConstantV);386EXPECT_EQ(ConstantV, static_cast<Value*>(ShouldBeVisited1));387EXPECT_EQ(ConstantV, static_cast<Value*>(ShouldBeVisited2));388}389
390{391WeakTrackingVH ShouldBeVisited1(BitcastV.get());392DestroyingVH C(BitcastV.get());393WeakTrackingVH ShouldBeVisited2(BitcastV.get());394
395BitcastV.reset();396EXPECT_EQ(nullptr, static_cast<Value*>(ShouldBeVisited1));397EXPECT_EQ(nullptr, static_cast<Value*>(ShouldBeVisited2));398}399}
400
401TEST_F(ValueHandle, AssertingVHCheckedLast) {402// If a CallbackVH exists to clear out a group of AssertingVHs on403// Value deletion, the CallbackVH should get a chance to do so404// before the AssertingVHs assert.405
406class ClearingVH final : public CallbackVH {407public:408AssertingVH<Value> *ToClear[2];409ClearingVH(Value *V,410AssertingVH<Value> &A0, AssertingVH<Value> &A1)411: CallbackVH(V) {412ToClear[0] = &A0;413ToClear[1] = &A1;414}415
416void deleted() override {417*ToClear[0] = nullptr;418*ToClear[1] = nullptr;419CallbackVH::deleted();420}421};422
423AssertingVH<Value> A1, A2;424A1 = BitcastV.get();425ClearingVH C(BitcastV.get(), A1, A2);426A2 = BitcastV.get();427// C.deleted() should run first, clearing the two AssertingVHs,428// which should prevent them from asserting.429BitcastV.reset();430}
431
432TEST_F(ValueHandle, PoisoningVH_BasicOperation) {433PoisoningVH<CastInst> VH(BitcastV.get());434CastInst *implicit_to_exact_type = VH;435(void)implicit_to_exact_type; // Avoid warning.436
437PoisoningVH<Value> GenericVH(BitcastV.get());438EXPECT_EQ(BitcastV.get(), GenericVH);439GenericVH = ConstantV;440EXPECT_EQ(ConstantV, GenericVH);441
442// Make sure I can call a method on the underlying CastInst. It443// doesn't matter which method.444EXPECT_FALSE(VH->mayWriteToMemory());445EXPECT_FALSE((*VH).mayWriteToMemory());446}
447
448TEST_F(ValueHandle, PoisoningVH_Const) {449const CastInst *ConstBitcast = BitcastV.get();450PoisoningVH<const CastInst> VH(ConstBitcast);451const CastInst *implicit_to_exact_type = VH;452(void)implicit_to_exact_type; // Avoid warning.453}
454
455TEST_F(ValueHandle, PoisoningVH_Comparisons) {456PoisoningVH<Value> BitcastVH(BitcastV.get());457PoisoningVH<Value> ConstantVH(ConstantV);458
459EXPECT_TRUE(BitcastVH == BitcastVH);460EXPECT_TRUE(BitcastV.get() == BitcastVH);461EXPECT_TRUE(BitcastVH == BitcastV.get());462EXPECT_FALSE(BitcastVH == ConstantVH);463
464EXPECT_TRUE(BitcastVH != ConstantVH);465EXPECT_TRUE(BitcastV.get() != ConstantVH);466EXPECT_TRUE(BitcastVH != ConstantV);467EXPECT_FALSE(BitcastVH != BitcastVH);468
469// Cast to Value* so comparisons work.470Value *BV = BitcastV.get();471Value *CV = ConstantV;472EXPECT_EQ(BV < CV, BitcastVH < ConstantVH);473EXPECT_EQ(BV <= CV, BitcastVH <= ConstantVH);474EXPECT_EQ(BV > CV, BitcastVH > ConstantVH);475EXPECT_EQ(BV >= CV, BitcastVH >= ConstantVH);476
477EXPECT_EQ(BV < CV, BitcastV.get() < ConstantVH);478EXPECT_EQ(BV <= CV, BitcastV.get() <= ConstantVH);479EXPECT_EQ(BV > CV, BitcastV.get() > ConstantVH);480EXPECT_EQ(BV >= CV, BitcastV.get() >= ConstantVH);481
482EXPECT_EQ(BV < CV, BitcastVH < ConstantV);483EXPECT_EQ(BV <= CV, BitcastVH <= ConstantV);484EXPECT_EQ(BV > CV, BitcastVH > ConstantV);485EXPECT_EQ(BV >= CV, BitcastVH >= ConstantV);486}
487
488TEST_F(ValueHandle, PoisoningVH_DoesNotFollowRAUW) {489PoisoningVH<Value> VH(BitcastV.get());490BitcastV->replaceAllUsesWith(ConstantV);491EXPECT_TRUE(DenseMapInfo<PoisoningVH<Value>>::isEqual(VH, BitcastV.get()));492}
493
494TEST_F(ValueHandle, AssertingVH_DenseMap) {495DenseMap<AssertingVH<Value>, int> Map;496Map.insert({BitcastV.get(), 1});497Map.insert({ConstantV, 2});498// These will create a temporary AssertingVH during lookup.499EXPECT_TRUE(Map.contains(BitcastV.get()));500EXPECT_TRUE(Map.contains(ConstantV));501// These will not create a temporary AssertingVH.502EXPECT_TRUE(Map.find_as(BitcastV.get()) != Map.end());503EXPECT_TRUE(Map.find_as(ConstantV) != Map.end());504}
505
506TEST_F(ValueHandle, PoisoningVH_DenseMap) {507DenseMap<PoisoningVH<Value>, int> Map;508Map.insert({BitcastV.get(), 1});509Map.insert({ConstantV, 2});510// These will create a temporary PoisoningVH during lookup.511EXPECT_TRUE(Map.contains(BitcastV.get()));512EXPECT_TRUE(Map.contains(ConstantV));513// These will not create a temporary PoisoningVH.514EXPECT_TRUE(Map.find_as(BitcastV.get()) != Map.end());515EXPECT_TRUE(Map.find_as(ConstantV) != Map.end());516}
517
518#ifdef NDEBUG519
520TEST_F(ValueHandle, PoisoningVH_ReducesToPointer) {521EXPECT_EQ(sizeof(CastInst *), sizeof(PoisoningVH<CastInst>));522}
523
524#else // !NDEBUG525
526TEST_F(ValueHandle, TrackingVH_Tracks) {527TrackingVH<Value> VH(BitcastV.get());528BitcastV->replaceAllUsesWith(ConstantV);529EXPECT_EQ(VH, ConstantV);530}
531
532#ifdef GTEST_HAS_DEATH_TEST533#if LLVM_ENABLE_ABI_BREAKING_CHECKS534
535TEST_F(ValueHandle, PoisoningVH_Asserts) {536PoisoningVH<Value> VH(BitcastV.get());537
538// The poisoned handle shouldn't assert when the value is deleted.539BitcastV.reset(new BitCastInst(ConstantV, Type::getInt32Ty(Context)));540// But should when we access the handle.541EXPECT_DEATH((void)*VH, "Accessed a poisoned value handle!");542
543// Now check that poison catches RAUW.544VH = BitcastV.get();545// The replace doesn't trigger anything immediately.546BitcastV->replaceAllUsesWith(ConstantV);547// But a use does.548EXPECT_DEATH((void)*VH, "Accessed a poisoned value handle!");549
550// Don't clear anything out here as destroying the handles should be fine.551}
552
553#endif // LLVM_ENABLE_ABI_BREAKING_CHECKS554
555TEST_F(ValueHandle, TrackingVH_Asserts) {556{557TrackingVH<Value> VH(BitcastV.get());558
559// The tracking handle shouldn't assert when the value is deleted.560BitcastV.reset(new BitCastInst(ConstantV, Type::getInt32Ty(Context)));561// But should when we access the handle.562EXPECT_DEATH((void)*VH,563"TrackingVH must be non-null and valid on dereference!");564}565
566{567TrackingVH<Instruction> VH(BitcastV.get());568
569BitcastV->replaceAllUsesWith(ConstantV);570EXPECT_DEATH((void)*VH,571"Tracked Value was replaced by one with an invalid type!");572}573}
574
575#endif // GTEST_HAS_DEATH_TEST576
577#endif // NDEBUG578}
579