aot_emit_table.c 14 KB

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