1*c8dee2aaSAndroid Build Coastguard Worker /*
2*c8dee2aaSAndroid Build Coastguard Worker * Copyright 2006 The Android Open Source Project
3*c8dee2aaSAndroid Build Coastguard Worker *
4*c8dee2aaSAndroid Build Coastguard Worker * Use of this source code is governed by a BSD-style license that can be
5*c8dee2aaSAndroid Build Coastguard Worker * found in the LICENSE file.
6*c8dee2aaSAndroid Build Coastguard Worker */
7*c8dee2aaSAndroid Build Coastguard Worker
8*c8dee2aaSAndroid Build Coastguard Worker #ifndef SkUtils_DEFINED
9*c8dee2aaSAndroid Build Coastguard Worker #define SkUtils_DEFINED
10*c8dee2aaSAndroid Build Coastguard Worker
11*c8dee2aaSAndroid Build Coastguard Worker #include "include/private/base/SkAttributes.h"
12*c8dee2aaSAndroid Build Coastguard Worker
13*c8dee2aaSAndroid Build Coastguard Worker #include <cstring>
14*c8dee2aaSAndroid Build Coastguard Worker #include <type_traits> // is_trivially_copyable
15*c8dee2aaSAndroid Build Coastguard Worker
16*c8dee2aaSAndroid Build Coastguard Worker namespace SkHexadecimalDigits {
17*c8dee2aaSAndroid Build Coastguard Worker extern const char gUpper[16]; // 0-9A-F
18*c8dee2aaSAndroid Build Coastguard Worker extern const char gLower[16]; // 0-9a-f
19*c8dee2aaSAndroid Build Coastguard Worker } // namespace SkHexadecimalDigits
20*c8dee2aaSAndroid Build Coastguard Worker
21*c8dee2aaSAndroid Build Coastguard Worker ///////////////////////////////////////////////////////////////////////////////
22*c8dee2aaSAndroid Build Coastguard Worker
23*c8dee2aaSAndroid Build Coastguard Worker // If T is an 8-byte GCC or Clang vector extension type, it would naturally pass or return in the
24*c8dee2aaSAndroid Build Coastguard Worker // MMX mm0 register on 32-bit x86 builds. This has the fun side effect of clobbering any state in
25*c8dee2aaSAndroid Build Coastguard Worker // the x87 st0 register. (There is no ABI governing who should preserve mm?/st? registers, so no
26*c8dee2aaSAndroid Build Coastguard Worker // one does!)
27*c8dee2aaSAndroid Build Coastguard Worker //
28*c8dee2aaSAndroid Build Coastguard Worker // We force-inline sk_unaligned_load() and sk_unaligned_store() to avoid that, making them safe to
29*c8dee2aaSAndroid Build Coastguard Worker // use for all types on all platforms, thus solving the problem once and for all!
30*c8dee2aaSAndroid Build Coastguard Worker
31*c8dee2aaSAndroid Build Coastguard Worker // A separate problem exists with 32-bit x86. The default calling convention returns values in
32*c8dee2aaSAndroid Build Coastguard Worker // ST0 (the x87 FPU). Unfortunately, doing so can mutate some bit patterns (signaling NaNs
33*c8dee2aaSAndroid Build Coastguard Worker // become quiet). If you're using these functions to pass data around as floats, but it's actually
34*c8dee2aaSAndroid Build Coastguard Worker // integers, that can be bad -- raster pipeline does this.
35*c8dee2aaSAndroid Build Coastguard Worker //
36*c8dee2aaSAndroid Build Coastguard Worker // With GCC and Clang, the always_inline attribute ensures we don't have a problem. MSVC, though,
37*c8dee2aaSAndroid Build Coastguard Worker // ignores __forceinline in debug builds, so the return-via-ST0 is always present. Switching to
38*c8dee2aaSAndroid Build Coastguard Worker // __vectorcall changes the functions to return in xmm0.
39*c8dee2aaSAndroid Build Coastguard Worker #if defined(_MSC_VER) && defined(_M_IX86)
40*c8dee2aaSAndroid Build Coastguard Worker #define SK_FP_SAFE_ABI __vectorcall
41*c8dee2aaSAndroid Build Coastguard Worker #else
42*c8dee2aaSAndroid Build Coastguard Worker #define SK_FP_SAFE_ABI
43*c8dee2aaSAndroid Build Coastguard Worker #endif
44*c8dee2aaSAndroid Build Coastguard Worker
45*c8dee2aaSAndroid Build Coastguard Worker template <typename T, typename P>
sk_unaligned_load(const P * ptr)46*c8dee2aaSAndroid Build Coastguard Worker static SK_ALWAYS_INLINE T SK_FP_SAFE_ABI sk_unaligned_load(const P* ptr) {
47*c8dee2aaSAndroid Build Coastguard Worker static_assert(std::is_trivially_copyable_v<P> || std::is_void_v<P>);
48*c8dee2aaSAndroid Build Coastguard Worker static_assert(std::is_trivially_copyable_v<T>);
49*c8dee2aaSAndroid Build Coastguard Worker T val;
50*c8dee2aaSAndroid Build Coastguard Worker // gcc's class-memaccess sometimes triggers when:
51*c8dee2aaSAndroid Build Coastguard Worker // - `T` is trivially copyable but
52*c8dee2aaSAndroid Build Coastguard Worker // - `T` is non-trivial (e.g. at least one eligible default constructor is
53*c8dee2aaSAndroid Build Coastguard Worker // non-trivial).
54*c8dee2aaSAndroid Build Coastguard Worker // Use `reinterpret_cast<const void*>` to explicit suppress this warning; a
55*c8dee2aaSAndroid Build Coastguard Worker // trivially copyable type is safe to memcpy from/to.
56*c8dee2aaSAndroid Build Coastguard Worker memcpy(&val, static_cast<const void*>(ptr), sizeof(val));
57*c8dee2aaSAndroid Build Coastguard Worker return val;
58*c8dee2aaSAndroid Build Coastguard Worker }
59*c8dee2aaSAndroid Build Coastguard Worker
60*c8dee2aaSAndroid Build Coastguard Worker template <typename T, typename P>
sk_unaligned_store(P * ptr,T val)61*c8dee2aaSAndroid Build Coastguard Worker static SK_ALWAYS_INLINE void SK_FP_SAFE_ABI sk_unaligned_store(P* ptr, T val) {
62*c8dee2aaSAndroid Build Coastguard Worker static_assert(std::is_trivially_copyable<T>::value);
63*c8dee2aaSAndroid Build Coastguard Worker memcpy(ptr, &val, sizeof(val));
64*c8dee2aaSAndroid Build Coastguard Worker }
65*c8dee2aaSAndroid Build Coastguard Worker
66*c8dee2aaSAndroid Build Coastguard Worker // Copy the bytes from src into an instance of type Dst and return it.
67*c8dee2aaSAndroid Build Coastguard Worker template <typename Dst, typename Src>
sk_bit_cast(const Src & src)68*c8dee2aaSAndroid Build Coastguard Worker static SK_ALWAYS_INLINE Dst SK_FP_SAFE_ABI sk_bit_cast(const Src& src) {
69*c8dee2aaSAndroid Build Coastguard Worker static_assert(sizeof(Dst) == sizeof(Src));
70*c8dee2aaSAndroid Build Coastguard Worker static_assert(std::is_trivially_copyable<Dst>::value);
71*c8dee2aaSAndroid Build Coastguard Worker static_assert(std::is_trivially_copyable<Src>::value);
72*c8dee2aaSAndroid Build Coastguard Worker return sk_unaligned_load<Dst>(&src);
73*c8dee2aaSAndroid Build Coastguard Worker }
74*c8dee2aaSAndroid Build Coastguard Worker
75*c8dee2aaSAndroid Build Coastguard Worker #undef SK_FP_SAFE_ABI
76*c8dee2aaSAndroid Build Coastguard Worker
77*c8dee2aaSAndroid Build Coastguard Worker #endif
78