]> git.ipfire.org Git - thirdparty/ccache.git/commitdiff
test: Test both scalar and AVX2 source code scanning implementations
authorJoel Rosdahl <joel@rosdahl.net>
Wed, 15 Jul 2026 14:39:42 +0000 (16:39 +0200)
committerJoel Rosdahl <joel@rosdahl.net>
Thu, 16 Jul 2026 13:27:01 +0000 (15:27 +0200)
src/ccache/hashutil.cpp
src/ccache/hashutil.hpp
unittest/test_hashutil.cpp

index ead716b2a16d1d6236aab9058c07a56da08526e4..160329447e095733be2b92bb05030a2a779ca703 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2009-2025 Joel Rosdahl and other contributors
+// Copyright (C) 2009-2026 Joel Rosdahl and other contributors
 //
 // See doc/authors.adoc for a complete list of contributors.
 //
@@ -167,6 +167,17 @@ check_for_temporal_macros_avx2(std::string_view str)
 }
 #endif
 
+HashSourceCodeResult
+check_for_source_code_patterns(std::string_view str)
+{
+#ifdef HAVE_AVX2
+  if (util::cpu_supports_avx2()) {
+    return check_for_temporal_macros_avx2(str);
+  }
+#endif
+  return check_for_temporal_macros_bmh(str);
+}
+
 HashSourceCodeResult
 do_hash_file(const Context& ctx,
              Hash::Digest& digest,
@@ -197,7 +208,7 @@ do_hash_file(const Context& ctx,
 
   HashSourceCodeResult result;
   if (check_temporal_macros) {
-    result.insert(check_for_temporal_macros(util::to_string_view(*data)));
+    result.insert(check_for_source_code_patterns(util::to_string_view(*data)));
   }
 
   Hash hash;
@@ -213,14 +224,17 @@ do_hash_file(const Context& ctx,
 
 } // namespace
 
+#ifdef HAVE_AVX2
 HashSourceCodeResult
-check_for_temporal_macros(std::string_view str)
+check_for_source_code_patterns_avx2(std::string_view str)
 {
-#ifdef HAVE_AVX2
-  if (util::cpu_supports_avx2()) {
-    return check_for_temporal_macros_avx2(str);
-  }
+  return check_for_temporal_macros_avx2(str);
+}
 #endif
+
+HashSourceCodeResult
+check_for_source_code_patterns_scalar(std::string_view str)
+{
   return check_for_temporal_macros_bmh(str);
 }
 
index 5f94d8b638952c5dbad9895603ccc4d3268a321c..a10302058fc2c736b56ab6d0b5d199bedc3353c6 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2009-2024 Joel Rosdahl and other contributors
+// Copyright (C) 2009-2026 Joel Rosdahl and other contributors
 //
 // See doc/authors.adoc for a complete list of contributors.
 //
@@ -39,8 +39,14 @@ enum class HashSourceCode {
 
 using HashSourceCodeResult = util::BitSet<HashSourceCode>;
 
-// Search for tokens (described in HashSourceCode) in `str`.
-HashSourceCodeResult check_for_temporal_macros(std::string_view str);
+#ifdef HAVE_AVX2
+// Search for source code patterns in `str`, AVX2 version.
+HashSourceCodeResult check_for_source_code_patterns_avx2(std::string_view str);
+#endif
+
+// Search for source code patterns in `str`, non-SIMD version.
+HashSourceCodeResult
+check_for_source_code_patterns_scalar(std::string_view str);
 
 // Hash a source code file using the inode cache if enabled.
 HashSourceCodeResult hash_source_code_file(const Context& ctx,
index 4dc945ed1525588c8dbbd77a66616d494e2495ad..32f2894796a63386037f81adc36c4b81753404dd 100644 (file)
@@ -1,4 +1,4 @@
-// Copyright (C) 2010-2025 Joel Rosdahl and other contributors
+// Copyright (C) 2010-2026 Joel Rosdahl and other contributors
 //
 // See doc/authors.adoc for a complete list of contributors.
 //
@@ -20,6 +20,7 @@
 
 #include <ccache/hash.hpp>
 #include <ccache/hashutil.hpp>
+#include <ccache/util/cpu.hpp>
 #include <ccache/util/file.hpp>
 #include <ccache/util/format.hpp>
 
@@ -42,112 +43,11 @@ hco(Hash& hash, const std::string& command, const std::string& compiler)
 #endif
 }
 
-TEST_SUITE_BEGIN("hashutil");
-
-TEST_CASE("hash_command_output_simple")
-{
-  TestContext test_context;
-
-  Hash h1;
-  Hash h2;
-
-  CHECK(hco(h1, "echo", "not used"));
-  CHECK(hco(h2, "echo", "not used"));
-  CHECK(h1.digest() == h2.digest());
-}
-
-TEST_CASE("hash_command_output_space_removal")
-{
-  TestContext test_context;
-
-  Hash h1;
-  Hash h2;
-
-  CHECK(hco(h1, "echo", "not used"));
-  CHECK(hco(h2, " echo ", "not used"));
-  CHECK(h1.digest() == h2.digest());
-}
+using SourceCodePatternChecker = HashSourceCodeResult (*)(std::string_view);
 
-TEST_CASE("hash_command_output_hash_inequality")
-{
-  TestContext test_context;
-
-  Hash h1;
-  Hash h2;
-
-  CHECK(hco(h1, "echo foo", "not used"));
-  CHECK(hco(h2, "echo bar", "not used"));
-  CHECK(h1.digest() != h2.digest());
-}
-
-TEST_CASE("hash_command_output_compiler_substitution")
-{
-  TestContext test_context;
-
-  Hash h1;
-  Hash h2;
-
-  CHECK(hco(h1, "echo foo", "not used"));
-#ifdef _WIN32
-  REQUIRE(util::write_file("command.bat", "@echo off\r\necho foo\r\n"));
-  CHECK(hash_command_output(h2, "%compiler%", "command.bat"));
-#else
-  CHECK(hash_command_output(h2, "%compiler% foo", "echo"));
-#endif
-  CHECK(h1.digest() == h2.digest());
-}
-
-TEST_CASE("hash_command_output_stdout_versus_stderr")
+static void
+check_temporal_macros(SourceCodePatternChecker check)
 {
-  TestContext test_context;
-
-  Hash h1;
-  Hash h2;
-
-#ifdef _WIN32
-  REQUIRE(util::write_file("stderr.bat", "@echo off\r\necho foo>&2\r\n"));
-  CHECK(hco(h1, "echo foo", "not used"));
-  CHECK(hco(h2, "stderr.bat", "not used"));
-#else
-  CHECK(hco(h1, "echo foo", "not used"));
-  CHECK(hco(h2, "echo foo >&2", "not used"));
-#endif
-  CHECK(h1.digest() == h2.digest());
-}
-
-TEST_CASE("hash_multicommand_output")
-{
-  TestContext test_context;
-
-  Hash h1;
-  Hash h2;
-
-#ifdef _WIN32
-  h2.hash("foo\r\nbar\r\n");
-  REQUIRE(util::write_file("foo.bat", "@echo off\r\necho foo\r\n"));
-  REQUIRE(util::write_file("bar.bat", "@echo off\r\necho bar\r\n"));
-  CHECK(hash_multicommand_output(h1, "foo.bat; bar.bat", "not used"));
-#else
-  h2.hash("foo\nbar\n");
-  CHECK(hash_multicommand_output(h1, "echo foo; echo bar", "not used"));
-  CHECK(h1.digest() == h2.digest());
-#endif
-}
-
-TEST_CASE("hash_multicommand_output_error_handling")
-{
-  TestContext test_context;
-
-  Hash h1;
-  Hash h2;
-
-  CHECK(!hash_multicommand_output(h2, "false; true", "not used"));
-}
-
-TEST_CASE("check_for_temporal_macros")
-{
-  TestContext test_context;
-
   const std::string_view time_start =
     "__TIME__\n"
     "int a;\n";
@@ -203,8 +103,6 @@ TEST_CASE("check_for_temporal_macros")
     "#define alphabet abcdefghijklmnopqrstuvwxyz\n"
     "a__DATE__";
 
-  auto check = check_for_temporal_macros;
-
   CHECK(check(time_start).contains(HashSourceCode::found_time));
   CHECK(check(time_start.substr(1)).empty());
 
@@ -280,4 +178,125 @@ TEST_CASE("check_for_temporal_macros")
   }
 }
 
+TEST_SUITE_BEGIN("hashutil");
+
+TEST_CASE("hash_command_output_simple")
+{
+  TestContext test_context;
+
+  Hash h1;
+  Hash h2;
+
+  CHECK(hco(h1, "echo", "not used"));
+  CHECK(hco(h2, "echo", "not used"));
+  CHECK(h1.digest() == h2.digest());
+}
+
+TEST_CASE("hash_command_output_space_removal")
+{
+  TestContext test_context;
+
+  Hash h1;
+  Hash h2;
+
+  CHECK(hco(h1, "echo", "not used"));
+  CHECK(hco(h2, " echo ", "not used"));
+  CHECK(h1.digest() == h2.digest());
+}
+
+TEST_CASE("hash_command_output_hash_inequality")
+{
+  TestContext test_context;
+
+  Hash h1;
+  Hash h2;
+
+  CHECK(hco(h1, "echo foo", "not used"));
+  CHECK(hco(h2, "echo bar", "not used"));
+  CHECK(h1.digest() != h2.digest());
+}
+
+TEST_CASE("hash_command_output_compiler_substitution")
+{
+  TestContext test_context;
+
+  Hash h1;
+  Hash h2;
+
+  CHECK(hco(h1, "echo foo", "not used"));
+#ifdef _WIN32
+  REQUIRE(util::write_file("command.bat", "@echo off\r\necho foo\r\n"));
+  CHECK(hash_command_output(h2, "%compiler%", "command.bat"));
+#else
+  CHECK(hash_command_output(h2, "%compiler% foo", "echo"));
+#endif
+  CHECK(h1.digest() == h2.digest());
+}
+
+TEST_CASE("hash_command_output_stdout_versus_stderr")
+{
+  TestContext test_context;
+
+  Hash h1;
+  Hash h2;
+
+#ifdef _WIN32
+  REQUIRE(util::write_file("stderr.bat", "@echo off\r\necho foo>&2\r\n"));
+  CHECK(hco(h1, "echo foo", "not used"));
+  CHECK(hco(h2, "stderr.bat", "not used"));
+#else
+  CHECK(hco(h1, "echo foo", "not used"));
+  CHECK(hco(h2, "echo foo >&2", "not used"));
+#endif
+  CHECK(h1.digest() == h2.digest());
+}
+
+TEST_CASE("hash_multicommand_output")
+{
+  TestContext test_context;
+
+  Hash h1;
+  Hash h2;
+
+#ifdef _WIN32
+  h2.hash("foo\r\nbar\r\n");
+  REQUIRE(util::write_file("foo.bat", "@echo off\r\necho foo\r\n"));
+  REQUIRE(util::write_file("bar.bat", "@echo off\r\necho bar\r\n"));
+  CHECK(hash_multicommand_output(h1, "foo.bat; bar.bat", "not used"));
+#else
+  h2.hash("foo\nbar\n");
+  CHECK(hash_multicommand_output(h1, "echo foo; echo bar", "not used"));
+  CHECK(h1.digest() == h2.digest());
+#endif
+}
+
+TEST_CASE("hash_multicommand_output_error_handling")
+{
+  TestContext test_context;
+
+  Hash h1;
+  Hash h2;
+
+  CHECK(!hash_multicommand_output(h2, "false; true", "not used"));
+}
+
+TEST_CASE("check_for_temporal_macros")
+{
+  TestContext test_context;
+
+  SUBCASE("scalar")
+  {
+    check_temporal_macros(check_for_source_code_patterns_scalar);
+  }
+
+#ifdef HAVE_AVX2
+  if (util::cpu_supports_avx2()) {
+    SUBCASE("avx2")
+    {
+      check_temporal_macros(check_for_source_code_patterns_avx2);
+    }
+  }
+#endif
+}
+
 TEST_SUITE_END();