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