main.c 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. /*
  2. * Copyright (C) 2019 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include <stdlib.h>
  6. #include "bh_platform.h"
  7. #include "bh_read_file.h"
  8. #include "wasm_export.h"
  9. #include "aot_export.h"
  10. /* clang-format off */
  11. static void
  12. print_help()
  13. {
  14. printf("Usage: wamrc [options] -o output_file wasm_file\n");
  15. printf(" --target=<arch-name> Set the target arch, which has the general format: <arch><sub>\n");
  16. printf(" <arch> = x86_64, i386, aarch64, arm, thumb, xtensa, mips,\n");
  17. printf(" riscv64, riscv32.\n");
  18. printf(" Default is host arch, e.g. x86_64\n");
  19. printf(" <sub> = for ex. on arm or thumb: v5, v6m, v7a, v7m, etc.\n");
  20. printf(" Use --target=help to list supported targets\n");
  21. printf(" --target-abi=<abi> Set the target ABI, e.g. gnu, eabi, gnueabihf, msvc, etc.\n");
  22. printf(" Default is gnu if target isn't riscv64 or riscv32\n");
  23. printf(" For target riscv64 and riscv32, default is lp64d and ilp32d\n");
  24. printf(" Use --target-abi=help to list all the ABI supported\n");
  25. printf(" --cpu=<cpu> Set the target CPU (default: host CPU, e.g. skylake)\n");
  26. printf(" Use --cpu=help to list all the CPU supported\n");
  27. printf(" --cpu-features=<features> Enable or disable the CPU features\n");
  28. printf(" Use +feature to enable a feature, or -feature to disable it\n");
  29. printf(" For example, --cpu-features=+feature1,-feature2\n");
  30. printf(" Use --cpu-features=+help to list all the features supported\n");
  31. printf(" --opt-level=n Set the optimization level (0 to 3, default is 3)\n");
  32. printf(" --size-level=n Set the code size level (0 to 3, default is 3)\n");
  33. printf(" -sgx Generate code for SGX platform (Intel Software Guard Extention)\n");
  34. printf(" --bounds-checks=1/0 Enable or disable the bounds checks for memory access:\n");
  35. printf(" by default it is disabled in all 64-bit platforms except SGX and\n");
  36. printf(" in these platforms runtime does bounds checks with hardware trap,\n");
  37. printf(" and by default it is enabled in all 32-bit platforms\n");
  38. printf(" --stack-bounds-checks=1/0 Enable or disable the bounds checks for native stack:\n");
  39. printf(" if the option isn't set, the status is same as `--bounds-check`,\n");
  40. printf(" if the option is set:\n");
  41. printf(" (1) it is always enabled when `--bounds-checks` is enabled,\n");
  42. printf(" (2) else it is enabled/disabled according to the option value\n");
  43. printf(" --stack-usage=<file> Generate a stack-usage file.\n");
  44. printf(" Similarly to `clang -fstack-usage`.\n");
  45. printf(" --format=<format> Specifies the format of the output file\n");
  46. printf(" The format supported:\n");
  47. printf(" aot (default) AoT file\n");
  48. printf(" object Native object file\n");
  49. printf(" llvmir-unopt Unoptimized LLVM IR\n");
  50. printf(" llvmir-opt Optimized LLVM IR\n");
  51. printf(" --disable-bulk-memory Disable the MVP bulk memory feature\n");
  52. printf(" --enable-multi-thread Enable multi-thread feature, the dependent features bulk-memory and\n");
  53. printf(" thread-mgr will be enabled automatically\n");
  54. printf(" --enable-tail-call Enable the post-MVP tail call feature\n");
  55. printf(" --disable-simd Disable the post-MVP 128-bit SIMD feature:\n");
  56. printf(" currently 128-bit SIMD is supported for x86-64 and aarch64 targets,\n");
  57. printf(" and by default it is enabled in them and disabled in other targets\n");
  58. printf(" --disable-ref-types Disable the MVP reference types feature\n");
  59. printf(" --disable-aux-stack-check Disable auxiliary stack overflow/underflow check\n");
  60. printf(" --enable-dump-call-stack Enable stack trace feature\n");
  61. printf(" --enable-perf-profiling Enable function performance profiling\n");
  62. printf(" --enable-memory-profiling Enable memory usage profiling\n");
  63. printf(" --enable-indirect-mode Enalbe call function through symbol table but not direct call\n");
  64. printf(" --disable-llvm-intrinsics Disable the LLVM built-in intrinsics\n");
  65. printf(" --disable-llvm-lto Disable the LLVM link time optimization\n");
  66. printf(" --enable-llvm-pgo Enable LLVM PGO (Profile-Guided Optimization)\n");
  67. printf(" --use-prof-file=<file> Use profile file collected by LLVM PGO (Profile-Guided Optimization)\n");
  68. printf(" --enable-segue[=<flags>] Enable using segment register GS as the base address of linear memory,\n");
  69. printf(" only available on linux/linux-sgx x86-64, which may improve performance,\n");
  70. printf(" flags can be: i32.load, i64.load, f32.load, f64.load, v128.load,\n");
  71. printf(" i32.store, i64.store, f32.store, f64.store, v128.store\n");
  72. printf(" Use comma to separate, e.g. --enable-segue=i32.load,i64.store\n");
  73. printf(" and --enable-segue means all flags are added.\n");
  74. printf(" --emit-custom-sections=<section names>\n");
  75. printf(" Emit the specified custom sections to AoT file, using comma to separate\n");
  76. printf(" multiple names, e.g.\n");
  77. printf(" --emit-custom-sections=section1,section2,sectionN\n");
  78. printf(" -v=n Set log verbose level (0 to 5, default is 2), larger with more log\n");
  79. printf(" --version Show version information\n");
  80. printf("Examples: wamrc -o test.aot test.wasm\n");
  81. printf(" wamrc --target=i386 -o test.aot test.wasm\n");
  82. printf(" wamrc --target=i386 --format=object -o test.o test.wasm\n");
  83. }
  84. /* clang-format on */
  85. #define PRINT_HELP_AND_EXIT() \
  86. do { \
  87. print_help(); \
  88. goto fail0; \
  89. } while (0)
  90. /**
  91. * Split a string into an array of strings
  92. * Returns NULL on failure
  93. * Memory must be freed by caller
  94. * Based on: http://stackoverflow.com/a/11198630/471795
  95. */
  96. static char **
  97. split_string(char *str, int *count, const char *delimer)
  98. {
  99. char **res = NULL, **res1;
  100. char *p;
  101. int idx = 0;
  102. /* split string and append tokens to 'res' */
  103. do {
  104. p = strtok(str, delimer);
  105. str = NULL;
  106. res1 = res;
  107. res = (char **)realloc(res1, sizeof(char *) * (uint32)(idx + 1));
  108. if (res == NULL) {
  109. free(res1);
  110. return NULL;
  111. }
  112. res[idx++] = p;
  113. } while (p);
  114. /**
  115. * Due to the section name,
  116. * res[0] might contain a '\' to indicate a space
  117. * func\name -> func name
  118. */
  119. p = strchr(res[0], '\\');
  120. while (p) {
  121. *p = ' ';
  122. p = strchr(p, '\\');
  123. }
  124. if (count) {
  125. *count = idx - 1;
  126. }
  127. return res;
  128. }
  129. static uint32
  130. resolve_segue_flags(char *str_flags)
  131. {
  132. uint32 segue_flags = 0;
  133. int32 flag_count, i;
  134. char **flag_list;
  135. flag_list = split_string(str_flags, &flag_count, ",");
  136. if (flag_list) {
  137. for (i = 0; i < flag_count; i++) {
  138. if (!strcmp(flag_list[i], "i32.load")) {
  139. segue_flags |= 1 << 0;
  140. }
  141. else if (!strcmp(flag_list[i], "i64.load")) {
  142. segue_flags |= 1 << 1;
  143. }
  144. else if (!strcmp(flag_list[i], "f32.load")) {
  145. segue_flags |= 1 << 2;
  146. }
  147. else if (!strcmp(flag_list[i], "f64.load")) {
  148. segue_flags |= 1 << 3;
  149. }
  150. else if (!strcmp(flag_list[i], "v128.load")) {
  151. segue_flags |= 1 << 4;
  152. }
  153. else if (!strcmp(flag_list[i], "i32.store")) {
  154. segue_flags |= 1 << 8;
  155. }
  156. else if (!strcmp(flag_list[i], "i64.store")) {
  157. segue_flags |= 1 << 9;
  158. }
  159. else if (!strcmp(flag_list[i], "f32.store")) {
  160. segue_flags |= 1 << 10;
  161. }
  162. else if (!strcmp(flag_list[i], "f64.store")) {
  163. segue_flags |= 1 << 11;
  164. }
  165. else if (!strcmp(flag_list[i], "v128.store")) {
  166. segue_flags |= 1 << 12;
  167. }
  168. else {
  169. /* invalid flag */
  170. segue_flags = (uint32)-1;
  171. break;
  172. }
  173. }
  174. free(flag_list);
  175. }
  176. return segue_flags;
  177. }
  178. int
  179. main(int argc, char *argv[])
  180. {
  181. char *wasm_file_name = NULL, *out_file_name = NULL;
  182. uint8 *wasm_file = NULL;
  183. uint32 wasm_file_size;
  184. wasm_module_t wasm_module = NULL;
  185. aot_comp_data_t comp_data = NULL;
  186. aot_comp_context_t comp_ctx = NULL;
  187. RuntimeInitArgs init_args;
  188. AOTCompOption option = { 0 };
  189. char error_buf[128];
  190. int log_verbose_level = 2;
  191. bool sgx_mode = false, size_level_set = false;
  192. int exit_status = EXIT_FAILURE;
  193. option.opt_level = 3;
  194. option.size_level = 3;
  195. option.output_format = AOT_FORMAT_FILE;
  196. /* default value, enable or disable depends on the platform */
  197. option.bounds_checks = 2;
  198. /* default value, enable or disable depends on the platform */
  199. option.stack_bounds_checks = 2;
  200. option.enable_simd = true;
  201. option.enable_aux_stack_check = true;
  202. option.enable_bulk_memory = true;
  203. option.enable_ref_types = true;
  204. /* Process options */
  205. for (argc--, argv++; argc > 0 && argv[0][0] == '-'; argc--, argv++) {
  206. if (!strcmp(argv[0], "-o")) {
  207. argc--, argv++;
  208. if (argc < 2)
  209. PRINT_HELP_AND_EXIT();
  210. out_file_name = argv[0];
  211. }
  212. else if (!strncmp(argv[0], "--target=", 9)) {
  213. if (argv[0][9] == '\0')
  214. PRINT_HELP_AND_EXIT();
  215. option.target_arch = argv[0] + 9;
  216. }
  217. else if (!strncmp(argv[0], "--target-abi=", 13)) {
  218. if (argv[0][13] == '\0')
  219. PRINT_HELP_AND_EXIT();
  220. option.target_abi = argv[0] + 13;
  221. }
  222. else if (!strncmp(argv[0], "--cpu=", 6)) {
  223. if (argv[0][6] == '\0')
  224. PRINT_HELP_AND_EXIT();
  225. option.target_cpu = argv[0] + 6;
  226. }
  227. else if (!strncmp(argv[0], "--cpu-features=", 15)) {
  228. if (argv[0][15] == '\0')
  229. PRINT_HELP_AND_EXIT();
  230. option.cpu_features = argv[0] + 15;
  231. }
  232. else if (!strncmp(argv[0], "--opt-level=", 12)) {
  233. if (argv[0][12] == '\0')
  234. PRINT_HELP_AND_EXIT();
  235. option.opt_level = (uint32)atoi(argv[0] + 12);
  236. if (option.opt_level > 3)
  237. option.opt_level = 3;
  238. }
  239. else if (!strncmp(argv[0], "--size-level=", 13)) {
  240. if (argv[0][13] == '\0')
  241. PRINT_HELP_AND_EXIT();
  242. option.size_level = (uint32)atoi(argv[0] + 13);
  243. if (option.size_level > 3)
  244. option.size_level = 3;
  245. size_level_set = true;
  246. }
  247. else if (!strcmp(argv[0], "-sgx")) {
  248. sgx_mode = true;
  249. }
  250. else if (!strncmp(argv[0], "--bounds-checks=", 16)) {
  251. option.bounds_checks = (atoi(argv[0] + 16) == 1) ? 1 : 0;
  252. }
  253. else if (!strncmp(argv[0], "--stack-bounds-checks=", 22)) {
  254. option.stack_bounds_checks = (atoi(argv[0] + 22) == 1) ? 1 : 0;
  255. }
  256. else if (!strncmp(argv[0], "--stack-usage=", 14)) {
  257. option.stack_usage_file = argv[0] + 14;
  258. }
  259. else if (!strncmp(argv[0], "--format=", 9)) {
  260. if (argv[0][9] == '\0')
  261. PRINT_HELP_AND_EXIT();
  262. if (!strcmp(argv[0] + 9, "aot"))
  263. option.output_format = AOT_FORMAT_FILE;
  264. else if (!strcmp(argv[0] + 9, "object"))
  265. option.output_format = AOT_OBJECT_FILE;
  266. else if (!strcmp(argv[0] + 9, "llvmir-unopt"))
  267. option.output_format = AOT_LLVMIR_UNOPT_FILE;
  268. else if (!strcmp(argv[0] + 9, "llvmir-opt"))
  269. option.output_format = AOT_LLVMIR_OPT_FILE;
  270. else {
  271. printf("Invalid format %s.\n", argv[0] + 9);
  272. PRINT_HELP_AND_EXIT();
  273. }
  274. }
  275. else if (!strncmp(argv[0], "-v=", 3)) {
  276. log_verbose_level = atoi(argv[0] + 3);
  277. if (log_verbose_level < 0 || log_verbose_level > 5)
  278. PRINT_HELP_AND_EXIT();
  279. }
  280. else if (!strcmp(argv[0], "--disable-bulk-memory")) {
  281. option.enable_bulk_memory = false;
  282. }
  283. else if (!strcmp(argv[0], "--enable-multi-thread")) {
  284. option.enable_bulk_memory = true;
  285. option.enable_thread_mgr = true;
  286. option.enable_ref_types = false;
  287. }
  288. else if (!strcmp(argv[0], "--enable-tail-call")) {
  289. option.enable_tail_call = true;
  290. }
  291. else if (!strcmp(argv[0], "--enable-simd")) {
  292. /* obsolete option, kept for compatibility */
  293. option.enable_simd = true;
  294. }
  295. else if (!strcmp(argv[0], "--disable-simd")) {
  296. option.enable_simd = false;
  297. }
  298. else if (!strcmp(argv[0], "--disable-ref-types")) {
  299. option.enable_ref_types = false;
  300. }
  301. else if (!strcmp(argv[0], "--disable-aux-stack-check")) {
  302. option.enable_aux_stack_check = false;
  303. }
  304. else if (!strcmp(argv[0], "--enable-dump-call-stack")) {
  305. option.enable_aux_stack_frame = true;
  306. }
  307. else if (!strcmp(argv[0], "--enable-perf-profiling")) {
  308. option.enable_aux_stack_frame = true;
  309. }
  310. else if (!strcmp(argv[0], "--enable-memory-profiling")) {
  311. option.enable_stack_estimation = true;
  312. }
  313. else if (!strcmp(argv[0], "--enable-indirect-mode")) {
  314. option.is_indirect_mode = true;
  315. }
  316. else if (!strcmp(argv[0], "--disable-llvm-intrinsics")) {
  317. option.disable_llvm_intrinsics = true;
  318. }
  319. else if (!strcmp(argv[0], "--disable-llvm-lto")) {
  320. option.disable_llvm_lto = true;
  321. }
  322. else if (!strcmp(argv[0], "--enable-llvm-pgo")) {
  323. option.enable_llvm_pgo = true;
  324. }
  325. else if (!strncmp(argv[0], "--use-prof-file=", 16)) {
  326. if (argv[0][16] == '\0')
  327. PRINT_HELP_AND_EXIT();
  328. option.use_prof_file = argv[0] + 16;
  329. }
  330. else if (!strcmp(argv[0], "--enable-segue")) {
  331. /* all flags are enabled */
  332. option.segue_flags = 0x1F1F;
  333. }
  334. else if (!strncmp(argv[0], "--enable-segue=", 15)) {
  335. option.segue_flags = resolve_segue_flags(argv[0] + 15);
  336. if (option.segue_flags == (uint32)-1)
  337. PRINT_HELP_AND_EXIT();
  338. }
  339. else if (!strncmp(argv[0], "--emit-custom-sections=", 23)) {
  340. int len = 0;
  341. if (option.custom_sections) {
  342. free(option.custom_sections);
  343. }
  344. option.custom_sections = split_string(argv[0] + 23, &len, ",");
  345. if (!option.custom_sections) {
  346. printf("Failed to process emit-custom-sections: alloc "
  347. "memory failed\n");
  348. PRINT_HELP_AND_EXIT();
  349. }
  350. option.custom_sections_count = len;
  351. }
  352. else if (!strncmp(argv[0], "--version", 9)) {
  353. uint32 major, minor, patch;
  354. wasm_runtime_get_version(&major, &minor, &patch);
  355. printf("wamrc %u.%u.%u\n", major, minor, patch);
  356. return 0;
  357. }
  358. else
  359. PRINT_HELP_AND_EXIT();
  360. }
  361. if (argc == 0 || !out_file_name)
  362. PRINT_HELP_AND_EXIT();
  363. if (!size_level_set) {
  364. /**
  365. * Set opt level to 1 by default for Windows and MacOS as
  366. * they can not memory map out 0-2GB memory and might not
  367. * be able to meet the requirements of some AOT relocation
  368. * operations.
  369. */
  370. if (option.target_abi && !strcmp(option.target_abi, "msvc")) {
  371. LOG_VERBOSE("Set size level to 1 for Windows AOT file");
  372. option.size_level = 1;
  373. }
  374. #if defined(_WIN32) || defined(_WIN32_) || defined(__APPLE__) \
  375. || defined(__MACH__)
  376. if (!option.target_abi) {
  377. LOG_VERBOSE("Set size level to 1 for Windows or MacOS AOT file");
  378. option.size_level = 1;
  379. }
  380. #endif
  381. }
  382. if (sgx_mode) {
  383. option.size_level = 1;
  384. option.is_sgx_platform = true;
  385. }
  386. wasm_file_name = argv[0];
  387. if (!strcmp(wasm_file_name, out_file_name)) {
  388. printf("Error: input file and output file are the same");
  389. return -1;
  390. }
  391. memset(&init_args, 0, sizeof(RuntimeInitArgs));
  392. init_args.mem_alloc_type = Alloc_With_Allocator;
  393. init_args.mem_alloc_option.allocator.malloc_func = malloc;
  394. init_args.mem_alloc_option.allocator.realloc_func = realloc;
  395. init_args.mem_alloc_option.allocator.free_func = free;
  396. /* initialize runtime environment */
  397. if (!wasm_runtime_full_init(&init_args)) {
  398. printf("Init runtime environment failed.\n");
  399. return -1;
  400. }
  401. bh_log_set_verbose_level(log_verbose_level);
  402. bh_print_time("Begin to load wasm file");
  403. /* load WASM byte buffer from WASM bin file */
  404. if (!(wasm_file =
  405. (uint8 *)bh_read_file_to_buffer(wasm_file_name, &wasm_file_size)))
  406. goto fail1;
  407. if (get_package_type(wasm_file, wasm_file_size) != Wasm_Module_Bytecode) {
  408. printf("Invalid file type: expected wasm file but got other\n");
  409. goto fail2;
  410. }
  411. /* load WASM module */
  412. if (!(wasm_module = wasm_runtime_load(wasm_file, wasm_file_size, error_buf,
  413. sizeof(error_buf)))) {
  414. printf("%s\n", error_buf);
  415. goto fail2;
  416. }
  417. if (!(comp_data = aot_create_comp_data(wasm_module))) {
  418. printf("%s\n", aot_get_last_error());
  419. goto fail3;
  420. }
  421. #if WASM_ENABLE_DEBUG_AOT != 0
  422. if (!create_dwarf_extractor(comp_data, wasm_file_name)) {
  423. printf("%s:create dwarf extractor failed\n", wasm_file_name);
  424. }
  425. #endif
  426. bh_print_time("Begin to create compile context");
  427. if (!(comp_ctx = aot_create_comp_context(comp_data, &option))) {
  428. printf("%s\n", aot_get_last_error());
  429. goto fail4;
  430. }
  431. bh_print_time("Begin to compile");
  432. if (!aot_compile_wasm(comp_ctx)) {
  433. printf("%s\n", aot_get_last_error());
  434. goto fail5;
  435. }
  436. switch (option.output_format) {
  437. case AOT_LLVMIR_UNOPT_FILE:
  438. case AOT_LLVMIR_OPT_FILE:
  439. if (!aot_emit_llvm_file(comp_ctx, out_file_name)) {
  440. printf("%s\n", aot_get_last_error());
  441. goto fail5;
  442. }
  443. break;
  444. case AOT_OBJECT_FILE:
  445. if (!aot_emit_object_file(comp_ctx, out_file_name)) {
  446. printf("%s\n", aot_get_last_error());
  447. goto fail5;
  448. }
  449. break;
  450. case AOT_FORMAT_FILE:
  451. if (!aot_emit_aot_file(comp_ctx, comp_data, out_file_name)) {
  452. printf("%s\n", aot_get_last_error());
  453. goto fail5;
  454. }
  455. break;
  456. default:
  457. break;
  458. }
  459. bh_print_time("Compile end");
  460. printf("Compile success, file %s was generated.\n", out_file_name);
  461. exit_status = EXIT_SUCCESS;
  462. fail5:
  463. /* Destroy compiler context */
  464. aot_destroy_comp_context(comp_ctx);
  465. fail4:
  466. /* Destroy compile data */
  467. aot_destroy_comp_data(comp_data);
  468. fail3:
  469. /* Unload WASM module */
  470. wasm_runtime_unload(wasm_module);
  471. fail2:
  472. /* free the file buffer */
  473. wasm_runtime_free(wasm_file);
  474. fail1:
  475. /* Destroy runtime environment */
  476. wasm_runtime_destroy();
  477. fail0:
  478. /* free option.custom_sections */
  479. if (option.custom_sections) {
  480. free(option.custom_sections);
  481. }
  482. bh_print_time("wamrc return");
  483. return exit_status;
  484. }