| Haibo Huang | b9244ff | 2018-08-11 10:12:13 -0700 | [diff] [blame] | 1 | /* | 
|  | 2 | * Copyright (C) 2008 The Android Open Source Project | 
|  | 3 | * All rights reserved. | 
|  | 4 | * | 
|  | 5 | * Redistribution and use in source and binary forms, with or without | 
|  | 6 | * modification, are permitted provided that the following conditions | 
|  | 7 | * are met: | 
|  | 8 | *  * Redistributions of source code must retain the above copyright | 
|  | 9 | *    notice, this list of conditions and the following disclaimer. | 
|  | 10 | *  * Redistributions in binary form must reproduce the above copyright | 
|  | 11 | *    notice, this list of conditions and the following disclaimer in | 
|  | 12 | *    the documentation and/or other materials provided with the | 
|  | 13 | *    distribution. | 
|  | 14 | * | 
|  | 15 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS | 
|  | 16 | * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT | 
|  | 17 | * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS | 
|  | 18 | * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE | 
|  | 19 | * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, | 
|  | 20 | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | 
|  | 21 | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS | 
|  | 22 | * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | 
|  | 23 | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | 
|  | 24 | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT | 
|  | 25 | * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF | 
|  | 26 | * SUCH DAMAGE. | 
|  | 27 | */ | 
|  | 28 |  | 
|  | 29 | #include <stddef.h> | 
|  | 30 |  | 
|  | 31 | extern "C" { | 
|  | 32 |  | 
|  | 33 | struct __processor_model { | 
|  | 34 | unsigned int __cpu_vendor; | 
|  | 35 | unsigned int __cpu_type; | 
|  | 36 | unsigned int __cpu_subtype; | 
|  | 37 | unsigned int __cpu_features[1]; | 
|  | 38 | }; | 
|  | 39 |  | 
|  | 40 | __attribute__((visibility("hidden"))) | 
|  | 41 | extern struct __processor_model __cpu_model; | 
|  | 42 |  | 
|  | 43 | // These definitions have to match the values in | 
|  | 44 | // llvm/include/llvm/Support/X86TargetParser.def | 
|  | 45 | static constexpr int SSSE3  = 6; | 
|  | 46 | static constexpr int SSE4_1 = 7; | 
|  | 47 | static constexpr int ATOM   = 1; | 
|  | 48 |  | 
|  | 49 | // __builtin_cpu_supports and __builtin_cpu_is can not be used here. They | 
|  | 50 | // don't access __cpu_model directly but use GOT. | 
|  | 51 | // See https://reviews.llvm.org/D53850 | 
|  | 52 | static bool cpu_supports(unsigned int feature) { | 
|  | 53 | return (__cpu_model.__cpu_features[0] & (1U << feature)) != 0; | 
|  | 54 | } | 
|  | 55 |  | 
|  | 56 | static bool cpu_is(unsigned int type) { | 
|  | 57 | return (__cpu_model.__cpu_type == type); | 
|  | 58 | } | 
|  | 59 |  | 
|  | 60 | #define DEFINE_IFUNC_FOR(name) \ | 
|  | 61 | name##_func name __attribute__((ifunc(#name "_resolver"))); \ | 
|  | 62 | __attribute__((visibility("hidden"))) \ | 
|  | 63 | name##_func* name##_resolver() | 
|  | 64 |  | 
|  | 65 | #define DECLARE_FUNC(type, name) \ | 
|  | 66 | __attribute__((visibility("hidden"))) \ | 
|  | 67 | type name | 
|  | 68 |  | 
|  | 69 | #define RETURN_FUNC(type, name) { \ | 
|  | 70 | DECLARE_FUNC(type, name); \ | 
|  | 71 | return name; \ | 
|  | 72 | } | 
|  | 73 |  | 
|  | 74 | typedef int memcmp_func(const void* __lhs, const void* __rhs, size_t __n); | 
|  | 75 | DEFINE_IFUNC_FOR(memcmp) { | 
|  | 76 | __builtin_cpu_init(); | 
|  | 77 | if (cpu_is(ATOM)) RETURN_FUNC(memcmp_func, memcmp_atom); | 
|  | 78 | if (cpu_supports(SSE4_1)) RETURN_FUNC(memcmp_func, memcmp_sse4); | 
|  | 79 | RETURN_FUNC(memcmp_func, memcmp_generic); | 
|  | 80 | } | 
|  | 81 |  | 
|  | 82 | typedef void* memset_func(void* __dst, int __ch, size_t __n); | 
|  | 83 | DEFINE_IFUNC_FOR(memset) { | 
|  | 84 | __builtin_cpu_init(); | 
|  | 85 | if (cpu_is(ATOM)) RETURN_FUNC(memset_func, memset_atom); | 
|  | 86 | RETURN_FUNC(memset_func, memset_generic); | 
|  | 87 | } | 
|  | 88 |  | 
|  | 89 | typedef void* __memset_chk_func(void *s, int c, size_t n, size_t n2); | 
|  | 90 | DEFINE_IFUNC_FOR(__memset_chk) { | 
|  | 91 | __builtin_cpu_init(); | 
|  | 92 | if (cpu_is(ATOM)) RETURN_FUNC(__memset_chk_func, __memset_chk_atom); | 
|  | 93 | RETURN_FUNC(__memset_chk_func, __memset_chk_generic); | 
|  | 94 | } | 
|  | 95 |  | 
| Haibo Huang | b9244ff | 2018-08-11 10:12:13 -0700 | [diff] [blame] | 96 | typedef void* memmove_func(void* __dst, const void* __src, size_t __n); | 
|  | 97 | DEFINE_IFUNC_FOR(memmove) { | 
|  | 98 | __builtin_cpu_init(); | 
|  | 99 | if (cpu_is(ATOM)) RETURN_FUNC(memmove_func, memmove_atom); | 
|  | 100 | RETURN_FUNC(memmove_func, memmove_generic); | 
|  | 101 | } | 
|  | 102 |  | 
| Haibo Huang | e141362 | 2018-11-13 14:20:43 -0800 | [diff] [blame] | 103 | typedef void* memcpy_func(void*, const void*, size_t); | 
|  | 104 | DEFINE_IFUNC_FOR(memcpy) { | 
|  | 105 | return memmove_resolver(); | 
|  | 106 | } | 
|  | 107 |  | 
| Haibo Huang | b9244ff | 2018-08-11 10:12:13 -0700 | [diff] [blame] | 108 | typedef char* strcpy_func(char* __dst, const char* __src); | 
|  | 109 | DEFINE_IFUNC_FOR(strcpy) { | 
|  | 110 | __builtin_cpu_init(); | 
|  | 111 | if (cpu_is(ATOM)) RETURN_FUNC(strcpy_func, strcpy_atom); | 
|  | 112 | RETURN_FUNC(strcpy_func, strcpy_generic); | 
|  | 113 | } | 
|  | 114 |  | 
|  | 115 | typedef char* strncpy_func(char* __dst, const char* __src, size_t __n); | 
|  | 116 | DEFINE_IFUNC_FOR(strncpy) { | 
|  | 117 | __builtin_cpu_init(); | 
|  | 118 | if (cpu_is(ATOM)) RETURN_FUNC(strncpy_func, strncpy_atom); | 
|  | 119 | RETURN_FUNC(strncpy_func, strncpy_generic); | 
|  | 120 | } | 
|  | 121 |  | 
|  | 122 | typedef size_t strlen_func(const char* __s); | 
|  | 123 | DEFINE_IFUNC_FOR(strlen) { | 
|  | 124 | __builtin_cpu_init(); | 
|  | 125 | if (cpu_is(ATOM)) RETURN_FUNC(strlen_func, strlen_atom); | 
|  | 126 | RETURN_FUNC(strlen_func, strlen_generic); | 
|  | 127 | } | 
|  | 128 |  | 
|  | 129 | typedef int wmemcmp_func(const wchar_t* __lhs, const wchar_t* __rhs, size_t __n); | 
|  | 130 | DEFINE_IFUNC_FOR(wmemcmp) { | 
|  | 131 | __builtin_cpu_init(); | 
|  | 132 | if (cpu_supports(SSE4_1)) RETURN_FUNC(wmemcmp_func, wmemcmp_sse4); | 
|  | 133 | if (cpu_is(ATOM)) RETURN_FUNC(wmemcmp_func, wmemcmp_atom); | 
|  | 134 | RETURN_FUNC(wmemcmp_func, wmemcmp_freebsd); | 
|  | 135 | } | 
|  | 136 |  | 
|  | 137 | typedef int strcmp_func(const char* __lhs, const char* __rhs); | 
|  | 138 | DEFINE_IFUNC_FOR(strcmp) { | 
|  | 139 | __builtin_cpu_init(); | 
|  | 140 | if (cpu_supports(SSSE3)) RETURN_FUNC(strcmp_func, strcmp_ssse3); | 
|  | 141 | RETURN_FUNC(strcmp_func, strcmp_generic); | 
|  | 142 | } | 
|  | 143 |  | 
|  | 144 | typedef int strncmp_func(const char* __lhs, const char* __rhs, size_t __n); | 
|  | 145 | DEFINE_IFUNC_FOR(strncmp) { | 
|  | 146 | __builtin_cpu_init(); | 
|  | 147 | if (cpu_supports(SSSE3)) RETURN_FUNC(strncmp_func, strncmp_ssse3); | 
|  | 148 | RETURN_FUNC(strncmp_func, strncmp_generic); | 
|  | 149 | } | 
|  | 150 |  | 
|  | 151 | typedef char* strcat_func(char* __dst, const char* __src); | 
|  | 152 | DEFINE_IFUNC_FOR(strcat) { | 
|  | 153 | __builtin_cpu_init(); | 
|  | 154 | if (cpu_supports(SSSE3)) RETURN_FUNC(strcat_func, strcat_ssse3); | 
|  | 155 | RETURN_FUNC(strcat_func, strcat_generic); | 
|  | 156 | } | 
|  | 157 |  | 
|  | 158 | typedef char* strncat_func(char* __dst, const char* __src, size_t __n); | 
|  | 159 | DEFINE_IFUNC_FOR(strncat) { | 
|  | 160 | __builtin_cpu_init(); | 
|  | 161 | if (cpu_supports(SSSE3)) RETURN_FUNC(strncat_func, strncat_ssse3); | 
|  | 162 | RETURN_FUNC(strncat_func, strncat_openbsd); | 
|  | 163 | } | 
|  | 164 |  | 
|  | 165 | typedef size_t strlcat_func(char *dst, const char *src, size_t dsize); | 
|  | 166 | DEFINE_IFUNC_FOR(strlcat) { | 
|  | 167 | __builtin_cpu_init(); | 
|  | 168 | if (cpu_supports(SSSE3)) RETURN_FUNC(strlcat_func, strlcat_ssse3); | 
|  | 169 | RETURN_FUNC(strlcat_func, strlcat_openbsd); | 
|  | 170 | } | 
|  | 171 |  | 
|  | 172 | typedef size_t strlcpy_func(char *dst, const char *src, size_t dsize); | 
|  | 173 | DEFINE_IFUNC_FOR(strlcpy) { | 
|  | 174 | __builtin_cpu_init(); | 
|  | 175 | if (cpu_supports(SSSE3)) RETURN_FUNC(strlcpy_func, strlcpy_ssse3); | 
|  | 176 | RETURN_FUNC(strlcpy_func, strlcpy_openbsd); | 
|  | 177 | } | 
|  | 178 |  | 
|  | 179 | typedef wchar_t* wcscat_func(wchar_t *s1, const wchar_t *s2); | 
|  | 180 | DEFINE_IFUNC_FOR(wcscat) { | 
|  | 181 | __builtin_cpu_init(); | 
|  | 182 | if (cpu_supports(SSSE3)) RETURN_FUNC(wcscat_func, wcscat_ssse3); | 
|  | 183 | RETURN_FUNC(wcscat_func, wcscat_freebsd); | 
|  | 184 | } | 
|  | 185 |  | 
|  | 186 | typedef wchar_t* wcscpy_func(wchar_t *s1, const wchar_t *s2); | 
|  | 187 | DEFINE_IFUNC_FOR(wcscpy) { | 
|  | 188 | __builtin_cpu_init(); | 
|  | 189 | if (cpu_supports(SSSE3)) RETURN_FUNC(wcscpy_func, wcscpy_ssse3); | 
|  | 190 | RETURN_FUNC(wcscpy_func, wcscpy_freebsd); | 
|  | 191 | } | 
|  | 192 |  | 
|  | 193 | }  // extern "C" |