1 //===- MachineStableHashTest.cpp ------------------------------------------===// 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/CodeGen/MachineStableHash.h" 10 #include "llvm/CodeGen/MIRParser/MIRParser.h" 11 #include "llvm/CodeGen/MachineFunction.h" 12 #include "llvm/CodeGen/MachineModuleInfo.h" 13 #include "llvm/FileCheck/FileCheck.h" 14 #include "llvm/IR/Module.h" 15 #include "llvm/MC/TargetRegistry.h" 16 #include "llvm/Support/SourceMgr.h" 17 #include "llvm/Support/TargetSelect.h" 18 #include "llvm/Target/TargetMachine.h" 19 #include "gtest/gtest.h" 20 21 using namespace llvm; 22 23 class MachineStableHashTest : public testing::Test { 24 public: 25 MachineStableHashTest() {} 26 27 protected: 28 LLVMContext Context; 29 std::unique_ptr<Module> M; 30 std::unique_ptr<MIRParser> MIR; 31 32 static void SetUpTestCase() { 33 InitializeAllTargetInfos(); 34 InitializeAllTargets(); 35 InitializeAllTargetMCs(); 36 } 37 38 void SetUp() override { M = std::make_unique<Module>("Dummy", Context); } 39 40 std::unique_ptr<TargetMachine> 41 createTargetMachine(std::string TT, StringRef CPU, StringRef FS) { 42 std::string Error; 43 const Target *T = TargetRegistry::lookupTarget(TT, Error); 44 if (!T) 45 return nullptr; 46 TargetOptions Options; 47 return std::unique_ptr<TargetMachine>(T->createTargetMachine( 48 TT, CPU, FS, Options, std::nullopt, std::nullopt)); 49 } 50 51 std::unique_ptr<Module> parseMIR(const TargetMachine &TM, StringRef MIRCode, 52 MachineModuleInfo &MMI) { 53 SMDiagnostic Diagnostic; 54 std::unique_ptr<MemoryBuffer> MBuffer = MemoryBuffer::getMemBuffer(MIRCode); 55 MIR = createMIRParser(std::move(MBuffer), Context); 56 if (!MIR) 57 return nullptr; 58 59 std::unique_ptr<Module> Mod = MIR->parseIRModule(); 60 if (!Mod) 61 return nullptr; 62 63 Mod->setDataLayout(TM.createDataLayout()); 64 65 if (MIR->parseMachineFunctions(*Mod, MMI)) { 66 M.reset(); 67 return nullptr; 68 } 69 70 return Mod; 71 } 72 }; 73 74 TEST_F(MachineStableHashTest, StableGlobalName) { 75 auto TM = createTargetMachine(("aarch64--"), "", ""); 76 if (!TM) 77 GTEST_SKIP(); 78 StringRef MIRString = R"MIR( 79 --- | 80 define void @f1() { ret void } 81 define void @f2() { ret void } 82 define void @f3() { ret void } 83 define void @f4() { ret void } 84 declare void @goo() 85 declare void @goo.llvm.123() 86 declare void @goo.__uniq.456() 87 declare void @goo.invalid.789() 88 ... 89 --- 90 name: f1 91 alignment: 16 92 tracksRegLiveness: true 93 frameInfo: 94 maxAlignment: 16 95 machineFunctionInfo: {} 96 body: | 97 bb.0: 98 liveins: $lr 99 BL @goo 100 RET undef $lr 101 102 ... 103 --- 104 name: f2 105 body: | 106 bb.0: 107 liveins: $lr 108 BL @goo.llvm.123 109 RET undef $lr 110 ... 111 --- 112 name: f3 113 body: | 114 bb.0: 115 liveins: $lr 116 BL @goo.__uniq.456 117 RET undef $lr 118 ... 119 --- 120 name: f4 121 body: | 122 bb.0: 123 liveins: $lr 124 BL @goo.invalid.789 125 RET undef $lr 126 ... 127 )MIR"; 128 MachineModuleInfo MMI(TM.get()); 129 M = parseMIR(*TM, MIRString, MMI); 130 ASSERT_TRUE(M); 131 auto *MF1 = MMI.getMachineFunction(*M->getFunction("f1")); 132 auto *MF2 = MMI.getMachineFunction(*M->getFunction("f2")); 133 auto *MF3 = MMI.getMachineFunction(*M->getFunction("f3")); 134 auto *MF4 = MMI.getMachineFunction(*M->getFunction("f4")); 135 136 EXPECT_EQ(stableHashValue(*MF1), stableHashValue(*MF2)) 137 << "Expect the suffix, `.llvm.{number}` to be ignored."; 138 EXPECT_EQ(stableHashValue(*MF1), stableHashValue(*MF3)) 139 << "Expect the suffix, `.__uniq.{number}` to be ignored."; 140 // Do not ignore `.invalid.{number}`. 141 EXPECT_NE(stableHashValue(*MF1), stableHashValue(*MF4)); 142 } 143 144 TEST_F(MachineStableHashTest, ContentName) { 145 auto TM = createTargetMachine(("aarch64--"), "", ""); 146 if (!TM) 147 GTEST_SKIP(); 148 StringRef MIRString = R"MIR( 149 --- | 150 define void @f1() { ret void } 151 define void @f2() { ret void } 152 define void @f3() { ret void } 153 define void @f4() { ret void } 154 declare void @goo() 155 declare void @goo.content.123() 156 declare void @zoo.content.123() 157 declare void @goo.content.456() 158 ... 159 --- 160 name: f1 161 alignment: 16 162 tracksRegLiveness: true 163 frameInfo: 164 maxAlignment: 16 165 machineFunctionInfo: {} 166 body: | 167 bb.0: 168 liveins: $lr 169 BL @goo 170 RET undef $lr 171 ... 172 --- 173 name: f2 174 body: | 175 bb.0: 176 liveins: $lr 177 BL @goo.content.123 178 RET undef $lr 179 ... 180 --- 181 name: f3 182 body: | 183 bb.0: 184 liveins: $lr 185 BL @zoo.content.123 186 RET undef $lr 187 ... 188 --- 189 name: f4 190 body: | 191 bb.0: 192 liveins: $lr 193 BL @goo.content.456 194 RET undef $lr 195 ... 196 )MIR"; 197 MachineModuleInfo MMI(TM.get()); 198 M = parseMIR(*TM, MIRString, MMI); 199 ASSERT_TRUE(M); 200 auto *MF1 = MMI.getMachineFunction(*M->getFunction("f1")); 201 auto *MF2 = MMI.getMachineFunction(*M->getFunction("f2")); 202 auto *MF3 = MMI.getMachineFunction(*M->getFunction("f3")); 203 auto *MF4 = MMI.getMachineFunction(*M->getFunction("f4")); 204 205 // Do not ignore `.content.{number}`. 206 EXPECT_NE(stableHashValue(*MF1), stableHashValue(*MF2)); 207 EXPECT_EQ(stableHashValue(*MF2), stableHashValue(*MF3)) 208 << "Expect the same hash for the same suffix, `.content.{number}`"; 209 // Different suffixes should result in different hashes. 210 EXPECT_NE(stableHashValue(*MF2), stableHashValue(*MF4)); 211 EXPECT_NE(stableHashValue(*MF3), stableHashValue(*MF4)); 212 } 213