aot_intrinsic.c 26 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934
  1. /*
  2. * Copyright (C) 2021 XiaoMi Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include "aot_intrinsic.h"
  6. float32
  7. aot_intrinsic_fadd_f32(float32 a, float32 b)
  8. {
  9. return a + b;
  10. }
  11. float64
  12. aot_intrinsic_fadd_f64(float64 a, float64 b)
  13. {
  14. return a + b;
  15. }
  16. float32
  17. aot_intrinsic_fsub_f32(float32 a, float32 b)
  18. {
  19. return a - b;
  20. }
  21. float64
  22. aot_intrinsic_fsub_f64(float64 a, float64 b)
  23. {
  24. return a - b;
  25. }
  26. float32
  27. aot_intrinsic_fmul_f32(float32 a, float32 b)
  28. {
  29. return a * b;
  30. }
  31. float64
  32. aot_intrinsic_fmul_f64(float64 a, float64 b)
  33. {
  34. return a * b;
  35. }
  36. float32
  37. aot_intrinsic_fdiv_f32(float32 a, float32 b)
  38. {
  39. return a / b;
  40. }
  41. float64
  42. aot_intrinsic_fdiv_f64(float64 a, float64 b)
  43. {
  44. return a / b;
  45. }
  46. float32
  47. aot_intrinsic_fabs_f32(float32 a)
  48. {
  49. return fabsf(a);
  50. }
  51. float64
  52. aot_intrinsic_fabs_f64(float64 a)
  53. {
  54. return fabs(a);
  55. }
  56. float32
  57. aot_intrinsic_ceil_f32(float32 a)
  58. {
  59. return ceilf(a);
  60. }
  61. float64
  62. aot_intrinsic_ceil_f64(float64 a)
  63. {
  64. return ceil(a);
  65. }
  66. float32
  67. aot_intrinsic_floor_f32(float32 a)
  68. {
  69. return floorf(a);
  70. }
  71. float64
  72. aot_intrinsic_floor_f64(float64 a)
  73. {
  74. return floor(a);
  75. }
  76. float32
  77. aot_intrinsic_trunc_f32(float32 a)
  78. {
  79. return truncf(a);
  80. }
  81. float64
  82. aot_intrinsic_trunc_f64(float64 a)
  83. {
  84. return trunc(a);
  85. }
  86. float32
  87. aot_intrinsic_rint_f32(float32 a)
  88. {
  89. return rintf(a);
  90. }
  91. float64
  92. aot_intrinsic_rint_f64(float64 a)
  93. {
  94. return rint(a);
  95. }
  96. float32
  97. aot_intrinsic_sqrt_f32(float32 a)
  98. {
  99. return sqrtf(a);
  100. }
  101. float64
  102. aot_intrinsic_sqrt_f64(float64 a)
  103. {
  104. return sqrt(a);
  105. }
  106. float32
  107. aot_intrinsic_copysign_f32(float32 a, float32 b)
  108. {
  109. return signbit(b) ? -fabsf(a) : fabsf(a);
  110. }
  111. float64
  112. aot_intrinsic_copysign_f64(float64 a, float64 b)
  113. {
  114. return signbit(b) ? -fabs(a) : fabs(a);
  115. }
  116. float32
  117. aot_intrinsic_fmin_f32(float32 a, float32 b)
  118. {
  119. if (isnan(a) || isnan(b))
  120. return NAN;
  121. else if (a == 0 && a == b)
  122. return signbit(a) ? a : b;
  123. else
  124. return a > b ? b : a;
  125. }
  126. float64
  127. aot_intrinsic_fmin_f64(float64 a, float64 b)
  128. {
  129. if (isnan(a) || isnan(b))
  130. return (float64)NAN;
  131. else if (a == 0 && a == b)
  132. return signbit(a) ? a : b;
  133. else
  134. return a > b ? b : a;
  135. }
  136. float32
  137. aot_intrinsic_fmax_f32(float32 a, float32 b)
  138. {
  139. if (isnan(a) || isnan(b))
  140. return NAN;
  141. else if (a == 0 && a == b)
  142. return signbit(a) ? b : a;
  143. else
  144. return a > b ? a : b;
  145. }
  146. float64
  147. aot_intrinsic_fmax_f64(float64 a, float64 b)
  148. {
  149. if (isnan(a) || isnan(b))
  150. return (float64)NAN;
  151. else if (a == 0 && a == b)
  152. return signbit(a) ? b : a;
  153. else
  154. return a > b ? a : b;
  155. }
  156. uint32
  157. aot_intrinsic_clz_i32(uint32 type)
  158. {
  159. uint32 num = 0;
  160. if (type == 0)
  161. return 32;
  162. while (!(type & 0x80000000)) {
  163. num++;
  164. type <<= 1;
  165. }
  166. return num;
  167. }
  168. uint64
  169. aot_intrinsic_clz_i64(uint64 type)
  170. {
  171. uint32 num = 0;
  172. if (type == 0)
  173. return 64;
  174. while (!(type & 0x8000000000000000LL)) {
  175. num++;
  176. type <<= 1;
  177. }
  178. return num;
  179. }
  180. uint32
  181. aot_intrinsic_ctz_i32(uint32 type)
  182. {
  183. uint32 num = 0;
  184. if (type == 0)
  185. return 32;
  186. while (!(type & 1)) {
  187. num++;
  188. type >>= 1;
  189. }
  190. return num;
  191. }
  192. uint64
  193. aot_intrinsic_ctz_i64(uint64 type)
  194. {
  195. uint32 num = 0;
  196. if (type == 0)
  197. return 64;
  198. while (!(type & 1)) {
  199. num++;
  200. type >>= 1;
  201. }
  202. return num;
  203. }
  204. uint32
  205. aot_intrinsic_popcnt_i32(uint32 u)
  206. {
  207. uint32 ret = 0;
  208. while (u) {
  209. u = (u & (u - 1));
  210. ret++;
  211. }
  212. return ret;
  213. }
  214. uint64
  215. aot_intrinsic_popcnt_i64(uint64 u)
  216. {
  217. uint32 ret = 0;
  218. while (u) {
  219. u = (u & (u - 1));
  220. ret++;
  221. }
  222. return ret;
  223. }
  224. float32
  225. aot_intrinsic_i32_to_f32(int32 i)
  226. {
  227. return (float32)i;
  228. }
  229. float32
  230. aot_intrinsic_u32_to_f32(uint32 u)
  231. {
  232. return (float32)u;
  233. }
  234. float64
  235. aot_intrinsic_i32_to_f64(int32 i)
  236. {
  237. return (float64)i;
  238. }
  239. float64
  240. aot_intrinsic_u32_to_f64(uint32 u)
  241. {
  242. return (float64)u;
  243. }
  244. float32
  245. aot_intrinsic_i64_to_f32(int64 i)
  246. {
  247. return (float32)i;
  248. }
  249. float32
  250. aot_intrinsic_u64_to_f32(uint64 u)
  251. {
  252. return (float32)u;
  253. }
  254. float64
  255. aot_intrinsic_i64_to_f64(int64 i)
  256. {
  257. return (float64)i;
  258. }
  259. float64
  260. aot_intrinsic_u64_to_f64(uint64 u)
  261. {
  262. return (float64)u;
  263. }
  264. int32
  265. aot_intrinsic_f32_to_i32(float32 f)
  266. {
  267. return (int32)f;
  268. }
  269. uint32
  270. aot_intrinsic_f32_to_u32(float32 f)
  271. {
  272. return (uint32)f;
  273. }
  274. int64
  275. aot_intrinsic_f32_to_i64(float32 f)
  276. {
  277. return (int64)f;
  278. }
  279. uint64
  280. aot_intrinsic_f32_to_u64(float32 f)
  281. {
  282. return (uint64)f;
  283. }
  284. int32
  285. aot_intrinsic_f64_to_i32(float64 f)
  286. {
  287. return (int32)f;
  288. }
  289. uint32
  290. aot_intrinsic_f64_to_u32(float64 f)
  291. {
  292. return (uint32)f;
  293. }
  294. int64
  295. aot_intrinsic_f64_to_i64(float64 f)
  296. {
  297. return (int64)f;
  298. }
  299. uint64
  300. aot_intrinsic_f64_to_u64(float64 f)
  301. {
  302. return (uint64)f;
  303. }
  304. float64
  305. aot_intrinsic_f32_to_f64(float32 f)
  306. {
  307. return (float64)f;
  308. }
  309. float32
  310. aot_intrinsic_f64_to_f32(float64 f)
  311. {
  312. return (float32)f;
  313. }
  314. int32
  315. aot_intrinsic_f32_cmp(AOTFloatCond cond, float32 lhs, float32 rhs)
  316. {
  317. switch (cond) {
  318. case FLOAT_EQ:
  319. return lhs == rhs ? 1 : 0;
  320. case FLOAT_LT:
  321. return lhs < rhs ? 1 : 0;
  322. case FLOAT_GT:
  323. return lhs > rhs ? 1 : 0;
  324. case FLOAT_LE:
  325. return lhs <= rhs ? 1 : 0;
  326. case FLOAT_GE:
  327. return lhs >= rhs ? 1 : 0;
  328. case FLOAT_NE:
  329. return (isnan(lhs) || isnan(rhs) || lhs != rhs) ? 1 : 0;
  330. case FLOAT_UNO:
  331. return (isnan(lhs) || isnan(rhs)) ? 1 : 0;
  332. default:
  333. break;
  334. }
  335. return 0;
  336. }
  337. int32
  338. aot_intrinsic_f64_cmp(AOTFloatCond cond, float64 lhs, float64 rhs)
  339. {
  340. switch (cond) {
  341. case FLOAT_EQ:
  342. return lhs == rhs ? 1 : 0;
  343. case FLOAT_LT:
  344. return lhs < rhs ? 1 : 0;
  345. case FLOAT_GT:
  346. return lhs > rhs ? 1 : 0;
  347. case FLOAT_LE:
  348. return lhs <= rhs ? 1 : 0;
  349. case FLOAT_GE:
  350. return lhs >= rhs ? 1 : 0;
  351. case FLOAT_NE:
  352. return (isnan(lhs) || isnan(rhs) || lhs != rhs) ? 1 : 0;
  353. case FLOAT_UNO:
  354. return (isnan(lhs) || isnan(rhs)) ? 1 : 0;
  355. default:
  356. break;
  357. }
  358. return 0;
  359. }
  360. int64
  361. aot_intrinsic_i64_div_s(int64 l, int64 r)
  362. {
  363. return l / r;
  364. }
  365. int32
  366. aot_intrinsic_i32_div_s(int32 l, int32 r)
  367. {
  368. return l / r;
  369. }
  370. uint32
  371. aot_intrinsic_i32_div_u(uint32 l, uint32 r)
  372. {
  373. return l / r;
  374. }
  375. int32
  376. aot_intrinsic_i32_rem_s(int32 l, int32 r)
  377. {
  378. return l % r;
  379. }
  380. uint32
  381. aot_intrinsic_i32_rem_u(uint32 l, uint32 r)
  382. {
  383. return l % r;
  384. }
  385. uint64
  386. aot_intrinsic_i64_div_u(uint64 l, uint64 r)
  387. {
  388. return l / r;
  389. }
  390. int64
  391. aot_intrinsic_i64_rem_s(int64 l, int64 r)
  392. {
  393. return l % r;
  394. }
  395. uint64
  396. aot_intrinsic_i64_rem_u(uint64 l, uint64 r)
  397. {
  398. return l % r;
  399. }
  400. uint64
  401. aot_intrinsic_i64_bit_or(uint64 l, uint64 r)
  402. {
  403. return l | r;
  404. }
  405. uint64
  406. aot_intrinsic_i64_bit_and(uint64 l, uint64 r)
  407. {
  408. return l & r;
  409. }
  410. uint64
  411. aot_intrinsic_i64_mul(uint64 l, uint64 r)
  412. {
  413. return l * r;
  414. }
  415. uint64
  416. aot_intrinsic_i64_shl(uint64 l, uint64 r)
  417. {
  418. return l << r;
  419. }
  420. uint64
  421. aot_intrinsic_i64_shr_s(uint64 l, uint64 r)
  422. {
  423. return (int64)l >> r;
  424. }
  425. uint64
  426. aot_intrinsic_i64_shr_u(uint64 l, uint64 r)
  427. {
  428. return l >> r;
  429. }
  430. #if WASM_ENABLE_WAMR_COMPILER != 0 || WASM_ENABLE_JIT != 0
  431. typedef struct {
  432. const char *llvm_intrinsic;
  433. const char *native_intrinsic;
  434. uint64 flag;
  435. } aot_intrinsic;
  436. /* clang-format off */
  437. static const aot_intrinsic g_intrinsic_mapping[] = {
  438. { "llvm.experimental.constrained.fadd.f32", "aot_intrinsic_fadd_f32", AOT_INTRINSIC_FLAG_F32_FADD },
  439. { "llvm.experimental.constrained.fadd.f64", "aot_intrinsic_fadd_f64", AOT_INTRINSIC_FLAG_F64_FADD },
  440. { "llvm.experimental.constrained.fsub.f32", "aot_intrinsic_fsub_f32", AOT_INTRINSIC_FLAG_F32_FSUB },
  441. { "llvm.experimental.constrained.fsub.f64", "aot_intrinsic_fsub_f64", AOT_INTRINSIC_FLAG_F64_FSUB },
  442. { "llvm.experimental.constrained.fmul.f32", "aot_intrinsic_fmul_f32", AOT_INTRINSIC_FLAG_F32_FMUL },
  443. { "llvm.experimental.constrained.fmul.f64", "aot_intrinsic_fmul_f64", AOT_INTRINSIC_FLAG_F64_FMUL },
  444. { "llvm.experimental.constrained.fdiv.f32", "aot_intrinsic_fdiv_f32", AOT_INTRINSIC_FLAG_F32_FDIV },
  445. { "llvm.experimental.constrained.fdiv.f64", "aot_intrinsic_fdiv_f64", AOT_INTRINSIC_FLAG_F64_FDIV },
  446. { "llvm.fabs.f32", "aot_intrinsic_fabs_f32", AOT_INTRINSIC_FLAG_F32_FABS },
  447. { "llvm.fabs.f64", "aot_intrinsic_fabs_f64", AOT_INTRINSIC_FLAG_F64_FABS },
  448. { "llvm.ceil.f32", "aot_intrinsic_ceil_f32", AOT_INTRINSIC_FLAG_F32_CEIL },
  449. { "llvm.ceil.f64", "aot_intrinsic_ceil_f64", AOT_INTRINSIC_FLAG_F64_CEIL },
  450. { "llvm.floor.f32", "aot_intrinsic_floor_f32", AOT_INTRINSIC_FLAG_F32_FLOOR },
  451. { "llvm.floor.f64", "aot_intrinsic_floor_f64", AOT_INTRINSIC_FLAG_F64_FLOOR },
  452. { "llvm.trunc.f32", "aot_intrinsic_trunc_f32", AOT_INTRINSIC_FLAG_F32_TRUNC },
  453. { "llvm.trunc.f64", "aot_intrinsic_trunc_f64", AOT_INTRINSIC_FLAG_F64_TRUNC },
  454. { "llvm.rint.f32", "aot_intrinsic_rint_f32", AOT_INTRINSIC_FLAG_F32_RINT },
  455. { "llvm.rint.f64", "aot_intrinsic_rint_f64", AOT_INTRINSIC_FLAG_F64_RINT },
  456. { "llvm.sqrt.f32", "aot_intrinsic_sqrt_f32", AOT_INTRINSIC_FLAG_F32_SQRT },
  457. { "llvm.sqrt.f64", "aot_intrinsic_sqrt_f64", AOT_INTRINSIC_FLAG_F64_SQRT },
  458. { "llvm.copysign.f32", "aot_intrinsic_copysign_f32", AOT_INTRINSIC_FLAG_F32_COPYSIGN },
  459. { "llvm.copysign.f64", "aot_intrinsic_copysign_f64", AOT_INTRINSIC_FLAG_F64_COPYSIGN },
  460. { "llvm.minnum.f32", "aot_intrinsic_fmin_f32", AOT_INTRINSIC_FLAG_F32_MIN },
  461. { "llvm.minnum.f64", "aot_intrinsic_fmin_f64", AOT_INTRINSIC_FLAG_F64_MIN },
  462. { "llvm.maxnum.f32", "aot_intrinsic_fmax_f32", AOT_INTRINSIC_FLAG_F32_MAX },
  463. { "llvm.maxnum.f64", "aot_intrinsic_fmax_f64", AOT_INTRINSIC_FLAG_F64_MAX },
  464. { "llvm.ctlz.i32", "aot_intrinsic_clz_i32", AOT_INTRINSIC_FLAG_I32_CLZ },
  465. { "llvm.ctlz.i64", "aot_intrinsic_clz_i64", AOT_INTRINSIC_FLAG_I64_CLZ },
  466. { "llvm.cttz.i32", "aot_intrinsic_ctz_i32", AOT_INTRINSIC_FLAG_I32_CTZ },
  467. { "llvm.cttz.i64", "aot_intrinsic_ctz_i64", AOT_INTRINSIC_FLAG_I64_CTZ },
  468. { "llvm.ctpop.i32", "aot_intrinsic_popcnt_i32", AOT_INTRINSIC_FLAG_I32_POPCNT },
  469. { "llvm.ctpop.i64", "aot_intrinsic_popcnt_i64", AOT_INTRINSIC_FLAG_I64_POPCNT },
  470. { "f64_convert_i32_s", "aot_intrinsic_i32_to_f64", AOT_INTRINSIC_FLAG_I32_TO_F64 },
  471. { "f64_convert_i32_u", "aot_intrinsic_u32_to_f64", AOT_INTRINSIC_FLAG_U32_TO_F64 },
  472. { "f32_convert_i32_s", "aot_intrinsic_i32_to_f32", AOT_INTRINSIC_FLAG_I32_TO_F32 },
  473. { "f32_convert_i32_u", "aot_intrinsic_u32_to_f32", AOT_INTRINSIC_FLAG_U32_TO_F32 },
  474. { "f64_convert_i64_s", "aot_intrinsic_i64_to_f64", AOT_INTRINSIC_FLAG_I32_TO_F64 },
  475. { "f64_convert_i64_u", "aot_intrinsic_u64_to_f64", AOT_INTRINSIC_FLAG_U64_TO_F64 },
  476. { "f32_convert_i64_s", "aot_intrinsic_i64_to_f32", AOT_INTRINSIC_FLAG_I64_TO_F32 },
  477. { "f32_convert_i64_u", "aot_intrinsic_u64_to_f32", AOT_INTRINSIC_FLAG_U64_TO_F32 },
  478. { "i32_trunc_f32_u", "aot_intrinsic_f32_to_u32", AOT_INTRINSIC_FLAG_F32_TO_U32 },
  479. { "i32_trunc_f32_s", "aot_intrinsic_f32_to_i32", AOT_INTRINSIC_FLAG_F32_TO_I32 },
  480. { "i32_trunc_f64_u", "aot_intrinsic_f64_to_u32", AOT_INTRINSIC_FLAG_F64_TO_U32 },
  481. { "i32_trunc_f64_s", "aot_intrinsic_f64_to_i32", AOT_INTRINSIC_FLAG_F64_TO_I32 },
  482. { "i64_trunc_f64_u", "aot_intrinsic_f64_to_u64", AOT_INTRINSIC_FLAG_F64_TO_U64 },
  483. { "i64_trunc_f32_s", "aot_intrinsic_f32_to_i64", AOT_INTRINSIC_FLAG_F32_TO_I64 },
  484. { "i64_trunc_f32_u", "aot_intrinsic_f32_to_u64", AOT_INTRINSIC_FLAG_F32_TO_U64 },
  485. { "i64_trunc_f64_s", "aot_intrinsic_f64_to_i64", AOT_INTRINSIC_FLAG_F64_TO_I64 },
  486. { "f32_demote_f64", "aot_intrinsic_f64_to_f32", AOT_INTRINSIC_FLAG_F64_TO_F32 },
  487. { "f64_promote_f32", "aot_intrinsic_f32_to_f64", AOT_INTRINSIC_FLAG_F32_TO_F64 },
  488. { "f32_cmp", "aot_intrinsic_f32_cmp", AOT_INTRINSIC_FLAG_F32_CMP },
  489. { "f64_cmp", "aot_intrinsic_f64_cmp", AOT_INTRINSIC_FLAG_F64_CMP },
  490. { "i32.const", NULL, AOT_INTRINSIC_FLAG_I32_CONST },
  491. { "i64.const", NULL, AOT_INTRINSIC_FLAG_I64_CONST },
  492. { "f32.const", NULL, AOT_INTRINSIC_FLAG_F32_CONST },
  493. { "f64.const", NULL, AOT_INTRINSIC_FLAG_F64_CONST },
  494. { "i64.div_s", "aot_intrinsic_i64_div_s", AOT_INTRINSIC_FLAG_I64_DIV_S},
  495. { "i32.div_s", "aot_intrinsic_i32_div_s", AOT_INTRINSIC_FLAG_I32_DIV_S},
  496. { "i32.div_u", "aot_intrinsic_i32_div_u", AOT_INTRINSIC_FLAG_I32_DIV_U},
  497. { "i32.rem_s", "aot_intrinsic_i32_rem_s", AOT_INTRINSIC_FLAG_I32_REM_S},
  498. { "i32.rem_u", "aot_intrinsic_i32_rem_u", AOT_INTRINSIC_FLAG_I32_REM_U},
  499. { "i64.div_u", "aot_intrinsic_i64_div_u", AOT_INTRINSIC_FLAG_I64_DIV_U},
  500. { "i64.rem_s", "aot_intrinsic_i64_rem_s", AOT_INTRINSIC_FLAG_I64_REM_S},
  501. { "i64.rem_u", "aot_intrinsic_i64_rem_u", AOT_INTRINSIC_FLAG_I64_REM_U},
  502. { "i64.or", "aot_intrinsic_i64_bit_or", AOT_INTRINSIC_FLAG_I64_BIT_OR},
  503. { "i64.and", "aot_intrinsic_i64_bit_and", AOT_INTRINSIC_FLAG_I64_BIT_AND},
  504. { "i64.mul", "aot_intrinsic_i64_mul", AOT_INTRINSIC_FLAG_I64_MUL},
  505. { "i64.shl", "aot_intrinsic_i64_shl", AOT_INTRINSIC_FLAG_I64_SHL},
  506. { "i64.shr_s", "aot_intrinsic_i64_shr_s", AOT_INTRINSIC_FLAG_I64_SHR_S},
  507. { "i64.shr_u", "aot_intrinsic_i64_shr_u", AOT_INTRINSIC_FLAG_I64_SHR_U},
  508. };
  509. /* clang-format on */
  510. static const uint32 g_intrinsic_count =
  511. sizeof(g_intrinsic_mapping) / sizeof(aot_intrinsic);
  512. const char *
  513. aot_intrinsic_get_symbol(const char *llvm_intrinsic)
  514. {
  515. uint32 cnt;
  516. for (cnt = 0; cnt < g_intrinsic_count; cnt++) {
  517. if (!strcmp(llvm_intrinsic, g_intrinsic_mapping[cnt].llvm_intrinsic)) {
  518. return g_intrinsic_mapping[cnt].native_intrinsic;
  519. }
  520. }
  521. return NULL;
  522. }
  523. static void
  524. add_intrinsic_capability(AOTCompContext *comp_ctx, uint64 flag)
  525. {
  526. uint64 group = AOT_INTRINSIC_GET_GROUP_FROM_FLAG(flag);
  527. if (group < sizeof(comp_ctx->flags) / sizeof(uint64)) {
  528. comp_ctx->flags[group] |= flag;
  529. }
  530. else {
  531. bh_log(BH_LOG_LEVEL_WARNING, __FILE__, __LINE__,
  532. "intrinsic exceeds max limit.");
  533. }
  534. }
  535. static void
  536. add_i64_common_intrinsics(AOTCompContext *comp_ctx)
  537. {
  538. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_DIV_S);
  539. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_DIV_U);
  540. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_REM_S);
  541. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_REM_U);
  542. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_BIT_OR);
  543. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_BIT_AND);
  544. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_MUL);
  545. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_SHL);
  546. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_SHR_S);
  547. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_SHR_U);
  548. }
  549. static void
  550. add_i32_common_intrinsics(AOTCompContext *comp_ctx)
  551. {
  552. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I32_DIV_S);
  553. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I32_DIV_U);
  554. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I32_REM_S);
  555. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I32_REM_U);
  556. }
  557. static void
  558. add_f32_common_intrinsics(AOTCompContext *comp_ctx)
  559. {
  560. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_FABS);
  561. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_FADD);
  562. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_FSUB);
  563. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_FMUL);
  564. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_FDIV);
  565. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_SQRT);
  566. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_CMP);
  567. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_MIN);
  568. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_MAX);
  569. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_CEIL);
  570. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_FLOOR);
  571. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_TRUNC);
  572. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_RINT);
  573. }
  574. static void
  575. add_f64_common_intrinsics(AOTCompContext *comp_ctx)
  576. {
  577. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_FABS);
  578. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_FADD);
  579. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_FSUB);
  580. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_FMUL);
  581. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_MIN);
  582. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_MAX);
  583. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_CEIL);
  584. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_FLOOR);
  585. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_TRUNC);
  586. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_RINT);
  587. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_FDIV);
  588. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_SQRT);
  589. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_CMP);
  590. }
  591. static void
  592. add_f32xi32_intrinsics(AOTCompContext *comp_ctx)
  593. {
  594. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_TO_I32);
  595. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_TO_U32);
  596. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I32_TO_F32);
  597. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_U32_TO_F32);
  598. }
  599. static void
  600. add_f64xi32_intrinsics(AOTCompContext *comp_ctx)
  601. {
  602. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_TO_I32);
  603. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_TO_U32);
  604. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I32_TO_F64);
  605. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_U32_TO_F64);
  606. }
  607. static void
  608. add_f32xi64_intrinsics(AOTCompContext *comp_ctx)
  609. {
  610. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_TO_I64);
  611. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_TO_U64);
  612. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_TO_F32);
  613. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_U64_TO_F32);
  614. }
  615. static void
  616. add_f64xi64_intrinsics(AOTCompContext *comp_ctx)
  617. {
  618. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_TO_I64);
  619. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_TO_U64);
  620. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_TO_F64);
  621. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_U64_TO_F64);
  622. }
  623. static void
  624. add_common_float_integer_conversion(AOTCompContext *comp_ctx)
  625. {
  626. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I32_TO_F32);
  627. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_U32_TO_F32);
  628. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I32_TO_F64);
  629. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_U32_TO_F64);
  630. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_TO_F32);
  631. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_U64_TO_F32);
  632. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_TO_F64);
  633. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_U64_TO_F64);
  634. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_TO_I32);
  635. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_TO_U32);
  636. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_TO_I64);
  637. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_TO_U64);
  638. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_TO_I32);
  639. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_TO_U32);
  640. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_TO_I64);
  641. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_TO_U64);
  642. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_TO_F32);
  643. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_TO_F64);
  644. }
  645. bool
  646. aot_intrinsic_check_capability(const AOTCompContext *comp_ctx,
  647. const char *llvm_intrinsic)
  648. {
  649. uint32 cnt;
  650. uint64 flag;
  651. uint64 group;
  652. for (cnt = 0; cnt < g_intrinsic_count; cnt++) {
  653. if (!strcmp(llvm_intrinsic, g_intrinsic_mapping[cnt].llvm_intrinsic)) {
  654. flag = g_intrinsic_mapping[cnt].flag;
  655. group = AOT_INTRINSIC_GET_GROUP_FROM_FLAG(flag);
  656. flag &= AOT_INTRINSIC_FLAG_MASK;
  657. if (group < sizeof(comp_ctx->flags) / sizeof(uint64)) {
  658. if (comp_ctx->flags[group] & flag) {
  659. return true;
  660. }
  661. }
  662. else {
  663. bh_log(BH_LOG_LEVEL_WARNING, __FILE__, __LINE__,
  664. "intrinsic exceeds max limit.");
  665. }
  666. }
  667. }
  668. return false;
  669. }
  670. void
  671. aot_intrinsic_fill_capability_flags(AOTCompContext *comp_ctx)
  672. {
  673. uint32 i;
  674. memset(comp_ctx->flags, 0, sizeof(comp_ctx->flags));
  675. /* Intrinsics from command line have highest priority */
  676. if (comp_ctx->builtin_intrinsics) {
  677. /* Handle 'all' group */
  678. if (strstr(comp_ctx->builtin_intrinsics, "all")) {
  679. for (i = 0; i < g_intrinsic_count; i++) {
  680. add_intrinsic_capability(comp_ctx, g_intrinsic_mapping[i].flag);
  681. }
  682. return;
  683. }
  684. /* Handle 'i32.common' group */
  685. if (strstr(comp_ctx->builtin_intrinsics, "i32.common")) {
  686. add_i32_common_intrinsics(comp_ctx);
  687. }
  688. /* Handle 'i64.common' group */
  689. if (strstr(comp_ctx->builtin_intrinsics, "i64.common")) {
  690. add_i64_common_intrinsics(comp_ctx);
  691. }
  692. /* Handle 'fp.common' group */
  693. if (strstr(comp_ctx->builtin_intrinsics, "fp.common")) {
  694. add_f32_common_intrinsics(comp_ctx);
  695. add_f64_common_intrinsics(comp_ctx);
  696. }
  697. /* Handle 'f32.common' group */
  698. if (strstr(comp_ctx->builtin_intrinsics, "f32.common")) {
  699. add_f32_common_intrinsics(comp_ctx);
  700. }
  701. /* Handle 'f64.common' group */
  702. if (strstr(comp_ctx->builtin_intrinsics, "f64.common")) {
  703. add_f64_common_intrinsics(comp_ctx);
  704. }
  705. /* Handle 'f32xi32' group */
  706. if (strstr(comp_ctx->builtin_intrinsics, "f32xi32")) {
  707. add_f32xi32_intrinsics(comp_ctx);
  708. }
  709. /* Handle 'f64xi32' group */
  710. if (strstr(comp_ctx->builtin_intrinsics, "f64xi32")) {
  711. add_f64xi32_intrinsics(comp_ctx);
  712. }
  713. /* Handle 'f32xi64' group */
  714. if (strstr(comp_ctx->builtin_intrinsics, "f32xi64")) {
  715. add_f32xi64_intrinsics(comp_ctx);
  716. }
  717. /* Handle 'f64xi64' group */
  718. if (strstr(comp_ctx->builtin_intrinsics, "f64xi64")) {
  719. add_f64xi64_intrinsics(comp_ctx);
  720. }
  721. /* Handle 'fpxint' group */
  722. if (strstr(comp_ctx->builtin_intrinsics, "fpxint")) {
  723. add_f32xi32_intrinsics(comp_ctx);
  724. add_f64xi32_intrinsics(comp_ctx);
  725. add_f32xi64_intrinsics(comp_ctx);
  726. add_f64xi64_intrinsics(comp_ctx);
  727. }
  728. /* Handle 'constop' group */
  729. if (strstr(comp_ctx->builtin_intrinsics, "constop")) {
  730. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I32_CONST);
  731. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_CONST);
  732. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_CONST);
  733. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_CONST);
  734. }
  735. /* Handle 'fp.common' group */
  736. if (strstr(comp_ctx->builtin_intrinsics, "fp.common")) {
  737. add_f32_common_intrinsics(comp_ctx);
  738. add_f64_common_intrinsics(comp_ctx);
  739. }
  740. /* Handle other single items */
  741. for (i = 0; i < g_intrinsic_count; i++) {
  742. if (strstr(comp_ctx->builtin_intrinsics,
  743. g_intrinsic_mapping[i].llvm_intrinsic)) {
  744. add_intrinsic_capability(comp_ctx, g_intrinsic_mapping[i].flag);
  745. }
  746. }
  747. return;
  748. }
  749. if (!comp_ctx->target_cpu)
  750. return;
  751. if (!strncmp(comp_ctx->target_arch, "thumb", 5)) {
  752. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I32_CONST);
  753. add_i32_common_intrinsics(comp_ctx);
  754. if (!strcmp(comp_ctx->target_cpu, "cortex-m7")) {
  755. }
  756. else if (!strcmp(comp_ctx->target_cpu, "cortex-m4")) {
  757. add_f64_common_intrinsics(comp_ctx);
  758. }
  759. else {
  760. add_f32_common_intrinsics(comp_ctx);
  761. add_f64_common_intrinsics(comp_ctx);
  762. add_i64_common_intrinsics(comp_ctx);
  763. add_common_float_integer_conversion(comp_ctx);
  764. }
  765. }
  766. else if (!strncmp(comp_ctx->target_arch, "riscv", 5)) {
  767. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I32_CONST);
  768. /*
  769. * Note: Use builtin intrinsics since hardware float operation
  770. * will cause rodata relocation
  771. */
  772. add_f32_common_intrinsics(comp_ctx);
  773. add_f64_common_intrinsics(comp_ctx);
  774. add_common_float_integer_conversion(comp_ctx);
  775. if (!strncmp(comp_ctx->target_arch, "riscv32", 7)) {
  776. add_i64_common_intrinsics(comp_ctx);
  777. }
  778. /*
  779. * LLVM 16 and later expands cttz intrinsic to a table lookup,
  780. * which involves some relocations. (unless ZBB is available,
  781. * in which case the native instructions are preferred over
  782. * the table-based lowering.)
  783. * https://reviews.llvm.org/D128911
  784. */
  785. #if LLVM_VERSION_MAJOR >= 16
  786. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I32_CTZ);
  787. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_I64_CTZ);
  788. #endif
  789. }
  790. else if (!strncmp(comp_ctx->target_arch, "xtensa", 6)) {
  791. /*
  792. * Note: Use builtin intrinsics since hardware float operation
  793. * will cause rodata relocation
  794. */
  795. add_f32_common_intrinsics(comp_ctx);
  796. add_i32_common_intrinsics(comp_ctx);
  797. add_f64_common_intrinsics(comp_ctx);
  798. add_i64_common_intrinsics(comp_ctx);
  799. add_common_float_integer_conversion(comp_ctx);
  800. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_CONST);
  801. }
  802. else {
  803. /*
  804. * Use constant value table by default
  805. */
  806. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F32_CONST);
  807. add_intrinsic_capability(comp_ctx, AOT_INTRINSIC_FLAG_F64_CONST);
  808. }
  809. }
  810. #endif /* WASM_ENABLE_WAMR_COMPILER != 0 || WASM_ENABLE_JIT != 0 */