476 lines · cpp
1//===- ValueMapper.cpp - Unit tests for ValueMapper -----------------------===//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-exception6//7//===----------------------------------------------------------------------===//8 9#include "llvm/Transforms/Utils/ValueMapper.h"10#include "llvm/IR/Constants.h"11#include "llvm/IR/DebugInfoMetadata.h"12#include "llvm/IR/Function.h"13#include "llvm/IR/GlobalVariable.h"14#include "llvm/IR/LLVMContext.h"15#include "llvm/IR/Metadata.h"16#include "gtest/gtest.h"17 18using namespace llvm;19 20namespace {21 22TEST(ValueMapperTest, mapMDNode) {23 LLVMContext Context;24 auto *U = MDTuple::get(Context, {});25 26 // The node should be unchanged.27 ValueToValueMapTy VM;28 EXPECT_EQ(U, ValueMapper(VM).mapMDNode(*U));29}30 31TEST(ValueMapperTest, mapMDNodeCycle) {32 LLVMContext Context;33 MDNode *U0;34 MDNode *U1;35 {36 Metadata *Ops[] = {nullptr};37 auto T = MDTuple::getTemporary(Context, Ops);38 Ops[0] = T.get();39 U0 = MDTuple::get(Context, Ops);40 T->replaceOperandWith(0, U0);41 U1 = MDNode::replaceWithUniqued(std::move(T));42 U0->resolveCycles();43 }44 45 EXPECT_TRUE(U0->isResolved());46 EXPECT_TRUE(U0->isUniqued());47 EXPECT_TRUE(U1->isResolved());48 EXPECT_TRUE(U1->isUniqued());49 EXPECT_EQ(U1, U0->getOperand(0));50 EXPECT_EQ(U0, U1->getOperand(0));51 52 // Cycles shouldn't be duplicated.53 {54 ValueToValueMapTy VM;55 EXPECT_EQ(U0, ValueMapper(VM).mapMDNode(*U0));56 EXPECT_EQ(U1, ValueMapper(VM).mapMDNode(*U1));57 }58 59 // Check the other order.60 {61 ValueToValueMapTy VM;62 EXPECT_EQ(U1, ValueMapper(VM).mapMDNode(*U1));63 EXPECT_EQ(U0, ValueMapper(VM).mapMDNode(*U0));64 }65}66 67TEST(ValueMapperTest, mapMDNodeDuplicatedCycle) {68 LLVMContext Context;69 auto *PtrTy = PointerType::get(Context, 0);70 std::unique_ptr<GlobalVariable> G0 = std::make_unique<GlobalVariable>(71 PtrTy, false, GlobalValue::ExternalLinkage, nullptr, "G0");72 std::unique_ptr<GlobalVariable> G1 = std::make_unique<GlobalVariable>(73 PtrTy, false, GlobalValue::ExternalLinkage, nullptr, "G1");74 75 // Create a cycle that references G0.76 MDNode *N0; // !0 = !{!1}77 MDNode *N1; // !1 = !{!0, ptr @G0}78 {79 auto T0 = MDTuple::getTemporary(Context, nullptr);80 Metadata *Ops1[] = {T0.get(), ConstantAsMetadata::get(G0.get())};81 N1 = MDTuple::get(Context, Ops1);82 T0->replaceOperandWith(0, N1);83 N0 = MDNode::replaceWithUniqued(std::move(T0));84 }85 86 // Resolve N0 and N1.87 ASSERT_FALSE(N0->isResolved());88 ASSERT_FALSE(N1->isResolved());89 N0->resolveCycles();90 ASSERT_TRUE(N0->isResolved());91 ASSERT_TRUE(N1->isResolved());92 93 // Seed the value map to map G0 to G1 and map the nodes. The output should94 // have new nodes that reference G1 (instead of G0).95 ValueToValueMapTy VM;96 VM[G0.get()] = G1.get();97 MDNode *MappedN0 = ValueMapper(VM).mapMDNode(*N0);98 MDNode *MappedN1 = ValueMapper(VM).mapMDNode(*N1);99 EXPECT_NE(N0, MappedN0);100 EXPECT_NE(N1, MappedN1);101 EXPECT_EQ(ConstantAsMetadata::get(G1.get()), MappedN1->getOperand(1));102 103 // Check that the output nodes are resolved.104 EXPECT_TRUE(MappedN0->isResolved());105 EXPECT_TRUE(MappedN1->isResolved());106}107 108TEST(ValueMapperTest, mapMDNodeUnresolved) {109 LLVMContext Context;110 TempMDTuple T = MDTuple::getTemporary(Context, {});111 112 ValueToValueMapTy VM;113 EXPECT_EQ(T.get(), ValueMapper(VM, RF_NoModuleLevelChanges).mapMDNode(*T));114}115 116TEST(ValueMapperTest, mapMDNodeDistinct) {117 LLVMContext Context;118 auto *D = MDTuple::getDistinct(Context, {});119 120 {121 // The node should be cloned.122 ValueToValueMapTy VM;123 EXPECT_NE(D, ValueMapper(VM).mapMDNode(*D));124 }125 {126 // The node should be moved.127 ValueToValueMapTy VM;128 EXPECT_EQ(D, ValueMapper(VM, RF_ReuseAndMutateDistinctMDs).mapMDNode(*D));129 }130}131 132TEST(ValueMapperTest, mapMDNodeDistinctOperands) {133 LLVMContext Context;134 Metadata *Old = MDTuple::getDistinct(Context, {});135 auto *D = MDTuple::getDistinct(Context, Old);136 ASSERT_EQ(Old, D->getOperand(0));137 138 Metadata *New = MDTuple::getDistinct(Context, {});139 ValueToValueMapTy VM;140 VM.MD()[Old].reset(New);141 142 // Make sure operands are updated.143 EXPECT_EQ(D, ValueMapper(VM, RF_ReuseAndMutateDistinctMDs).mapMDNode(*D));144 EXPECT_EQ(New, D->getOperand(0));145}146 147TEST(ValueMapperTest, mapMDNodeSeeded) {148 LLVMContext Context;149 auto *D = MDTuple::getDistinct(Context, {});150 151 // The node should be moved.152 ValueToValueMapTy VM;153 EXPECT_EQ(std::nullopt, VM.getMappedMD(D));154 155 VM.MD().insert(std::make_pair(D, TrackingMDRef(D)));156 EXPECT_EQ(D, *VM.getMappedMD(D));157 EXPECT_EQ(D, ValueMapper(VM).mapMDNode(*D));158}159 160TEST(ValueMapperTest, mapMDNodeSeededWithNull) {161 LLVMContext Context;162 auto *D = MDTuple::getDistinct(Context, {});163 164 // The node should be moved.165 ValueToValueMapTy VM;166 EXPECT_EQ(std::nullopt, VM.getMappedMD(D));167 168 VM.MD().insert(std::make_pair(D, TrackingMDRef()));169 EXPECT_EQ(nullptr, *VM.getMappedMD(D));170 EXPECT_EQ(nullptr, ValueMapper(VM).mapMDNode(*D));171}172 173TEST(ValueMapperTest, mapMetadataNullMapGlobalWithIgnoreMissingLocals) {174 LLVMContext C;175 FunctionType *FTy =176 FunctionType::get(Type::getVoidTy(C), Type::getInt8Ty(C), false);177 std::unique_ptr<Function> F(178 Function::Create(FTy, GlobalValue::ExternalLinkage, "F"));179 180 ValueToValueMapTy VM;181 RemapFlags Flags = RF_IgnoreMissingLocals | RF_NullMapMissingGlobalValues;182 EXPECT_EQ(nullptr, ValueMapper(VM, Flags).mapValue(*F));183}184 185TEST(ValueMapperTest, mapMetadataMDString) {186 LLVMContext C;187 auto *S1 = MDString::get(C, "S1");188 ValueToValueMapTy VM;189 190 // Make sure S1 maps to itself, but isn't memoized.191 EXPECT_EQ(S1, ValueMapper(VM).mapMetadata(*S1));192 EXPECT_EQ(std::nullopt, VM.getMappedMD(S1));193 194 // We still expect VM.MD() to be respected.195 auto *S2 = MDString::get(C, "S2");196 VM.MD()[S1].reset(S2);197 EXPECT_EQ(S2, ValueMapper(VM).mapMetadata(*S1));198}199 200TEST(ValueMapperTest, mapMetadataGetMappedMD) {201 LLVMContext C;202 auto *N0 = MDTuple::get(C, {});203 auto *N1 = MDTuple::get(C, N0);204 205 // Make sure hasMD and getMappedMD work correctly.206 ValueToValueMapTy VM;207 EXPECT_FALSE(VM.hasMD());208 EXPECT_EQ(N0, ValueMapper(VM).mapMetadata(*N0));209 EXPECT_EQ(N1, ValueMapper(VM).mapMetadata(*N1));210 EXPECT_TRUE(VM.hasMD());211 ASSERT_NE(std::nullopt, VM.getMappedMD(N0));212 ASSERT_NE(std::nullopt, VM.getMappedMD(N1));213 EXPECT_EQ(N0, *VM.getMappedMD(N0));214 EXPECT_EQ(N1, *VM.getMappedMD(N1));215}216 217TEST(ValueMapperTest, mapMetadataNoModuleLevelChanges) {218 LLVMContext C;219 auto *N0 = MDTuple::get(C, {});220 auto *N1 = MDTuple::get(C, N0);221 222 // Nothing should be memoized when RF_NoModuleLevelChanges.223 ValueToValueMapTy VM;224 EXPECT_FALSE(VM.hasMD());225 EXPECT_EQ(N0, ValueMapper(VM, RF_NoModuleLevelChanges).mapMetadata(*N0));226 EXPECT_EQ(N1, ValueMapper(VM, RF_NoModuleLevelChanges).mapMetadata(*N1));227 EXPECT_FALSE(VM.hasMD());228 EXPECT_EQ(std::nullopt, VM.getMappedMD(N0));229 EXPECT_EQ(std::nullopt, VM.getMappedMD(N1));230}231 232TEST(ValueMapperTest, mapMetadataConstantAsMetadata) {233 LLVMContext C;234 FunctionType *FTy =235 FunctionType::get(Type::getVoidTy(C), Type::getInt8Ty(C), false);236 std::unique_ptr<Function> F(237 Function::Create(FTy, GlobalValue::ExternalLinkage, "F"));238 239 auto *CAM = ConstantAsMetadata::get(F.get());240 {241 // ConstantAsMetadata shouldn't be memoized.242 ValueToValueMapTy VM;243 EXPECT_EQ(CAM, ValueMapper(VM).mapMetadata(*CAM));244 EXPECT_FALSE(VM.MD().count(CAM));245 EXPECT_EQ(CAM, ValueMapper(VM, RF_IgnoreMissingLocals).mapMetadata(*CAM));246 EXPECT_FALSE(VM.MD().count(CAM));247 248 // But it should respect a mapping that gets seeded.249 auto *N = MDTuple::get(C, {});250 VM.MD()[CAM].reset(N);251 EXPECT_EQ(N, ValueMapper(VM).mapMetadata(*CAM));252 EXPECT_EQ(N, ValueMapper(VM, RF_IgnoreMissingLocals).mapMetadata(*CAM));253 }254 255 std::unique_ptr<Function> F2(256 Function::Create(FTy, GlobalValue::ExternalLinkage, "F2"));257 ValueToValueMapTy VM;258 VM[F.get()] = F2.get();259 auto *F2MD = ValueMapper(VM).mapMetadata(*CAM);260 EXPECT_FALSE(VM.MD().count(CAM));261 EXPECT_TRUE(F2MD);262 EXPECT_EQ(F2.get(), cast<ConstantAsMetadata>(F2MD)->getValue());263}264 265#ifdef GTEST_HAS_DEATH_TEST266#ifndef NDEBUG267TEST(ValueMapperTest, mapMetadataLocalAsMetadata) {268 LLVMContext C;269 FunctionType *FTy =270 FunctionType::get(Type::getVoidTy(C), Type::getInt8Ty(C), false);271 std::unique_ptr<Function> F(272 Function::Create(FTy, GlobalValue::ExternalLinkage, "F"));273 Argument &A = *F->arg_begin();274 275 // mapMetadata doesn't support LocalAsMetadata. The only valid container for276 // LocalAsMetadata is a MetadataAsValue instance, so use it directly.277 auto *LAM = LocalAsMetadata::get(&A);278 ValueToValueMapTy VM;279 EXPECT_DEATH(ValueMapper(VM).mapMetadata(*LAM), "Unexpected local metadata");280 EXPECT_DEATH(ValueMapper(VM, RF_IgnoreMissingLocals).mapMetadata(*LAM),281 "Unexpected local metadata");282}283#endif284#endif285 286TEST(ValueMapperTest, mapValueLocalAsMetadata) {287 LLVMContext C;288 FunctionType *FTy =289 FunctionType::get(Type::getVoidTy(C), Type::getInt8Ty(C), false);290 std::unique_ptr<Function> F(291 Function::Create(FTy, GlobalValue::ExternalLinkage, "F"));292 Argument &A = *F->arg_begin();293 294 auto *LAM = LocalAsMetadata::get(&A);295 auto *MAV = MetadataAsValue::get(C, LAM);296 297 // The principled answer to a LocalAsMetadata of an unmapped SSA value would298 // be to return nullptr (regardless of RF_IgnoreMissingLocals).299 //300 // However, algorithms that use RemapInstruction assume that each instruction301 // only references SSA values from previous instructions. Arguments of302 // such as "metadata i32 %x" don't currently successfully maintain that303 // property. To keep RemapInstruction from crashing we need a non-null304 // return here, but we also shouldn't reference the unmapped local. Use305 // "metadata !{}".306 auto *N0 = MDTuple::get(C, {});307 auto *N0AV = MetadataAsValue::get(C, N0);308 ValueToValueMapTy VM;309 EXPECT_EQ(N0AV, ValueMapper(VM).mapValue(*MAV));310 EXPECT_EQ(nullptr, ValueMapper(VM, RF_IgnoreMissingLocals).mapValue(*MAV));311 EXPECT_FALSE(VM.count(MAV));312 EXPECT_FALSE(VM.count(&A));313 EXPECT_EQ(std::nullopt, VM.getMappedMD(LAM));314 315 VM[MAV] = MAV;316 EXPECT_EQ(MAV, ValueMapper(VM).mapValue(*MAV));317 EXPECT_EQ(MAV, ValueMapper(VM, RF_IgnoreMissingLocals).mapValue(*MAV));318 EXPECT_TRUE(VM.count(MAV));319 EXPECT_FALSE(VM.count(&A));320 321 VM[MAV] = &A;322 EXPECT_EQ(&A, ValueMapper(VM).mapValue(*MAV));323 EXPECT_EQ(&A, ValueMapper(VM, RF_IgnoreMissingLocals).mapValue(*MAV));324 EXPECT_TRUE(VM.count(MAV));325 EXPECT_FALSE(VM.count(&A));326}327 328TEST(ValueMapperTest, mapValueLocalInArgList) {329 LLVMContext C;330 FunctionType *FTy =331 FunctionType::get(Type::getVoidTy(C), Type::getInt8Ty(C), false);332 std::unique_ptr<Function> F(333 Function::Create(FTy, GlobalValue::ExternalLinkage, "F"));334 Argument &A = *F->arg_begin();335 336 auto *LAM = LocalAsMetadata::get(&A);337 std::vector<ValueAsMetadata*> Elts;338 Elts.push_back(LAM);339 auto *ArgList = DIArgList::get(C, Elts);340 auto *MAV = MetadataAsValue::get(C, ArgList);341 342 // The principled answer to a LocalAsMetadata of an unmapped SSA value would343 // be to return nullptr (regardless of RF_IgnoreMissingLocals).344 //345 // However, algorithms that use RemapInstruction assume that each instruction346 // only references SSA values from previous instructions. Arguments of347 // such as "metadata i32 %x" don't currently successfully maintain that348 // property. To keep RemapInstruction from crashing we need a non-null349 // return here, but we also shouldn't reference the unmapped local. Use350 // poison for uses in a DIArgList.351 auto *N0 = PoisonValue::get(Type::getInt8Ty(C));352 auto *N0AM = ValueAsMetadata::get(N0);353 std::vector<ValueAsMetadata*> N0Elts;354 N0Elts.push_back(N0AM);355 auto *N0ArgList = DIArgList::get(C, N0Elts);356 auto *N0AV = MetadataAsValue::get(C, N0ArgList);357 ValueToValueMapTy VM;358 EXPECT_EQ(N0AV, ValueMapper(VM).mapValue(*MAV));359 EXPECT_EQ(MAV, ValueMapper(VM, RF_IgnoreMissingLocals).mapValue(*MAV));360 EXPECT_FALSE(VM.count(MAV));361 EXPECT_FALSE(VM.count(&A));362 EXPECT_EQ(std::nullopt, VM.getMappedMD(LAM));363 EXPECT_EQ(std::nullopt, VM.getMappedMD(ArgList));364 365 VM[MAV] = MAV;366 EXPECT_EQ(MAV, ValueMapper(VM).mapValue(*MAV));367 EXPECT_EQ(MAV, ValueMapper(VM, RF_IgnoreMissingLocals).mapValue(*MAV));368 EXPECT_TRUE(VM.count(MAV));369 EXPECT_FALSE(VM.count(&A));370 371 VM[MAV] = &A;372 EXPECT_EQ(&A, ValueMapper(VM).mapValue(*MAV));373 EXPECT_EQ(&A, ValueMapper(VM, RF_IgnoreMissingLocals).mapValue(*MAV));374 EXPECT_TRUE(VM.count(MAV));375 EXPECT_FALSE(VM.count(&A));376}377 378TEST(ValueMapperTest, mapValueLocalAsMetadataToConstant) {379 LLVMContext Context;380 auto *Int8 = Type::getInt8Ty(Context);381 FunctionType *FTy = FunctionType::get(Type::getVoidTy(Context), Int8, false);382 std::unique_ptr<Function> F(383 Function::Create(FTy, GlobalValue::ExternalLinkage, "F"));384 385 // Map a local value to a constant.386 Argument &A = *F->arg_begin();387 Constant &C = *ConstantInt::get(Int8, 42);388 ValueToValueMapTy VM;389 VM[&A] = &C;390 391 // Look up the metadata-as-value wrapper. Don't crash.392 auto *MDA = MetadataAsValue::get(Context, ValueAsMetadata::get(&A));393 auto *MDC = MetadataAsValue::get(Context, ValueAsMetadata::get(&C));394 EXPECT_TRUE(isa<LocalAsMetadata>(MDA->getMetadata()));395 EXPECT_TRUE(isa<ConstantAsMetadata>(MDC->getMetadata()));396 EXPECT_EQ(&C, ValueMapper(VM).mapValue(A));397 EXPECT_EQ(MDC, ValueMapper(VM).mapValue(*MDA));398}399 400// Type remapper which remaps all types to same destination.401class TestTypeRemapper : public ValueMapTypeRemapper {402public:403 TestTypeRemapper(Type *Ty) : DstTy(Ty) { }404 Type *remapType(Type *srcTy) override { return DstTy; }405 406private:407 Type *DstTy;408};409 410TEST(ValueMapperTest, mapValuePoisonWithTypeRemap) {411 LLVMContext C;412 Type *OldTy = Type::getInt8Ty(C);413 Type *NewTy = Type::getInt32Ty(C);414 415 TestTypeRemapper TM(NewTy);416 ValueToValueMapTy VM;417 ValueMapper Mapper(VM, RF_None, &TM);418 419 // Check that poison is still poison and has not been converted to undef.420 auto *OldPoison = PoisonValue::get(OldTy);421 auto *NewPoison = PoisonValue::get(NewTy);422 EXPECT_EQ(NewPoison, Mapper.mapValue(*OldPoison));423}424 425TEST(ValueMapperTest, mapValueConstantTargetNoneToLayoutTypeNullValue) {426 LLVMContext C;427 auto *OldTy = TargetExtType::get(C, "spirv.Event");428 Type *NewTy = OldTy->getLayoutType();429 430 TestTypeRemapper TM(NewTy);431 ValueToValueMapTy VM;432 ValueMapper Mapper(VM, RF_None, &TM);433 434 // Check that ConstantTargetNone is mapped to '0' constant of its layout type.435 auto *OldConstant = ConstantTargetNone::get(OldTy);436 auto *NewConstant = Constant::getNullValue(NewTy);437 EXPECT_EQ(NewConstant, Mapper.mapValue(*OldConstant));438}439 440TEST(ValueMapperTest, mapValuePtrAuth) {441 LLVMContext C;442 Type *PtrTy = PointerType::get(C, 0);443 IntegerType *Int32Ty = Type::getInt32Ty(C);444 IntegerType *Int64Ty = Type::getInt64Ty(C);445 446 std::unique_ptr<GlobalVariable> Var0 = std::make_unique<GlobalVariable>(447 PtrTy, false, GlobalValue::ExternalLinkage, nullptr, "Var0");448 std::unique_ptr<GlobalVariable> Var1 = std::make_unique<GlobalVariable>(449 PtrTy, false, GlobalValue::ExternalLinkage, nullptr, "Var1");450 std::unique_ptr<GlobalVariable> Storage0 = std::make_unique<GlobalVariable>(451 PtrTy, false, GlobalValue::ExternalLinkage, nullptr, "Storage0");452 std::unique_ptr<GlobalVariable> Storage1 = std::make_unique<GlobalVariable>(453 PtrTy, false, GlobalValue::ExternalLinkage, nullptr, "Storage1");454 std::unique_ptr<GlobalVariable> DS0 = std::make_unique<GlobalVariable>(455 PtrTy, false, GlobalValue::ExternalLinkage, nullptr, "DS0");456 std::unique_ptr<GlobalVariable> DS1 = std::make_unique<GlobalVariable>(457 PtrTy, false, GlobalValue::ExternalLinkage, nullptr, "DS1");458 459 ConstantInt *ConstKey = ConstantInt::get(Int32Ty, 1);460 ConstantInt *ConstDisc = ConstantInt::get(Int64Ty, 1234);461 462 ValueToValueMapTy VM;463 VM[Var0.get()] = Var1.get();464 VM[Storage0.get()] = Storage1.get();465 VM[DS0.get()] = DS1.get();466 467 ConstantPtrAuth *Value = ConstantPtrAuth::get(Var0.get(), ConstKey, ConstDisc,468 Storage0.get(), DS0.get());469 ConstantPtrAuth *MappedValue = ConstantPtrAuth::get(470 Var1.get(), ConstKey, ConstDisc, Storage1.get(), DS1.get());471 472 EXPECT_EQ(ValueMapper(VM).mapValue(*Value), MappedValue);473}474 475} // end namespace476