/
GitCaptain
/
llvm-project
Обзор
Документация
Войти
/
GitCaptain
/
llvm-project
Код
Запросы
0
Задачи
Вики
Пакеты
0
Релизы
0
Аналитика
Безопасность
fix-tests
libc/src/string/memory_utils/address.h
133 строки
5 KB
Guillaume Chatelet
[libc][mem*] Address facility + test enum support
01 июн 2022, 12:09
01 июн 2022, 12:09
4cbfd2e
Код
Авторство
О чём код?
//===-- Strongly typed address with alignment and access semantics --------===// // // 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 // //===----------------------------------------------------------------------===// // // //===----------------------------------------------------------------------===// #ifndef LLVM_LIBC_SRC_STRING_MEMORY_UTILS_COMMON_H #define LLVM_LIBC_SRC_STRING_MEMORY_UTILS_COMMON_H #include "src/__support/CPP/TypeTraits.h" // cpp::ConditionalType #include "src/string/memory_utils/utils.h" // is_power2 #include <stddef.h> // size_t #include <stdint.h> // uint8_t, uint16_t, uint32_t, uint64_t namespace __llvm_libc { // Utility to enable static_assert(false) in templates. template <bool flag = false> static void DeferredStaticAssert(const char *msg) { static_assert(flag, "compilation error"); } // A non-coercible type to represent raw data. enum class ubyte : unsigned char { ZERO = 0 }; // Address attribute specifying whether the underlying load / store operations // are temporal or non-temporal. enum class Temporality { TEMPORAL, NON_TEMPORAL }; // Address attribute specifying whether the underlying load / store operations // are aligned or unaligned. enum class Aligned { NO, YES }; // Address attribute to discriminate between readable and writable addresses. enum class Permission { Read, Write }; // Address is semantically equivalent to a pointer but also conveys compile time // information that helps with instructions selection (aligned/unaligned, // temporal/non-temporal). template <size_t Alignment, Permission P, Temporality TS> struct Address { static_assert(is_power2(Alignment)); static constexpr size_t ALIGNMENT = Alignment; static constexpr Permission PERMISSION = P; static constexpr Temporality TEMPORALITY = TS; static constexpr bool IS_READ = P == Permission::Read; static constexpr bool IS_WRITE = P == Permission::Write; using PointeeType = cpp::ConditionalType<!IS_WRITE, const ubyte, ubyte>; using VoidType = cpp::ConditionalType<!IS_WRITE, const void, void>; Address(VoidType *ptr) : ptr_(reinterpret_cast<PointeeType *>(ptr)) {} PointeeType *ptr() const { return reinterpret_cast<PointeeType *>( __builtin_assume_aligned(ptr_, ALIGNMENT)); } PointeeType *const ptr_; template <size_t ByteOffset> auto offset(size_t byte_offset) const { static constexpr size_t NewAlignment = commonAlign<ByteOffset>(); return Address<NewAlignment, PERMISSION, TEMPORALITY>(ptr_ + byte_offset); } private: static constexpr size_t gcd(size_t A, size_t B) { return B == 0 ? A : gcd(B, A % B); } template <size_t ByteOffset> static constexpr size_t commonAlign() { constexpr size_t GCD = gcd(ByteOffset, ALIGNMENT); if constexpr (is_power2(GCD)) return GCD; else return 1; } }; template <typename T> struct IsAddressType : public cpp::FalseValue {}; template <size_t Alignment, Permission P, Temporality TS> struct IsAddressType<Address<Alignment, P, TS>> : public cpp::TrueValue {}; // Reinterpret the address as a pointer to T. // This is not UB since the underlying pointer always refers to a `char` in a // buffer of raw data. template <typename T, typename AddrT> static T *as(AddrT addr) { static_assert(IsAddressType<AddrT>::Value); return reinterpret_cast<T *>(addr.ptr()); } // Offsets the address by a compile time amount, this allows propagating // alignment whenever possible. template <size_t ByteOffset, typename AddrT> static auto offsetAddr(AddrT addr) { static_assert(IsAddressType<AddrT>::Value); return addr.template offset<ByteOffset>(ByteOffset); } // Offsets the address by a runtime amount but assuming that the resulting // address will be Alignment aligned. template <size_t Alignment, typename AddrT> static auto offsetAddrAssumeAligned(AddrT addr, size_t byte_offset) { static_assert(IsAddressType<AddrT>::Value); return Address<Alignment, AddrT::PERMISSION, AddrT::TEMPORALITY>(addr.ptr_ + byte_offset); } // Offsets the address by a runtime amount that is assumed to be a multiple of // ByteOffset. This allows to propagate the address alignment whenever possible. template <size_t ByteOffset, typename AddrT> static auto offsetAddrMultiplesOf(AddrT addr, ptrdiff_t byte_offset) { static_assert(IsAddressType<AddrT>::Value); return addr.template offset<ByteOffset>(byte_offset); } // User friendly aliases for common address types. template <size_t Alignment> using SrcAddr = Address<Alignment, Permission::Read, Temporality::TEMPORAL>; template <size_t Alignment> using DstAddr = Address<Alignment, Permission::Write, Temporality::TEMPORAL>; template <size_t Alignment> using NtSrcAddr = Address<Alignment, Permission::Read, Temporality::NON_TEMPORAL>; template <size_t Alignment> using NtDstAddr = Address<Alignment, Permission::Write, Temporality::NON_TEMPORAL>; } // namespace __llvm_libc #endif // LLVM_LIBC_SRC_STRING_MEMORY_UTILS_COMMON_H