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