#ifndef LLVM_LIBC_SRC_STRING_MEMORY_UTILS_SIZED_OP_H
#define LLVM_LIBC_SRC_STRING_MEMORY_UTILS_SIZED_OP_H
#include <stddef.h>
#ifndef LLVM_LIBC_USE_BUILTIN_MEMCPY_INLINE
#define LLVM_LIBC_USE_BUILTIN_MEMCPY_INLINE \
__has_builtin(__builtin_memcpy_inline)
#endif
#ifndef LLVM_LIBC_USE_BUILTIN_MEMSET_INLINE
#define LLVM_LIBC_USE_BUILTIN_MEMSET_INLINE \
__has_builtin(__builtin_memset_inline)
#endif
namespace __llvm_libc {
template <typename Backend, size_t Size> struct SizedOp {
static constexpr size_t SIZE = Size;
static constexpr bool IS_FIXED_SIZE = true;
private:
static_assert(Backend::IS_BACKEND_TYPE);
static_assert(SIZE > 0);
using type = typename Backend::template getNextType<Size>;
static constexpr size_t TYPE_SIZE = sizeof(type);
static_assert(SIZE >= TYPE_SIZE);
static constexpr size_t NEXT_SIZE = Size - TYPE_SIZE;
using NextBlock = SizedOp<Backend, NEXT_SIZE>;
template <typename T, typename AddrT> static constexpr Aligned isAligned() {
static_assert(IsAddressType<AddrT>::Value);
return AddrT::ALIGNMENT > 1 && AddrT::ALIGNMENT >= sizeof(T) ? Aligned::YES
: Aligned::NO;
}
template <typename SrcAddrT> static inline auto nativeLoad(SrcAddrT src) {
static_assert(IsAddressType<SrcAddrT>::Value && SrcAddrT::IS_READ);
constexpr auto AS = isAligned<type, SrcAddrT>();
constexpr auto TS = SrcAddrT::TEMPORALITY;
return Backend::template load<type, TS, AS>(as<const type>(src));
}
template <typename DstAddrT>
static inline void nativeStore(type value, DstAddrT dst) {
static_assert(IsAddressType<DstAddrT>::Value && DstAddrT::IS_WRITE);
constexpr auto AS = isAligned<type, DstAddrT>();
constexpr auto TS = DstAddrT::TEMPORALITY;
return Backend::template store<type, TS, AS>(as<type>(dst), value);
}
struct Value {
alignas(alignof(type)) ubyte payload[Size];
};
public:
template <typename DstAddrT, typename SrcAddrT>
static inline void copy(DstAddrT dst, SrcAddrT src) {
static_assert(IsAddressType<DstAddrT>::Value && DstAddrT::IS_WRITE);
static_assert(IsAddressType<SrcAddrT>::Value && SrcAddrT::IS_READ);
if constexpr (LLVM_LIBC_USE_BUILTIN_MEMCPY_INLINE &&
DstAddrT::TEMPORALITY == Temporality::TEMPORAL &&
SrcAddrT::TEMPORALITY == Temporality::TEMPORAL) {
__builtin_memcpy_inline(dst.ptr(), src.ptr(), Size);
return;
}
nativeStore(nativeLoad(src), dst);
if constexpr (NEXT_SIZE > 0)
NextBlock::copy(offsetAddr<TYPE_SIZE>(dst), offsetAddr<TYPE_SIZE>(src));
}
template <typename DstAddrT, typename SrcAddrT>
static inline void move(DstAddrT dst, SrcAddrT src) {
const auto payload = nativeLoad(src);
if constexpr (NEXT_SIZE > 0)
NextBlock::move(offsetAddr<TYPE_SIZE>(dst), offsetAddr<TYPE_SIZE>(src));
nativeStore(payload, dst);
}
template <typename DstAddrT>
static inline void set(DstAddrT dst, ubyte value) {
if constexpr (LLVM_LIBC_USE_BUILTIN_MEMSET_INLINE &&
DstAddrT::TEMPORALITY == Temporality::TEMPORAL) {
__builtin_memset_inline(dst.ptr(), static_cast<int>(value), Size);
return;
}
nativeStore(Backend::template splat<type>(value), dst);
if constexpr (NEXT_SIZE > 0)
NextBlock::set(offsetAddr<TYPE_SIZE>(dst), value);
}
template <typename SrcAddrT1, typename SrcAddrT2>
static inline uint64_t isDifferent(SrcAddrT1 src1, SrcAddrT2 src2) {
const uint64_t current =
Backend::template notEquals<type>(nativeLoad(src1), nativeLoad(src2));
if constexpr (NEXT_SIZE > 0) {
return current | (NextBlock::isDifferent(offsetAddr<TYPE_SIZE>(src1),
offsetAddr<TYPE_SIZE>(src2)));
} else {
return current;
}
}
template <typename SrcAddrT1, typename SrcAddrT2>
static inline int32_t threeWayCmp(SrcAddrT1 src1, SrcAddrT2 src2) {
const auto a = nativeLoad(src1);
const auto b = nativeLoad(src2);
if (int32_t res = Backend::template threeWayCmp<type>(a, b))
return res;
if constexpr (NEXT_SIZE > 0)
return NextBlock::threeWayCmp(offsetAddr<TYPE_SIZE>(src1),
offsetAddr<TYPE_SIZE>(src2));
return 0;
}
template <typename SrcAddrT> static Value load(SrcAddrT src) {
Value output;
copy(DstAddr<alignof(type)>(output.payload), src);
return output;
}
template <typename DstAddrT> static void store(DstAddrT dst, Value value) {
copy(dst, SrcAddr<alignof(type)>(value.payload));
}
};
}
#endif