xref: /llvm-project/llvm/unittests/IR/StructuralHashTest.cpp (revision f532d61de02befccd429c0d260d37275b72f2aa2)
1 //===- llvm/unittest/IR/StructuralHashTest.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/IR/StructuralHash.h"
10 #include "llvm/AsmParser/Parser.h"
11 #include "llvm/IR/Module.h"
12 #include "llvm/Support/SourceMgr.h"
13 #include "gtest/gtest.h"
14 
15 #include <memory>
16 
17 using namespace llvm;
18 
19 namespace {
20 
21 std::unique_ptr<Module> parseIR(LLVMContext &Context, const char *IR) {
22   SMDiagnostic Err;
23   std::unique_ptr<Module> M = parseAssemblyString(IR, Err, Context);
24   if (!M)
25     Err.print("StructuralHashTest", errs());
26   return M;
27 }
28 
29 TEST(StructuralHashTest, Empty) {
30   LLVMContext Ctx;
31   std::unique_ptr<Module> M1 = parseIR(Ctx, "");
32   std::unique_ptr<Module> M2 = parseIR(Ctx, "");
33   EXPECT_EQ(StructuralHash(*M1), StructuralHash(*M2));
34 }
35 
36 TEST(StructuralHashTest, Basic) {
37   LLVMContext Ctx;
38   std::unique_ptr<Module> M0 = parseIR(Ctx, "");
39   std::unique_ptr<Module> M1 = parseIR(Ctx, "define void @f() { ret void }");
40   std::unique_ptr<Module> M2 = parseIR(Ctx, "define void @f() { ret void }");
41   std::unique_ptr<Module> M3 = parseIR(Ctx, "@g = global i32 2");
42   std::unique_ptr<Module> M4 = parseIR(Ctx, "@g = global i32 2");
43   EXPECT_NE(StructuralHash(*M0), StructuralHash(*M1));
44   EXPECT_NE(StructuralHash(*M0), StructuralHash(*M3));
45   EXPECT_NE(StructuralHash(*M1), StructuralHash(*M3));
46   EXPECT_EQ(StructuralHash(*M1), StructuralHash(*M2));
47   EXPECT_EQ(StructuralHash(*M3), StructuralHash(*M4));
48 }
49 
50 TEST(StructuralHashTest, BasicFunction) {
51   LLVMContext Ctx;
52   std::unique_ptr<Module> M = parseIR(Ctx, "define void @f() {\n"
53                                            "  ret void\n"
54                                            "}\n"
55                                            "define void @g() {\n"
56                                            "  ret void\n"
57                                            "}\n"
58                                            "define i32 @h(i32 %i) {\n"
59                                            "  ret i32 %i\n"
60                                            "}\n");
61   EXPECT_EQ(StructuralHash(*M->getFunction("f")),
62             StructuralHash(*M->getFunction("g")));
63   EXPECT_NE(StructuralHash(*M->getFunction("f")),
64             StructuralHash(*M->getFunction("h")));
65 }
66 
67 TEST(StructuralHashTest, Declaration) {
68   LLVMContext Ctx;
69   std::unique_ptr<Module> M0 = parseIR(Ctx, "");
70   std::unique_ptr<Module> M1 = parseIR(Ctx, "declare void @f()");
71   std::unique_ptr<Module> M2 = parseIR(Ctx, "@g = external global i32");
72   EXPECT_EQ(StructuralHash(*M0), StructuralHash(*M1));
73   EXPECT_EQ(StructuralHash(*M0), StructuralHash(*M2));
74 }
75 
76 TEST(StructuralHashTest, GlobalType) {
77   LLVMContext Ctx;
78   std::unique_ptr<Module> M1 = parseIR(Ctx, "@g = global i32 1");
79   std::unique_ptr<Module> M2 = parseIR(Ctx, "@g = global float 1.0");
80   EXPECT_NE(StructuralHash(*M1), StructuralHash(*M2));
81 }
82 
83 TEST(StructuralHashTest, Function) {
84   LLVMContext Ctx;
85   std::unique_ptr<Module> M1 = parseIR(Ctx, "define void @f() { ret void }");
86   std::unique_ptr<Module> M2 = parseIR(Ctx, "define void @f(i32) { ret void }");
87   EXPECT_NE(StructuralHash(*M1), StructuralHash(*M2));
88 }
89 
90 TEST(StructuralHashTest, FunctionRetType) {
91   LLVMContext Ctx;
92   std::unique_ptr<Module> M1 = parseIR(Ctx, "define void @f() { ret void }");
93   std::unique_ptr<Module> M2 = parseIR(Ctx, "define i32 @f() { ret i32 0 }");
94   EXPECT_EQ(StructuralHash(*M1), StructuralHash(*M2));
95   EXPECT_NE(StructuralHash(*M1, true), StructuralHash(*M2, true));
96 }
97 
98 TEST(StructuralHashTest, InstructionOpCode) {
99   LLVMContext Ctx;
100   std::unique_ptr<Module> M1 = parseIR(Ctx, "define void @f(ptr %p) {\n"
101                                             "  %a = load i32, ptr %p\n"
102                                             "  ret void\n"
103                                             "}\n");
104   std::unique_ptr<Module> M2 =
105       parseIR(Ctx, "define void @f(ptr %p) {\n"
106                    "  %a = getelementptr i8, ptr %p, i32 1\n"
107                    "  ret void\n"
108                    "}\n");
109   EXPECT_NE(StructuralHash(*M1), StructuralHash(*M2));
110 }
111 
112 TEST(StructuralHashTest, InstructionSubType) {
113   LLVMContext Ctx;
114   std::unique_ptr<Module> M1 = parseIR(Ctx, "define void @f(ptr %p) {\n"
115                                             "  %a = load i32, ptr %p\n"
116                                             "  ret void\n"
117                                             "}\n");
118   std::unique_ptr<Module> M2 = parseIR(Ctx, "define void @f(ptr %p) {\n"
119                                             "  %a = load i64, ptr %p\n"
120                                             "  ret void\n"
121                                             "}\n");
122   EXPECT_EQ(StructuralHash(*M1), StructuralHash(*M2));
123   EXPECT_NE(StructuralHash(*M1, true), StructuralHash(*M2, true));
124 }
125 
126 TEST(StructuralHashTest, InstructionType) {
127   LLVMContext Ctx;
128   std::unique_ptr<Module> M1 = parseIR(Ctx, "define void @f(ptr %p) {\n"
129                                             "  %1 = load i32, ptr %p\n"
130                                             "  ret void\n"
131                                             "}\n");
132   std::unique_ptr<Module> M2 = parseIR(Ctx, "define void @f(ptr %p) {\n"
133                                             "  %1 = load float, ptr %p\n"
134                                             "  ret void\n"
135                                             "}\n");
136   EXPECT_EQ(StructuralHash(*M1), StructuralHash(*M2));
137   EXPECT_NE(StructuralHash(*M1, true), StructuralHash(*M2, true));
138 }
139 
140 TEST(StructuralHashTest, IgnoredMetadata) {
141   LLVMContext Ctx;
142   std::unique_ptr<Module> M1 = parseIR(Ctx, "@a = global i32 1\n");
143   // clang-format off
144   std::unique_ptr<Module> M2 = parseIR(
145       Ctx, R"(
146         @a = global i32 1
147         @llvm.embedded.object = private constant [4 x i8] c"BC\C0\00", section ".llvm.lto", align 1, !exclude !0
148         @llvm.compiler.used = appending global [1 x ptr] [ptr @llvm.embedded.object], section "llvm.metadata"
149 
150         !llvm.embedded.objects = !{!1}
151 
152         !0 = !{}
153         !1 = !{ptr @llvm.embedded.object, !".llvm.lto"}
154         )");
155   // clang-format on
156   EXPECT_EQ(StructuralHash(*M1), StructuralHash(*M2));
157 }
158 
159 TEST(StructuralHashTest, ComparisonInstructionPredicate) {
160   LLVMContext Ctx;
161   std::unique_ptr<Module> M1 = parseIR(Ctx, "define i1 @f(i64 %a, i64 %b) {\n"
162                                             "  %1 = icmp eq i64 %a, %b\n"
163                                             "  ret i1 %1\n"
164                                             "}\n");
165   std::unique_ptr<Module> M2 = parseIR(Ctx, "define i1 @f(i64 %a, i64 %b) {\n"
166                                             "  %1 = icmp ne i64 %a, %b\n"
167                                             " ret i1 %1\n"
168                                             "}\n");
169   EXPECT_EQ(StructuralHash(*M1), StructuralHash(*M2));
170   EXPECT_NE(StructuralHash(*M1, true), StructuralHash(*M2, true));
171 }
172 
173 TEST(StructuralHashTest, IntrinsicInstruction) {
174   LLVMContext Ctx;
175   std::unique_ptr<Module> M1 =
176       parseIR(Ctx, "define float @f(float %a) {\n"
177                    "  %b = call float @llvm.sin.f32(float %a)\n"
178                    "  ret float %b\n"
179                    "}\n"
180                    "declare float @llvm.sin.f32(float)\n");
181   std::unique_ptr<Module> M2 =
182       parseIR(Ctx, "define float @f(float %a) {\n"
183                    "  %b = call float @llvm.cos.f32(float %a)\n"
184                    "  ret float %b\n"
185                    "}\n"
186                    "declare float @llvm.cos.f32(float)\n");
187   EXPECT_EQ(StructuralHash(*M1), StructuralHash(*M2));
188   EXPECT_NE(StructuralHash(*M1, true), StructuralHash(*M2, true));
189 }
190 
191 TEST(StructuralHashTest, CallInstruction) {
192   LLVMContext Ctx;
193   std::unique_ptr<Module> M1 = parseIR(Ctx, "define i64 @f(i64 %a) {\n"
194                                             "  %b = call i64 @f1(i64 %a)\n"
195                                             "  ret i64 %b\n"
196                                             "}\n"
197                                             "declare i64 @f1(i64)");
198   std::unique_ptr<Module> M2 = parseIR(Ctx, "define i64 @f(i64 %a) {\n"
199                                             "  %b = call i64 @f2(i64 %a)\n"
200                                             "  ret i64 %b\n"
201                                             "}\n"
202                                             "declare i64 @f2(i64)");
203   EXPECT_EQ(StructuralHash(*M1), StructuralHash(*M2));
204   EXPECT_NE(StructuralHash(*M1, true), StructuralHash(*M2, true));
205 }
206 
207 TEST(StructuralHashTest, ConstantInteger) {
208   LLVMContext Ctx;
209   std::unique_ptr<Module> M1 = parseIR(Ctx, "define i64 @f1() {\n"
210                                             "  ret i64 1\n"
211                                             "}\n");
212   std::unique_ptr<Module> M2 = parseIR(Ctx, "define i64 @f2() {\n"
213                                             "  ret i64 2\n"
214                                             "}\n");
215   EXPECT_EQ(StructuralHash(*M1), StructuralHash(*M2));
216   EXPECT_NE(StructuralHash(*M1, true), StructuralHash(*M2, true));
217 }
218 
219 TEST(StructuralHashTest, BigConstantInteger) {
220   LLVMContext Ctx;
221   std::unique_ptr<Module> M1 = parseIR(Ctx, "define i128 @f1() {\n"
222                                             "  ret i128 18446744073709551616\n"
223                                             "}\n");
224   std::unique_ptr<Module> M2 = parseIR(Ctx, "define i128 @f2() {\n"
225                                             "  ret i128 18446744073709551617\n"
226                                             "}\n");
227   EXPECT_EQ(StructuralHash(*M1), StructuralHash(*M2));
228   EXPECT_NE(StructuralHash(*M1, true), StructuralHash(*M2, true));
229 }
230 
231 TEST(StructuralHashTest, ArgumentNumber) {
232   LLVMContext Ctx;
233   std::unique_ptr<Module> M1 = parseIR(Ctx, "define i64 @f1(i64 %a, i64 %b) {\n"
234                                             "  ret i64 %a\n"
235                                             "}\n");
236   std::unique_ptr<Module> M2 = parseIR(Ctx, "define i64 @f2(i64 %a, i64 %b) {\n"
237                                             "  ret i64 %b\n"
238                                             "}\n");
239   EXPECT_EQ(StructuralHash(*M1), StructuralHash(*M2));
240   EXPECT_NE(StructuralHash(*M1, true), StructuralHash(*M2, true));
241 }
242 } // end anonymous namespace
243