diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h index 3cbbf1a3074ac..e43112b4bb98b 100644 --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -22,10 +22,10 @@ #include "llvm/Frontend/Driver/CodeGenOptions.h" #include "llvm/MC/MCTargetOptions.h" #include "llvm/Support/CodeGen.h" -#include "llvm/Support/Hash.h" #include "llvm/Support/Regex.h" #include "llvm/Target/TargetOptions.h" #include "llvm/Transforms/Instrumentation/AddressSanitizerOptions.h" +#include "llvm/Transforms/Utils/KCFIHash.h" #include #include #include diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp index 106f1e63cd904..2d91b7eaa52dc 100644 --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -70,7 +70,6 @@ #include "llvm/Support/CommandLine.h" #include "llvm/Support/ConvertUTF.h" #include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/Hash.h" #include "llvm/Support/TimeProfiler.h" #include "llvm/TargetParser/AArch64TargetParser.h" #include "llvm/TargetParser/RISCVISAInfo.h" @@ -78,6 +77,7 @@ #include "llvm/TargetParser/X86TargetParser.h" #include "llvm/Transforms/Instrumentation/KCFI.h" #include "llvm/Transforms/Utils/BuildLibCalls.h" +#include "llvm/Transforms/Utils/KCFIHash.h" #include #include diff --git a/llvm/include/llvm/Support/xxhash.h b/llvm/include/llvm/Support/xxhash.h index 15c4f1bfd4563..b03aaa1e907b4 100644 --- a/llvm/include/llvm/Support/xxhash.h +++ b/llvm/include/llvm/Support/xxhash.h @@ -32,9 +32,6 @@ - xxHash source repository : https://github.com/Cyan4973/xxHash */ -/* based on revision d2df04efcbef7d7f6886d345861e5dfda4edacc1 Removed - * everything but a simple interface for computing XXh64. */ - #ifndef LLVM_SUPPORT_XXHASH_H #define LLVM_SUPPORT_XXHASH_H @@ -44,9 +41,6 @@ namespace llvm { -// Deprecated pre-xxh3 64-bit hash. -LLVM_ABI uint64_t xxHash64(const uint8_t *data, size_t len); - /// XXH3's 64-bit variant. Inline ArrayRef and StringRef overloads live in /// llvm/ADT/ArrayRef.h and llvm/ADT/StringRef.h. LLVM_ABI uint64_t xxh3_64bits(const uint8_t *data, size_t len); diff --git a/llvm/include/llvm/Support/Hash.h b/llvm/include/llvm/Transforms/Utils/KCFIHash.h similarity index 78% rename from llvm/include/llvm/Support/Hash.h rename to llvm/include/llvm/Transforms/Utils/KCFIHash.h index 7a2cfb8774ae8..553c24d1289aa 100644 --- a/llvm/include/llvm/Support/Hash.h +++ b/llvm/include/llvm/Transforms/Utils/KCFIHash.h @@ -1,4 +1,4 @@ -//===- llvm/Support/Hash.h - Hash functions --------------------*- C++ -*-===// +//===----------------------------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,12 +6,12 @@ // //===----------------------------------------------------------------------===// // -// This file provides hash functions. +// Helpers for computing the 32-bit KCFI type ID from a mangled type name. // //===----------------------------------------------------------------------===// -#ifndef LLVM_SUPPORT_HASH_H -#define LLVM_SUPPORT_HASH_H +#ifndef LLVM_TRANSFORMS_UTILS_KCFIHASH_H +#define LLVM_TRANSFORMS_UTILS_KCFIHASH_H #include "llvm/ADT/StringRef.h" #include @@ -34,4 +34,4 @@ LLVM_ABI uint32_t getKCFITypeID(StringRef MangledTypeName, } // end namespace llvm -#endif // LLVM_SUPPORT_HASH_H +#endif // LLVM_TRANSFORMS_UTILS_KCFIHASH_H diff --git a/llvm/lib/Support/CMakeLists.txt b/llvm/lib/Support/CMakeLists.txt index e8d505f218b69..100cfb567c348 100644 --- a/llvm/lib/Support/CMakeLists.txt +++ b/llvm/lib/Support/CMakeLists.txt @@ -204,7 +204,6 @@ add_llvm_component_library(LLVMSupport FormatVariadic.cpp GlobPattern.cpp GraphWriter.cpp - Hash.cpp HexagonAttributeParser.cpp HexagonAttributes.cpp InitLLVM.cpp diff --git a/llvm/lib/Support/Hash.cpp b/llvm/lib/Support/Hash.cpp deleted file mode 100644 index 6b5d000ee27c9..0000000000000 --- a/llvm/lib/Support/Hash.cpp +++ /dev/null @@ -1,54 +0,0 @@ -//===- Hash.cpp - Hash functions ---------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This file implements hash functions. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Support/Hash.h" -#include "llvm/Support/ErrorHandling.h" -#include "llvm/Support/xxhash.h" - -using namespace llvm; - -KCFIHashAlgorithm llvm::parseKCFIHashAlgorithm(StringRef Name) { - if (Name == "FNV-1a") - return KCFIHashAlgorithm::FNV1a; - // Default to xxHash64 for backward compatibility - return KCFIHashAlgorithm::xxHash64; -} - -StringRef llvm::stringifyKCFIHashAlgorithm(KCFIHashAlgorithm Algorithm) { - switch (Algorithm) { - case KCFIHashAlgorithm::xxHash64: - return "xxHash64"; - case KCFIHashAlgorithm::FNV1a: - return "FNV-1a"; - } - llvm_unreachable("Unknown KCFI hash algorithm"); -} - -uint32_t llvm::getKCFITypeID(StringRef MangledTypeName, - KCFIHashAlgorithm Algorithm) { - switch (Algorithm) { - case KCFIHashAlgorithm::xxHash64: - // Use lower 32 bits of xxHash64 - return static_cast( - xxHash64(reinterpret_cast(MangledTypeName.data()), - MangledTypeName.size())); - case KCFIHashAlgorithm::FNV1a: - // FNV-1a hash (32-bit) - uint32_t Hash = 2166136261u; // FNV offset basis - for (unsigned char C : MangledTypeName) { - Hash ^= C; - Hash *= 16777619u; // FNV prime - } - return Hash; - } - llvm_unreachable("Unknown KCFI hash algorithm"); -} diff --git a/llvm/lib/Support/xxhash.cpp b/llvm/lib/Support/xxhash.cpp index 6997fed7e8336..a1aee00b82637 100644 --- a/llvm/lib/Support/xxhash.cpp +++ b/llvm/lib/Support/xxhash.cpp @@ -32,9 +32,6 @@ * - xxHash source repository : https://github.com/Cyan4973/xxHash */ -// xxhash64 is based on commit d2df04efcbef7d7f6886d345861e5dfda4edacc1. Removed -// everything but a simple interface for computing xxh64. - // xxh3_64bits is based on commit d5891596637d21366b9b1dcf2c0007a3edb26a9e (July // 2023). @@ -77,20 +74,6 @@ static const uint64_t PRIME64_3 = 1609587929392839161ULL; static const uint64_t PRIME64_4 = 9650029242287828579ULL; static const uint64_t PRIME64_5 = 2870177450012600261ULL; -static uint64_t round(uint64_t Acc, uint64_t Input) { - Acc += Input * PRIME64_2; - Acc = rotl64(Acc, 31); - Acc *= PRIME64_1; - return Acc; -} - -static uint64_t mergeRound(uint64_t Acc, uint64_t Val) { - Val = round(0, Val); - Acc ^= Val; - Acc = Acc * PRIME64_1 + PRIME64_4; - return Acc; -} - static uint64_t XXH64_avalanche(uint64_t hash) { hash ^= hash >> 33; hash *= PRIME64_2; @@ -100,64 +83,6 @@ static uint64_t XXH64_avalanche(uint64_t hash) { return hash; } -uint64_t llvm::xxHash64(const uint8_t *P, size_t Len) { - uint64_t Seed = 0; - const uint8_t *const BEnd = P + Len; - uint64_t H64; - - if (Len >= 32) { - const unsigned char *const Limit = BEnd - 32; - uint64_t V1 = Seed + PRIME64_1 + PRIME64_2; - uint64_t V2 = Seed + PRIME64_2; - uint64_t V3 = Seed + 0; - uint64_t V4 = Seed - PRIME64_1; - - do { - V1 = round(V1, endian::read64le(P)); - P += 8; - V2 = round(V2, endian::read64le(P)); - P += 8; - V3 = round(V3, endian::read64le(P)); - P += 8; - V4 = round(V4, endian::read64le(P)); - P += 8; - } while (P <= Limit); - - H64 = rotl64(V1, 1) + rotl64(V2, 7) + rotl64(V3, 12) + rotl64(V4, 18); - H64 = mergeRound(H64, V1); - H64 = mergeRound(H64, V2); - H64 = mergeRound(H64, V3); - H64 = mergeRound(H64, V4); - - } else { - H64 = Seed + PRIME64_5; - } - - H64 += (uint64_t)Len; - - while (reinterpret_cast(P) + 8 <= - reinterpret_cast(BEnd)) { - uint64_t const K1 = round(0, endian::read64le(P)); - H64 ^= K1; - H64 = rotl64(H64, 27) * PRIME64_1 + PRIME64_4; - P += 8; - } - - if (reinterpret_cast(P) + 4 <= reinterpret_cast(BEnd)) { - H64 ^= (uint64_t)(endian::read32le(P)) * PRIME64_1; - H64 = rotl64(H64, 23) * PRIME64_2 + PRIME64_3; - P += 4; - } - - while (P < BEnd) { - H64 ^= (*P) * PRIME64_5; - H64 = rotl64(H64, 11) * PRIME64_1; - P++; - } - - return XXH64_avalanche(H64); -} - constexpr size_t XXH3_SECRETSIZE_MIN = 136; constexpr size_t XXH_SECRET_DEFAULT_SIZE = 192; diff --git a/llvm/lib/Transforms/Utils/CMakeLists.txt b/llvm/lib/Transforms/Utils/CMakeLists.txt index 82e9edf674866..933e204081ad2 100644 --- a/llvm/lib/Transforms/Utils/CMakeLists.txt +++ b/llvm/lib/Transforms/Utils/CMakeLists.txt @@ -40,6 +40,7 @@ add_llvm_component_library(LLVMTransformUtils Instrumentation.cpp IntegerDivision.cpp IRNormalizer.cpp + KCFIHash.cpp LCSSA.cpp LibCallsShrinkWrap.cpp Local.cpp diff --git a/llvm/lib/Transforms/Utils/KCFIHash.cpp b/llvm/lib/Transforms/Utils/KCFIHash.cpp new file mode 100644 index 0000000000000..df65ed53b66b6 --- /dev/null +++ b/llvm/lib/Transforms/Utils/KCFIHash.cpp @@ -0,0 +1,142 @@ +//===----------------------------------------------------------------------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "llvm/Transforms/Utils/KCFIHash.h" +#include "llvm/Support/Endian.h" +#include "llvm/Support/ErrorHandling.h" + +using namespace llvm; +using namespace support; + +// xxHash64 is a deprecated pre-xxh3 hash, retained here only as the default +// KCFI type-ID hash for ABI compatibility. + +static uint64_t rotl64(uint64_t X, size_t R) { + return (X << R) | (X >> (64 - R)); +} + +constexpr uint64_t PRIME64_1 = 11400714785074694791ULL; +constexpr uint64_t PRIME64_2 = 14029467366897019727ULL; +constexpr uint64_t PRIME64_3 = 1609587929392839161ULL; +constexpr uint64_t PRIME64_4 = 9650029242287828579ULL; +constexpr uint64_t PRIME64_5 = 2870177450012600261ULL; + +static uint64_t round(uint64_t Acc, uint64_t Input) { + Acc += Input * PRIME64_2; + Acc = rotl64(Acc, 31); + Acc *= PRIME64_1; + return Acc; +} + +static uint64_t mergeRound(uint64_t Acc, uint64_t Val) { + Val = round(0, Val); + Acc ^= Val; + Acc = Acc * PRIME64_1 + PRIME64_4; + return Acc; +} + +static uint64_t avalanche(uint64_t H) { + H ^= H >> 33; + H *= PRIME64_2; + H ^= H >> 29; + H *= PRIME64_3; + H ^= H >> 32; + return H; +} + +static uint64_t xxHash64(const uint8_t *P, size_t Len) { + const uint8_t *const BEnd = P + Len; + uint64_t H64; + + if (Len >= 32) { + const uint8_t *const Limit = BEnd - 32; + uint64_t V1 = PRIME64_1 + PRIME64_2; + uint64_t V2 = PRIME64_2; + uint64_t V3 = 0; + uint64_t V4 = -PRIME64_1; + + do { + V1 = round(V1, endian::read64le(P)); + P += 8; + V2 = round(V2, endian::read64le(P)); + P += 8; + V3 = round(V3, endian::read64le(P)); + P += 8; + V4 = round(V4, endian::read64le(P)); + P += 8; + } while (P <= Limit); + + H64 = rotl64(V1, 1) + rotl64(V2, 7) + rotl64(V3, 12) + rotl64(V4, 18); + H64 = mergeRound(H64, V1); + H64 = mergeRound(H64, V2); + H64 = mergeRound(H64, V3); + H64 = mergeRound(H64, V4); + } else { + H64 = PRIME64_5; + } + + H64 += (uint64_t)Len; + + while (reinterpret_cast(P) + 8 <= + reinterpret_cast(BEnd)) { + H64 ^= round(0, endian::read64le(P)); + H64 = rotl64(H64, 27) * PRIME64_1 + PRIME64_4; + P += 8; + } + + if (reinterpret_cast(P) + 4 <= reinterpret_cast(BEnd)) { + H64 ^= (uint64_t)endian::read32le(P) * PRIME64_1; + H64 = rotl64(H64, 23) * PRIME64_2 + PRIME64_3; + P += 4; + } + + while (P < BEnd) { + H64 ^= (*P) * PRIME64_5; + H64 = rotl64(H64, 11) * PRIME64_1; + ++P; + } + + return avalanche(H64); +} + +KCFIHashAlgorithm llvm::parseKCFIHashAlgorithm(StringRef Name) { + if (Name == "FNV-1a") + return KCFIHashAlgorithm::FNV1a; + // Default to xxHash64 for backward compatibility + return KCFIHashAlgorithm::xxHash64; +} + +StringRef llvm::stringifyKCFIHashAlgorithm(KCFIHashAlgorithm Algorithm) { + switch (Algorithm) { + case KCFIHashAlgorithm::xxHash64: + return "xxHash64"; + case KCFIHashAlgorithm::FNV1a: + return "FNV-1a"; + } + llvm_unreachable("Unknown KCFI hash algorithm"); +} + +uint32_t llvm::getKCFITypeID(StringRef MangledTypeName, + KCFIHashAlgorithm Algorithm) { + switch (Algorithm) { + case KCFIHashAlgorithm::xxHash64: + // Use lower 32 bits of xxHash64 + return static_cast( + xxHash64(reinterpret_cast(MangledTypeName.data()), + MangledTypeName.size())); + case KCFIHashAlgorithm::FNV1a: + // FNV-1a hash (32-bit) + uint32_t Hash = 2166136261u; // FNV offset basis + for (unsigned char C : MangledTypeName) { + Hash ^= C; + Hash *= 16777619u; // FNV prime + } + return Hash; + } + llvm_unreachable("Unknown KCFI hash algorithm"); +} diff --git a/llvm/lib/Transforms/Utils/ModuleUtils.cpp b/llvm/lib/Transforms/Utils/ModuleUtils.cpp index 63a234960a0ad..2976ebf46c9b7 100644 --- a/llvm/lib/Transforms/Utils/ModuleUtils.cpp +++ b/llvm/lib/Transforms/Utils/ModuleUtils.cpp @@ -19,9 +19,9 @@ #include "llvm/IR/MDBuilder.h" #include "llvm/IR/Module.h" #include "llvm/Support/Casting.h" -#include "llvm/Support/Hash.h" #include "llvm/Support/MD5.h" #include "llvm/Support/raw_ostream.h" +#include "llvm/Transforms/Utils/KCFIHash.h" using namespace llvm; diff --git a/llvm/unittests/Support/xxhashTest.cpp b/llvm/unittests/Support/xxhashTest.cpp index 9f91fc79e1f62..6097f0525e2b2 100644 --- a/llvm/unittests/Support/xxhashTest.cpp +++ b/llvm/unittests/Support/xxhashTest.cpp @@ -32,18 +32,6 @@ static void fillTestBuffer(uint8_t *buffer, size_t len) { } } -TEST(xxhashTest, Basic) { - EXPECT_EQ(0xef46db3751d8e999U, xxHash64(nullptr, 0)); - EXPECT_EQ(0x33bf00a859c4ba3fU, - xxHash64(reinterpret_cast("foo"), 3)); - EXPECT_EQ(0x48a37c90ad27a659U, - xxHash64(reinterpret_cast("bar"), 3)); - EXPECT_EQ(0x69196c1b3af0bff9U, - xxHash64(reinterpret_cast( - "0123456789abcdefghijklmnopqrstuvwxyz"), - 36)); -} - TEST(xxhashTest, xxh3) { constexpr size_t size = 2243; uint8_t a[size];