aot_emit_variable.c 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333
  1. /*
  2. * Copyright (C) 2019 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include "aot_emit_variable.h"
  6. #include "aot_emit_exception.h"
  7. #include "../aot/aot_runtime.h"
  8. #define CHECK_LOCAL(idx) \
  9. do { \
  10. if (idx >= func_ctx->aot_func->func_type->param_count \
  11. + func_ctx->aot_func->local_count) { \
  12. aot_set_last_error("local index out of range"); \
  13. return false; \
  14. } \
  15. } while (0)
  16. static uint8
  17. get_local_type(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  18. uint32 local_idx)
  19. {
  20. AOTFunc *aot_func = func_ctx->aot_func;
  21. uint32 param_count = aot_func->func_type->param_count;
  22. uint8 local_type;
  23. local_type = local_idx < param_count
  24. ? aot_func->func_type->types[local_idx]
  25. : aot_func->local_types_wp[local_idx - param_count];
  26. if (comp_ctx->enable_gc && aot_is_type_gc_reftype(local_type))
  27. local_type = VALUE_TYPE_GC_REF;
  28. return local_type;
  29. }
  30. bool
  31. aot_compile_op_get_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  32. uint32 local_idx)
  33. {
  34. char name[32];
  35. LLVMValueRef value;
  36. AOTValue *aot_value_top;
  37. uint8 local_type;
  38. CHECK_LOCAL(local_idx);
  39. local_type = get_local_type(comp_ctx, func_ctx, local_idx);
  40. snprintf(name, sizeof(name), "%s%d%s", "local", local_idx, "#");
  41. if (!(value = LLVMBuildLoad2(comp_ctx->builder, TO_LLVM_TYPE(local_type),
  42. func_ctx->locals[local_idx], name))) {
  43. aot_set_last_error("llvm build load fail");
  44. return false;
  45. }
  46. PUSH(value, local_type);
  47. aot_value_top =
  48. func_ctx->block_stack.block_list_end->value_stack.value_list_end;
  49. aot_value_top->is_local = true;
  50. aot_value_top->local_idx = local_idx;
  51. return true;
  52. fail:
  53. return false;
  54. }
  55. static bool
  56. aot_compile_op_set_or_tee_local(AOTCompContext *comp_ctx,
  57. AOTFuncContext *func_ctx, uint32 local_idx,
  58. bool is_tee_local)
  59. {
  60. LLVMValueRef value;
  61. uint8 local_type;
  62. uint32 n;
  63. CHECK_LOCAL(local_idx);
  64. local_type = get_local_type(comp_ctx, func_ctx, local_idx);
  65. POP(value, local_type);
  66. if (comp_ctx->aot_frame) {
  67. /* Get the slot index */
  68. n = func_ctx->aot_func->local_offsets[local_idx];
  69. bh_assert(comp_ctx->aot_frame->lp[n].type == local_type);
  70. switch (local_type) {
  71. case VALUE_TYPE_I32:
  72. set_local_i32(comp_ctx->aot_frame, n, value);
  73. break;
  74. case VALUE_TYPE_I64:
  75. set_local_i64(comp_ctx->aot_frame, n, value);
  76. break;
  77. case VALUE_TYPE_F32:
  78. set_local_f32(comp_ctx->aot_frame, n, value);
  79. break;
  80. case VALUE_TYPE_F64:
  81. set_local_f64(comp_ctx->aot_frame, n, value);
  82. break;
  83. case VALUE_TYPE_V128:
  84. set_local_v128(comp_ctx->aot_frame, n, value);
  85. break;
  86. case VALUE_TYPE_FUNCREF:
  87. case VALUE_TYPE_EXTERNREF:
  88. set_local_ref(comp_ctx->aot_frame, n, value, local_type);
  89. break;
  90. #if WASM_ENABLE_GC != 0
  91. case VALUE_TYPE_GC_REF:
  92. set_local_gc_ref(comp_ctx->aot_frame, n, value, local_type);
  93. break;
  94. #endif
  95. default:
  96. bh_assert(0);
  97. break;
  98. }
  99. }
  100. if (!LLVMBuildStore(comp_ctx->builder, value,
  101. func_ctx->locals[local_idx])) {
  102. aot_set_last_error("llvm build store fail");
  103. return false;
  104. }
  105. if (is_tee_local) {
  106. PUSH(value, local_type);
  107. }
  108. aot_checked_addr_list_del(func_ctx, local_idx);
  109. return true;
  110. fail:
  111. return false;
  112. }
  113. bool
  114. aot_compile_op_set_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  115. uint32 local_idx)
  116. {
  117. return aot_compile_op_set_or_tee_local(comp_ctx, func_ctx, local_idx,
  118. false);
  119. }
  120. bool
  121. aot_compile_op_tee_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  122. uint32 local_idx)
  123. {
  124. return aot_compile_op_set_or_tee_local(comp_ctx, func_ctx, local_idx, true);
  125. }
  126. static bool
  127. compile_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  128. uint32 global_idx, bool is_set, bool is_aux_stack)
  129. {
  130. const AOTCompData *comp_data = comp_ctx->comp_data;
  131. uint32 import_global_count = comp_data->import_global_count;
  132. uint32 global_base_offset;
  133. uint32 global_offset;
  134. uint8 global_type;
  135. LLVMValueRef offset, global_ptr, global, res;
  136. LLVMTypeRef ptr_type = NULL;
  137. global_base_offset = offsetof(AOTModuleInstance, global_table_data.bytes)
  138. + sizeof(AOTMemoryInstance)
  139. * (comp_ctx->comp_data->memory_count
  140. + comp_ctx->comp_data->import_memory_count);
  141. bh_assert(global_idx < import_global_count + comp_data->global_count);
  142. if (global_idx < import_global_count) {
  143. global_offset =
  144. global_base_offset
  145. /* Get global data offset according to target info */
  146. + (comp_ctx->pointer_size == sizeof(uint64)
  147. ? comp_data->import_globals[global_idx].data_offset_64bit
  148. : comp_data->import_globals[global_idx].data_offset_32bit);
  149. global_type = comp_data->import_globals[global_idx].type.val_type;
  150. }
  151. else {
  152. global_offset =
  153. global_base_offset
  154. /* Get global data offset according to target info */
  155. + (comp_ctx->pointer_size == sizeof(uint64)
  156. ? comp_data->globals[global_idx - import_global_count]
  157. .data_offset_64bit
  158. : comp_data->globals[global_idx - import_global_count]
  159. .data_offset_32bit);
  160. global_type =
  161. comp_data->globals[global_idx - import_global_count].type.val_type;
  162. }
  163. if (comp_ctx->enable_gc && aot_is_type_gc_reftype(global_type))
  164. global_type = VALUE_TYPE_GC_REF;
  165. offset = I32_CONST(global_offset);
  166. if (!(global_ptr = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
  167. func_ctx->aot_inst, &offset, 1,
  168. "global_ptr_tmp"))) {
  169. aot_set_last_error("llvm build in bounds gep failed.");
  170. return false;
  171. }
  172. switch (global_type) {
  173. case VALUE_TYPE_I32:
  174. case VALUE_TYPE_EXTERNREF:
  175. case VALUE_TYPE_FUNCREF:
  176. ptr_type = INT32_PTR_TYPE;
  177. break;
  178. case VALUE_TYPE_I64:
  179. ptr_type = INT64_PTR_TYPE;
  180. break;
  181. case VALUE_TYPE_F32:
  182. ptr_type = F32_PTR_TYPE;
  183. break;
  184. case VALUE_TYPE_F64:
  185. ptr_type = F64_PTR_TYPE;
  186. break;
  187. case VALUE_TYPE_V128:
  188. ptr_type = V128_PTR_TYPE;
  189. break;
  190. #if WASM_ENABLE_GC != 0
  191. case VALUE_TYPE_GC_REF:
  192. ptr_type = GC_REF_PTR_TYPE;
  193. break;
  194. #endif
  195. default:
  196. bh_assert("unknown type");
  197. break;
  198. }
  199. if (!(global_ptr = LLVMBuildBitCast(comp_ctx->builder, global_ptr, ptr_type,
  200. "global_ptr"))) {
  201. aot_set_last_error("llvm build bit cast failed.");
  202. return false;
  203. }
  204. if (!is_set) {
  205. if (!(global =
  206. LLVMBuildLoad2(comp_ctx->builder, TO_LLVM_TYPE(global_type),
  207. global_ptr, "global"))) {
  208. aot_set_last_error("llvm build load failed.");
  209. return false;
  210. }
  211. /* All globals' data is 4-byte aligned */
  212. LLVMSetAlignment(global, 4);
  213. PUSH(global, global_type);
  214. }
  215. else {
  216. POP(global, global_type);
  217. if (is_aux_stack && comp_ctx->enable_aux_stack_check) {
  218. LLVMBasicBlockRef block_curr =
  219. LLVMGetInsertBlock(comp_ctx->builder);
  220. LLVMBasicBlockRef check_overflow_succ, check_underflow_succ;
  221. LLVMValueRef cmp, global_i64;
  222. /* Add basic blocks */
  223. if (!(check_overflow_succ = LLVMAppendBasicBlockInContext(
  224. comp_ctx->context, func_ctx->func,
  225. "check_overflow_succ"))) {
  226. aot_set_last_error("llvm add basic block failed.");
  227. return false;
  228. }
  229. LLVMMoveBasicBlockAfter(check_overflow_succ, block_curr);
  230. if (!(check_underflow_succ = LLVMAppendBasicBlockInContext(
  231. comp_ctx->context, func_ctx->func,
  232. "check_underflow_succ"))) {
  233. aot_set_last_error("llvm add basic block failed.");
  234. return false;
  235. }
  236. LLVMMoveBasicBlockAfter(check_underflow_succ, check_overflow_succ);
  237. if (!(global_i64 = LLVMBuildZExt(comp_ctx->builder, global,
  238. I64_TYPE, "global_i64"))) {
  239. aot_set_last_error("llvm build zext failed.");
  240. return false;
  241. }
  242. /* Check aux stack overflow */
  243. if (!(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntULE, global_i64,
  244. func_ctx->aux_stack_bound, "cmp"))) {
  245. aot_set_last_error("llvm build icmp failed.");
  246. return false;
  247. }
  248. if (!aot_emit_exception(comp_ctx, func_ctx, EXCE_AUX_STACK_OVERFLOW,
  249. true, cmp, check_overflow_succ)) {
  250. return false;
  251. }
  252. /* Check aux stack underflow */
  253. LLVMPositionBuilderAtEnd(comp_ctx->builder, check_overflow_succ);
  254. if (!(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGT, global_i64,
  255. func_ctx->aux_stack_bottom, "cmp"))) {
  256. aot_set_last_error("llvm build icmp failed.");
  257. return false;
  258. }
  259. if (!aot_emit_exception(comp_ctx, func_ctx,
  260. EXCE_AUX_STACK_UNDERFLOW, true, cmp,
  261. check_underflow_succ)) {
  262. return false;
  263. }
  264. LLVMPositionBuilderAtEnd(comp_ctx->builder, check_underflow_succ);
  265. }
  266. if (!(res = LLVMBuildStore(comp_ctx->builder, global, global_ptr))) {
  267. aot_set_last_error("llvm build store failed.");
  268. return false;
  269. }
  270. /* All globals' data is 4-byte aligned */
  271. LLVMSetAlignment(res, 4);
  272. }
  273. return true;
  274. fail:
  275. return false;
  276. }
  277. bool
  278. aot_compile_op_get_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  279. uint32 global_idx)
  280. {
  281. return compile_global(comp_ctx, func_ctx, global_idx, false, false);
  282. }
  283. bool
  284. aot_compile_op_set_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  285. uint32 global_idx, bool is_aux_stack)
  286. {
  287. return compile_global(comp_ctx, func_ctx, global_idx, true, is_aux_stack);
  288. }