asmjit 0.2.0 → 0.2.2

Sign up to get free protection for your applications and to get access to all the features.
Files changed (204) hide show
  1. checksums.yaml +4 -4
  2. data/Gemfile.lock +1 -1
  3. data/Rakefile +5 -3
  4. data/asmjit.gemspec +1 -3
  5. data/ext/asmjit/asmjit/.editorconfig +10 -0
  6. data/ext/asmjit/asmjit/.github/FUNDING.yml +1 -0
  7. data/ext/asmjit/asmjit/.github/workflows/build-config.json +47 -0
  8. data/ext/asmjit/asmjit/.github/workflows/build.yml +156 -0
  9. data/ext/asmjit/asmjit/.gitignore +6 -0
  10. data/ext/asmjit/asmjit/CMakeLists.txt +611 -0
  11. data/ext/asmjit/asmjit/LICENSE.md +17 -0
  12. data/ext/asmjit/asmjit/README.md +69 -0
  13. data/ext/asmjit/asmjit/src/asmjit/a64.h +62 -0
  14. data/ext/asmjit/asmjit/src/asmjit/arm/a64archtraits_p.h +81 -0
  15. data/ext/asmjit/asmjit/src/asmjit/arm/a64assembler.cpp +5115 -0
  16. data/ext/asmjit/asmjit/src/asmjit/arm/a64assembler.h +72 -0
  17. data/ext/asmjit/asmjit/src/asmjit/arm/a64builder.cpp +51 -0
  18. data/ext/asmjit/asmjit/src/asmjit/arm/a64builder.h +57 -0
  19. data/ext/asmjit/asmjit/src/asmjit/arm/a64compiler.cpp +60 -0
  20. data/ext/asmjit/asmjit/src/asmjit/arm/a64compiler.h +247 -0
  21. data/ext/asmjit/asmjit/src/asmjit/arm/a64emithelper.cpp +464 -0
  22. data/ext/asmjit/asmjit/src/asmjit/arm/a64emithelper_p.h +50 -0
  23. data/ext/asmjit/asmjit/src/asmjit/arm/a64emitter.h +1228 -0
  24. data/ext/asmjit/asmjit/src/asmjit/arm/a64formatter.cpp +298 -0
  25. data/ext/asmjit/asmjit/src/asmjit/arm/a64formatter_p.h +59 -0
  26. data/ext/asmjit/asmjit/src/asmjit/arm/a64func.cpp +189 -0
  27. data/ext/asmjit/asmjit/src/asmjit/arm/a64func_p.h +33 -0
  28. data/ext/asmjit/asmjit/src/asmjit/arm/a64globals.h +1894 -0
  29. data/ext/asmjit/asmjit/src/asmjit/arm/a64instapi.cpp +278 -0
  30. data/ext/asmjit/asmjit/src/asmjit/arm/a64instapi_p.h +41 -0
  31. data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb.cpp +1957 -0
  32. data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb.h +74 -0
  33. data/ext/asmjit/asmjit/src/asmjit/arm/a64instdb_p.h +876 -0
  34. data/ext/asmjit/asmjit/src/asmjit/arm/a64operand.cpp +85 -0
  35. data/ext/asmjit/asmjit/src/asmjit/arm/a64operand.h +312 -0
  36. data/ext/asmjit/asmjit/src/asmjit/arm/a64rapass.cpp +852 -0
  37. data/ext/asmjit/asmjit/src/asmjit/arm/a64rapass_p.h +105 -0
  38. data/ext/asmjit/asmjit/src/asmjit/arm/a64utils.h +179 -0
  39. data/ext/asmjit/asmjit/src/asmjit/arm/armformatter.cpp +143 -0
  40. data/ext/asmjit/asmjit/src/asmjit/arm/armformatter_p.h +44 -0
  41. data/ext/asmjit/asmjit/src/asmjit/arm/armglobals.h +21 -0
  42. data/ext/asmjit/asmjit/src/asmjit/arm/armoperand.h +621 -0
  43. data/ext/asmjit/asmjit/src/asmjit/arm.h +62 -0
  44. data/ext/asmjit/asmjit/src/asmjit/asmjit-scope-begin.h +17 -0
  45. data/ext/asmjit/asmjit/src/asmjit/asmjit-scope-end.h +9 -0
  46. data/ext/asmjit/asmjit/src/asmjit/asmjit.h +33 -0
  47. data/ext/asmjit/asmjit/src/asmjit/core/api-build_p.h +55 -0
  48. data/ext/asmjit/asmjit/src/asmjit/core/api-config.h +613 -0
  49. data/ext/asmjit/asmjit/src/asmjit/core/archcommons.h +229 -0
  50. data/ext/asmjit/asmjit/src/asmjit/core/archtraits.cpp +160 -0
  51. data/ext/asmjit/asmjit/src/asmjit/core/archtraits.h +290 -0
  52. data/ext/asmjit/asmjit/src/asmjit/core/assembler.cpp +406 -0
  53. data/ext/asmjit/asmjit/src/asmjit/core/assembler.h +129 -0
  54. data/ext/asmjit/asmjit/src/asmjit/core/builder.cpp +889 -0
  55. data/ext/asmjit/asmjit/src/asmjit/core/builder.h +1391 -0
  56. data/ext/asmjit/asmjit/src/asmjit/core/codebuffer.h +113 -0
  57. data/ext/asmjit/asmjit/src/asmjit/core/codeholder.cpp +1149 -0
  58. data/ext/asmjit/asmjit/src/asmjit/core/codeholder.h +1035 -0
  59. data/ext/asmjit/asmjit/src/asmjit/core/codewriter.cpp +175 -0
  60. data/ext/asmjit/asmjit/src/asmjit/core/codewriter_p.h +179 -0
  61. data/ext/asmjit/asmjit/src/asmjit/core/compiler.cpp +582 -0
  62. data/ext/asmjit/asmjit/src/asmjit/core/compiler.h +737 -0
  63. data/ext/asmjit/asmjit/src/asmjit/core/compilerdefs.h +173 -0
  64. data/ext/asmjit/asmjit/src/asmjit/core/constpool.cpp +363 -0
  65. data/ext/asmjit/asmjit/src/asmjit/core/constpool.h +250 -0
  66. data/ext/asmjit/asmjit/src/asmjit/core/cpuinfo.cpp +1162 -0
  67. data/ext/asmjit/asmjit/src/asmjit/core/cpuinfo.h +813 -0
  68. data/ext/asmjit/asmjit/src/asmjit/core/emithelper.cpp +323 -0
  69. data/ext/asmjit/asmjit/src/asmjit/core/emithelper_p.h +58 -0
  70. data/ext/asmjit/asmjit/src/asmjit/core/emitter.cpp +333 -0
  71. data/ext/asmjit/asmjit/src/asmjit/core/emitter.h +741 -0
  72. data/ext/asmjit/asmjit/src/asmjit/core/emitterutils.cpp +129 -0
  73. data/ext/asmjit/asmjit/src/asmjit/core/emitterutils_p.h +89 -0
  74. data/ext/asmjit/asmjit/src/asmjit/core/environment.cpp +46 -0
  75. data/ext/asmjit/asmjit/src/asmjit/core/environment.h +508 -0
  76. data/ext/asmjit/asmjit/src/asmjit/core/errorhandler.cpp +14 -0
  77. data/ext/asmjit/asmjit/src/asmjit/core/errorhandler.h +228 -0
  78. data/ext/asmjit/asmjit/src/asmjit/core/formatter.cpp +584 -0
  79. data/ext/asmjit/asmjit/src/asmjit/core/formatter.h +247 -0
  80. data/ext/asmjit/asmjit/src/asmjit/core/formatter_p.h +34 -0
  81. data/ext/asmjit/asmjit/src/asmjit/core/func.cpp +286 -0
  82. data/ext/asmjit/asmjit/src/asmjit/core/func.h +1445 -0
  83. data/ext/asmjit/asmjit/src/asmjit/core/funcargscontext.cpp +293 -0
  84. data/ext/asmjit/asmjit/src/asmjit/core/funcargscontext_p.h +199 -0
  85. data/ext/asmjit/asmjit/src/asmjit/core/globals.cpp +133 -0
  86. data/ext/asmjit/asmjit/src/asmjit/core/globals.h +393 -0
  87. data/ext/asmjit/asmjit/src/asmjit/core/inst.cpp +113 -0
  88. data/ext/asmjit/asmjit/src/asmjit/core/inst.h +772 -0
  89. data/ext/asmjit/asmjit/src/asmjit/core/jitallocator.cpp +1242 -0
  90. data/ext/asmjit/asmjit/src/asmjit/core/jitallocator.h +261 -0
  91. data/ext/asmjit/asmjit/src/asmjit/core/jitruntime.cpp +80 -0
  92. data/ext/asmjit/asmjit/src/asmjit/core/jitruntime.h +89 -0
  93. data/ext/asmjit/asmjit/src/asmjit/core/logger.cpp +69 -0
  94. data/ext/asmjit/asmjit/src/asmjit/core/logger.h +198 -0
  95. data/ext/asmjit/asmjit/src/asmjit/core/misc_p.h +33 -0
  96. data/ext/asmjit/asmjit/src/asmjit/core/operand.cpp +132 -0
  97. data/ext/asmjit/asmjit/src/asmjit/core/operand.h +1611 -0
  98. data/ext/asmjit/asmjit/src/asmjit/core/osutils.cpp +84 -0
  99. data/ext/asmjit/asmjit/src/asmjit/core/osutils.h +61 -0
  100. data/ext/asmjit/asmjit/src/asmjit/core/osutils_p.h +68 -0
  101. data/ext/asmjit/asmjit/src/asmjit/core/raassignment_p.h +418 -0
  102. data/ext/asmjit/asmjit/src/asmjit/core/rabuilders_p.h +612 -0
  103. data/ext/asmjit/asmjit/src/asmjit/core/radefs_p.h +1204 -0
  104. data/ext/asmjit/asmjit/src/asmjit/core/ralocal.cpp +1166 -0
  105. data/ext/asmjit/asmjit/src/asmjit/core/ralocal_p.h +254 -0
  106. data/ext/asmjit/asmjit/src/asmjit/core/rapass.cpp +1969 -0
  107. data/ext/asmjit/asmjit/src/asmjit/core/rapass_p.h +1183 -0
  108. data/ext/asmjit/asmjit/src/asmjit/core/rastack.cpp +184 -0
  109. data/ext/asmjit/asmjit/src/asmjit/core/rastack_p.h +171 -0
  110. data/ext/asmjit/asmjit/src/asmjit/core/string.cpp +559 -0
  111. data/ext/asmjit/asmjit/src/asmjit/core/string.h +372 -0
  112. data/ext/asmjit/asmjit/src/asmjit/core/support.cpp +494 -0
  113. data/ext/asmjit/asmjit/src/asmjit/core/support.h +1773 -0
  114. data/ext/asmjit/asmjit/src/asmjit/core/target.cpp +14 -0
  115. data/ext/asmjit/asmjit/src/asmjit/core/target.h +53 -0
  116. data/ext/asmjit/asmjit/src/asmjit/core/type.cpp +74 -0
  117. data/ext/asmjit/asmjit/src/asmjit/core/type.h +419 -0
  118. data/ext/asmjit/asmjit/src/asmjit/core/virtmem.cpp +722 -0
  119. data/ext/asmjit/asmjit/src/asmjit/core/virtmem.h +242 -0
  120. data/ext/asmjit/asmjit/src/asmjit/core/zone.cpp +353 -0
  121. data/ext/asmjit/asmjit/src/asmjit/core/zone.h +615 -0
  122. data/ext/asmjit/asmjit/src/asmjit/core/zonehash.cpp +309 -0
  123. data/ext/asmjit/asmjit/src/asmjit/core/zonehash.h +186 -0
  124. data/ext/asmjit/asmjit/src/asmjit/core/zonelist.cpp +163 -0
  125. data/ext/asmjit/asmjit/src/asmjit/core/zonelist.h +209 -0
  126. data/ext/asmjit/asmjit/src/asmjit/core/zonestack.cpp +176 -0
  127. data/ext/asmjit/asmjit/src/asmjit/core/zonestack.h +239 -0
  128. data/ext/asmjit/asmjit/src/asmjit/core/zonestring.h +120 -0
  129. data/ext/asmjit/asmjit/src/asmjit/core/zonetree.cpp +99 -0
  130. data/ext/asmjit/asmjit/src/asmjit/core/zonetree.h +380 -0
  131. data/ext/asmjit/asmjit/src/asmjit/core/zonevector.cpp +356 -0
  132. data/ext/asmjit/asmjit/src/asmjit/core/zonevector.h +690 -0
  133. data/ext/asmjit/asmjit/src/asmjit/core.h +1861 -0
  134. data/ext/asmjit/asmjit/src/asmjit/x86/x86archtraits_p.h +148 -0
  135. data/ext/asmjit/asmjit/src/asmjit/x86/x86assembler.cpp +5110 -0
  136. data/ext/asmjit/asmjit/src/asmjit/x86/x86assembler.h +685 -0
  137. data/ext/asmjit/asmjit/src/asmjit/x86/x86builder.cpp +52 -0
  138. data/ext/asmjit/asmjit/src/asmjit/x86/x86builder.h +351 -0
  139. data/ext/asmjit/asmjit/src/asmjit/x86/x86compiler.cpp +61 -0
  140. data/ext/asmjit/asmjit/src/asmjit/x86/x86compiler.h +721 -0
  141. data/ext/asmjit/asmjit/src/asmjit/x86/x86emithelper.cpp +619 -0
  142. data/ext/asmjit/asmjit/src/asmjit/x86/x86emithelper_p.h +60 -0
  143. data/ext/asmjit/asmjit/src/asmjit/x86/x86emitter.h +4315 -0
  144. data/ext/asmjit/asmjit/src/asmjit/x86/x86formatter.cpp +944 -0
  145. data/ext/asmjit/asmjit/src/asmjit/x86/x86formatter_p.h +58 -0
  146. data/ext/asmjit/asmjit/src/asmjit/x86/x86func.cpp +503 -0
  147. data/ext/asmjit/asmjit/src/asmjit/x86/x86func_p.h +33 -0
  148. data/ext/asmjit/asmjit/src/asmjit/x86/x86globals.h +2169 -0
  149. data/ext/asmjit/asmjit/src/asmjit/x86/x86instapi.cpp +1732 -0
  150. data/ext/asmjit/asmjit/src/asmjit/x86/x86instapi_p.h +41 -0
  151. data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb.cpp +4427 -0
  152. data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb.h +563 -0
  153. data/ext/asmjit/asmjit/src/asmjit/x86/x86instdb_p.h +311 -0
  154. data/ext/asmjit/asmjit/src/asmjit/x86/x86opcode_p.h +436 -0
  155. data/ext/asmjit/asmjit/src/asmjit/x86/x86operand.cpp +231 -0
  156. data/ext/asmjit/asmjit/src/asmjit/x86/x86operand.h +1085 -0
  157. data/ext/asmjit/asmjit/src/asmjit/x86/x86rapass.cpp +1509 -0
  158. data/ext/asmjit/asmjit/src/asmjit/x86/x86rapass_p.h +94 -0
  159. data/ext/asmjit/asmjit/src/asmjit/x86.h +93 -0
  160. data/ext/asmjit/asmjit/src/asmjit.natvis +245 -0
  161. data/ext/asmjit/asmjit/test/asmjit_test_assembler.cpp +84 -0
  162. data/ext/asmjit/asmjit/test/asmjit_test_assembler.h +85 -0
  163. data/ext/asmjit/asmjit/test/asmjit_test_assembler_a64.cpp +4006 -0
  164. data/ext/asmjit/asmjit/test/asmjit_test_assembler_x64.cpp +17833 -0
  165. data/ext/asmjit/asmjit/test/asmjit_test_assembler_x86.cpp +8300 -0
  166. data/ext/asmjit/asmjit/test/asmjit_test_compiler.cpp +253 -0
  167. data/ext/asmjit/asmjit/test/asmjit_test_compiler.h +73 -0
  168. data/ext/asmjit/asmjit/test/asmjit_test_compiler_a64.cpp +690 -0
  169. data/ext/asmjit/asmjit/test/asmjit_test_compiler_x86.cpp +4317 -0
  170. data/ext/asmjit/asmjit/test/asmjit_test_emitters.cpp +197 -0
  171. data/ext/asmjit/asmjit/test/asmjit_test_instinfo.cpp +181 -0
  172. data/ext/asmjit/asmjit/test/asmjit_test_misc.h +257 -0
  173. data/ext/asmjit/asmjit/test/asmjit_test_perf.cpp +62 -0
  174. data/ext/asmjit/asmjit/test/asmjit_test_perf.h +61 -0
  175. data/ext/asmjit/asmjit/test/asmjit_test_perf_a64.cpp +699 -0
  176. data/ext/asmjit/asmjit/test/asmjit_test_perf_x86.cpp +5032 -0
  177. data/ext/asmjit/asmjit/test/asmjit_test_unit.cpp +172 -0
  178. data/ext/asmjit/asmjit/test/asmjit_test_x86_sections.cpp +172 -0
  179. data/ext/asmjit/asmjit/test/asmjitutils.h +38 -0
  180. data/ext/asmjit/asmjit/test/broken.cpp +312 -0
  181. data/ext/asmjit/asmjit/test/broken.h +148 -0
  182. data/ext/asmjit/asmjit/test/cmdline.h +61 -0
  183. data/ext/asmjit/asmjit/test/performancetimer.h +41 -0
  184. data/ext/asmjit/asmjit/tools/configure-makefiles.sh +13 -0
  185. data/ext/asmjit/asmjit/tools/configure-ninja.sh +13 -0
  186. data/ext/asmjit/asmjit/tools/configure-sanitizers.sh +13 -0
  187. data/ext/asmjit/asmjit/tools/configure-vs2019-x64.bat +2 -0
  188. data/ext/asmjit/asmjit/tools/configure-vs2019-x86.bat +2 -0
  189. data/ext/asmjit/asmjit/tools/configure-vs2022-x64.bat +2 -0
  190. data/ext/asmjit/asmjit/tools/configure-vs2022-x86.bat +2 -0
  191. data/ext/asmjit/asmjit/tools/configure-xcode.sh +8 -0
  192. data/ext/asmjit/asmjit/tools/enumgen.js +417 -0
  193. data/ext/asmjit/asmjit/tools/enumgen.sh +3 -0
  194. data/ext/asmjit/asmjit/tools/tablegen-arm.js +365 -0
  195. data/ext/asmjit/asmjit/tools/tablegen-arm.sh +3 -0
  196. data/ext/asmjit/asmjit/tools/tablegen-x86.js +2638 -0
  197. data/ext/asmjit/asmjit/tools/tablegen-x86.sh +3 -0
  198. data/ext/asmjit/asmjit/tools/tablegen.js +947 -0
  199. data/ext/asmjit/asmjit/tools/tablegen.sh +4 -0
  200. data/ext/asmjit/asmjit.cc +167 -30
  201. data/ext/asmjit/extconf.rb +9 -9
  202. data/lib/asmjit/version.rb +1 -1
  203. data/lib/asmjit.rb +14 -4
  204. metadata +198 -17
@@ -0,0 +1,1773 @@
1
+ // This file is part of AsmJit project <https://asmjit.com>
2
+ //
3
+ // See asmjit.h or LICENSE.md for license and copyright information
4
+ // SPDX-License-Identifier: Zlib
5
+
6
+ #ifndef ASMJIT_CORE_SUPPORT_H_INCLUDED
7
+ #define ASMJIT_CORE_SUPPORT_H_INCLUDED
8
+
9
+ #include "../core/globals.h"
10
+
11
+ #if defined(_MSC_VER)
12
+ #include <intrin.h>
13
+ #endif
14
+
15
+ ASMJIT_BEGIN_NAMESPACE
16
+
17
+ //! \addtogroup asmjit_utilities
18
+ //! \{
19
+
20
+ //! Contains support classes and functions that may be used by AsmJit source and header files. Anything defined
21
+ //! here is considered internal and should not be used outside of AsmJit and related projects like AsmTK.
22
+ namespace Support {
23
+
24
+ // Support - Basic Traits
25
+ // ======================
26
+
27
+ #if ASMJIT_ARCH_X86
28
+ typedef uint8_t FastUInt8;
29
+ #else
30
+ typedef uint32_t FastUInt8;
31
+ #endif
32
+
33
+ //! \cond INTERNAL
34
+ namespace Internal {
35
+ template<typename T, size_t Alignment>
36
+ struct AliasedUInt {};
37
+
38
+ template<> struct AliasedUInt<uint16_t, 2> { typedef uint16_t ASMJIT_MAY_ALIAS T; };
39
+ template<> struct AliasedUInt<uint32_t, 4> { typedef uint32_t ASMJIT_MAY_ALIAS T; };
40
+ template<> struct AliasedUInt<uint64_t, 8> { typedef uint64_t ASMJIT_MAY_ALIAS T; };
41
+
42
+ template<> struct AliasedUInt<uint16_t, 1> { typedef uint16_t ASMJIT_MAY_ALIAS ASMJIT_ALIGN_TYPE(T, 1); };
43
+ template<> struct AliasedUInt<uint32_t, 1> { typedef uint32_t ASMJIT_MAY_ALIAS ASMJIT_ALIGN_TYPE(T, 1); };
44
+ template<> struct AliasedUInt<uint32_t, 2> { typedef uint32_t ASMJIT_MAY_ALIAS ASMJIT_ALIGN_TYPE(T, 2); };
45
+ template<> struct AliasedUInt<uint64_t, 1> { typedef uint64_t ASMJIT_MAY_ALIAS ASMJIT_ALIGN_TYPE(T, 1); };
46
+ template<> struct AliasedUInt<uint64_t, 2> { typedef uint64_t ASMJIT_MAY_ALIAS ASMJIT_ALIGN_TYPE(T, 2); };
47
+ template<> struct AliasedUInt<uint64_t, 4> { typedef uint64_t ASMJIT_MAY_ALIAS ASMJIT_ALIGN_TYPE(T, 4); };
48
+
49
+ // StdInt - Make an int-type by size (signed or unsigned) that is the
50
+ // same as types defined by <stdint.h>.
51
+ // Int32Or64 - Make an int-type that has at least 32 bits: [u]int[32|64]_t.
52
+
53
+ template<size_t Size, unsigned Unsigned>
54
+ struct StdInt {}; // Fail if not specialized.
55
+
56
+ template<> struct StdInt<1, 0> { typedef int8_t Type; };
57
+ template<> struct StdInt<1, 1> { typedef uint8_t Type; };
58
+ template<> struct StdInt<2, 0> { typedef int16_t Type; };
59
+ template<> struct StdInt<2, 1> { typedef uint16_t Type; };
60
+ template<> struct StdInt<4, 0> { typedef int32_t Type; };
61
+ template<> struct StdInt<4, 1> { typedef uint32_t Type; };
62
+ template<> struct StdInt<8, 0> { typedef int64_t Type; };
63
+ template<> struct StdInt<8, 1> { typedef uint64_t Type; };
64
+
65
+ template<typename T, int Unsigned = std::is_unsigned<T>::value>
66
+ struct Int32Or64 : public StdInt<sizeof(T) <= 4 ? size_t(4) : sizeof(T), Unsigned> {};
67
+ }
68
+ //! \endcond
69
+
70
+ template<typename T>
71
+ static constexpr bool isUnsigned() noexcept { return std::is_unsigned<T>::value; }
72
+
73
+ //! Casts an integer `x` to either `int32_t` or `int64_t` depending on `T`.
74
+ template<typename T>
75
+ static constexpr typename Internal::Int32Or64<T, 0>::Type asInt(const T& x) noexcept {
76
+ return (typename Internal::Int32Or64<T, 0>::Type)x;
77
+ }
78
+
79
+ //! Casts an integer `x` to either `uint32_t` or `uint64_t` depending on `T`.
80
+ template<typename T>
81
+ static constexpr typename Internal::Int32Or64<T, 1>::Type asUInt(const T& x) noexcept {
82
+ return (typename Internal::Int32Or64<T, 1>::Type)x;
83
+ }
84
+
85
+ //! Casts an integer `x` to either `int32_t`, uint32_t`, `int64_t`, or `uint64_t` depending on `T`.
86
+ template<typename T>
87
+ static constexpr typename Internal::Int32Or64<T>::Type asNormalized(const T& x) noexcept {
88
+ return (typename Internal::Int32Or64<T>::Type)x;
89
+ }
90
+
91
+ //! Casts an integer `x` to the same type as defined by `<stdint.h>`.
92
+ template<typename T>
93
+ static constexpr typename Internal::StdInt<sizeof(T), isUnsigned<T>()>::Type asStdInt(const T& x) noexcept {
94
+ return (typename Internal::StdInt<sizeof(T), isUnsigned<T>()>::Type)x;
95
+ }
96
+
97
+ //! A helper class that can be used to iterate over enum values.
98
+ template<typename T, T from = (T)0, T to = T::kMaxValue>
99
+ struct EnumValues {
100
+ typedef typename std::underlying_type<T>::type ValueType;
101
+
102
+ struct Iterator {
103
+ ValueType value;
104
+
105
+ inline T operator*() const { return (T)value; }
106
+ inline void operator++() { ++value; }
107
+
108
+ inline bool operator==(const Iterator& other) const noexcept { return value == other.value; }
109
+ inline bool operator!=(const Iterator& other) const noexcept { return value != other.value; }
110
+ };
111
+
112
+ inline Iterator begin() const noexcept { return Iterator{ValueType(from)}; }
113
+ inline Iterator end() const noexcept { return Iterator{ValueType(to) + 1}; }
114
+ };
115
+
116
+ // Support - BitCast
117
+ // =================
118
+
119
+ //! \cond
120
+ namespace Internal {
121
+ template<typename DstT, typename SrcT>
122
+ union BitCastUnion {
123
+ inline BitCastUnion(SrcT src) noexcept : src(src) {}
124
+ SrcT src;
125
+ DstT dst;
126
+ };
127
+ }
128
+ //! \endcond
129
+
130
+ //! Bit-casts from `Src` type to `Dst` type.
131
+ //!
132
+ //! Useful to bit-cast between integers and floating points.
133
+ template<typename Dst, typename Src>
134
+ static inline Dst bitCast(const Src& x) noexcept { return Internal::BitCastUnion<Dst, Src>(x).dst; }
135
+
136
+ // Support - BitOps
137
+ // ================
138
+
139
+ //! Storage used to store a pack of bits (should by compatible with a machine word).
140
+ typedef Internal::StdInt<sizeof(uintptr_t), 1>::Type BitWord;
141
+
142
+ template<typename T>
143
+ static constexpr uint32_t bitSizeOf() noexcept { return uint32_t(sizeof(T) * 8u); }
144
+
145
+ //! Number of bits stored in a single `BitWord`.
146
+ static constexpr uint32_t kBitWordSizeInBits = bitSizeOf<BitWord>();
147
+
148
+ //! Returns `0 - x` in a safe way (no undefined behavior), works for unsigned numbers as well.
149
+ template<typename T>
150
+ static constexpr T neg(const T& x) noexcept {
151
+ typedef typename std::make_unsigned<T>::type U;
152
+ return T(U(0) - U(x));
153
+ }
154
+
155
+ template<typename T>
156
+ static constexpr T allOnes() noexcept { return neg<T>(T(1)); }
157
+
158
+ //! Returns `x << y` (shift left logical) by explicitly casting `x` to an unsigned type and back.
159
+ template<typename X, typename Y>
160
+ static constexpr X shl(const X& x, const Y& y) noexcept {
161
+ typedef typename std::make_unsigned<X>::type U;
162
+ return X(U(x) << y);
163
+ }
164
+
165
+ //! Returns `x >> y` (shift right logical) by explicitly casting `x` to an unsigned type and back.
166
+ template<typename X, typename Y>
167
+ static constexpr X shr(const X& x, const Y& y) noexcept {
168
+ typedef typename std::make_unsigned<X>::type U;
169
+ return X(U(x) >> y);
170
+ }
171
+
172
+ //! Returns `x >> y` (shift right arithmetic) by explicitly casting `x` to a signed type and back.
173
+ template<typename X, typename Y>
174
+ static constexpr X sar(const X& x, const Y& y) noexcept {
175
+ typedef typename std::make_signed<X>::type S;
176
+ return X(S(x) >> y);
177
+ }
178
+
179
+ template<typename X, typename Y>
180
+ static constexpr X ror(const X& x, const Y& y) noexcept {
181
+ typedef typename std::make_unsigned<X>::type U;
182
+ return X((U(x) >> y) | (U(x) << (bitSizeOf<U>() - y)));
183
+ }
184
+
185
+ //! Returns `x | (x >> y)` - helper used by some bit manipulation helpers.
186
+ template<typename X, typename Y>
187
+ static constexpr X or_shr(const X& x, const Y& y) noexcept { return X(x | shr(x, y)); }
188
+
189
+ //! Returns `x & -x` - extracts lowest set isolated bit (like BLSI instruction).
190
+ template<typename T>
191
+ static constexpr T blsi(T x) noexcept {
192
+ typedef typename std::make_unsigned<T>::type U;
193
+ return T(U(x) & neg(U(x)));
194
+ }
195
+
196
+ //! Tests whether the given value `x` has `n`th bit set.
197
+ template<typename T, typename IndexT>
198
+ static constexpr bool bitTest(T x, IndexT n) noexcept {
199
+ typedef typename std::make_unsigned<T>::type U;
200
+ return (U(x) & (U(1) << asStdInt(n))) != 0;
201
+ }
202
+
203
+ // Tests whether the given `value` is a consecutive mask of bits that starts at
204
+ // the least significant bit.
205
+ template<typename T>
206
+ static inline constexpr bool isLsbMask(const T& value) {
207
+ typedef typename std::make_unsigned<T>::type U;
208
+ return value && ((U(value) + 1u) & U(value)) == 0;
209
+ }
210
+
211
+ // Tests whether the given value contains at least one bit or whether it's a
212
+ // bit-mask of consecutive bits.
213
+ //
214
+ // This function is similar to \ref isLsbMask(), but the mask doesn't have to
215
+ // start at a least significant bit.
216
+ template<typename T>
217
+ static inline constexpr bool isConsecutiveMask(const T& value) {
218
+ typedef typename std::make_unsigned<T>::type U;
219
+ return value && isLsbMask((U(value) - 1u) | U(value));
220
+ }
221
+
222
+ //! Generates a trailing bit-mask that has `n` least significant (trailing) bits set.
223
+ template<typename T, typename CountT>
224
+ static constexpr T lsbMask(const CountT& n) noexcept {
225
+ typedef typename std::make_unsigned<T>::type U;
226
+ return (sizeof(U) < sizeof(uintptr_t))
227
+ // Prevent undefined behavior by using a larger type than T.
228
+ ? T(U((uintptr_t(1) << n) - uintptr_t(1)))
229
+ // Prevent undefined behavior by checking `n` before shift.
230
+ : n ? T(shr(allOnes<T>(), bitSizeOf<T>() - size_t(n))) : T(0);
231
+ }
232
+
233
+ //! Generats a leading bit-mask that has `n` most significant (leading) bits set.
234
+ template<typename T, typename CountT>
235
+ static constexpr T msbMask(const CountT& n) noexcept {
236
+ typedef typename std::make_unsigned<T>::type U;
237
+ return (sizeof(U) < sizeof(uintptr_t))
238
+ // Prevent undefined behavior by using a larger type than T.
239
+ ? T(allOnes<uintptr_t>() >> (bitSizeOf<uintptr_t>() - n))
240
+ // Prevent undefined behavior by performing `n & (nBits - 1)` so it's always within the range.
241
+ : T(sar(U(n != 0) << (bitSizeOf<U>() - 1), n ? uint32_t(n - 1) : uint32_t(0)));
242
+ }
243
+
244
+ //! Returns a bit-mask that has `x` bit set.
245
+ template<typename Index>
246
+ static constexpr uint32_t bitMask(const Index& x) noexcept { return (1u << asUInt(x)); }
247
+
248
+ //! Returns a bit-mask that has `x` bit set (multiple arguments).
249
+ template<typename Index, typename... Args>
250
+ static constexpr uint32_t bitMask(const Index& x, Args... args) noexcept { return bitMask(x) | bitMask(args...); }
251
+
252
+ //! Converts a boolean value `b` to zero or full mask (all bits set).
253
+ template<typename DstT, typename SrcT>
254
+ static constexpr DstT bitMaskFromBool(SrcT b) noexcept {
255
+ typedef typename std::make_unsigned<DstT>::type U;
256
+ return DstT(U(0) - U(b));
257
+ }
258
+
259
+ //! Tests whether `a & b` is non-zero.
260
+ template<typename A, typename B>
261
+ static inline constexpr bool test(A a, B b) noexcept { return (asUInt(a) & asUInt(b)) != 0; }
262
+
263
+ //! \cond
264
+ namespace Internal {
265
+ // Fills all trailing bits right from the first most significant bit set.
266
+ static constexpr uint8_t fillTrailingBitsImpl(uint8_t x) noexcept { return or_shr(or_shr(or_shr(x, 1), 2), 4); }
267
+ // Fills all trailing bits right from the first most significant bit set.
268
+ static constexpr uint16_t fillTrailingBitsImpl(uint16_t x) noexcept { return or_shr(or_shr(or_shr(or_shr(x, 1), 2), 4), 8); }
269
+ // Fills all trailing bits right from the first most significant bit set.
270
+ static constexpr uint32_t fillTrailingBitsImpl(uint32_t x) noexcept { return or_shr(or_shr(or_shr(or_shr(or_shr(x, 1), 2), 4), 8), 16); }
271
+ // Fills all trailing bits right from the first most significant bit set.
272
+ static constexpr uint64_t fillTrailingBitsImpl(uint64_t x) noexcept { return or_shr(or_shr(or_shr(or_shr(or_shr(or_shr(x, 1), 2), 4), 8), 16), 32); }
273
+ }
274
+ //! \endcond
275
+
276
+ // Fills all trailing bits right from the first most significant bit set.
277
+ template<typename T>
278
+ static constexpr T fillTrailingBits(const T& x) noexcept {
279
+ typedef typename std::make_unsigned<T>::type U;
280
+ return T(Internal::fillTrailingBitsImpl(U(x)));
281
+ }
282
+
283
+ // Support - Count Leading/Trailing Zeros
284
+ // ======================================
285
+
286
+ //! \cond
287
+ namespace Internal {
288
+ namespace {
289
+
290
+ template<typename T>
291
+ struct BitScanData { T x; uint32_t n; };
292
+
293
+ template<typename T, uint32_t N>
294
+ struct BitScanCalc {
295
+ static constexpr BitScanData<T> advanceLeft(const BitScanData<T>& data, uint32_t n) noexcept {
296
+ return BitScanData<T> { data.x << n, data.n + n };
297
+ }
298
+
299
+ static constexpr BitScanData<T> advanceRight(const BitScanData<T>& data, uint32_t n) noexcept {
300
+ return BitScanData<T> { data.x >> n, data.n + n };
301
+ }
302
+
303
+ static constexpr BitScanData<T> clz(const BitScanData<T>& data) noexcept {
304
+ return BitScanCalc<T, N / 2>::clz(advanceLeft(data, data.x & (allOnes<T>() << (bitSizeOf<T>() - N)) ? uint32_t(0) : N));
305
+ }
306
+
307
+ static constexpr BitScanData<T> ctz(const BitScanData<T>& data) noexcept {
308
+ return BitScanCalc<T, N / 2>::ctz(advanceRight(data, data.x & (allOnes<T>() >> (bitSizeOf<T>() - N)) ? uint32_t(0) : N));
309
+ }
310
+ };
311
+
312
+ template<typename T>
313
+ struct BitScanCalc<T, 0> {
314
+ static constexpr BitScanData<T> clz(const BitScanData<T>& ctx) noexcept {
315
+ return BitScanData<T> { 0, ctx.n - uint32_t(ctx.x >> (bitSizeOf<T>() - 1)) };
316
+ }
317
+
318
+ static constexpr BitScanData<T> ctz(const BitScanData<T>& ctx) noexcept {
319
+ return BitScanData<T> { 0, ctx.n - uint32_t(ctx.x & 0x1) };
320
+ }
321
+ };
322
+
323
+ template<typename T>
324
+ constexpr uint32_t clzFallback(const T& x) noexcept {
325
+ return BitScanCalc<T, bitSizeOf<T>() / 2u>::clz(BitScanData<T>{x, 1}).n;
326
+ }
327
+
328
+ template<typename T>
329
+ constexpr uint32_t ctzFallback(const T& x) noexcept {
330
+ return BitScanCalc<T, bitSizeOf<T>() / 2u>::ctz(BitScanData<T>{x, 1}).n;
331
+ }
332
+
333
+ template<typename T> inline uint32_t clzImpl(const T& x) noexcept { return clzFallback(asUInt(x)); }
334
+ template<typename T> inline uint32_t ctzImpl(const T& x) noexcept { return ctzFallback(asUInt(x)); }
335
+
336
+ #if !defined(ASMJIT_NO_INTRINSICS)
337
+ # if defined(__GNUC__)
338
+ template<> inline uint32_t clzImpl(const uint32_t& x) noexcept { return uint32_t(__builtin_clz(x)); }
339
+ template<> inline uint32_t clzImpl(const uint64_t& x) noexcept { return uint32_t(__builtin_clzll(x)); }
340
+ template<> inline uint32_t ctzImpl(const uint32_t& x) noexcept { return uint32_t(__builtin_ctz(x)); }
341
+ template<> inline uint32_t ctzImpl(const uint64_t& x) noexcept { return uint32_t(__builtin_ctzll(x)); }
342
+ # elif defined(_MSC_VER)
343
+ template<> inline uint32_t clzImpl(const uint32_t& x) noexcept { unsigned long i; _BitScanReverse(&i, x); return uint32_t(i ^ 31); }
344
+ template<> inline uint32_t ctzImpl(const uint32_t& x) noexcept { unsigned long i; _BitScanForward(&i, x); return uint32_t(i); }
345
+ # if ASMJIT_ARCH_X86 == 64 || ASMJIT_ARCH_ARM == 64
346
+ template<> inline uint32_t clzImpl(const uint64_t& x) noexcept { unsigned long i; _BitScanReverse64(&i, x); return uint32_t(i ^ 63); }
347
+ template<> inline uint32_t ctzImpl(const uint64_t& x) noexcept { unsigned long i; _BitScanForward64(&i, x); return uint32_t(i); }
348
+ # endif
349
+ # endif
350
+ #endif
351
+
352
+ } // {anonymous}
353
+ } // {Internal}
354
+ //! \endcond
355
+
356
+ //! Count leading zeros in `x` (returns a position of a first bit set in `x`).
357
+ //!
358
+ //! \note The input MUST NOT be zero, otherwise the result is undefined.
359
+ template<typename T>
360
+ static inline uint32_t clz(T x) noexcept { return Internal::clzImpl(asUInt(x)); }
361
+
362
+ //! Count trailing zeros in `x` (returns a position of a first bit set in `x`).
363
+ //!
364
+ //! \note The input MUST NOT be zero, otherwise the result is undefined.
365
+ template<typename T>
366
+ static inline uint32_t ctz(T x) noexcept { return Internal::ctzImpl(asUInt(x)); }
367
+
368
+ template<uint64_t kInput>
369
+ struct ConstCTZ {
370
+ static constexpr uint32_t value =
371
+ (kInput & (uint64_t(1) << 0)) ? 0 :
372
+ (kInput & (uint64_t(1) << 1)) ? 1 :
373
+ (kInput & (uint64_t(1) << 2)) ? 2 :
374
+ (kInput & (uint64_t(1) << 3)) ? 3 :
375
+ (kInput & (uint64_t(1) << 4)) ? 4 :
376
+ (kInput & (uint64_t(1) << 5)) ? 5 :
377
+ (kInput & (uint64_t(1) << 6)) ? 6 :
378
+ (kInput & (uint64_t(1) << 7)) ? 7 :
379
+ (kInput & (uint64_t(1) << 8)) ? 8 :
380
+ (kInput & (uint64_t(1) << 9)) ? 9 :
381
+ (kInput & (uint64_t(1) << 10)) ? 10 :
382
+ (kInput & (uint64_t(1) << 11)) ? 11 :
383
+ (kInput & (uint64_t(1) << 12)) ? 12 :
384
+ (kInput & (uint64_t(1) << 13)) ? 13 :
385
+ (kInput & (uint64_t(1) << 14)) ? 14 :
386
+ (kInput & (uint64_t(1) << 15)) ? 15 :
387
+ (kInput & (uint64_t(1) << 16)) ? 16 :
388
+ (kInput & (uint64_t(1) << 17)) ? 17 :
389
+ (kInput & (uint64_t(1) << 18)) ? 18 :
390
+ (kInput & (uint64_t(1) << 19)) ? 19 :
391
+ (kInput & (uint64_t(1) << 20)) ? 20 :
392
+ (kInput & (uint64_t(1) << 21)) ? 21 :
393
+ (kInput & (uint64_t(1) << 22)) ? 22 :
394
+ (kInput & (uint64_t(1) << 23)) ? 23 :
395
+ (kInput & (uint64_t(1) << 24)) ? 24 :
396
+ (kInput & (uint64_t(1) << 25)) ? 25 :
397
+ (kInput & (uint64_t(1) << 26)) ? 26 :
398
+ (kInput & (uint64_t(1) << 27)) ? 27 :
399
+ (kInput & (uint64_t(1) << 28)) ? 28 :
400
+ (kInput & (uint64_t(1) << 29)) ? 29 :
401
+ (kInput & (uint64_t(1) << 30)) ? 30 :
402
+ (kInput & (uint64_t(1) << 31)) ? 31 :
403
+ (kInput & (uint64_t(1) << 32)) ? 32 :
404
+ (kInput & (uint64_t(1) << 33)) ? 33 :
405
+ (kInput & (uint64_t(1) << 34)) ? 34 :
406
+ (kInput & (uint64_t(1) << 35)) ? 35 :
407
+ (kInput & (uint64_t(1) << 36)) ? 36 :
408
+ (kInput & (uint64_t(1) << 37)) ? 37 :
409
+ (kInput & (uint64_t(1) << 38)) ? 38 :
410
+ (kInput & (uint64_t(1) << 39)) ? 39 :
411
+ (kInput & (uint64_t(1) << 40)) ? 40 :
412
+ (kInput & (uint64_t(1) << 41)) ? 41 :
413
+ (kInput & (uint64_t(1) << 42)) ? 42 :
414
+ (kInput & (uint64_t(1) << 43)) ? 43 :
415
+ (kInput & (uint64_t(1) << 44)) ? 44 :
416
+ (kInput & (uint64_t(1) << 45)) ? 45 :
417
+ (kInput & (uint64_t(1) << 46)) ? 46 :
418
+ (kInput & (uint64_t(1) << 47)) ? 47 :
419
+ (kInput & (uint64_t(1) << 48)) ? 48 :
420
+ (kInput & (uint64_t(1) << 49)) ? 49 :
421
+ (kInput & (uint64_t(1) << 50)) ? 50 :
422
+ (kInput & (uint64_t(1) << 51)) ? 51 :
423
+ (kInput & (uint64_t(1) << 52)) ? 52 :
424
+ (kInput & (uint64_t(1) << 53)) ? 53 :
425
+ (kInput & (uint64_t(1) << 54)) ? 54 :
426
+ (kInput & (uint64_t(1) << 55)) ? 55 :
427
+ (kInput & (uint64_t(1) << 56)) ? 56 :
428
+ (kInput & (uint64_t(1) << 57)) ? 57 :
429
+ (kInput & (uint64_t(1) << 58)) ? 58 :
430
+ (kInput & (uint64_t(1) << 59)) ? 59 :
431
+ (kInput & (uint64_t(1) << 60)) ? 60 :
432
+ (kInput & (uint64_t(1) << 61)) ? 61 :
433
+ (kInput & (uint64_t(1) << 62)) ? 62 :
434
+ (kInput & (uint64_t(1) << 63)) ? 63 : 64;
435
+ };
436
+
437
+ // Support - PopCnt
438
+ // ================
439
+
440
+ // Based on the following resource:
441
+ // http://graphics.stanford.edu/~seander/bithacks.html
442
+ //
443
+ // Alternatively, for a very small number of bits in `x`:
444
+ // uint32_t n = 0;
445
+ // while (x) {
446
+ // x &= x - 1;
447
+ // n++;
448
+ // }
449
+ // return n;
450
+
451
+ //! \cond
452
+ namespace Internal {
453
+ static inline uint32_t constPopcntImpl(uint32_t x) noexcept {
454
+ x = x - ((x >> 1) & 0x55555555u);
455
+ x = (x & 0x33333333u) + ((x >> 2) & 0x33333333u);
456
+ return (((x + (x >> 4)) & 0x0F0F0F0Fu) * 0x01010101u) >> 24;
457
+ }
458
+
459
+ static inline uint32_t constPopcntImpl(uint64_t x) noexcept {
460
+ if (ASMJIT_ARCH_BITS >= 64) {
461
+ x = x - ((x >> 1) & 0x5555555555555555u);
462
+ x = (x & 0x3333333333333333u) + ((x >> 2) & 0x3333333333333333u);
463
+ return uint32_t((((x + (x >> 4)) & 0x0F0F0F0F0F0F0F0Fu) * 0x0101010101010101u) >> 56);
464
+ }
465
+ else {
466
+ return constPopcntImpl(uint32_t(x >> 32)) +
467
+ constPopcntImpl(uint32_t(x & 0xFFFFFFFFu));
468
+ }
469
+ }
470
+
471
+ static inline uint32_t popcntImpl(uint32_t x) noexcept {
472
+ #if defined(__GNUC__)
473
+ return uint32_t(__builtin_popcount(x));
474
+ #else
475
+ return constPopcntImpl(asUInt(x));
476
+ #endif
477
+ }
478
+
479
+ static inline uint32_t popcntImpl(uint64_t x) noexcept {
480
+ #if defined(__GNUC__)
481
+ return uint32_t(__builtin_popcountll(x));
482
+ #else
483
+ return constPopcntImpl(asUInt(x));
484
+ #endif
485
+ }
486
+ }
487
+ //! \endcond
488
+
489
+ //! Calculates count of bits in `x`.
490
+ template<typename T>
491
+ static inline uint32_t popcnt(T x) noexcept { return Internal::popcntImpl(asUInt(x)); }
492
+
493
+ //! Calculates count of bits in `x` (useful in constant expressions).
494
+ template<typename T>
495
+ static inline uint32_t constPopcnt(T x) noexcept { return Internal::constPopcntImpl(asUInt(x)); }
496
+
497
+ // Support - Min/Max
498
+ // =================
499
+
500
+ // NOTE: These are constexpr `min()` and `max()` implementations that are not
501
+ // exactly the same as `std::min()` and `std::max()`. The return value is not
502
+ // a reference to `a` or `b` but it's a new value instead.
503
+
504
+ template<typename T>
505
+ static constexpr T min(const T& a, const T& b) noexcept { return b < a ? b : a; }
506
+
507
+ template<typename T, typename... Args>
508
+ static constexpr T min(const T& a, const T& b, Args&&... args) noexcept { return min(min(a, b), std::forward<Args>(args)...); }
509
+
510
+ template<typename T>
511
+ static constexpr T max(const T& a, const T& b) noexcept { return a < b ? b : a; }
512
+
513
+ template<typename T, typename... Args>
514
+ static constexpr T max(const T& a, const T& b, Args&&... args) noexcept { return max(max(a, b), std::forward<Args>(args)...); }
515
+
516
+ // Support - Immediate Helpers
517
+ // ===========================
518
+
519
+ namespace Internal {
520
+ template<typename T, bool IsFloat>
521
+ struct ImmConv {
522
+ static inline int64_t fromT(const T& x) noexcept { return int64_t(x); }
523
+ static inline T toT(int64_t x) noexcept { return T(uint64_t(x) & Support::allOnes<typename std::make_unsigned<T>::type>()); }
524
+ };
525
+
526
+ template<typename T>
527
+ struct ImmConv<T, true> {
528
+ static inline int64_t fromT(const T& x) noexcept { return int64_t(bitCast<int64_t>(double(x))); }
529
+ static inline T toT(int64_t x) noexcept { return T(bitCast<double>(x)); }
530
+ };
531
+ }
532
+
533
+ template<typename T>
534
+ static inline int64_t immediateFromT(const T& x) noexcept { return Internal::ImmConv<T, std::is_floating_point<T>::value>::fromT(x); }
535
+
536
+ template<typename T>
537
+ static inline T immediateToT(int64_t x) noexcept { return Internal::ImmConv<T, std::is_floating_point<T>::value>::toT(x); }
538
+
539
+ // Support - Overflow Arithmetic
540
+ // =============================
541
+
542
+ //! \cond
543
+ namespace Internal {
544
+ template<typename T>
545
+ inline T addOverflowFallback(T x, T y, FastUInt8* of) noexcept {
546
+ typedef typename std::make_unsigned<T>::type U;
547
+
548
+ U result = U(x) + U(y);
549
+ *of = FastUInt8(*of | FastUInt8(isUnsigned<T>() ? result < U(x) : T((U(x) ^ ~U(y)) & (U(x) ^ result)) < 0));
550
+ return T(result);
551
+ }
552
+
553
+ template<typename T>
554
+ inline T subOverflowFallback(T x, T y, FastUInt8* of) noexcept {
555
+ typedef typename std::make_unsigned<T>::type U;
556
+
557
+ U result = U(x) - U(y);
558
+ *of = FastUInt8(*of | FastUInt8(isUnsigned<T>() ? result > U(x) : T((U(x) ^ U(y)) & (U(x) ^ result)) < 0));
559
+ return T(result);
560
+ }
561
+
562
+ template<typename T>
563
+ inline T mulOverflowFallback(T x, T y, FastUInt8* of) noexcept {
564
+ typedef typename Internal::StdInt<sizeof(T) * 2, isUnsigned<T>()>::Type I;
565
+ typedef typename std::make_unsigned<I>::type U;
566
+
567
+ U mask = allOnes<U>();
568
+ if (std::is_signed<T>::value) {
569
+ U prod = U(I(x)) * U(I(y));
570
+ *of = FastUInt8(*of | FastUInt8(I(prod) < I(std::numeric_limits<T>::lowest()) || I(prod) > I(std::numeric_limits<T>::max())));
571
+ return T(I(prod & mask));
572
+ }
573
+ else {
574
+ U prod = U(x) * U(y);
575
+ *of = FastUInt8(*of | FastUInt8((prod & ~mask) != 0));
576
+ return T(prod & mask);
577
+ }
578
+ }
579
+
580
+ template<>
581
+ inline int64_t mulOverflowFallback(int64_t x, int64_t y, FastUInt8* of) noexcept {
582
+ int64_t result = int64_t(uint64_t(x) * uint64_t(y));
583
+ *of = FastUInt8(*of | FastUInt8(x && (result / x != y)));
584
+ return result;
585
+ }
586
+
587
+ template<>
588
+ inline uint64_t mulOverflowFallback(uint64_t x, uint64_t y, FastUInt8* of) noexcept {
589
+ uint64_t result = x * y;
590
+ *of = FastUInt8(*of | FastUInt8(y != 0 && allOnes<uint64_t>() / y < x));
591
+ return result;
592
+ }
593
+
594
+ // These can be specialized.
595
+ template<typename T> inline T addOverflowImpl(const T& x, const T& y, FastUInt8* of) noexcept { return addOverflowFallback(x, y, of); }
596
+ template<typename T> inline T subOverflowImpl(const T& x, const T& y, FastUInt8* of) noexcept { return subOverflowFallback(x, y, of); }
597
+ template<typename T> inline T mulOverflowImpl(const T& x, const T& y, FastUInt8* of) noexcept { return mulOverflowFallback(x, y, of); }
598
+
599
+ #if defined(__GNUC__) && !defined(ASMJIT_NO_INTRINSICS)
600
+ #if defined(__clang__) || __GNUC__ >= 5
601
+ #define ASMJIT_ARITH_OVERFLOW_SPECIALIZE(FUNC, T, RESULT_T, BUILTIN) \
602
+ template<> \
603
+ inline T FUNC(const T& x, const T& y, FastUInt8* of) noexcept { \
604
+ RESULT_T result; \
605
+ *of = FastUInt8(*of | (BUILTIN((RESULT_T)x, (RESULT_T)y, &result))); \
606
+ return T(result); \
607
+ }
608
+ ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, int32_t , int , __builtin_sadd_overflow )
609
+ ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, uint32_t, unsigned int , __builtin_uadd_overflow )
610
+ ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, int64_t , long long , __builtin_saddll_overflow)
611
+ ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, uint64_t, unsigned long long, __builtin_uaddll_overflow)
612
+ ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, int32_t , int , __builtin_ssub_overflow )
613
+ ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, uint32_t, unsigned int , __builtin_usub_overflow )
614
+ ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, int64_t , long long , __builtin_ssubll_overflow)
615
+ ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, uint64_t, unsigned long long, __builtin_usubll_overflow)
616
+ ASMJIT_ARITH_OVERFLOW_SPECIALIZE(mulOverflowImpl, int32_t , int , __builtin_smul_overflow )
617
+ ASMJIT_ARITH_OVERFLOW_SPECIALIZE(mulOverflowImpl, uint32_t, unsigned int , __builtin_umul_overflow )
618
+ ASMJIT_ARITH_OVERFLOW_SPECIALIZE(mulOverflowImpl, int64_t , long long , __builtin_smulll_overflow)
619
+ ASMJIT_ARITH_OVERFLOW_SPECIALIZE(mulOverflowImpl, uint64_t, unsigned long long, __builtin_umulll_overflow)
620
+ #undef ASMJIT_ARITH_OVERFLOW_SPECIALIZE
621
+ #endif
622
+ #endif
623
+
624
+ // There is a bug in MSVC that makes these specializations unusable, maybe in the future...
625
+ #if defined(_MSC_VER) && 0
626
+ #define ASMJIT_ARITH_OVERFLOW_SPECIALIZE(FUNC, T, ALT_T, BUILTIN) \
627
+ template<> \
628
+ inline T FUNC(T x, T y, FastUInt8* of) noexcept { \
629
+ ALT_T result; \
630
+ *of = FastUInt8(*of | BUILTIN(0, (ALT_T)x, (ALT_T)y, &result)); \
631
+ return T(result); \
632
+ }
633
+ ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, uint32_t, unsigned int , _addcarry_u32 )
634
+ ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, uint32_t, unsigned int , _subborrow_u32)
635
+ #if ARCH_BITS >= 64
636
+ ASMJIT_ARITH_OVERFLOW_SPECIALIZE(addOverflowImpl, uint64_t, unsigned __int64 , _addcarry_u64 )
637
+ ASMJIT_ARITH_OVERFLOW_SPECIALIZE(subOverflowImpl, uint64_t, unsigned __int64 , _subborrow_u64)
638
+ #endif
639
+ #undef ASMJIT_ARITH_OVERFLOW_SPECIALIZE
640
+ #endif
641
+ } // {Internal}
642
+ //! \endcond
643
+
644
+ template<typename T>
645
+ static inline T addOverflow(const T& x, const T& y, FastUInt8* of) noexcept { return T(Internal::addOverflowImpl(asStdInt(x), asStdInt(y), of)); }
646
+
647
+ template<typename T>
648
+ static inline T subOverflow(const T& x, const T& y, FastUInt8* of) noexcept { return T(Internal::subOverflowImpl(asStdInt(x), asStdInt(y), of)); }
649
+
650
+ template<typename T>
651
+ static inline T mulOverflow(const T& x, const T& y, FastUInt8* of) noexcept { return T(Internal::mulOverflowImpl(asStdInt(x), asStdInt(y), of)); }
652
+
653
+ // Support - Alignment
654
+ // ===================
655
+
656
+ template<typename X, typename Y>
657
+ static constexpr bool isAligned(X base, Y alignment) noexcept {
658
+ typedef typename Internal::StdInt<sizeof(X), 1>::Type U;
659
+ return ((U)base % (U)alignment) == 0;
660
+ }
661
+
662
+ //! Tests whether the `x` is a power of two (only one bit is set).
663
+ template<typename T>
664
+ static constexpr bool isPowerOf2(T x) noexcept {
665
+ typedef typename std::make_unsigned<T>::type U;
666
+ return x && !(U(x) & (U(x) - U(1)));
667
+ }
668
+
669
+ template<typename X, typename Y>
670
+ static constexpr X alignUp(X x, Y alignment) noexcept {
671
+ typedef typename Internal::StdInt<sizeof(X), 1>::Type U;
672
+ return (X)( ((U)x + ((U)(alignment) - 1u)) & ~((U)(alignment) - 1u) );
673
+ }
674
+
675
+ template<typename T>
676
+ static constexpr T alignUpPowerOf2(T x) noexcept {
677
+ typedef typename Internal::StdInt<sizeof(T), 1>::Type U;
678
+ return (T)(fillTrailingBits(U(x) - 1u) + 1u);
679
+ }
680
+
681
+ //! Returns either zero or a positive difference between `base` and `base` when
682
+ //! aligned to `alignment`.
683
+ template<typename X, typename Y>
684
+ static constexpr typename Internal::StdInt<sizeof(X), 1>::Type alignUpDiff(X base, Y alignment) noexcept {
685
+ typedef typename Internal::StdInt<sizeof(X), 1>::Type U;
686
+ return alignUp(U(base), alignment) - U(base);
687
+ }
688
+
689
+ template<typename X, typename Y>
690
+ static constexpr X alignDown(X x, Y alignment) noexcept {
691
+ typedef typename Internal::StdInt<sizeof(X), 1>::Type U;
692
+ return (X)( (U)x & ~((U)(alignment) - 1u) );
693
+ }
694
+
695
+ // Support - NumGranularized
696
+ // =========================
697
+
698
+ //! Calculates the number of elements that would be required if `base` is
699
+ //! granularized by `granularity`. This function can be used to calculate
700
+ //! the number of BitWords to represent N bits, for example.
701
+ template<typename X, typename Y>
702
+ static constexpr X numGranularized(X base, Y granularity) noexcept {
703
+ typedef typename Internal::StdInt<sizeof(X), 1>::Type U;
704
+ return X((U(base) + U(granularity) - 1) / U(granularity));
705
+ }
706
+
707
+ // Support - IsBetween
708
+ // ===================
709
+
710
+ //! Checks whether `x` is greater than or equal to `a` and lesser than or equal to `b`.
711
+ template<typename T>
712
+ static constexpr bool isBetween(const T& x, const T& a, const T& b) noexcept {
713
+ return x >= a && x <= b;
714
+ }
715
+
716
+ // Support - IsInt & IsUInt
717
+ // ========================
718
+
719
+ //! Checks whether the given integer `x` can be casted to a 4-bit signed integer.
720
+ template<typename T>
721
+ static constexpr bool isInt4(T x) noexcept {
722
+ typedef typename std::make_signed<T>::type S;
723
+ typedef typename std::make_unsigned<T>::type U;
724
+
725
+ return std::is_signed<T>::value ? isBetween<S>(S(x), -8, 7) : U(x) <= U(7u);
726
+ }
727
+
728
+ //! Checks whether the given integer `x` can be casted to a 7-bit signed integer.
729
+ template<typename T>
730
+ static constexpr bool isInt7(T x) noexcept {
731
+ typedef typename std::make_signed<T>::type S;
732
+ typedef typename std::make_unsigned<T>::type U;
733
+
734
+ return std::is_signed<T>::value ? isBetween<S>(S(x), -64, 63) : U(x) <= U(63u);
735
+ }
736
+
737
+ //! Checks whether the given integer `x` can be casted to an 8-bit signed integer.
738
+ template<typename T>
739
+ static constexpr bool isInt8(T x) noexcept {
740
+ typedef typename std::make_signed<T>::type S;
741
+ typedef typename std::make_unsigned<T>::type U;
742
+
743
+ return std::is_signed<T>::value ? sizeof(T) <= 1 || isBetween<S>(S(x), -128, 127) : U(x) <= U(127u);
744
+ }
745
+
746
+ //! Checks whether the given integer `x` can be casted to a 9-bit signed integer.
747
+ template<typename T>
748
+ static constexpr bool isInt9(T x) noexcept {
749
+ typedef typename std::make_signed<T>::type S;
750
+ typedef typename std::make_unsigned<T>::type U;
751
+
752
+ return std::is_signed<T>::value ? sizeof(T) <= 1 || isBetween<S>(S(x), -256, 255)
753
+ : sizeof(T) <= 1 || U(x) <= U(255u);
754
+ }
755
+
756
+ //! Checks whether the given integer `x` can be casted to a 10-bit signed integer.
757
+ template<typename T>
758
+ static constexpr bool isInt10(T x) noexcept {
759
+ typedef typename std::make_signed<T>::type S;
760
+ typedef typename std::make_unsigned<T>::type U;
761
+
762
+ return std::is_signed<T>::value ? sizeof(T) <= 1 || isBetween<S>(S(x), -512, 511)
763
+ : sizeof(T) <= 1 || U(x) <= U(511u);
764
+ }
765
+
766
+ //! Checks whether the given integer `x` can be casted to a 16-bit signed integer.
767
+ template<typename T>
768
+ static constexpr bool isInt16(T x) noexcept {
769
+ typedef typename std::make_signed<T>::type S;
770
+ typedef typename std::make_unsigned<T>::type U;
771
+
772
+ return std::is_signed<T>::value ? sizeof(T) <= 2 || isBetween<S>(S(x), -32768, 32767)
773
+ : sizeof(T) <= 1 || U(x) <= U(32767u);
774
+ }
775
+
776
+ //! Checks whether the given integer `x` can be casted to a 32-bit signed integer.
777
+ template<typename T>
778
+ static constexpr bool isInt32(T x) noexcept {
779
+ typedef typename std::make_signed<T>::type S;
780
+ typedef typename std::make_unsigned<T>::type U;
781
+
782
+ return std::is_signed<T>::value ? sizeof(T) <= 4 || isBetween<S>(S(x), -2147483647 - 1, 2147483647)
783
+ : sizeof(T) <= 2 || U(x) <= U(2147483647u);
784
+ }
785
+
786
+ //! Checks whether the given integer `x` can be casted to a 4-bit unsigned integer.
787
+ template<typename T>
788
+ static constexpr bool isUInt4(T x) noexcept {
789
+ typedef typename std::make_unsigned<T>::type U;
790
+
791
+ return std::is_signed<T>::value ? x >= T(0) && x <= T(15)
792
+ : U(x) <= U(15u);
793
+ }
794
+
795
+ //! Checks whether the given integer `x` can be casted to an 8-bit unsigned integer.
796
+ template<typename T>
797
+ static constexpr bool isUInt8(T x) noexcept {
798
+ typedef typename std::make_unsigned<T>::type U;
799
+
800
+ return std::is_signed<T>::value ? (sizeof(T) <= 1 || T(x) <= T(255)) && x >= T(0)
801
+ : (sizeof(T) <= 1 || U(x) <= U(255u));
802
+ }
803
+
804
+ //! Checks whether the given integer `x` can be casted to a 12-bit unsigned integer (ARM specific).
805
+ template<typename T>
806
+ static constexpr bool isUInt12(T x) noexcept {
807
+ typedef typename std::make_unsigned<T>::type U;
808
+
809
+ return std::is_signed<T>::value ? (sizeof(T) <= 1 || T(x) <= T(4095)) && x >= T(0)
810
+ : (sizeof(T) <= 1 || U(x) <= U(4095u));
811
+ }
812
+
813
+ //! Checks whether the given integer `x` can be casted to a 16-bit unsigned integer.
814
+ template<typename T>
815
+ static constexpr bool isUInt16(T x) noexcept {
816
+ typedef typename std::make_unsigned<T>::type U;
817
+
818
+ return std::is_signed<T>::value ? (sizeof(T) <= 2 || T(x) <= T(65535)) && x >= T(0)
819
+ : (sizeof(T) <= 2 || U(x) <= U(65535u));
820
+ }
821
+
822
+ //! Checks whether the given integer `x` can be casted to a 32-bit unsigned integer.
823
+ template<typename T>
824
+ static constexpr bool isUInt32(T x) noexcept {
825
+ typedef typename std::make_unsigned<T>::type U;
826
+
827
+ return std::is_signed<T>::value ? (sizeof(T) <= 4 || T(x) <= T(4294967295u)) && x >= T(0)
828
+ : (sizeof(T) <= 4 || U(x) <= U(4294967295u));
829
+ }
830
+
831
+ //! Checks whether the given integer `x` can be casted to a 32-bit unsigned integer.
832
+ template<typename T>
833
+ static constexpr bool isIntOrUInt32(T x) noexcept {
834
+ return sizeof(T) <= 4 ? true : (uint32_t(uint64_t(x) >> 32) + 1u) <= 1u;
835
+ }
836
+
837
+ static bool inline isEncodableOffset32(int32_t offset, uint32_t nBits) noexcept {
838
+ uint32_t nRev = 32 - nBits;
839
+ return Support::sar(Support::shl(offset, nRev), nRev) == offset;
840
+ }
841
+
842
+ static bool inline isEncodableOffset64(int64_t offset, uint32_t nBits) noexcept {
843
+ uint32_t nRev = 64 - nBits;
844
+ return Support::sar(Support::shl(offset, nRev), nRev) == offset;
845
+ }
846
+
847
+ // Support - ByteSwap
848
+ // ==================
849
+
850
+ static inline uint16_t byteswap16(uint16_t x) noexcept {
851
+ return uint16_t(((x >> 8) & 0xFFu) | ((x & 0xFFu) << 8));
852
+ }
853
+
854
+ static inline uint32_t byteswap32(uint32_t x) noexcept {
855
+ return (x << 24) | (x >> 24) | ((x << 8) & 0x00FF0000u) | ((x >> 8) & 0x0000FF00);
856
+ }
857
+
858
+ static inline uint64_t byteswap64(uint64_t x) noexcept {
859
+ #if (defined(__GNUC__) || defined(__clang__)) && !defined(ASMJIT_NO_INTRINSICS)
860
+ return uint64_t(__builtin_bswap64(uint64_t(x)));
861
+ #elif defined(_MSC_VER) && !defined(ASMJIT_NO_INTRINSICS)
862
+ return uint64_t(_byteswap_uint64(uint64_t(x)));
863
+ #else
864
+ return (uint64_t(byteswap32(uint32_t(uint64_t(x) >> 32 ))) ) |
865
+ (uint64_t(byteswap32(uint32_t(uint64_t(x) & 0xFFFFFFFFu))) << 32) ;
866
+ #endif
867
+ }
868
+
869
+ // Support - BytePack & Unpack
870
+ // ===========================
871
+
872
+ //! Pack four 8-bit integer into a 32-bit integer as it is an array of `{b0,b1,b2,b3}`.
873
+ static constexpr uint32_t bytepack32_4x8(uint32_t a, uint32_t b, uint32_t c, uint32_t d) noexcept {
874
+ return ASMJIT_ARCH_LE ? (a | (b << 8) | (c << 16) | (d << 24))
875
+ : (d | (c << 8) | (b << 16) | (a << 24));
876
+ }
877
+
878
+ template<typename T>
879
+ static constexpr uint32_t unpackU32At0(T x) noexcept { return ASMJIT_ARCH_LE ? uint32_t(uint64_t(x) & 0xFFFFFFFFu) : uint32_t(uint64_t(x) >> 32); }
880
+ template<typename T>
881
+ static constexpr uint32_t unpackU32At1(T x) noexcept { return ASMJIT_ARCH_BE ? uint32_t(uint64_t(x) & 0xFFFFFFFFu) : uint32_t(uint64_t(x) >> 32); }
882
+
883
+ // Support - Position of byte (in bit-shift)
884
+ // =========================================
885
+
886
+ static inline uint32_t byteShiftOfDWordStruct(uint32_t index) noexcept {
887
+ return ASMJIT_ARCH_LE ? index * 8 : (uint32_t(sizeof(uint32_t)) - 1u - index) * 8;
888
+ }
889
+
890
+ // Support - String Utilities
891
+ // ==========================
892
+
893
+ template<typename T>
894
+ static constexpr T asciiToLower(T c) noexcept { return T(c ^ T(T(c >= T('A') && c <= T('Z')) << 5)); }
895
+
896
+ template<typename T>
897
+ static constexpr T asciiToUpper(T c) noexcept { return T(c ^ T(T(c >= T('a') && c <= T('z')) << 5)); }
898
+
899
+ static ASMJIT_FORCE_INLINE size_t strLen(const char* s, size_t maxSize) noexcept {
900
+ size_t i = 0;
901
+ while (i < maxSize && s[i] != '\0')
902
+ i++;
903
+ return i;
904
+ }
905
+
906
+ static constexpr uint32_t hashRound(uint32_t hash, uint32_t c) noexcept { return hash * 65599 + c; }
907
+
908
+ // Gets a hash of the given string `data` of size `size`. Size must be valid
909
+ // as this function doesn't check for a null terminator and allows it in the
910
+ // middle of the string.
911
+ static inline uint32_t hashString(const char* data, size_t size) noexcept {
912
+ uint32_t hashCode = 0;
913
+ for (uint32_t i = 0; i < size; i++)
914
+ hashCode = hashRound(hashCode, uint8_t(data[i]));
915
+ return hashCode;
916
+ }
917
+
918
+ static ASMJIT_FORCE_INLINE const char* findPackedString(const char* p, uint32_t id) noexcept {
919
+ uint32_t i = 0;
920
+ while (i < id) {
921
+ while (p[0])
922
+ p++;
923
+ p++;
924
+ i++;
925
+ }
926
+ return p;
927
+ }
928
+
929
+ //! Compares two instruction names.
930
+ //!
931
+ //! `a` is a null terminated instruction name from arch-specific `nameData[]`
932
+ //! table. `b` is a possibly non-null terminated instruction name passed to
933
+ //! `InstAPI::stringToInstId()`.
934
+ static ASMJIT_FORCE_INLINE int cmpInstName(const char* a, const char* b, size_t size) noexcept {
935
+ for (size_t i = 0; i < size; i++) {
936
+ int c = int(uint8_t(a[i])) - int(uint8_t(b[i]));
937
+ if (c != 0) return c;
938
+ }
939
+ return int(uint8_t(a[size]));
940
+ }
941
+
942
+ // Support - Memory Read Access - 8 Bits
943
+ // =====================================
944
+
945
+ static inline uint8_t readU8(const void* p) noexcept { return static_cast<const uint8_t*>(p)[0]; }
946
+ static inline int8_t readI8(const void* p) noexcept { return static_cast<const int8_t*>(p)[0]; }
947
+
948
+ // Support - Memory Read Access - 16 Bits
949
+ // ======================================
950
+
951
+ template<ByteOrder BO, size_t Alignment>
952
+ static inline uint16_t readU16x(const void* p) noexcept {
953
+ typedef typename Internal::AliasedUInt<uint16_t, Alignment>::T U16AlignedToN;
954
+ uint16_t x = static_cast<const U16AlignedToN*>(p)[0];
955
+ return BO == ByteOrder::kNative ? x : byteswap16(x);
956
+ }
957
+
958
+ template<size_t Alignment = 1>
959
+ static inline uint16_t readU16u(const void* p) noexcept { return readU16x<ByteOrder::kNative, Alignment>(p); }
960
+ template<size_t Alignment = 1>
961
+ static inline uint16_t readU16uLE(const void* p) noexcept { return readU16x<ByteOrder::kLE, Alignment>(p); }
962
+ template<size_t Alignment = 1>
963
+ static inline uint16_t readU16uBE(const void* p) noexcept { return readU16x<ByteOrder::kBE, Alignment>(p); }
964
+
965
+ static inline uint16_t readU16a(const void* p) noexcept { return readU16x<ByteOrder::kNative, 2>(p); }
966
+ static inline uint16_t readU16aLE(const void* p) noexcept { return readU16x<ByteOrder::kLE, 2>(p); }
967
+ static inline uint16_t readU16aBE(const void* p) noexcept { return readU16x<ByteOrder::kBE, 2>(p); }
968
+
969
+ template<ByteOrder BO, size_t Alignment>
970
+ static inline int16_t readI16x(const void* p) noexcept { return int16_t(readU16x<BO, Alignment>(p)); }
971
+
972
+ template<size_t Alignment = 1>
973
+ static inline int16_t readI16u(const void* p) noexcept { return int16_t(readU16x<ByteOrder::kNative, Alignment>(p)); }
974
+ template<size_t Alignment = 1>
975
+ static inline int16_t readI16uLE(const void* p) noexcept { return int16_t(readU16x<ByteOrder::kLE, Alignment>(p)); }
976
+ template<size_t Alignment = 1>
977
+ static inline int16_t readI16uBE(const void* p) noexcept { return int16_t(readU16x<ByteOrder::kBE, Alignment>(p)); }
978
+
979
+ static inline int16_t readI16a(const void* p) noexcept { return int16_t(readU16x<ByteOrder::kNative, 2>(p)); }
980
+ static inline int16_t readI16aLE(const void* p) noexcept { return int16_t(readU16x<ByteOrder::kLE, 2>(p)); }
981
+ static inline int16_t readI16aBE(const void* p) noexcept { return int16_t(readU16x<ByteOrder::kBE, 2>(p)); }
982
+
983
+ // Support - Memory Read Access - 24 Bits
984
+ // ======================================
985
+
986
+ template<ByteOrder BO = ByteOrder::kNative>
987
+ static inline uint32_t readU24u(const void* p) noexcept {
988
+ uint32_t b0 = readU8(static_cast<const uint8_t*>(p) + (BO == ByteOrder::kLE ? 2 : 0));
989
+ uint32_t b1 = readU8(static_cast<const uint8_t*>(p) + (BO == ByteOrder::kLE ? 1 : 1));
990
+ uint32_t b2 = readU8(static_cast<const uint8_t*>(p) + (BO == ByteOrder::kLE ? 0 : 2));
991
+ return (b0 << 16) | (b1 << 8) | b2;
992
+ }
993
+
994
+ static inline uint32_t readU24uLE(const void* p) noexcept { return readU24u<ByteOrder::kLE>(p); }
995
+ static inline uint32_t readU24uBE(const void* p) noexcept { return readU24u<ByteOrder::kBE>(p); }
996
+
997
+ // Support - Memory Read Access - 32 Bits
998
+ // ======================================
999
+
1000
+ template<ByteOrder BO, size_t Alignment>
1001
+ static inline uint32_t readU32x(const void* p) noexcept {
1002
+ typedef typename Internal::AliasedUInt<uint32_t, Alignment>::T U32AlignedToN;
1003
+ uint32_t x = static_cast<const U32AlignedToN*>(p)[0];
1004
+ return BO == ByteOrder::kNative ? x : byteswap32(x);
1005
+ }
1006
+
1007
+ template<size_t Alignment = 1>
1008
+ static inline uint32_t readU32u(const void* p) noexcept { return readU32x<ByteOrder::kNative, Alignment>(p); }
1009
+ template<size_t Alignment = 1>
1010
+ static inline uint32_t readU32uLE(const void* p) noexcept { return readU32x<ByteOrder::kLE, Alignment>(p); }
1011
+ template<size_t Alignment = 1>
1012
+ static inline uint32_t readU32uBE(const void* p) noexcept { return readU32x<ByteOrder::kBE, Alignment>(p); }
1013
+
1014
+ static inline uint32_t readU32a(const void* p) noexcept { return readU32x<ByteOrder::kNative, 4>(p); }
1015
+ static inline uint32_t readU32aLE(const void* p) noexcept { return readU32x<ByteOrder::kLE, 4>(p); }
1016
+ static inline uint32_t readU32aBE(const void* p) noexcept { return readU32x<ByteOrder::kBE, 4>(p); }
1017
+
1018
+ template<ByteOrder BO, size_t Alignment>
1019
+ static inline uint32_t readI32x(const void* p) noexcept { return int32_t(readU32x<BO, Alignment>(p)); }
1020
+
1021
+ template<size_t Alignment = 1>
1022
+ static inline int32_t readI32u(const void* p) noexcept { return int32_t(readU32x<ByteOrder::kNative, Alignment>(p)); }
1023
+ template<size_t Alignment = 1>
1024
+ static inline int32_t readI32uLE(const void* p) noexcept { return int32_t(readU32x<ByteOrder::kLE, Alignment>(p)); }
1025
+ template<size_t Alignment = 1>
1026
+ static inline int32_t readI32uBE(const void* p) noexcept { return int32_t(readU32x<ByteOrder::kBE, Alignment>(p)); }
1027
+
1028
+ static inline int32_t readI32a(const void* p) noexcept { return int32_t(readU32x<ByteOrder::kNative, 4>(p)); }
1029
+ static inline int32_t readI32aLE(const void* p) noexcept { return int32_t(readU32x<ByteOrder::kLE, 4>(p)); }
1030
+ static inline int32_t readI32aBE(const void* p) noexcept { return int32_t(readU32x<ByteOrder::kBE, 4>(p)); }
1031
+
1032
+ // Support - Memory Read Access - 64 Bits
1033
+ // ======================================
1034
+
1035
+ template<ByteOrder BO, size_t Alignment>
1036
+ static inline uint64_t readU64x(const void* p) noexcept {
1037
+ typedef typename Internal::AliasedUInt<uint64_t, Alignment>::T U64AlignedToN;
1038
+ uint64_t x = static_cast<const U64AlignedToN*>(p)[0];
1039
+ return BO == ByteOrder::kNative ? x : byteswap64(x);
1040
+ }
1041
+
1042
+ template<size_t Alignment = 1>
1043
+ static inline uint64_t readU64u(const void* p) noexcept { return readU64x<ByteOrder::kNative, Alignment>(p); }
1044
+ template<size_t Alignment = 1>
1045
+ static inline uint64_t readU64uLE(const void* p) noexcept { return readU64x<ByteOrder::kLE, Alignment>(p); }
1046
+ template<size_t Alignment = 1>
1047
+ static inline uint64_t readU64uBE(const void* p) noexcept { return readU64x<ByteOrder::kBE, Alignment>(p); }
1048
+
1049
+ static inline uint64_t readU64a(const void* p) noexcept { return readU64x<ByteOrder::kNative, 8>(p); }
1050
+ static inline uint64_t readU64aLE(const void* p) noexcept { return readU64x<ByteOrder::kLE, 8>(p); }
1051
+ static inline uint64_t readU64aBE(const void* p) noexcept { return readU64x<ByteOrder::kBE, 8>(p); }
1052
+
1053
+ template<ByteOrder BO, size_t Alignment>
1054
+ static inline int64_t readI64x(const void* p) noexcept { return int64_t(readU64x<BO, Alignment>(p)); }
1055
+
1056
+ template<size_t Alignment = 1>
1057
+ static inline int64_t readI64u(const void* p) noexcept { return int64_t(readU64x<ByteOrder::kNative, Alignment>(p)); }
1058
+ template<size_t Alignment = 1>
1059
+ static inline int64_t readI64uLE(const void* p) noexcept { return int64_t(readU64x<ByteOrder::kLE, Alignment>(p)); }
1060
+ template<size_t Alignment = 1>
1061
+ static inline int64_t readI64uBE(const void* p) noexcept { return int64_t(readU64x<ByteOrder::kBE, Alignment>(p)); }
1062
+
1063
+ static inline int64_t readI64a(const void* p) noexcept { return int64_t(readU64x<ByteOrder::kNative, 8>(p)); }
1064
+ static inline int64_t readI64aLE(const void* p) noexcept { return int64_t(readU64x<ByteOrder::kLE, 8>(p)); }
1065
+ static inline int64_t readI64aBE(const void* p) noexcept { return int64_t(readU64x<ByteOrder::kBE, 8>(p)); }
1066
+
1067
+ // Support - Memory Write Access - 8 Bits
1068
+ // ======================================
1069
+
1070
+ static inline void writeU8(void* p, uint8_t x) noexcept { static_cast<uint8_t*>(p)[0] = x; }
1071
+ static inline void writeI8(void* p, int8_t x) noexcept { static_cast<int8_t*>(p)[0] = x; }
1072
+
1073
+ // Support - Memory Write Access - 16 Bits
1074
+ // =======================================
1075
+
1076
+ template<ByteOrder BO = ByteOrder::kNative, size_t Alignment = 1>
1077
+ static inline void writeU16x(void* p, uint16_t x) noexcept {
1078
+ typedef typename Internal::AliasedUInt<uint16_t, Alignment>::T U16AlignedToN;
1079
+ static_cast<U16AlignedToN*>(p)[0] = BO == ByteOrder::kNative ? x : byteswap16(x);
1080
+ }
1081
+
1082
+ template<size_t Alignment = 1>
1083
+ static inline void writeU16uLE(void* p, uint16_t x) noexcept { writeU16x<ByteOrder::kLE, Alignment>(p, x); }
1084
+ template<size_t Alignment = 1>
1085
+ static inline void writeU16uBE(void* p, uint16_t x) noexcept { writeU16x<ByteOrder::kBE, Alignment>(p, x); }
1086
+
1087
+ static inline void writeU16a(void* p, uint16_t x) noexcept { writeU16x<ByteOrder::kNative, 2>(p, x); }
1088
+ static inline void writeU16aLE(void* p, uint16_t x) noexcept { writeU16x<ByteOrder::kLE, 2>(p, x); }
1089
+ static inline void writeU16aBE(void* p, uint16_t x) noexcept { writeU16x<ByteOrder::kBE, 2>(p, x); }
1090
+
1091
+
1092
+ template<ByteOrder BO = ByteOrder::kNative, size_t Alignment = 1>
1093
+ static inline void writeI16x(void* p, int16_t x) noexcept { writeU16x<BO, Alignment>(p, uint16_t(x)); }
1094
+
1095
+ template<size_t Alignment = 1>
1096
+ static inline void writeI16uLE(void* p, int16_t x) noexcept { writeU16x<ByteOrder::kLE, Alignment>(p, uint16_t(x)); }
1097
+ template<size_t Alignment = 1>
1098
+ static inline void writeI16uBE(void* p, int16_t x) noexcept { writeU16x<ByteOrder::kBE, Alignment>(p, uint16_t(x)); }
1099
+
1100
+ static inline void writeI16a(void* p, int16_t x) noexcept { writeU16x<ByteOrder::kNative, 2>(p, uint16_t(x)); }
1101
+ static inline void writeI16aLE(void* p, int16_t x) noexcept { writeU16x<ByteOrder::kLE, 2>(p, uint16_t(x)); }
1102
+ static inline void writeI16aBE(void* p, int16_t x) noexcept { writeU16x<ByteOrder::kBE, 2>(p, uint16_t(x)); }
1103
+
1104
+ // Support - Memory Write Access - 24 Bits
1105
+ // =======================================
1106
+
1107
+ template<ByteOrder BO = ByteOrder::kNative>
1108
+ static inline void writeU24u(void* p, uint32_t v) noexcept {
1109
+ static_cast<uint8_t*>(p)[0] = uint8_t((v >> (BO == ByteOrder::kLE ? 0 : 16)) & 0xFFu);
1110
+ static_cast<uint8_t*>(p)[1] = uint8_t((v >> (BO == ByteOrder::kLE ? 8 : 8)) & 0xFFu);
1111
+ static_cast<uint8_t*>(p)[2] = uint8_t((v >> (BO == ByteOrder::kLE ? 16 : 0)) & 0xFFu);
1112
+ }
1113
+
1114
+ static inline void writeU24uLE(void* p, uint32_t v) noexcept { writeU24u<ByteOrder::kLE>(p, v); }
1115
+ static inline void writeU24uBE(void* p, uint32_t v) noexcept { writeU24u<ByteOrder::kBE>(p, v); }
1116
+
1117
+ // Support - Memory Write Access - 32 Bits
1118
+ // =======================================
1119
+
1120
+ template<ByteOrder BO = ByteOrder::kNative, size_t Alignment = 1>
1121
+ static inline void writeU32x(void* p, uint32_t x) noexcept {
1122
+ typedef typename Internal::AliasedUInt<uint32_t, Alignment>::T U32AlignedToN;
1123
+ static_cast<U32AlignedToN*>(p)[0] = (BO == ByteOrder::kNative) ? x : Support::byteswap32(x);
1124
+ }
1125
+
1126
+ template<size_t Alignment = 1>
1127
+ static inline void writeU32u(void* p, uint32_t x) noexcept { writeU32x<ByteOrder::kNative, Alignment>(p, x); }
1128
+ template<size_t Alignment = 1>
1129
+ static inline void writeU32uLE(void* p, uint32_t x) noexcept { writeU32x<ByteOrder::kLE, Alignment>(p, x); }
1130
+ template<size_t Alignment = 1>
1131
+ static inline void writeU32uBE(void* p, uint32_t x) noexcept { writeU32x<ByteOrder::kBE, Alignment>(p, x); }
1132
+
1133
+ static inline void writeU32a(void* p, uint32_t x) noexcept { writeU32x<ByteOrder::kNative, 4>(p, x); }
1134
+ static inline void writeU32aLE(void* p, uint32_t x) noexcept { writeU32x<ByteOrder::kLE, 4>(p, x); }
1135
+ static inline void writeU32aBE(void* p, uint32_t x) noexcept { writeU32x<ByteOrder::kBE, 4>(p, x); }
1136
+
1137
+ template<ByteOrder BO = ByteOrder::kNative, size_t Alignment = 1>
1138
+ static inline void writeI32x(void* p, int32_t x) noexcept { writeU32x<BO, Alignment>(p, uint32_t(x)); }
1139
+
1140
+ template<size_t Alignment = 1>
1141
+ static inline void writeI32u(void* p, int32_t x) noexcept { writeU32x<ByteOrder::kNative, Alignment>(p, uint32_t(x)); }
1142
+ template<size_t Alignment = 1>
1143
+ static inline void writeI32uLE(void* p, int32_t x) noexcept { writeU32x<ByteOrder::kLE, Alignment>(p, uint32_t(x)); }
1144
+ template<size_t Alignment = 1>
1145
+ static inline void writeI32uBE(void* p, int32_t x) noexcept { writeU32x<ByteOrder::kBE, Alignment>(p, uint32_t(x)); }
1146
+
1147
+ static inline void writeI32a(void* p, int32_t x) noexcept { writeU32x<ByteOrder::kNative, 4>(p, uint32_t(x)); }
1148
+ static inline void writeI32aLE(void* p, int32_t x) noexcept { writeU32x<ByteOrder::kLE, 4>(p, uint32_t(x)); }
1149
+ static inline void writeI32aBE(void* p, int32_t x) noexcept { writeU32x<ByteOrder::kBE, 4>(p, uint32_t(x)); }
1150
+
1151
+ // Support - Memory Write Access - 64 Bits
1152
+ // =======================================
1153
+
1154
+ template<ByteOrder BO = ByteOrder::kNative, size_t Alignment = 1>
1155
+ static inline void writeU64x(void* p, uint64_t x) noexcept {
1156
+ typedef typename Internal::AliasedUInt<uint64_t, Alignment>::T U64AlignedToN;
1157
+ static_cast<U64AlignedToN*>(p)[0] = BO == ByteOrder::kNative ? x : byteswap64(x);
1158
+ }
1159
+
1160
+ template<size_t Alignment = 1>
1161
+ static inline void writeU64u(void* p, uint64_t x) noexcept { writeU64x<ByteOrder::kNative, Alignment>(p, x); }
1162
+ template<size_t Alignment = 1>
1163
+ static inline void writeU64uLE(void* p, uint64_t x) noexcept { writeU64x<ByteOrder::kLE, Alignment>(p, x); }
1164
+ template<size_t Alignment = 1>
1165
+ static inline void writeU64uBE(void* p, uint64_t x) noexcept { writeU64x<ByteOrder::kBE, Alignment>(p, x); }
1166
+
1167
+ static inline void writeU64a(void* p, uint64_t x) noexcept { writeU64x<ByteOrder::kNative, 8>(p, x); }
1168
+ static inline void writeU64aLE(void* p, uint64_t x) noexcept { writeU64x<ByteOrder::kLE, 8>(p, x); }
1169
+ static inline void writeU64aBE(void* p, uint64_t x) noexcept { writeU64x<ByteOrder::kBE, 8>(p, x); }
1170
+
1171
+ template<ByteOrder BO = ByteOrder::kNative, size_t Alignment = 1>
1172
+ static inline void writeI64x(void* p, int64_t x) noexcept { writeU64x<BO, Alignment>(p, uint64_t(x)); }
1173
+
1174
+ template<size_t Alignment = 1>
1175
+ static inline void writeI64u(void* p, int64_t x) noexcept { writeU64x<ByteOrder::kNative, Alignment>(p, uint64_t(x)); }
1176
+ template<size_t Alignment = 1>
1177
+ static inline void writeI64uLE(void* p, int64_t x) noexcept { writeU64x<ByteOrder::kLE, Alignment>(p, uint64_t(x)); }
1178
+ template<size_t Alignment = 1>
1179
+ static inline void writeI64uBE(void* p, int64_t x) noexcept { writeU64x<ByteOrder::kBE, Alignment>(p, uint64_t(x)); }
1180
+
1181
+ static inline void writeI64a(void* p, int64_t x) noexcept { writeU64x<ByteOrder::kNative, 8>(p, uint64_t(x)); }
1182
+ static inline void writeI64aLE(void* p, int64_t x) noexcept { writeU64x<ByteOrder::kLE, 8>(p, uint64_t(x)); }
1183
+ static inline void writeI64aBE(void* p, int64_t x) noexcept { writeU64x<ByteOrder::kBE, 8>(p, uint64_t(x)); }
1184
+
1185
+ // Support - Operators
1186
+ // ===================
1187
+
1188
+ //! \cond INTERNAL
1189
+ struct Set { template<typename T> static inline T op(T x, T y) noexcept { DebugUtils::unused(x); return y; } };
1190
+ struct SetNot { template<typename T> static inline T op(T x, T y) noexcept { DebugUtils::unused(x); return ~y; } };
1191
+ struct And { template<typename T> static inline T op(T x, T y) noexcept { return x & y; } };
1192
+ struct AndNot { template<typename T> static inline T op(T x, T y) noexcept { return x & ~y; } };
1193
+ struct NotAnd { template<typename T> static inline T op(T x, T y) noexcept { return ~x & y; } };
1194
+ struct Or { template<typename T> static inline T op(T x, T y) noexcept { return x | y; } };
1195
+ struct Xor { template<typename T> static inline T op(T x, T y) noexcept { return x ^ y; } };
1196
+ struct Add { template<typename T> static inline T op(T x, T y) noexcept { return x + y; } };
1197
+ struct Sub { template<typename T> static inline T op(T x, T y) noexcept { return x - y; } };
1198
+ struct Min { template<typename T> static inline T op(T x, T y) noexcept { return min<T>(x, y); } };
1199
+ struct Max { template<typename T> static inline T op(T x, T y) noexcept { return max<T>(x, y); } };
1200
+ //! \endcond
1201
+
1202
+ // Support - BitWordIterator
1203
+ // =========================
1204
+
1205
+ //! Iterates over each bit in a number which is set to 1.
1206
+ //!
1207
+ //! Example of use:
1208
+ //!
1209
+ //! ```
1210
+ //! uint32_t bitsToIterate = 0x110F;
1211
+ //! Support::BitWordIterator<uint32_t> it(bitsToIterate);
1212
+ //!
1213
+ //! while (it.hasNext()) {
1214
+ //! uint32_t bitIndex = it.next();
1215
+ //! std::printf("Bit at %u is set\n", unsigned(bitIndex));
1216
+ //! }
1217
+ //! ```
1218
+ template<typename T>
1219
+ class BitWordIterator {
1220
+ public:
1221
+ ASMJIT_FORCE_INLINE explicit BitWordIterator(T bitWord) noexcept
1222
+ : _bitWord(bitWord) {}
1223
+
1224
+ ASMJIT_FORCE_INLINE void init(T bitWord) noexcept { _bitWord = bitWord; }
1225
+ ASMJIT_FORCE_INLINE bool hasNext() const noexcept { return _bitWord != 0; }
1226
+
1227
+ ASMJIT_FORCE_INLINE uint32_t next() noexcept {
1228
+ ASMJIT_ASSERT(_bitWord != 0);
1229
+ uint32_t index = ctz(_bitWord);
1230
+ _bitWord ^= T(1u) << index;
1231
+ return index;
1232
+ }
1233
+
1234
+ T _bitWord;
1235
+ };
1236
+
1237
+ // Support - BitWordFlipIterator
1238
+ // =============================
1239
+
1240
+ template<typename T>
1241
+ class BitWordFlipIterator {
1242
+ public:
1243
+ ASMJIT_FORCE_INLINE explicit BitWordFlipIterator(T bitWord) noexcept
1244
+ : _bitWord(bitWord) {}
1245
+
1246
+ ASMJIT_FORCE_INLINE void init(T bitWord) noexcept { _bitWord = bitWord; }
1247
+ ASMJIT_FORCE_INLINE bool hasNext() const noexcept { return _bitWord != 0; }
1248
+
1249
+ ASMJIT_FORCE_INLINE uint32_t nextAndFlip() noexcept {
1250
+ ASMJIT_ASSERT(_bitWord != 0);
1251
+ uint32_t index = ctz(_bitWord);
1252
+ _bitWord ^= T(1u) << index;
1253
+ return index;
1254
+ }
1255
+
1256
+ T _bitWord;
1257
+ T _xorMask;
1258
+ };
1259
+
1260
+ // Support - BitVectorOps
1261
+ // ======================
1262
+
1263
+ //! \cond
1264
+ namespace Internal {
1265
+ template<typename T, class OperatorT, class FullWordOpT>
1266
+ static inline void bitVectorOp(T* buf, size_t index, size_t count) noexcept {
1267
+ if (count == 0)
1268
+ return;
1269
+
1270
+ const size_t kTSizeInBits = bitSizeOf<T>();
1271
+ size_t vecIndex = index / kTSizeInBits; // T[]
1272
+ size_t bitIndex = index % kTSizeInBits; // T[][]
1273
+
1274
+ buf += vecIndex;
1275
+
1276
+ // The first BitWord requires special handling to preserve bits outside the fill region.
1277
+ const T kFillMask = allOnes<T>();
1278
+ size_t firstNBits = min<size_t>(kTSizeInBits - bitIndex, count);
1279
+
1280
+ buf[0] = OperatorT::op(buf[0], (kFillMask >> (kTSizeInBits - firstNBits)) << bitIndex);
1281
+ buf++;
1282
+ count -= firstNBits;
1283
+
1284
+ // All bits between the first and last affected BitWords can be just filled.
1285
+ while (count >= kTSizeInBits) {
1286
+ buf[0] = FullWordOpT::op(buf[0], kFillMask);
1287
+ buf++;
1288
+ count -= kTSizeInBits;
1289
+ }
1290
+
1291
+ // The last BitWord requires special handling as well
1292
+ if (count)
1293
+ buf[0] = OperatorT::op(buf[0], kFillMask >> (kTSizeInBits - count));
1294
+ }
1295
+ }
1296
+ //! \endcond
1297
+
1298
+ //! Sets bit in a bit-vector `buf` at `index`.
1299
+ template<typename T>
1300
+ static inline bool bitVectorGetBit(T* buf, size_t index) noexcept {
1301
+ const size_t kTSizeInBits = bitSizeOf<T>();
1302
+
1303
+ size_t vecIndex = index / kTSizeInBits;
1304
+ size_t bitIndex = index % kTSizeInBits;
1305
+
1306
+ return bool((buf[vecIndex] >> bitIndex) & 0x1u);
1307
+ }
1308
+
1309
+ //! Sets bit in a bit-vector `buf` at `index` to `value`.
1310
+ template<typename T>
1311
+ static inline void bitVectorSetBit(T* buf, size_t index, bool value) noexcept {
1312
+ const size_t kTSizeInBits = bitSizeOf<T>();
1313
+
1314
+ size_t vecIndex = index / kTSizeInBits;
1315
+ size_t bitIndex = index % kTSizeInBits;
1316
+
1317
+ T bitMask = T(1u) << bitIndex;
1318
+ if (value)
1319
+ buf[vecIndex] |= bitMask;
1320
+ else
1321
+ buf[vecIndex] &= ~bitMask;
1322
+ }
1323
+
1324
+ //! Sets bit in a bit-vector `buf` at `index` to `value`.
1325
+ template<typename T>
1326
+ static inline void bitVectorFlipBit(T* buf, size_t index) noexcept {
1327
+ const size_t kTSizeInBits = bitSizeOf<T>();
1328
+
1329
+ size_t vecIndex = index / kTSizeInBits;
1330
+ size_t bitIndex = index % kTSizeInBits;
1331
+
1332
+ T bitMask = T(1u) << bitIndex;
1333
+ buf[vecIndex] ^= bitMask;
1334
+ }
1335
+
1336
+ //! Fills `count` bits in bit-vector `buf` starting at bit-index `index`.
1337
+ template<typename T>
1338
+ static inline void bitVectorFill(T* buf, size_t index, size_t count) noexcept { Internal::bitVectorOp<T, Or, Set>(buf, index, count); }
1339
+
1340
+ //! Clears `count` bits in bit-vector `buf` starting at bit-index `index`.
1341
+ template<typename T>
1342
+ static inline void bitVectorClear(T* buf, size_t index, size_t count) noexcept { Internal::bitVectorOp<T, AndNot, SetNot>(buf, index, count); }
1343
+
1344
+ template<typename T>
1345
+ static inline size_t bitVectorIndexOf(T* buf, size_t start, bool value) noexcept {
1346
+ const size_t kTSizeInBits = bitSizeOf<T>();
1347
+ size_t vecIndex = start / kTSizeInBits; // T[]
1348
+ size_t bitIndex = start % kTSizeInBits; // T[][]
1349
+
1350
+ T* p = buf + vecIndex;
1351
+
1352
+ // We always look for zeros, if value is `true` we have to flip all bits before the search.
1353
+ const T kFillMask = allOnes<T>();
1354
+ const T kFlipMask = value ? T(0) : kFillMask;
1355
+
1356
+ // The first BitWord requires special handling as there are some bits we want to ignore.
1357
+ T bits = (*p ^ kFlipMask) & (kFillMask << bitIndex);
1358
+ for (;;) {
1359
+ if (bits)
1360
+ return (size_t)(p - buf) * kTSizeInBits + ctz(bits);
1361
+ bits = *++p ^ kFlipMask;
1362
+ }
1363
+ }
1364
+
1365
+ // Support - BitVectorIterator
1366
+ // ===========================
1367
+
1368
+ template<typename T>
1369
+ class BitVectorIterator {
1370
+ public:
1371
+ const T* _ptr;
1372
+ size_t _idx;
1373
+ size_t _end;
1374
+ T _current;
1375
+
1376
+ ASMJIT_FORCE_INLINE BitVectorIterator(const BitVectorIterator& other) noexcept = default;
1377
+
1378
+ ASMJIT_FORCE_INLINE BitVectorIterator(const T* data, size_t numBitWords, size_t start = 0) noexcept {
1379
+ init(data, numBitWords, start);
1380
+ }
1381
+
1382
+ ASMJIT_FORCE_INLINE void init(const T* data, size_t numBitWords, size_t start = 0) noexcept {
1383
+ const T* ptr = data + (start / bitSizeOf<T>());
1384
+ size_t idx = alignDown(start, bitSizeOf<T>());
1385
+ size_t end = numBitWords * bitSizeOf<T>();
1386
+
1387
+ T bitWord = T(0);
1388
+ if (idx < end) {
1389
+ bitWord = *ptr++ & (allOnes<T>() << (start % bitSizeOf<T>()));
1390
+ while (!bitWord && (idx += bitSizeOf<T>()) < end)
1391
+ bitWord = *ptr++;
1392
+ }
1393
+
1394
+ _ptr = ptr;
1395
+ _idx = idx;
1396
+ _end = end;
1397
+ _current = bitWord;
1398
+ }
1399
+
1400
+ ASMJIT_FORCE_INLINE bool hasNext() const noexcept {
1401
+ return _current != T(0);
1402
+ }
1403
+
1404
+ ASMJIT_FORCE_INLINE size_t next() noexcept {
1405
+ T bitWord = _current;
1406
+ ASMJIT_ASSERT(bitWord != T(0));
1407
+
1408
+ uint32_t bit = ctz(bitWord);
1409
+ bitWord ^= T(1u) << bit;
1410
+
1411
+ size_t n = _idx + bit;
1412
+ while (!bitWord && (_idx += bitSizeOf<T>()) < _end)
1413
+ bitWord = *_ptr++;
1414
+
1415
+ _current = bitWord;
1416
+ return n;
1417
+ }
1418
+
1419
+ ASMJIT_FORCE_INLINE size_t peekNext() const noexcept {
1420
+ ASMJIT_ASSERT(_current != T(0));
1421
+ return _idx + ctz(_current);
1422
+ }
1423
+ };
1424
+
1425
+ // Support - BitVectorOpIterator
1426
+ // =============================
1427
+
1428
+ template<typename T, class OperatorT>
1429
+ class BitVectorOpIterator {
1430
+ public:
1431
+ enum : uint32_t {
1432
+ kTSizeInBits = bitSizeOf<T>()
1433
+ };
1434
+
1435
+ const T* _aPtr;
1436
+ const T* _bPtr;
1437
+ size_t _idx;
1438
+ size_t _end;
1439
+ T _current;
1440
+
1441
+ ASMJIT_FORCE_INLINE BitVectorOpIterator(const T* aData, const T* bData, size_t numBitWords, size_t start = 0) noexcept {
1442
+ init(aData, bData, numBitWords, start);
1443
+ }
1444
+
1445
+ ASMJIT_FORCE_INLINE void init(const T* aData, const T* bData, size_t numBitWords, size_t start = 0) noexcept {
1446
+ const T* aPtr = aData + (start / bitSizeOf<T>());
1447
+ const T* bPtr = bData + (start / bitSizeOf<T>());
1448
+ size_t idx = alignDown(start, bitSizeOf<T>());
1449
+ size_t end = numBitWords * bitSizeOf<T>();
1450
+
1451
+ T bitWord = T(0);
1452
+ if (idx < end) {
1453
+ bitWord = OperatorT::op(*aPtr++, *bPtr++) & (allOnes<T>() << (start % bitSizeOf<T>()));
1454
+ while (!bitWord && (idx += kTSizeInBits) < end)
1455
+ bitWord = OperatorT::op(*aPtr++, *bPtr++);
1456
+ }
1457
+
1458
+ _aPtr = aPtr;
1459
+ _bPtr = bPtr;
1460
+ _idx = idx;
1461
+ _end = end;
1462
+ _current = bitWord;
1463
+ }
1464
+
1465
+ ASMJIT_FORCE_INLINE bool hasNext() noexcept {
1466
+ return _current != T(0);
1467
+ }
1468
+
1469
+ ASMJIT_FORCE_INLINE size_t next() noexcept {
1470
+ T bitWord = _current;
1471
+ ASMJIT_ASSERT(bitWord != T(0));
1472
+
1473
+ uint32_t bit = ctz(bitWord);
1474
+ bitWord ^= T(1u) << bit;
1475
+
1476
+ size_t n = _idx + bit;
1477
+ while (!bitWord && (_idx += kTSizeInBits) < _end)
1478
+ bitWord = OperatorT::op(*_aPtr++, *_bPtr++);
1479
+
1480
+ _current = bitWord;
1481
+ return n;
1482
+ }
1483
+ };
1484
+
1485
+ // Support - Sorting
1486
+ // =================
1487
+
1488
+ //! Sort order.
1489
+ enum class SortOrder : uint32_t {
1490
+ //!< Ascending order.
1491
+ kAscending = 0,
1492
+ //!< Descending order.
1493
+ kDescending = 1
1494
+ };
1495
+
1496
+ //! A helper class that provides comparison of any user-defined type that
1497
+ //! implements `<` and `>` operators (primitive types are supported as well).
1498
+ template<SortOrder kOrder = SortOrder::kAscending>
1499
+ struct Compare {
1500
+ template<typename A, typename B>
1501
+ inline int operator()(const A& a, const B& b) const noexcept {
1502
+ return kOrder == SortOrder::kAscending ? int(a > b) - int(a < b) : int(a < b) - int(a > b);
1503
+ }
1504
+ };
1505
+
1506
+ //! Insertion sort.
1507
+ template<typename T, typename CompareT = Compare<SortOrder::kAscending>>
1508
+ static inline void iSort(T* base, size_t size, const CompareT& cmp = CompareT()) noexcept {
1509
+ for (T* pm = base + 1; pm < base + size; pm++)
1510
+ for (T* pl = pm; pl > base && cmp(pl[-1], pl[0]) > 0; pl--)
1511
+ std::swap(pl[-1], pl[0]);
1512
+ }
1513
+
1514
+ //! \cond
1515
+ namespace Internal {
1516
+ //! Quick-sort implementation.
1517
+ template<typename T, class CompareT>
1518
+ struct QSortImpl {
1519
+ enum : size_t {
1520
+ kStackSize = 64 * 2,
1521
+ kISortThreshold = 7
1522
+ };
1523
+
1524
+ // Based on "PDCLib - Public Domain C Library" and rewritten to C++.
1525
+ static void sort(T* base, size_t size, const CompareT& cmp) noexcept {
1526
+ T* end = base + size;
1527
+ T* stack[kStackSize];
1528
+ T** stackptr = stack;
1529
+
1530
+ for (;;) {
1531
+ if ((size_t)(end - base) > kISortThreshold) {
1532
+ // We work from second to last - first will be pivot element.
1533
+ T* pi = base + 1;
1534
+ T* pj = end - 1;
1535
+ std::swap(base[(size_t)(end - base) / 2], base[0]);
1536
+
1537
+ if (cmp(*pi , *pj ) > 0) std::swap(*pi , *pj );
1538
+ if (cmp(*base, *pj ) > 0) std::swap(*base, *pj );
1539
+ if (cmp(*pi , *base) > 0) std::swap(*pi , *base);
1540
+
1541
+ // Now we have the median for pivot element, entering main loop.
1542
+ for (;;) {
1543
+ while (pi < pj && cmp(*++pi, *base) < 0) continue; // Move `i` right until `*i >= pivot`.
1544
+ while (pj > base && cmp(*--pj, *base) > 0) continue; // Move `j` left until `*j <= pivot`.
1545
+
1546
+ if (pi > pj) break;
1547
+ std::swap(*pi, *pj);
1548
+ }
1549
+
1550
+ // Move pivot into correct place.
1551
+ std::swap(*base, *pj);
1552
+
1553
+ // Larger subfile base / end to stack, sort smaller.
1554
+ if (pj - base > end - pi) {
1555
+ // Left is larger.
1556
+ *stackptr++ = base;
1557
+ *stackptr++ = pj;
1558
+ base = pi;
1559
+ }
1560
+ else {
1561
+ // Right is larger.
1562
+ *stackptr++ = pi;
1563
+ *stackptr++ = end;
1564
+ end = pj;
1565
+ }
1566
+ ASMJIT_ASSERT(stackptr <= stack + kStackSize);
1567
+ }
1568
+ else {
1569
+ // UB sanitizer doesn't like applying offset to a nullptr base.
1570
+ if (base != end)
1571
+ iSort(base, (size_t)(end - base), cmp);
1572
+
1573
+ if (stackptr == stack)
1574
+ break;
1575
+
1576
+ end = *--stackptr;
1577
+ base = *--stackptr;
1578
+ }
1579
+ }
1580
+ }
1581
+ };
1582
+ }
1583
+ //! \endcond
1584
+
1585
+ //! Quick sort implementation.
1586
+ //!
1587
+ //! The main reason to provide a custom qsort implementation is that we needed something that will
1588
+ //! never throw `bad_alloc` exception. This implementation doesn't use dynamic memory allocation.
1589
+ template<typename T, class CompareT = Compare<SortOrder::kAscending>>
1590
+ static inline void qSort(T* base, size_t size, const CompareT& cmp = CompareT()) noexcept {
1591
+ Internal::QSortImpl<T, CompareT>::sort(base, size, cmp);
1592
+ }
1593
+
1594
+ // Support - Array
1595
+ // ===============
1596
+
1597
+ //! Array type, similar to std::array<T, N>, with the possibility to use enums in operator[].
1598
+ //!
1599
+ //! \note The array has C semantics - the elements in the array are not initialized.
1600
+ template<typename T, size_t N>
1601
+ struct Array {
1602
+ //! \name Members
1603
+ //! \{
1604
+
1605
+ //! The underlying array data, use \ref data() to access it.
1606
+ T _data[N];
1607
+
1608
+ //! \}
1609
+
1610
+ //! \cond
1611
+ // std compatibility.
1612
+ typedef T value_type;
1613
+ typedef size_t size_type;
1614
+ typedef ptrdiff_t difference_type;
1615
+
1616
+ typedef value_type& reference;
1617
+ typedef const value_type& const_reference;
1618
+
1619
+ typedef value_type* pointer;
1620
+ typedef const value_type* const_pointer;
1621
+
1622
+ typedef pointer iterator;
1623
+ typedef const_pointer const_iterator;
1624
+ //! \endcond
1625
+
1626
+ //! \name Overloaded Operators
1627
+ //! \{
1628
+
1629
+ template<typename Index>
1630
+ inline T& operator[](const Index& index) noexcept {
1631
+ typedef typename Internal::StdInt<sizeof(Index), 1>::Type U;
1632
+ ASMJIT_ASSERT(U(index) < N);
1633
+ return _data[U(index)];
1634
+ }
1635
+
1636
+ template<typename Index>
1637
+ inline const T& operator[](const Index& index) const noexcept {
1638
+ typedef typename Internal::StdInt<sizeof(Index), 1>::Type U;
1639
+ ASMJIT_ASSERT(U(index) < N);
1640
+ return _data[U(index)];
1641
+ }
1642
+
1643
+ inline bool operator==(const Array& other) const noexcept {
1644
+ for (size_t i = 0; i < N; i++)
1645
+ if (_data[i] != other._data[i])
1646
+ return false;
1647
+ return true;
1648
+ }
1649
+
1650
+ inline bool operator!=(const Array& other) const noexcept {
1651
+ return !operator==(other);
1652
+ }
1653
+
1654
+ //! \}
1655
+
1656
+ //! \name Accessors
1657
+ //! \{
1658
+
1659
+ inline bool empty() const noexcept { return false; }
1660
+ inline size_t size() const noexcept { return N; }
1661
+
1662
+ inline T* data() noexcept { return _data; }
1663
+ inline const T* data() const noexcept { return _data; }
1664
+
1665
+ inline T& front() noexcept { return _data[0]; }
1666
+ inline const T& front() const noexcept { return _data[0]; }
1667
+
1668
+ inline T& back() noexcept { return _data[N - 1]; }
1669
+ inline const T& back() const noexcept { return _data[N - 1]; }
1670
+
1671
+ inline T* begin() noexcept { return _data; }
1672
+ inline T* end() noexcept { return _data + N; }
1673
+
1674
+ inline const T* begin() const noexcept { return _data; }
1675
+ inline const T* end() const noexcept { return _data + N; }
1676
+
1677
+ inline const T* cbegin() const noexcept { return _data; }
1678
+ inline const T* cend() const noexcept { return _data + N; }
1679
+
1680
+ //! \}
1681
+
1682
+ //! \name Utilities
1683
+ //! \{
1684
+
1685
+ inline void swap(Array& other) noexcept {
1686
+ for (size_t i = 0; i < N; i++)
1687
+ std::swap(_data[i], other._data[i]);
1688
+ }
1689
+
1690
+ inline void fill(const T& value) noexcept {
1691
+ for (size_t i = 0; i < N; i++)
1692
+ _data[i] = value;
1693
+ }
1694
+
1695
+ inline void copyFrom(const Array& other) noexcept {
1696
+ for (size_t i = 0; i < N; i++)
1697
+ _data[i] = other._data[i];
1698
+ }
1699
+
1700
+ template<typename Operator>
1701
+ inline void combine(const Array& other) noexcept {
1702
+ for (size_t i = 0; i < N; i++)
1703
+ _data[i] = Operator::op(_data[i], other._data[i]);
1704
+ }
1705
+
1706
+ template<typename Operator>
1707
+ inline T aggregate(T initialValue = T()) const noexcept {
1708
+ T value = initialValue;
1709
+ for (size_t i = 0; i < N; i++)
1710
+ value = Operator::op(value, _data[i]);
1711
+ return value;
1712
+ }
1713
+
1714
+ template<typename Fn>
1715
+ inline void forEach(Fn&& fn) noexcept {
1716
+ for (size_t i = 0; i < N; i++)
1717
+ fn(_data[i]);
1718
+ }
1719
+ //! \}
1720
+ };
1721
+
1722
+ // Support::Temporary
1723
+ // ==================
1724
+
1725
+ //! Used to pass a temporary buffer to:
1726
+ //!
1727
+ //! - Containers that use user-passed buffer as an initial storage (still can grow).
1728
+ //! - Zone allocator that would use the temporary buffer as a first block.
1729
+ struct Temporary {
1730
+ //! \name Members
1731
+ //! \{
1732
+
1733
+ void* _data;
1734
+ size_t _size;
1735
+
1736
+ //! \}
1737
+
1738
+ //! \name Construction & Destruction
1739
+ //! \{
1740
+
1741
+ inline constexpr Temporary(const Temporary& other) noexcept = default;
1742
+ inline constexpr Temporary(void* data, size_t size) noexcept
1743
+ : _data(data),
1744
+ _size(size) {}
1745
+
1746
+ //! \}
1747
+
1748
+ //! \name Overloaded Operators
1749
+ //! \{
1750
+
1751
+ inline Temporary& operator=(const Temporary& other) noexcept = default;
1752
+
1753
+ //! \}
1754
+
1755
+ //! \name Accessors
1756
+ //! \{
1757
+
1758
+ //! Returns the data storage.
1759
+ template<typename T = void>
1760
+ inline constexpr T* data() const noexcept { return static_cast<T*>(_data); }
1761
+ //! Returns the data storage size in bytes.
1762
+ inline constexpr size_t size() const noexcept { return _size; }
1763
+
1764
+ //! \}
1765
+ };
1766
+
1767
+ } // {Support}
1768
+
1769
+ //! \}
1770
+
1771
+ ASMJIT_END_NAMESPACE
1772
+
1773
+ #endif // ASMJIT_CORE_SUPPORT_H_INCLUDED