aot_emit_variable.c 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298
  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(AOTFuncContext *func_ctx, uint32 local_idx)
  18. {
  19. AOTFunc *aot_func = func_ctx->aot_func;
  20. uint32 param_count = aot_func->func_type->param_count;
  21. return local_idx < param_count
  22. ? aot_func->func_type->types[local_idx]
  23. : aot_func->local_types[local_idx - param_count];
  24. }
  25. bool
  26. aot_compile_op_get_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  27. uint32 local_idx)
  28. {
  29. char name[32];
  30. LLVMValueRef value;
  31. AOTValue *aot_value;
  32. CHECK_LOCAL(local_idx);
  33. snprintf(name, sizeof(name), "%s%d%s", "local", local_idx, "#");
  34. if (!(value = LLVMBuildLoad(comp_ctx->builder, func_ctx->locals[local_idx],
  35. name))) {
  36. aot_set_last_error("llvm build load fail");
  37. return false;
  38. }
  39. PUSH(value, get_local_type(func_ctx, local_idx));
  40. aot_value =
  41. func_ctx->block_stack.block_list_end->value_stack.value_list_end;
  42. aot_value->is_local = true;
  43. aot_value->local_idx = local_idx;
  44. return true;
  45. fail:
  46. return false;
  47. }
  48. bool
  49. aot_compile_op_set_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  50. uint32 local_idx)
  51. {
  52. LLVMValueRef value;
  53. CHECK_LOCAL(local_idx);
  54. POP(value, get_local_type(func_ctx, local_idx));
  55. if (!LLVMBuildStore(comp_ctx->builder, value,
  56. func_ctx->locals[local_idx])) {
  57. aot_set_last_error("llvm build store fail");
  58. return false;
  59. }
  60. aot_checked_addr_list_del(func_ctx, local_idx);
  61. return true;
  62. fail:
  63. return false;
  64. }
  65. bool
  66. aot_compile_op_tee_local(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  67. uint32 local_idx)
  68. {
  69. LLVMValueRef value;
  70. uint8 type;
  71. CHECK_LOCAL(local_idx);
  72. type = get_local_type(func_ctx, local_idx);
  73. POP(value, type);
  74. if (!LLVMBuildStore(comp_ctx->builder, value,
  75. func_ctx->locals[local_idx])) {
  76. aot_set_last_error("llvm build store fail");
  77. return false;
  78. }
  79. PUSH(value, type);
  80. aot_checked_addr_list_del(func_ctx, local_idx);
  81. return true;
  82. fail:
  83. return false;
  84. }
  85. static bool
  86. compile_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  87. uint32 global_idx, bool is_set, bool is_aux_stack)
  88. {
  89. WASMRuntime * runtime = wasm_runtime_get_runtime();
  90. AOTCompData *comp_data = comp_ctx->comp_data;
  91. uint32 import_global_count = comp_data->import_global_count;
  92. uint32 global_base_offset =
  93. offsetof(AOTModuleInstance, global_table_data.bytes)
  94. + sizeof(AOTMemoryInstance) * comp_ctx->comp_data->memory_count;
  95. uint32 global_offset;
  96. uint8 global_type;
  97. LLVMValueRef offset, global_ptr_ptr, global_ptr, global, res;
  98. LLVMTypeRef ptr_type = NULL, mutable_ptr_type = NULL;
  99. bh_assert(global_idx < import_global_count + comp_data->global_count);
  100. if (global_idx < import_global_count) {
  101. global_offset = global_base_offset
  102. + comp_data->import_globals[global_idx].data_offset;
  103. global_type = comp_data->import_globals[global_idx].type;
  104. }
  105. else {
  106. global_offset =
  107. global_base_offset
  108. + comp_data->globals[global_idx - import_global_count].data_offset;
  109. global_type = comp_data->globals[global_idx - import_global_count].type;
  110. }
  111. offset = I32_CONST(global_offset);
  112. if (!(global_ptr =
  113. LLVMBuildInBoundsGEP(comp_ctx->builder, func_ctx->aot_inst,
  114. &offset, 1, "global_ptr_tmp"))) {
  115. aot_set_last_error("llvm build in bounds gep failed.");
  116. return false;
  117. }
  118. switch (global_type) {
  119. case VALUE_TYPE_I32:
  120. case VALUE_TYPE_EXTERNREF:
  121. case VALUE_TYPE_FUNCREF:
  122. ptr_type = comp_ctx->basic_types.int32_ptr_type;
  123. break;
  124. case VALUE_TYPE_I64:
  125. ptr_type = comp_ctx->basic_types.int64_ptr_type;
  126. break;
  127. case VALUE_TYPE_F32:
  128. ptr_type = comp_ctx->basic_types.float32_ptr_type;
  129. break;
  130. case VALUE_TYPE_F64:
  131. ptr_type = comp_ctx->basic_types.float64_ptr_type;
  132. break;
  133. case VALUE_TYPE_V128:
  134. ptr_type = comp_ctx->basic_types.v128_ptr_type;
  135. break;
  136. default:
  137. bh_assert("unknown type");
  138. break;
  139. }
  140. // check if import mutable global
  141. if (!(global_idx < import_global_count &&
  142. comp_data->import_globals[global_idx].is_mutable &&
  143. comp_data->import_globals[global_idx].module_name != CONST_STR_POOL_DESC(runtime, WAMR_CSP_GOT_func))) {
  144. if (!(global_ptr = LLVMBuildBitCast(comp_ctx->builder, global_ptr,
  145. ptr_type, "global_ptr"))) {
  146. aot_set_last_error("llvm build bit cast failed.");
  147. return false;
  148. }
  149. } else {
  150. // if yes, a pointer to origin value is saved in the global data
  151. if (comp_ctx->pointer_size == sizeof(uint32))
  152. mutable_ptr_type = comp_ctx->basic_types.int32_ptr_type;
  153. else
  154. mutable_ptr_type = comp_ctx->basic_types.int64_ptr_type;
  155. if (!(global_ptr_ptr = LLVMBuildBitCast(comp_ctx->builder, global_ptr,
  156. mutable_ptr_type, "global_ptr_ptr"))) {
  157. aot_set_last_error("llvm build bit cast failed.");
  158. return false;
  159. }
  160. if (!(global_ptr = LLVMBuildLoad(comp_ctx->builder,
  161. global_ptr_ptr, "global_ptr"))) {
  162. aot_set_last_error("llvm build load failed.");
  163. return false;
  164. }
  165. if (!(global_ptr = LLVMBuildIntToPtr(comp_ctx->builder,
  166. global_ptr,
  167. ptr_type, "global_ptr"))) {
  168. aot_set_last_error("llvm build bit cast failed.");
  169. return false;
  170. }
  171. if (!(global = LLVMBuildLoad(comp_ctx->builder,
  172. global_ptr, "global"))) {
  173. aot_set_last_error("llvm build load failed.");
  174. return false;
  175. }
  176. }
  177. if (!is_set) {
  178. if (!(global =
  179. LLVMBuildLoad(comp_ctx->builder, global_ptr, "global"))) {
  180. aot_set_last_error("llvm build load failed.");
  181. return false;
  182. }
  183. /* All globals' data is 4-byte aligned */
  184. LLVMSetAlignment(global, 4);
  185. PUSH(global, global_type);
  186. }
  187. else {
  188. POP(global, global_type);
  189. if (is_aux_stack && comp_ctx->enable_aux_stack_check) {
  190. LLVMBasicBlockRef block_curr =
  191. LLVMGetInsertBlock(comp_ctx->builder);
  192. LLVMBasicBlockRef check_overflow_succ, check_underflow_succ;
  193. LLVMValueRef cmp;
  194. /* Add basic blocks */
  195. if (!(check_overflow_succ = LLVMAppendBasicBlockInContext(
  196. comp_ctx->context, func_ctx->func,
  197. "check_overflow_succ"))) {
  198. aot_set_last_error("llvm add basic block failed.");
  199. return false;
  200. }
  201. LLVMMoveBasicBlockAfter(check_overflow_succ, block_curr);
  202. if (!(check_underflow_succ = LLVMAppendBasicBlockInContext(
  203. comp_ctx->context, func_ctx->func,
  204. "check_underflow_succ"))) {
  205. aot_set_last_error("llvm add basic block failed.");
  206. return false;
  207. }
  208. LLVMMoveBasicBlockAfter(check_underflow_succ, check_overflow_succ);
  209. /* Check aux stack overflow */
  210. if (!(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntULE, global,
  211. func_ctx->aux_stack_bound, "cmp"))) {
  212. aot_set_last_error("llvm build icmp failed.");
  213. return false;
  214. }
  215. if (!aot_emit_exception(comp_ctx, func_ctx, EXCE_AUX_STACK_OVERFLOW,
  216. true, cmp, check_overflow_succ)) {
  217. return false;
  218. }
  219. /* Check aux stack underflow */
  220. LLVMPositionBuilderAtEnd(comp_ctx->builder, check_overflow_succ);
  221. if (!(cmp = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGT, global,
  222. func_ctx->aux_stack_bottom, "cmp"))) {
  223. aot_set_last_error("llvm build icmp failed.");
  224. return false;
  225. }
  226. if (!aot_emit_exception(comp_ctx, func_ctx,
  227. EXCE_AUX_STACK_UNDERFLOW, true, cmp,
  228. check_underflow_succ)) {
  229. return false;
  230. }
  231. LLVMPositionBuilderAtEnd(comp_ctx->builder, check_underflow_succ);
  232. }
  233. if (!(res = LLVMBuildStore(comp_ctx->builder, global, global_ptr))) {
  234. aot_set_last_error("llvm build store failed.");
  235. return false;
  236. }
  237. /* All globals' data is 4-byte aligned */
  238. LLVMSetAlignment(res, 4);
  239. }
  240. return true;
  241. fail:
  242. return false;
  243. }
  244. bool
  245. aot_compile_op_get_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  246. uint32 global_idx)
  247. {
  248. return compile_global(comp_ctx, func_ctx, global_idx, false, false);
  249. }
  250. bool
  251. aot_compile_op_set_global(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  252. uint32 global_idx, bool is_aux_stack)
  253. {
  254. return compile_global(comp_ctx, func_ctx, global_idx, true, is_aux_stack);
  255. }