/* * Copyright (C) 2019 Intel Corporation. All rights reserved. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include using namespace llvm; extern "C" LLVMBool WAMRCreateMCJITCompilerForModule(LLVMExecutionEngineRef *OutJIT, LLVMModuleRef M, LLVMMCJITCompilerOptions *PassedOptions, size_t SizeOfPassedOptions, char **OutError); extern "C" bool aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str); LLVMBool WAMRCreateMCJITCompilerForModule(LLVMExecutionEngineRef *OutJIT, LLVMModuleRef M, LLVMMCJITCompilerOptions *PassedOptions, size_t SizeOfPassedOptions, char **OutError) { LLVMMCJITCompilerOptions options; // If the user passed a larger sized options struct, then they were compiled // against a newer LLVM. Tell them that something is wrong. if (SizeOfPassedOptions > sizeof(options)) { *OutError = strdup( "Refusing to use options struct that is larger than my own; assuming " "LLVM library mismatch."); return 1; } // Defend against the user having an old version of the API by ensuring that // any fields they didn't see are cleared. We must defend against fields being // set to the bitwise equivalent of zero, and assume that this means "do the // default" as if that option hadn't been available. LLVMInitializeMCJITCompilerOptions(&options, sizeof(options)); memcpy(&options, PassedOptions, SizeOfPassedOptions); TargetOptions targetOptions; targetOptions.EnableFastISel = options.EnableFastISel; std::unique_ptr Mod(unwrap(M)); if (Mod) { // Set function attribute "frame-pointer" based on // NoFramePointerElim. for (auto &F : *Mod) { auto Attrs = F.getAttributes(); StringRef Value = options.NoFramePointerElim ? "all" : "none"; Attrs = Attrs.addAttribute(F.getContext(), AttributeList::FunctionIndex, "frame-pointer", Value); F.setAttributes(Attrs); } } std::string Error; bool JIT; char *host_cpu = LLVMGetHostCPUName(); if (!host_cpu) { *OutError = NULL; return false; } std::string mcpu(host_cpu); LLVMDisposeMessage(host_cpu); EngineBuilder builder(std::move(Mod)); builder.setEngineKind(EngineKind::JIT) .setErrorStr(&Error) .setMCPU(mcpu) .setOptLevel((CodeGenOpt::Level)options.OptLevel) .setTargetOptions(targetOptions); if (Optional CM = unwrap(options.CodeModel, JIT)) builder.setCodeModel(*CM); if (options.MCJMM) builder.setMCJITMemoryManager( std::unique_ptr(unwrap(options.MCJMM))); if (ExecutionEngine *JIT = builder.create()) { *OutJIT = wrap(JIT); return 0; } *OutError = strdup(Error.c_str()); return 1; } 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 targetAttributes; llvm::Triple targetTriple(arch_c_str, "", ""); auto targetMachine = std::unique_ptr(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 */ }