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,612 @@
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_RABUILDERS_P_H_INCLUDED
7
+ #define ASMJIT_CORE_RABUILDERS_P_H_INCLUDED
8
+
9
+ #include "../core/api-config.h"
10
+ #ifndef ASMJIT_NO_COMPILER
11
+
12
+ #include "../core/formatter.h"
13
+ #include "../core/rapass_p.h"
14
+
15
+ ASMJIT_BEGIN_NAMESPACE
16
+
17
+ //! \cond INTERNAL
18
+ //! \addtogroup asmjit_ra
19
+ //! \{
20
+
21
+ template<typename This>
22
+ class RACFGBuilderT {
23
+ public:
24
+ enum : uint32_t {
25
+ kRootIndentation = 2,
26
+ kCodeIndentation = 4,
27
+
28
+ // NOTE: This is a bit hacky. There are some nodes which are processed twice (see `onBeforeInvoke()` and
29
+ // `onBeforeRet()`) as they can insert some nodes around them. Since we don't have any flags to mark these
30
+ // we just use their position that is [at that time] unassigned.
31
+ kNodePositionDidOnBefore = 0xFFFFFFFFu
32
+ };
33
+
34
+ //! \name Members
35
+ //! \{
36
+
37
+ BaseRAPass* _pass = nullptr;
38
+ BaseCompiler* _cc = nullptr;
39
+ RABlock* _curBlock = nullptr;
40
+ RABlock* _retBlock = nullptr;
41
+ FuncNode* _funcNode = nullptr;
42
+ RARegsStats _blockRegStats {};
43
+ uint32_t _exitLabelId = Globals::kInvalidId;
44
+ ZoneVector<uint32_t> _sharedAssignmentsMap {};
45
+
46
+ // Only used by logging, it's fine to be here to prevent more #ifdefs...
47
+ bool _hasCode = false;
48
+ RABlock* _lastLoggedBlock = nullptr;
49
+
50
+ #ifndef ASMJIT_NO_LOGGING
51
+ Logger* _logger = nullptr;
52
+ FormatOptions _formatOptions {};
53
+ StringTmp<512> _sb;
54
+ #endif
55
+
56
+ //! \}
57
+
58
+ inline RACFGBuilderT(BaseRAPass* pass) noexcept
59
+ : _pass(pass),
60
+ _cc(pass->cc()) {
61
+ #ifndef ASMJIT_NO_LOGGING
62
+ _logger = _pass->hasDiagnosticOption(DiagnosticOptions::kRADebugCFG) ? _pass->logger() : nullptr;
63
+ if (_logger)
64
+ _formatOptions = _logger->options();
65
+ #endif
66
+ }
67
+
68
+ inline BaseCompiler* cc() const noexcept { return _cc; }
69
+
70
+ //! \name Run
71
+ //! \{
72
+
73
+ //! Called per function by an architecture-specific CFG builder.
74
+ Error run() noexcept {
75
+ log("[BuildCFG]\n");
76
+ ASMJIT_PROPAGATE(prepare());
77
+
78
+ logNode(_funcNode, kRootIndentation);
79
+ logBlock(_curBlock, kRootIndentation);
80
+
81
+ RABlock* entryBlock = _curBlock;
82
+ BaseNode* node = _funcNode->next();
83
+ if (ASMJIT_UNLIKELY(!node))
84
+ return DebugUtils::errored(kErrorInvalidState);
85
+
86
+ _curBlock->setFirst(_funcNode);
87
+ _curBlock->setLast(_funcNode);
88
+
89
+ RAInstBuilder ib;
90
+ ZoneVector<RABlock*> blocksWithUnknownJumps;
91
+
92
+ for (;;) {
93
+ BaseNode* next = node->next();
94
+ ASMJIT_ASSERT(node->position() == 0 || node->position() == kNodePositionDidOnBefore);
95
+
96
+ if (node->isInst()) {
97
+ // Instruction | Jump | Invoke | Return
98
+ // ------------------------------------
99
+
100
+ // Handle `InstNode`, `InvokeNode`, and `FuncRetNode`. All of them share the same interface that provides
101
+ // operands that have read/write semantics.
102
+ if (ASMJIT_UNLIKELY(!_curBlock)) {
103
+ // Unreachable code has to be removed, we cannot allocate registers in such code as we cannot do proper
104
+ // liveness analysis in such case.
105
+ removeNode(node);
106
+ node = next;
107
+ continue;
108
+ }
109
+
110
+ _hasCode = true;
111
+
112
+ if (node->isInvoke() || node->isFuncRet()) {
113
+ if (node->position() != kNodePositionDidOnBefore) {
114
+ // Call and Reg are complicated as they may insert some surrounding code around them. The simplest
115
+ // approach is to get the previous node, call the `onBefore()` handlers and then check whether
116
+ // anything changed and restart if so. By restart we mean that the current `node` would go back to
117
+ // the first possible inserted node by `onBeforeInvoke()` or `onBeforeRet()`.
118
+ BaseNode* prev = node->prev();
119
+
120
+ if (node->type() == NodeType::kInvoke)
121
+ ASMJIT_PROPAGATE(static_cast<This*>(this)->onBeforeInvoke(node->as<InvokeNode>()));
122
+ else
123
+ ASMJIT_PROPAGATE(static_cast<This*>(this)->onBeforeRet(node->as<FuncRetNode>()));
124
+
125
+ if (prev != node->prev()) {
126
+ // If this was the first node in the block and something was
127
+ // inserted before it then we have to update the first block.
128
+ if (_curBlock->first() == node)
129
+ _curBlock->setFirst(prev->next());
130
+
131
+ node->setPosition(kNodePositionDidOnBefore);
132
+ node = prev->next();
133
+
134
+ // `onBeforeInvoke()` and `onBeforeRet()` can only insert instructions.
135
+ ASMJIT_ASSERT(node->isInst());
136
+ }
137
+
138
+ // Necessary if something was inserted after `node`, but nothing before.
139
+ next = node->next();
140
+ }
141
+ else {
142
+ // Change the position back to its original value.
143
+ node->setPosition(0);
144
+ }
145
+ }
146
+
147
+ InstNode* inst = node->as<InstNode>();
148
+ logNode(inst, kCodeIndentation);
149
+
150
+ InstControlFlow cf = InstControlFlow::kRegular;
151
+ ib.reset();
152
+ ASMJIT_PROPAGATE(static_cast<This*>(this)->onInst(inst, cf, ib));
153
+
154
+ if (node->isInvoke()) {
155
+ ASMJIT_PROPAGATE(static_cast<This*>(this)->onInvoke(inst->as<InvokeNode>(), ib));
156
+ }
157
+
158
+ if (node->isFuncRet()) {
159
+ ASMJIT_PROPAGATE(static_cast<This*>(this)->onRet(inst->as<FuncRetNode>(), ib));
160
+ cf = InstControlFlow::kReturn;
161
+ }
162
+
163
+ if (cf == InstControlFlow::kJump) {
164
+ uint32_t fixedRegCount = 0;
165
+ for (RATiedReg& tiedReg : ib) {
166
+ RAWorkReg* workReg = _pass->workRegById(tiedReg.workId());
167
+ if (workReg->group() == RegGroup::kGp) {
168
+ uint32_t useId = tiedReg.useId();
169
+ if (useId == BaseReg::kIdBad) {
170
+ useId = _pass->_scratchRegIndexes[fixedRegCount++];
171
+ tiedReg.setUseId(useId);
172
+ }
173
+ _curBlock->addExitScratchGpRegs(Support::bitMask(useId));
174
+ }
175
+ }
176
+ }
177
+
178
+ ASMJIT_PROPAGATE(_pass->assignRAInst(inst, _curBlock, ib));
179
+ _blockRegStats.combineWith(ib._stats);
180
+
181
+ if (cf != InstControlFlow::kRegular) {
182
+ // Support for conditional and unconditional jumps.
183
+ if (cf == InstControlFlow::kJump || cf == InstControlFlow::kBranch) {
184
+ _curBlock->setLast(node);
185
+ _curBlock->addFlags(RABlockFlags::kHasTerminator);
186
+ _curBlock->makeConstructed(_blockRegStats);
187
+
188
+ if (!inst->hasOption(InstOptions::kUnfollow)) {
189
+ // Jmp/Jcc/Call/Loop/etc...
190
+ uint32_t opCount = inst->opCount();
191
+ const Operand* opArray = inst->operands();
192
+
193
+ // Cannot jump anywhere without operands.
194
+ if (ASMJIT_UNLIKELY(!opCount))
195
+ return DebugUtils::errored(kErrorInvalidState);
196
+
197
+ if (opArray[opCount - 1].isLabel()) {
198
+ // Labels are easy for constructing the control flow.
199
+ LabelNode* labelNode;
200
+ ASMJIT_PROPAGATE(cc()->labelNodeOf(&labelNode, opArray[opCount - 1].as<Label>()));
201
+
202
+ RABlock* targetBlock = _pass->newBlockOrExistingAt(labelNode);
203
+ if (ASMJIT_UNLIKELY(!targetBlock))
204
+ return DebugUtils::errored(kErrorOutOfMemory);
205
+
206
+ targetBlock->makeTargetable();
207
+ ASMJIT_PROPAGATE(_curBlock->appendSuccessor(targetBlock));
208
+ }
209
+ else {
210
+ // Not a label - could be jump with reg/mem operand, which means that it can go anywhere. Such jumps
211
+ // must either be annotated so the CFG can be properly constructed, otherwise we assume the worst case
212
+ // - can jump to any basic block.
213
+ JumpAnnotation* jumpAnnotation = nullptr;
214
+ _curBlock->addFlags(RABlockFlags::kHasJumpTable);
215
+
216
+ if (inst->type() == NodeType::kJump)
217
+ jumpAnnotation = inst->as<JumpNode>()->annotation();
218
+
219
+ if (jumpAnnotation) {
220
+ uint64_t timestamp = _pass->nextTimestamp();
221
+ for (uint32_t id : jumpAnnotation->labelIds()) {
222
+ LabelNode* labelNode;
223
+ ASMJIT_PROPAGATE(cc()->labelNodeOf(&labelNode, id));
224
+
225
+ RABlock* targetBlock = _pass->newBlockOrExistingAt(labelNode);
226
+ if (ASMJIT_UNLIKELY(!targetBlock))
227
+ return DebugUtils::errored(kErrorOutOfMemory);
228
+
229
+ // Prevents adding basic-block successors multiple times.
230
+ if (!targetBlock->hasTimestamp(timestamp)) {
231
+ targetBlock->setTimestamp(timestamp);
232
+ targetBlock->makeTargetable();
233
+ ASMJIT_PROPAGATE(_curBlock->appendSuccessor(targetBlock));
234
+ }
235
+ }
236
+ ASMJIT_PROPAGATE(shareAssignmentAcrossSuccessors(_curBlock));
237
+ }
238
+ else {
239
+ ASMJIT_PROPAGATE(blocksWithUnknownJumps.append(_pass->allocator(), _curBlock));
240
+ }
241
+ }
242
+ }
243
+
244
+ if (cf == InstControlFlow::kJump) {
245
+ // Unconditional jump makes the code after the jump unreachable, which will be removed instantly during
246
+ // the CFG construction; as we cannot allocate registers for instructions that are not part of any block.
247
+ // Of course we can leave these instructions as they are, however, that would only postpone the problem
248
+ // as assemblers can't encode instructions that use virtual registers.
249
+ _curBlock = nullptr;
250
+ }
251
+ else {
252
+ node = next;
253
+ if (ASMJIT_UNLIKELY(!node))
254
+ return DebugUtils::errored(kErrorInvalidState);
255
+
256
+ RABlock* consecutiveBlock;
257
+ if (node->type() == NodeType::kLabel) {
258
+ if (node->hasPassData()) {
259
+ consecutiveBlock = node->passData<RABlock>();
260
+ }
261
+ else {
262
+ consecutiveBlock = _pass->newBlock(node);
263
+ if (ASMJIT_UNLIKELY(!consecutiveBlock))
264
+ return DebugUtils::errored(kErrorOutOfMemory);
265
+ node->setPassData<RABlock>(consecutiveBlock);
266
+ }
267
+ }
268
+ else {
269
+ consecutiveBlock = _pass->newBlock(node);
270
+ if (ASMJIT_UNLIKELY(!consecutiveBlock))
271
+ return DebugUtils::errored(kErrorOutOfMemory);
272
+ }
273
+
274
+ _curBlock->addFlags(RABlockFlags::kHasConsecutive);
275
+ ASMJIT_PROPAGATE(_curBlock->prependSuccessor(consecutiveBlock));
276
+
277
+ _curBlock = consecutiveBlock;
278
+ _hasCode = false;
279
+ _blockRegStats.reset();
280
+
281
+ if (_curBlock->isConstructed())
282
+ break;
283
+ ASMJIT_PROPAGATE(_pass->addBlock(consecutiveBlock));
284
+
285
+ logBlock(_curBlock, kRootIndentation);
286
+ continue;
287
+ }
288
+ }
289
+
290
+ if (cf == InstControlFlow::kReturn) {
291
+ _curBlock->setLast(node);
292
+ _curBlock->makeConstructed(_blockRegStats);
293
+ ASMJIT_PROPAGATE(_curBlock->appendSuccessor(_retBlock));
294
+
295
+ _curBlock = nullptr;
296
+ }
297
+ }
298
+ }
299
+ else if (node->type() == NodeType::kLabel) {
300
+ // Label - Basic-Block Management
301
+ // ------------------------------
302
+
303
+ if (!_curBlock) {
304
+ // If the current code is unreachable the label makes it reachable again. We may remove the whole block in
305
+ // the future if it's not referenced though.
306
+ _curBlock = node->passData<RABlock>();
307
+
308
+ if (_curBlock) {
309
+ // If the label has a block assigned we can either continue with it or skip it if the block has been
310
+ // constructed already.
311
+ if (_curBlock->isConstructed())
312
+ break;
313
+ }
314
+ else {
315
+ // No block assigned - create a new one and assign it.
316
+ _curBlock = _pass->newBlock(node);
317
+ if (ASMJIT_UNLIKELY(!_curBlock))
318
+ return DebugUtils::errored(kErrorOutOfMemory);
319
+ node->setPassData<RABlock>(_curBlock);
320
+ }
321
+
322
+ _curBlock->makeTargetable();
323
+ _hasCode = false;
324
+ _blockRegStats.reset();
325
+ ASMJIT_PROPAGATE(_pass->addBlock(_curBlock));
326
+ }
327
+ else {
328
+ if (node->hasPassData()) {
329
+ RABlock* consecutive = node->passData<RABlock>();
330
+ consecutive->makeTargetable();
331
+
332
+ if (_curBlock == consecutive) {
333
+ // The label currently processed is part of the current block. This is only possible for multiple labels
334
+ // that are right next to each other or labels that are separated by non-code nodes like directives and
335
+ // comments.
336
+ if (ASMJIT_UNLIKELY(_hasCode))
337
+ return DebugUtils::errored(kErrorInvalidState);
338
+ }
339
+ else {
340
+ // Label makes the current block constructed. There is a chance that the Label is not used, but we don't
341
+ // know that at this point. In the worst case there would be two blocks next to each other, it's just fine.
342
+ ASMJIT_ASSERT(_curBlock->last() != node);
343
+ _curBlock->setLast(node->prev());
344
+ _curBlock->addFlags(RABlockFlags::kHasConsecutive);
345
+ _curBlock->makeConstructed(_blockRegStats);
346
+
347
+ ASMJIT_PROPAGATE(_curBlock->appendSuccessor(consecutive));
348
+ ASMJIT_PROPAGATE(_pass->addBlock(consecutive));
349
+
350
+ _curBlock = consecutive;
351
+ _hasCode = false;
352
+ _blockRegStats.reset();
353
+ }
354
+ }
355
+ else {
356
+ // First time we see this label.
357
+ if (_hasCode || _curBlock == entryBlock) {
358
+ // Cannot continue the current block if it already contains some code or it's a block entry. We need to
359
+ // create a new block and make it a successor.
360
+ ASMJIT_ASSERT(_curBlock->last() != node);
361
+ _curBlock->setLast(node->prev());
362
+ _curBlock->addFlags(RABlockFlags::kHasConsecutive);
363
+ _curBlock->makeConstructed(_blockRegStats);
364
+
365
+ RABlock* consecutive = _pass->newBlock(node);
366
+ if (ASMJIT_UNLIKELY(!consecutive))
367
+ return DebugUtils::errored(kErrorOutOfMemory);
368
+ consecutive->makeTargetable();
369
+
370
+ ASMJIT_PROPAGATE(_curBlock->appendSuccessor(consecutive));
371
+ ASMJIT_PROPAGATE(_pass->addBlock(consecutive));
372
+
373
+ _curBlock = consecutive;
374
+ _hasCode = false;
375
+ _blockRegStats.reset();
376
+ }
377
+
378
+ node->setPassData<RABlock>(_curBlock);
379
+ }
380
+ }
381
+
382
+ if (_curBlock && _curBlock != _lastLoggedBlock)
383
+ logBlock(_curBlock, kRootIndentation);
384
+ logNode(node, kRootIndentation);
385
+
386
+ // Unlikely: Assume that the exit label is reached only once per function.
387
+ if (ASMJIT_UNLIKELY(node->as<LabelNode>()->labelId() == _exitLabelId)) {
388
+ _curBlock->setLast(node);
389
+ _curBlock->makeConstructed(_blockRegStats);
390
+ ASMJIT_PROPAGATE(_pass->addExitBlock(_curBlock));
391
+
392
+ _curBlock = nullptr;
393
+ }
394
+ }
395
+ else {
396
+ // Other Nodes | Function Exit
397
+ // ---------------------------
398
+
399
+ logNode(node, kCodeIndentation);
400
+
401
+ if (node->type() == NodeType::kSentinel) {
402
+ if (node == _funcNode->endNode()) {
403
+ // Make sure we didn't flow here if this is the end of the function sentinel.
404
+ if (ASMJIT_UNLIKELY(_curBlock))
405
+ return DebugUtils::errored(kErrorInvalidState);
406
+ break;
407
+ }
408
+ }
409
+ else if (node->type() == NodeType::kFunc) {
410
+ // RAPass can only compile a single function at a time. If we
411
+ // encountered a function it must be the current one, bail if not.
412
+ if (ASMJIT_UNLIKELY(node != _funcNode))
413
+ return DebugUtils::errored(kErrorInvalidState);
414
+ // PASS if this is the first node.
415
+ }
416
+ else {
417
+ // PASS if this is a non-interesting or unknown node.
418
+ }
419
+ }
420
+
421
+ // Advance to the next node.
422
+ node = next;
423
+
424
+ // NOTE: We cannot encounter a NULL node, because every function must be terminated by a sentinel (`stop`)
425
+ // node. If we encountered a NULL node it means that something went wrong and this node list is corrupted;
426
+ // bail in such case.
427
+ if (ASMJIT_UNLIKELY(!node))
428
+ return DebugUtils::errored(kErrorInvalidState);
429
+ }
430
+
431
+ if (_pass->hasDanglingBlocks())
432
+ return DebugUtils::errored(kErrorInvalidState);
433
+
434
+ for (RABlock* block : blocksWithUnknownJumps)
435
+ handleBlockWithUnknownJump(block);
436
+
437
+ return _pass->initSharedAssignments(_sharedAssignmentsMap);
438
+ }
439
+
440
+ //! \}
441
+
442
+ //! \name Prepare
443
+ //! \{
444
+
445
+ //! Prepares the CFG builder of the current function.
446
+ Error prepare() noexcept {
447
+ FuncNode* func = _pass->func();
448
+ BaseNode* node = nullptr;
449
+
450
+ // Create entry and exit blocks.
451
+ _funcNode = func;
452
+ _retBlock = _pass->newBlockOrExistingAt(func->exitNode(), &node);
453
+
454
+ if (ASMJIT_UNLIKELY(!_retBlock))
455
+ return DebugUtils::errored(kErrorOutOfMemory);
456
+
457
+ _retBlock->makeTargetable();
458
+ ASMJIT_PROPAGATE(_pass->addExitBlock(_retBlock));
459
+
460
+ if (node != func) {
461
+ _curBlock = _pass->newBlock();
462
+ if (ASMJIT_UNLIKELY(!_curBlock))
463
+ return DebugUtils::errored(kErrorOutOfMemory);
464
+ }
465
+ else {
466
+ // Function that has no code at all.
467
+ _curBlock = _retBlock;
468
+ }
469
+
470
+ // Reset everything we may need.
471
+ _blockRegStats.reset();
472
+ _exitLabelId = func->exitNode()->labelId();
473
+
474
+ // Initially we assume there is no code in the function body.
475
+ _hasCode = false;
476
+
477
+ return _pass->addBlock(_curBlock);
478
+ }
479
+
480
+ //! \}
481
+
482
+ //! \name Utilities
483
+ //! \{
484
+
485
+ //! Called when a `node` is removed, e.g. because of a dead code elimination.
486
+ void removeNode(BaseNode* node) noexcept {
487
+ logNode(node, kRootIndentation, "<Removed>");
488
+ cc()->removeNode(node);
489
+ }
490
+
491
+ //! Handles block with unknown jump, which could be a jump to a jump table.
492
+ //!
493
+ //! If we encounter such block we basically insert all existing blocks as successors except the function entry
494
+ //! block and a natural successor, if such block exists.
495
+ Error handleBlockWithUnknownJump(RABlock* block) noexcept {
496
+ RABlocks& blocks = _pass->blocks();
497
+ size_t blockCount = blocks.size();
498
+
499
+ // NOTE: Iterate from `1` as the first block is the entry block, we don't
500
+ // allow the entry to be a successor of any block.
501
+ RABlock* consecutive = block->consecutive();
502
+ for (size_t i = 1; i < blockCount; i++) {
503
+ RABlock* candidate = blocks[i];
504
+ if (candidate == consecutive || !candidate->isTargetable())
505
+ continue;
506
+ block->appendSuccessor(candidate);
507
+ }
508
+
509
+ return shareAssignmentAcrossSuccessors(block);
510
+ }
511
+
512
+ Error shareAssignmentAcrossSuccessors(RABlock* block) noexcept {
513
+ if (block->successors().size() <= 1)
514
+ return kErrorOk;
515
+
516
+ RABlock* consecutive = block->consecutive();
517
+ uint32_t sharedAssignmentId = Globals::kInvalidId;
518
+
519
+ for (RABlock* successor : block->successors()) {
520
+ if (successor == consecutive)
521
+ continue;
522
+
523
+ if (successor->hasSharedAssignmentId()) {
524
+ if (sharedAssignmentId == Globals::kInvalidId)
525
+ sharedAssignmentId = successor->sharedAssignmentId();
526
+ else
527
+ _sharedAssignmentsMap[successor->sharedAssignmentId()] = sharedAssignmentId;
528
+ }
529
+ else {
530
+ if (sharedAssignmentId == Globals::kInvalidId)
531
+ ASMJIT_PROPAGATE(newSharedAssignmentId(&sharedAssignmentId));
532
+ successor->setSharedAssignmentId(sharedAssignmentId);
533
+ }
534
+ }
535
+ return kErrorOk;
536
+ }
537
+
538
+ Error newSharedAssignmentId(uint32_t* out) noexcept {
539
+ uint32_t id = _sharedAssignmentsMap.size();
540
+ ASMJIT_PROPAGATE(_sharedAssignmentsMap.append(_pass->allocator(), id));
541
+
542
+ *out = id;
543
+ return kErrorOk;
544
+ }
545
+
546
+ //! \}
547
+
548
+ //! \name Logging
549
+ //! \{
550
+
551
+ #ifndef ASMJIT_NO_LOGGING
552
+ template<typename... Args>
553
+ inline void log(const char* fmt, Args&&... args) noexcept {
554
+ if (_logger)
555
+ _logger->logf(fmt, std::forward<Args>(args)...);
556
+ }
557
+
558
+ inline void logBlock(RABlock* block, uint32_t indentation = 0) noexcept {
559
+ if (_logger)
560
+ _logBlock(block, indentation);
561
+ }
562
+
563
+ inline void logNode(BaseNode* node, uint32_t indentation = 0, const char* action = nullptr) noexcept {
564
+ if (_logger)
565
+ _logNode(node, indentation, action);
566
+ }
567
+
568
+ void _logBlock(RABlock* block, uint32_t indentation) noexcept {
569
+ _sb.clear();
570
+ _sb.appendChars(' ', indentation);
571
+ _sb.appendFormat("{#%u}\n", block->blockId());
572
+ _logger->log(_sb);
573
+ _lastLoggedBlock = block;
574
+ }
575
+
576
+ void _logNode(BaseNode* node, uint32_t indentation, const char* action) noexcept {
577
+ _sb.clear();
578
+ _sb.appendChars(' ', indentation);
579
+ if (action) {
580
+ _sb.append(action);
581
+ _sb.append(' ');
582
+ }
583
+ Formatter::formatNode(_sb, _formatOptions, cc(), node);
584
+ _sb.append('\n');
585
+ _logger->log(_sb);
586
+ }
587
+ #else
588
+ template<typename... Args>
589
+ inline void log(const char* fmt, Args&&... args) noexcept {
590
+ DebugUtils::unused(fmt);
591
+ DebugUtils::unused(std::forward<Args>(args)...);
592
+ }
593
+
594
+ inline void logBlock(RABlock* block, uint32_t indentation = 0) noexcept {
595
+ DebugUtils::unused(block, indentation);
596
+ }
597
+
598
+ inline void logNode(BaseNode* node, uint32_t indentation = 0, const char* action = nullptr) noexcept {
599
+ DebugUtils::unused(node, indentation, action);
600
+ }
601
+ #endif
602
+
603
+ //! \}
604
+ };
605
+
606
+ //! \}
607
+ //! \endcond
608
+
609
+ ASMJIT_END_NAMESPACE
610
+
611
+ #endif // !ASMJIT_NO_COMPILER
612
+ #endif // ASMJIT_CORE_RABUILDERS_P_H_INCLUDED