brintos

brintos / llvm-project-archived public Read only

0
0
Text · 16.1 KiB · 60e9c56 Raw
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