aot_emit_table.c 14 KB

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