| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419 |
- /*
- * Copyright (C) 2019 Intel Corporation. All rights reserved.
- * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- */
- #include <llvm/Passes/StandardInstrumentations.h>
- #include <llvm/Support/Error.h>
- #include <llvm/ADT/None.h>
- #include <llvm/ADT/Optional.h>
- #include <llvm/ADT/SmallVector.h>
- #include <llvm/ADT/Twine.h>
- #include <llvm/ADT/Triple.h>
- #include <llvm/Analysis/TargetTransformInfo.h>
- #include <llvm/CodeGen/TargetPassConfig.h>
- #include <llvm/ExecutionEngine/ExecutionEngine.h>
- #include <llvm/MC/MCSubtargetInfo.h>
- #include <llvm/Support/TargetSelect.h>
- #include <llvm/Target/TargetMachine.h>
- #include <llvm-c/Core.h>
- #include <llvm-c/ExecutionEngine.h>
- #include <llvm-c/Initialization.h>
- #include <llvm/ExecutionEngine/GenericValue.h>
- #include <llvm/ExecutionEngine/JITEventListener.h>
- #include <llvm/ExecutionEngine/RTDyldMemoryManager.h>
- #include <llvm/ExecutionEngine/Orc/LLJIT.h>
- #include <llvm/IR/DerivedTypes.h>
- #include <llvm/IR/Module.h>
- #include <llvm/IR/Instructions.h>
- #include <llvm/IR/IntrinsicInst.h>
- #include <llvm/IR/LegacyPassManager.h>
- #include <llvm/Support/CommandLine.h>
- #include <llvm/Support/ErrorHandling.h>
- #include <llvm/Target/CodeGenCWrappers.h>
- #include <llvm/Target/TargetMachine.h>
- #include <llvm/Target/TargetOptions.h>
- #include <llvm/Transforms/Utils/LowerMemIntrinsics.h>
- #include <llvm/Transforms/Vectorize/LoopVectorize.h>
- #include <llvm/Transforms/Vectorize/LoadStoreVectorizer.h>
- #include <llvm/Transforms/Vectorize/SLPVectorizer.h>
- #include <llvm/Transforms/Scalar/LoopRotation.h>
- #include <llvm/Transforms/Scalar/SimpleLoopUnswitch.h>
- #include <llvm/Transforms/Scalar/LICM.h>
- #include <llvm/Transforms/Scalar/GVN.h>
- #include <llvm/Passes/PassBuilder.h>
- #include <llvm/Analysis/TargetLibraryInfo.h>
- #if LLVM_VERSION_MAJOR >= 12
- #include <llvm/Analysis/AliasAnalysis.h>
- #endif
- #include <llvm/ProfileData/InstrProf.h>
- #include <cstring>
- #include "../aot/aot_runtime.h"
- #include "aot_llvm.h"
- using namespace llvm;
- using namespace llvm::orc;
- LLVM_C_EXTERN_C_BEGIN
- bool
- aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str);
- void
- aot_add_expand_memory_op_pass(LLVMPassManagerRef pass);
- void
- aot_add_simple_loop_unswitch_pass(LLVMPassManagerRef pass);
- void
- aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx, LLVMModuleRef module);
- LLVM_C_EXTERN_C_END
- ExitOnError ExitOnErr;
- class ExpandMemoryOpPass : public llvm::ModulePass
- {
- public:
- 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<TargetTransformInfoWrapperPass>();
- }
- };
- char ExpandMemoryOpPass::ID = 0;
- bool
- ExpandMemoryOpPass::expandMemIntrinsicUses(Function &F)
- {
- Intrinsic::ID ID = F.getIntrinsicID();
- bool Changed = false;
- for (auto I = F.user_begin(), E = F.user_end(); I != E;) {
- Instruction *Inst = cast<Instruction>(*I);
- ++I;
- switch (ID) {
- case Intrinsic::memcpy:
- {
- auto *Memcpy = cast<MemCpyInst>(Inst);
- Function *ParentFunc = Memcpy->getParent()->getParent();
- const TargetTransformInfo &TTI =
- getAnalysis<TargetTransformInfoWrapperPass>().getTTI(
- *ParentFunc);
- expandMemCpyAsLoop(Memcpy, TTI);
- Changed = true;
- Memcpy->eraseFromParent();
- break;
- }
- case Intrinsic::memmove:
- {
- auto *Memmove = cast<MemMoveInst>(Inst);
- expandMemMoveAsLoop(Memmove);
- Changed = true;
- Memmove->eraseFromParent();
- break;
- }
- case Intrinsic::memset:
- {
- auto *Memset = cast<MemSetInst>(Inst);
- expandMemSetAsLoop(Memset);
- Changed = true;
- Memset->eraseFromParent();
- break;
- }
- default:
- break;
- }
- }
- 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<legacy::PassManager *>(pass)->add(
- new ExpandMemoryOpPass());
- }
- void
- aot_add_simple_loop_unswitch_pass(LLVMPassManagerRef pass)
- {
- reinterpret_cast<legacy::PassManager *>(pass)->add(
- createSimpleLoopUnswitchLegacyPass());
- }
- bool
- aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str)
- {
- #if WASM_ENABLE_SIMD != 0
- if (!arch_c_str || !cpu_c_str) {
- return false;
- }
- llvm::SmallVector<std::string, 1> targetAttributes;
- llvm::Triple targetTriple(arch_c_str, "", "");
- auto targetMachine =
- std::unique_ptr<llvm::TargetMachine>(llvm::EngineBuilder().selectTarget(
- targetTriple, "", std::string(cpu_c_str), targetAttributes));
- if (!targetMachine) {
- return false;
- }
- const llvm::Triple::ArchType targetArch =
- targetMachine->getTargetTriple().getArch();
- const llvm::MCSubtargetInfo *subTargetInfo =
- targetMachine->getMCSubtargetInfo();
- if (subTargetInfo == nullptr) {
- return false;
- }
- if (targetArch == llvm::Triple::x86_64) {
- return subTargetInfo->checkFeatures("+sse4.1");
- }
- else if (targetArch == llvm::Triple::aarch64) {
- return subTargetInfo->checkFeatures("+neon");
- }
- else {
- return false;
- }
- #else
- (void)arch_c_str;
- (void)cpu_c_str;
- return true;
- #endif /* WASM_ENABLE_SIMD */
- }
- void
- aot_apply_llvm_new_pass_manager(AOTCompContext *comp_ctx, LLVMModuleRef module)
- {
- TargetMachine *TM =
- reinterpret_cast<TargetMachine *>(comp_ctx->target_machine);
- PipelineTuningOptions PTO;
- PTO.LoopVectorization = true;
- PTO.SLPVectorization = true;
- PTO.LoopUnrolling = true;
- Optional<PGOOptions> PGO = None;
- if (comp_ctx->enable_llvm_pgo) {
- /* Disable static counter allocation for value profiler,
- it will be allocated by runtime */
- const char *argv[] = { "", "-vp-static-alloc=false" };
- cl::ParseCommandLineOptions(2, argv);
- PGO = PGOOptions("", "", "", PGOOptions::IRInstr);
- }
- else if (comp_ctx->use_prof_file) {
- PGO = PGOOptions(comp_ctx->use_prof_file, "", "", PGOOptions::IRUse);
- }
- #ifdef DEBUG_PASS
- PassInstrumentationCallbacks PIC;
- PassBuilder PB(TM, PTO, PGO, &PIC);
- #else
- #if LLVM_VERSION_MAJOR == 12
- PassBuilder PB(false, TM, PTO, PGO);
- #else
- PassBuilder PB(TM, PTO, PGO);
- #endif
- #endif
- /* Register all the basic analyses with the managers */
- LoopAnalysisManager LAM;
- FunctionAnalysisManager FAM;
- CGSCCAnalysisManager CGAM;
- ModuleAnalysisManager MAM;
- /* Register the target library analysis directly and give it a
- customized preset TLI */
- std::unique_ptr<TargetLibraryInfoImpl> TLII(
- new TargetLibraryInfoImpl(Triple(TM->getTargetTriple())));
- FAM.registerPass([&] { return TargetLibraryAnalysis(*TLII); });
- /* Register the AA manager first so that our version is the one used */
- AAManager AA = PB.buildDefaultAAPipeline();
- FAM.registerPass([&] { return std::move(AA); });
- #ifdef DEBUG_PASS
- StandardInstrumentations SI(true, false);
- SI.registerCallbacks(PIC, &FAM);
- #endif
- PB.registerFunctionAnalyses(FAM);
- PB.registerLoopAnalyses(LAM);
- PB.registerModuleAnalyses(MAM);
- PB.registerCGSCCAnalyses(CGAM);
- PB.crossRegisterProxies(LAM, FAM, CGAM, MAM);
- #if LLVM_VERSION_MAJOR <= 13
- PassBuilder::OptimizationLevel OL;
- switch (comp_ctx->opt_level) {
- case 0:
- OL = PassBuilder::OptimizationLevel::O0;
- break;
- case 1:
- OL = PassBuilder::OptimizationLevel::O1;
- break;
- case 2:
- OL = PassBuilder::OptimizationLevel::O2;
- break;
- case 3:
- default:
- OL = PassBuilder::OptimizationLevel::O3;
- break;
- }
- #else
- OptimizationLevel OL;
- switch (comp_ctx->opt_level) {
- case 0:
- OL = OptimizationLevel::O0;
- break;
- case 1:
- OL = OptimizationLevel::O1;
- break;
- case 2:
- OL = OptimizationLevel::O2;
- break;
- case 3:
- default:
- OL = OptimizationLevel::O3;
- break;
- }
- #endif /* end of LLVM_VERSION_MAJOR */
- bool disable_llvm_lto = comp_ctx->disable_llvm_lto;
- #if WASM_ENABLE_SPEC_TEST != 0
- disable_llvm_lto = true;
- #endif
- Module *M = reinterpret_cast<Module *>(module);
- if (disable_llvm_lto) {
- for (Function &F : *M) {
- F.addFnAttr("disable-tail-calls", "true");
- }
- }
- ModulePassManager MPM;
- if (comp_ctx->is_jit_mode) {
- const char *Passes =
- "mem2reg,instcombine,simplifycfg,jump-threading,indvars";
- ExitOnErr(PB.parsePassPipeline(MPM, Passes));
- }
- else {
- FunctionPassManager FPM;
- /* Apply Vectorize related passes for AOT mode */
- FPM.addPass(LoopVectorizePass());
- FPM.addPass(SLPVectorizerPass());
- FPM.addPass(LoadStoreVectorizerPass());
- 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
- show it is good to enable it when pgo is enabled. */
- #if LLVM_VERSION_MAJOR >= 15
- LICMOptions licm_opt;
- FPM.addPass(
- createFunctionToLoopPassAdaptor(LICMPass(licm_opt), true));
- #else
- FPM.addPass(createFunctionToLoopPassAdaptor(LICMPass(), true));
- #endif
- }
- /*
- FPM.addPass(createFunctionToLoopPassAdaptor(LoopRotatePass()));
- FPM.addPass(createFunctionToLoopPassAdaptor(SimpleLoopUnswitchPass()));
- */
- MPM.addPass(createModuleToFunctionPassAdaptor(std::move(FPM)));
- if (!disable_llvm_lto) {
- /* Apply LTO for AOT mode */
- if (comp_ctx->comp_data->func_count >= 10
- || comp_ctx->enable_llvm_pgo || comp_ctx->use_prof_file)
- /* Add the pre-link optimizations if the func count
- is large enough or PGO is enabled */
- MPM.addPass(PB.buildLTOPreLinkDefaultPipeline(OL));
- else
- MPM.addPass(PB.buildLTODefaultPipeline(OL, NULL));
- }
- else {
- MPM.addPass(PB.buildPerModuleDefaultPipeline(OL));
- }
- }
- MPM.run(*M, MAM);
- }
- char *
- aot_compress_aot_func_names(AOTCompContext *comp_ctx, uint32 *p_size)
- {
- std::vector<std::string> NameStrs;
- std::string Result;
- char buf[32], *compressed_str;
- uint32 compressed_str_len, i;
- for (i = 0; i < comp_ctx->func_ctx_count; i++) {
- snprintf(buf, sizeof(buf), "%s%d", AOT_FUNC_PREFIX, i);
- std::string str(buf);
- NameStrs.push_back(str);
- }
- if (collectPGOFuncNameStrings(NameStrs, true, Result)) {
- aot_set_last_error("collect pgo func name strings failed");
- return NULL;
- }
- compressed_str_len = Result.size();
- if (!(compressed_str = (char *)wasm_runtime_malloc(compressed_str_len))) {
- aot_set_last_error("allocate memory failed");
- return NULL;
- }
- bh_memcpy_s(compressed_str, compressed_str_len, Result.c_str(),
- compressed_str_len);
- *p_size = compressed_str_len;
- return compressed_str;
- }
|