diff --git a/core/iwasm/compilation/aot_compiler.c b/core/iwasm/compilation/aot_compiler.c index e99e2ae722..46bc91f019 100644 --- a/core/iwasm/compilation/aot_compiler.c +++ b/core/iwasm/compilation/aot_compiler.c @@ -2617,6 +2617,64 @@ verify_module(AOTCompContext *comp_ctx) return true; } +/* Check whether the target supports hardware atomic instructions */ +static bool +aot_require_lower_atomic_pass(AOTCompContext *comp_ctx) +{ + bool ret = false; + if (!strncmp(comp_ctx->target_arch, "riscv", 5)) { + char *feature = + LLVMGetTargetMachineFeatureString(comp_ctx->target_machine); + + if (feature) { + if (!strstr(feature, "+a")) { + ret = true; + } + LLVMDisposeMessage(feature); + } + } + return ret; +} + +/* Check whether the target needs to expand switch to if/else */ +static bool +aot_require_lower_switch_pass(AOTCompContext *comp_ctx) +{ + bool ret = false; + + /* IR switch/case will cause .rodata relocation on riscv/xtensa */ + if (!strncmp(comp_ctx->target_arch, "riscv", 5) + || !strncmp(comp_ctx->target_arch, "xtensa", 6)) { + ret = true; + } + + return ret; +} + +static bool +apply_passes_for_indirect_mode(AOTCompContext *comp_ctx) +{ + LLVMPassManagerRef common_pass_mgr; + + if (!(common_pass_mgr = LLVMCreatePassManager())) { + aot_set_last_error("create pass manager failed"); + return false; + } + + aot_add_expand_memory_op_pass(common_pass_mgr); + + if (aot_require_lower_atomic_pass(comp_ctx)) + LLVMAddLowerAtomicPass(common_pass_mgr); + + if (aot_require_lower_switch_pass(comp_ctx)) + LLVMAddLowerSwitchPass(common_pass_mgr); + + LLVMRunPassManager(common_pass_mgr, comp_ctx->module); + + LLVMDisposePassManager(common_pass_mgr); + return true; +} + bool aot_compile_wasm(AOTCompContext *comp_ctx) { @@ -2656,6 +2714,17 @@ aot_compile_wasm(AOTCompContext *comp_ctx) possible core dump. */ bh_print_time("Begin to run llvm optimization passes"); aot_apply_llvm_new_pass_manager(comp_ctx, comp_ctx->module); + + /* Run specific passes for AOT indirect mode in last since general + optimization may create some intrinsic function calls like + llvm.memset, so let's remove these function calls here. */ + if (!comp_ctx->is_jit_mode && comp_ctx->is_indirect_mode) { + bh_print_time("Begin to run optimization passes " + "for indirect mode"); + if (!apply_passes_for_indirect_mode(comp_ctx)) { + return false; + } + } bh_print_time("Finish llvm optimization passes"); } diff --git a/core/iwasm/compilation/aot_llvm_extra.cpp b/core/iwasm/compilation/aot_llvm_extra.cpp index 1ccb2f5490..47568d54b2 100644 --- a/core/iwasm/compilation/aot_llvm_extra.cpp +++ b/core/iwasm/compilation/aot_llvm_extra.cpp @@ -27,7 +27,7 @@ #include #include #include -#include +#include #include #include #include @@ -73,14 +73,33 @@ LLVM_C_EXTERN_C_END ExitOnError ExitOnErr; -class ExpandMemoryOpPass : public PassInfoMixin +class ExpandMemoryOpPass : public llvm::ModulePass { public: - PreservedAnalyses run(Function &F, FunctionAnalysisManager &AM); + static char ID; + + ExpandMemoryOpPass() + : ModulePass(ID) + {} + + bool runOnModule(Module &M) override; + + bool expandMemIntrinsicUses(Function &F); + StringRef getPassName() const override + { + return "Expand memory operation intrinsics"; + } + + void getAnalysisUsage(AnalysisUsage &AU) const override + { + AU.addRequired(); + } }; -PreservedAnalyses -ExpandMemoryOpPass::run(Function &F, FunctionAnalysisManager &AM) +char ExpandMemoryOpPass::ID = 0; + +bool +ExpandMemoryOpPass::expandMemIntrinsicUses(Function &F) { Intrinsic::ID ID = F.getIntrinsicID(); bool Changed = false; @@ -95,26 +114,27 @@ ExpandMemoryOpPass::run(Function &F, FunctionAnalysisManager &AM) auto *Memcpy = cast(Inst); Function *ParentFunc = Memcpy->getParent()->getParent(); const TargetTransformInfo &TTI = - AM.getResult(*ParentFunc); + getAnalysis().getTTI( + *ParentFunc); expandMemCpyAsLoop(Memcpy, TTI); - Memcpy->eraseFromParent(); Changed = true; + Memcpy->eraseFromParent(); break; } case Intrinsic::memmove: { auto *Memmove = cast(Inst); expandMemMoveAsLoop(Memmove); - Memmove->eraseFromParent(); Changed = true; + Memmove->eraseFromParent(); break; } case Intrinsic::memset: { auto *Memset = cast(Inst); expandMemSetAsLoop(Memset); - Memset->eraseFromParent(); Changed = true; + Memset->eraseFromParent(); break; } default: @@ -122,10 +142,46 @@ ExpandMemoryOpPass::run(Function &F, FunctionAnalysisManager &AM) } } - PreservedAnalyses PA; - PA.preserveSet(); + return Changed; +} + +bool +ExpandMemoryOpPass::runOnModule(Module &M) +{ + bool Changed = false; + + for (Function &F : M) { + if (!F.isDeclaration()) + continue; + + switch (F.getIntrinsicID()) { + case Intrinsic::memcpy: + case Intrinsic::memmove: + case Intrinsic::memset: + if (expandMemIntrinsicUses(F)) + Changed = true; + break; + + default: + break; + } + } + + return Changed; +} + +void +aot_add_expand_memory_op_pass(LLVMPassManagerRef pass) +{ + reinterpret_cast(pass)->add( + new ExpandMemoryOpPass()); +} - return PA; +void +aot_add_simple_loop_unswitch_pass(LLVMPassManagerRef pass) +{ + reinterpret_cast(pass)->add( + createSimpleLoopUnswitchLegacyPass()); } bool @@ -297,13 +353,6 @@ aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx, LLVMModuleRef module) FPM.addPass(SLPVectorizerPass()); FPM.addPass(LoadStoreVectorizerPass()); - /* Run specific passes for AOT indirect mode in last since general - optimization may create some intrinsic function calls like - llvm.memset, so let's remove these function calls here. */ - if (comp_ctx->is_indirect_mode) { - FPM.addPass(ExpandMemoryOpPass()); - } - if (comp_ctx->enable_llvm_pgo || comp_ctx->use_prof_file) { /* LICM pass: loop invariant code motion, attempting to remove as much code from the body of a loop as possible. Experiments