aot_emit_table.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515
  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_table.h"
  6. #include "aot_emit_exception.h"
  7. #include "../aot/aot_runtime.h"
  8. uint64
  9. get_tbl_inst_offset(const AOTCompContext *comp_ctx,
  10. const AOTFuncContext *func_ctx, uint32 tbl_idx)
  11. {
  12. uint64 offset = 0, i = 0;
  13. AOTImportTable *imp_tbls = comp_ctx->comp_data->import_tables;
  14. AOTTable *tbls = comp_ctx->comp_data->tables;
  15. offset =
  16. offsetof(AOTModuleInstance, global_table_data.bytes)
  17. + (uint64)comp_ctx->comp_data->memory_count * sizeof(AOTMemoryInstance)
  18. + comp_ctx->comp_data->global_data_size;
  19. while (i < tbl_idx && i < comp_ctx->comp_data->import_table_count) {
  20. offset += offsetof(AOTTableInstance, elems);
  21. /* avoid loading from current AOTTableInstance */
  22. offset +=
  23. sizeof(uint32)
  24. * aot_get_imp_tbl_data_slots(imp_tbls + i, comp_ctx->is_jit_mode);
  25. ++i;
  26. }
  27. if (i == tbl_idx) {
  28. return offset;
  29. }
  30. tbl_idx -= comp_ctx->comp_data->import_table_count;
  31. i -= comp_ctx->comp_data->import_table_count;
  32. while (i < tbl_idx && i < comp_ctx->comp_data->table_count) {
  33. offset += offsetof(AOTTableInstance, elems);
  34. /* avoid loading from current AOTTableInstance */
  35. offset += sizeof(uint32)
  36. * aot_get_tbl_data_slots(tbls + i, comp_ctx->is_jit_mode);
  37. ++i;
  38. }
  39. return offset;
  40. }
  41. uint32
  42. get_module_inst_extra_offset(AOTCompContext *comp_ctx)
  43. {
  44. const AOTCompData *comp_data = comp_ctx->comp_data;
  45. uint32 table_count = comp_data->import_table_count + comp_data->table_count;
  46. uint64 offset = get_tbl_inst_offset(comp_ctx, NULL, table_count);
  47. uint32 offset_32 = (uint32)offset;
  48. bh_assert(offset <= UINT32_MAX);
  49. offset_32 = align_uint(offset_32, 8);
  50. return offset_32;
  51. }
  52. #if WASM_ENABLE_REF_TYPES != 0
  53. LLVMValueRef
  54. aot_compile_get_tbl_inst(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  55. uint32 tbl_idx)
  56. {
  57. LLVMValueRef offset, tbl_inst;
  58. if (!(offset =
  59. I64_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)))) {
  60. HANDLE_FAILURE("LLVMConstInt");
  61. goto fail;
  62. }
  63. if (!(tbl_inst = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
  64. func_ctx->aot_inst, &offset, 1,
  65. "tbl_inst"))) {
  66. HANDLE_FAILURE("LLVMBuildInBoundsGEP");
  67. goto fail;
  68. }
  69. return tbl_inst;
  70. fail:
  71. return NULL;
  72. }
  73. bool
  74. aot_compile_op_elem_drop(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  75. uint32 tbl_seg_idx)
  76. {
  77. LLVMTypeRef param_types[2], ret_type, func_type, func_ptr_type;
  78. LLVMValueRef param_values[2], ret_value, func, value;
  79. /* void aot_drop_table_seg(AOTModuleInstance *, uint32 ) */
  80. param_types[0] = INT8_PTR_TYPE;
  81. param_types[1] = I32_TYPE;
  82. ret_type = VOID_TYPE;
  83. if (comp_ctx->is_jit_mode)
  84. GET_AOT_FUNCTION(llvm_jit_drop_table_seg, 2);
  85. else
  86. GET_AOT_FUNCTION(aot_drop_table_seg, 2);
  87. param_values[0] = func_ctx->aot_inst;
  88. if (!(param_values[1] = I32_CONST(tbl_seg_idx))) {
  89. HANDLE_FAILURE("LLVMConstInt");
  90. goto fail;
  91. }
  92. /* "" means return void */
  93. if (!(ret_value = LLVMBuildCall2(comp_ctx->builder, func_type, func,
  94. param_values, 2, ""))) {
  95. HANDLE_FAILURE("LLVMBuildCall");
  96. goto fail;
  97. }
  98. return true;
  99. fail:
  100. return false;
  101. }
  102. static bool
  103. aot_check_table_access(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  104. uint32 tbl_idx, LLVMValueRef elem_idx)
  105. {
  106. LLVMValueRef offset, tbl_sz, cmp_elem_idx;
  107. LLVMBasicBlockRef check_elem_idx_succ;
  108. /* get the cur size of the table instance */
  109. if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
  110. + offsetof(AOTTableInstance, cur_size)))) {
  111. HANDLE_FAILURE("LLVMConstInt");
  112. goto fail;
  113. }
  114. if (!(tbl_sz = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
  115. func_ctx->aot_inst, &offset, 1,
  116. "cur_size_i8p"))) {
  117. HANDLE_FAILURE("LLVMBuildInBoundsGEP");
  118. goto fail;
  119. }
  120. if (!(tbl_sz = LLVMBuildBitCast(comp_ctx->builder, tbl_sz, INT32_PTR_TYPE,
  121. "cur_siuze_i32p"))) {
  122. HANDLE_FAILURE("LLVMBuildBitCast");
  123. goto fail;
  124. }
  125. if (!(tbl_sz = LLVMBuildLoad2(comp_ctx->builder, I32_TYPE, tbl_sz,
  126. "cur_size"))) {
  127. HANDLE_FAILURE("LLVMBuildLoad");
  128. goto fail;
  129. }
  130. /* Check if (uint32)elem index >= table size */
  131. if (!(cmp_elem_idx = LLVMBuildICmp(comp_ctx->builder, LLVMIntUGE, elem_idx,
  132. tbl_sz, "cmp_elem_idx"))) {
  133. aot_set_last_error("llvm build icmp failed.");
  134. goto fail;
  135. }
  136. /* Throw exception if elem index >= table size */
  137. if (!(check_elem_idx_succ = LLVMAppendBasicBlockInContext(
  138. comp_ctx->context, func_ctx->func, "check_elem_idx_succ"))) {
  139. aot_set_last_error("llvm add basic block failed.");
  140. goto fail;
  141. }
  142. LLVMMoveBasicBlockAfter(check_elem_idx_succ,
  143. LLVMGetInsertBlock(comp_ctx->builder));
  144. if (!(aot_emit_exception(comp_ctx, func_ctx,
  145. EXCE_OUT_OF_BOUNDS_TABLE_ACCESS, true,
  146. cmp_elem_idx, check_elem_idx_succ)))
  147. goto fail;
  148. return true;
  149. fail:
  150. return false;
  151. }
  152. bool
  153. aot_compile_op_table_get(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  154. uint32 tbl_idx)
  155. {
  156. LLVMValueRef elem_idx, offset, table_elem, func_idx;
  157. POP_I32(elem_idx);
  158. if (!aot_check_table_access(comp_ctx, func_ctx, tbl_idx, elem_idx)) {
  159. goto fail;
  160. }
  161. /* load data as i32* */
  162. if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
  163. + offsetof(AOTTableInstance, elems)))) {
  164. HANDLE_FAILURE("LLVMConstInt");
  165. goto fail;
  166. }
  167. if (!(table_elem = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
  168. func_ctx->aot_inst, &offset, 1,
  169. "table_elem_i8p"))) {
  170. aot_set_last_error("llvm build add failed.");
  171. goto fail;
  172. }
  173. if (!(table_elem = LLVMBuildBitCast(comp_ctx->builder, table_elem,
  174. INT32_PTR_TYPE, "table_elem_i32p"))) {
  175. HANDLE_FAILURE("LLVMBuildBitCast");
  176. goto fail;
  177. }
  178. /* Load function index */
  179. if (!(table_elem =
  180. LLVMBuildInBoundsGEP2(comp_ctx->builder, I32_TYPE, table_elem,
  181. &elem_idx, 1, "table_elem"))) {
  182. HANDLE_FAILURE("LLVMBuildNUWAdd");
  183. goto fail;
  184. }
  185. if (!(func_idx = LLVMBuildLoad2(comp_ctx->builder, I32_TYPE, table_elem,
  186. "func_idx"))) {
  187. HANDLE_FAILURE("LLVMBuildLoad");
  188. goto fail;
  189. }
  190. PUSH_I32(func_idx);
  191. return true;
  192. fail:
  193. return false;
  194. }
  195. bool
  196. aot_compile_op_table_set(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  197. uint32 tbl_idx)
  198. {
  199. LLVMValueRef val, elem_idx, offset, table_elem;
  200. POP_I32(val);
  201. POP_I32(elem_idx);
  202. if (!aot_check_table_access(comp_ctx, func_ctx, tbl_idx, elem_idx)) {
  203. goto fail;
  204. }
  205. /* load data as i32* */
  206. if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
  207. + offsetof(AOTTableInstance, elems)))) {
  208. HANDLE_FAILURE("LLVMConstInt");
  209. goto fail;
  210. }
  211. if (!(table_elem = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
  212. func_ctx->aot_inst, &offset, 1,
  213. "table_elem_i8p"))) {
  214. HANDLE_FAILURE("LLVMBuildInBoundsGEP");
  215. goto fail;
  216. }
  217. if (!(table_elem = LLVMBuildBitCast(comp_ctx->builder, table_elem,
  218. INT32_PTR_TYPE, "table_elem_i32p"))) {
  219. HANDLE_FAILURE("LLVMBuildBitCast");
  220. goto fail;
  221. }
  222. /* Load function index */
  223. if (!(table_elem =
  224. LLVMBuildInBoundsGEP2(comp_ctx->builder, I32_TYPE, table_elem,
  225. &elem_idx, 1, "table_elem"))) {
  226. HANDLE_FAILURE("LLVMBuildInBoundsGEP");
  227. goto fail;
  228. }
  229. if (!(LLVMBuildStore(comp_ctx->builder, val, table_elem))) {
  230. HANDLE_FAILURE("LLVMBuildStore");
  231. goto fail;
  232. }
  233. return true;
  234. fail:
  235. return false;
  236. }
  237. bool
  238. aot_compile_op_table_init(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  239. uint32 tbl_idx, uint32 tbl_seg_idx)
  240. {
  241. LLVMValueRef func, param_values[6], value;
  242. LLVMTypeRef param_types[6], ret_type, func_type, func_ptr_type;
  243. param_types[0] = INT8_PTR_TYPE;
  244. param_types[1] = I32_TYPE;
  245. param_types[2] = I32_TYPE;
  246. param_types[3] = I32_TYPE;
  247. param_types[4] = I32_TYPE;
  248. param_types[5] = I32_TYPE;
  249. ret_type = VOID_TYPE;
  250. if (comp_ctx->is_jit_mode)
  251. GET_AOT_FUNCTION(llvm_jit_table_init, 6);
  252. else
  253. GET_AOT_FUNCTION(aot_table_init, 6);
  254. param_values[0] = func_ctx->aot_inst;
  255. if (!(param_values[1] = I32_CONST(tbl_idx))) {
  256. HANDLE_FAILURE("LLVMConstInt");
  257. goto fail;
  258. }
  259. if (!(param_values[2] = I32_CONST(tbl_seg_idx))) {
  260. HANDLE_FAILURE("LLVMConstInt");
  261. goto fail;
  262. }
  263. /* n */
  264. POP_I32(param_values[3]);
  265. /* s */
  266. POP_I32(param_values[4]);
  267. /* d */
  268. POP_I32(param_values[5]);
  269. /* "" means return void */
  270. if (!(LLVMBuildCall2(comp_ctx->builder, func_type, func, param_values, 6,
  271. ""))) {
  272. HANDLE_FAILURE("LLVMBuildCall");
  273. goto fail;
  274. }
  275. return true;
  276. fail:
  277. return false;
  278. }
  279. bool
  280. aot_compile_op_table_copy(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  281. uint32 src_tbl_idx, uint32 dst_tbl_idx)
  282. {
  283. LLVMTypeRef param_types[6], ret_type, func_type, func_ptr_type;
  284. LLVMValueRef func, param_values[6], value;
  285. param_types[0] = INT8_PTR_TYPE;
  286. param_types[1] = I32_TYPE;
  287. param_types[2] = I32_TYPE;
  288. param_types[3] = I32_TYPE;
  289. param_types[4] = I32_TYPE;
  290. param_types[5] = I32_TYPE;
  291. ret_type = VOID_TYPE;
  292. if (comp_ctx->is_jit_mode)
  293. GET_AOT_FUNCTION(llvm_jit_table_copy, 6);
  294. else
  295. GET_AOT_FUNCTION(aot_table_copy, 6);
  296. param_values[0] = func_ctx->aot_inst;
  297. if (!(param_values[1] = I32_CONST(src_tbl_idx))) {
  298. HANDLE_FAILURE("LLVMConstInt");
  299. goto fail;
  300. }
  301. if (!(param_values[2] = I32_CONST(dst_tbl_idx))) {
  302. HANDLE_FAILURE("LLVMConstInt");
  303. goto fail;
  304. }
  305. /* n */
  306. POP_I32(param_values[3]);
  307. /* s */
  308. POP_I32(param_values[4]);
  309. /* d */
  310. POP_I32(param_values[5]);
  311. /* "" means return void */
  312. if (!(LLVMBuildCall2(comp_ctx->builder, func_type, func, param_values, 6,
  313. ""))) {
  314. HANDLE_FAILURE("LLVMBuildCall");
  315. goto fail;
  316. }
  317. return true;
  318. fail:
  319. return false;
  320. }
  321. bool
  322. aot_compile_op_table_size(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  323. uint32 tbl_idx)
  324. {
  325. LLVMValueRef offset, tbl_sz;
  326. if (!(offset = I32_CONST(get_tbl_inst_offset(comp_ctx, func_ctx, tbl_idx)
  327. + offsetof(AOTTableInstance, cur_size)))) {
  328. HANDLE_FAILURE("LLVMConstInt");
  329. goto fail;
  330. }
  331. if (!(tbl_sz = LLVMBuildInBoundsGEP2(comp_ctx->builder, INT8_TYPE,
  332. func_ctx->aot_inst, &offset, 1,
  333. "tbl_sz_ptr_i8"))) {
  334. HANDLE_FAILURE("LLVMBuildInBoundsGEP");
  335. goto fail;
  336. }
  337. if (!(tbl_sz = LLVMBuildBitCast(comp_ctx->builder, tbl_sz, INT32_PTR_TYPE,
  338. "tbl_sz_ptr"))) {
  339. HANDLE_FAILURE("LLVMBuildBitCast");
  340. goto fail;
  341. }
  342. if (!(tbl_sz =
  343. LLVMBuildLoad2(comp_ctx->builder, I32_TYPE, tbl_sz, "tbl_sz"))) {
  344. HANDLE_FAILURE("LLVMBuildLoad");
  345. goto fail;
  346. }
  347. PUSH_I32(tbl_sz);
  348. return true;
  349. fail:
  350. return false;
  351. }
  352. bool
  353. aot_compile_op_table_grow(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  354. uint32 tbl_idx)
  355. {
  356. LLVMTypeRef param_types[4], ret_type, func_type, func_ptr_type;
  357. LLVMValueRef func, param_values[4], ret, value;
  358. param_types[0] = INT8_PTR_TYPE;
  359. param_types[1] = I32_TYPE;
  360. param_types[2] = I32_TYPE;
  361. param_types[3] = I32_TYPE;
  362. ret_type = I32_TYPE;
  363. if (comp_ctx->is_jit_mode)
  364. GET_AOT_FUNCTION(llvm_jit_table_grow, 4);
  365. else
  366. GET_AOT_FUNCTION(aot_table_grow, 4);
  367. param_values[0] = func_ctx->aot_inst;
  368. if (!(param_values[1] = I32_CONST(tbl_idx))) {
  369. HANDLE_FAILURE("LLVMConstInt");
  370. goto fail;
  371. }
  372. /* n */
  373. POP_I32(param_values[2]);
  374. /* v */
  375. POP_I32(param_values[3]);
  376. if (!(ret = LLVMBuildCall2(comp_ctx->builder, func_type, func, param_values,
  377. 4, "table_grow"))) {
  378. HANDLE_FAILURE("LLVMBuildCall");
  379. goto fail;
  380. }
  381. PUSH_I32(ret);
  382. return true;
  383. fail:
  384. return false;
  385. }
  386. bool
  387. aot_compile_op_table_fill(AOTCompContext *comp_ctx, AOTFuncContext *func_ctx,
  388. uint32 tbl_idx)
  389. {
  390. LLVMTypeRef param_types[5], ret_type, func_type, func_ptr_type;
  391. LLVMValueRef func, param_values[5], value;
  392. param_types[0] = INT8_PTR_TYPE;
  393. param_types[1] = I32_TYPE;
  394. param_types[2] = I32_TYPE;
  395. param_types[3] = I32_TYPE;
  396. param_types[4] = I32_TYPE;
  397. ret_type = VOID_TYPE;
  398. if (comp_ctx->is_jit_mode)
  399. GET_AOT_FUNCTION(llvm_jit_table_fill, 5);
  400. else
  401. GET_AOT_FUNCTION(aot_table_fill, 5);
  402. param_values[0] = func_ctx->aot_inst;
  403. if (!(param_values[1] = I32_CONST(tbl_idx))) {
  404. HANDLE_FAILURE("LLVMConstInt");
  405. goto fail;
  406. }
  407. /* n */
  408. POP_I32(param_values[2]);
  409. /* v */
  410. POP_I32(param_values[3]);
  411. /* i */
  412. POP_I32(param_values[4]);
  413. /* "" means return void */
  414. if (!(LLVMBuildCall2(comp_ctx->builder, func_type, func, param_values, 5,
  415. ""))) {
  416. HANDLE_FAILURE("LLVMBuildCall");
  417. goto fail;
  418. }
  419. return true;
  420. fail:
  421. return false;
  422. }
  423. #endif /* WASM_ENABLE_REF_TYPES != 0 */