aot_llvm_extra.cpp 8.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274
  1. /*
  2. * Copyright (C) 2019 Intel Corporation. All rights reserved.
  3. * SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
  4. */
  5. #include <llvm/ADT/SmallVector.h>
  6. #include <llvm/ADT/Twine.h>
  7. #include <llvm/ADT/Triple.h>
  8. #include <llvm/Analysis/TargetTransformInfo.h>
  9. #include <llvm/CodeGen/TargetPassConfig.h>
  10. #include <llvm/ExecutionEngine/ExecutionEngine.h>
  11. #include <llvm/MC/MCSubtargetInfo.h>
  12. #include <llvm/Support/TargetSelect.h>
  13. #include <llvm/Target/TargetMachine.h>
  14. #include <llvm-c/Core.h>
  15. #include <llvm-c/ExecutionEngine.h>
  16. #include <llvm-c/Initialization.h>
  17. #include <llvm/ExecutionEngine/GenericValue.h>
  18. #include <llvm/ExecutionEngine/JITEventListener.h>
  19. #include <llvm/ExecutionEngine/RTDyldMemoryManager.h>
  20. #include <llvm/IR/DerivedTypes.h>
  21. #include <llvm/IR/Module.h>
  22. #include <llvm/IR/Instructions.h>
  23. #include <llvm/IR/IntrinsicInst.h>
  24. #include <llvm/IR/LegacyPassManager.h>
  25. #include <llvm/Support/CommandLine.h>
  26. #include <llvm/Support/ErrorHandling.h>
  27. #include <llvm/Target/CodeGenCWrappers.h>
  28. #include <llvm/Target/TargetMachine.h>
  29. #include <llvm/Target/TargetOptions.h>
  30. #include <llvm/Transforms/Utils/LowerMemIntrinsics.h>
  31. #include <cstring>
  32. using namespace llvm;
  33. extern "C" LLVMBool
  34. WAMRCreateMCJITCompilerForModule(LLVMExecutionEngineRef *OutJIT,
  35. LLVMModuleRef M,
  36. LLVMMCJITCompilerOptions *PassedOptions,
  37. size_t SizeOfPassedOptions, char **OutError);
  38. extern "C" bool
  39. aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str);
  40. extern "C" void
  41. aot_add_expand_memory_op_pass(LLVMPassManagerRef pass);
  42. extern "C" void
  43. aot_func_disable_tce(LLVMValueRef func);
  44. LLVMBool
  45. WAMRCreateMCJITCompilerForModule(LLVMExecutionEngineRef *OutJIT,
  46. LLVMModuleRef M,
  47. LLVMMCJITCompilerOptions *PassedOptions,
  48. size_t SizeOfPassedOptions, char **OutError)
  49. {
  50. LLVMMCJITCompilerOptions options;
  51. // If the user passed a larger sized options struct, then they were compiled
  52. // against a newer LLVM. Tell them that something is wrong.
  53. if (SizeOfPassedOptions > sizeof(options)) {
  54. *OutError = strdup("Refusing to use options struct that is larger than "
  55. "my own; assuming LLVM library mismatch.");
  56. return 1;
  57. }
  58. // Defend against the user having an old version of the API by ensuring that
  59. // any fields they didn't see are cleared. We must defend against fields
  60. // being set to the bitwise equivalent of zero, and assume that this means
  61. // "do the default" as if that option hadn't been available.
  62. LLVMInitializeMCJITCompilerOptions(&options, sizeof(options));
  63. memcpy(&options, PassedOptions, SizeOfPassedOptions);
  64. TargetOptions targetOptions;
  65. targetOptions.EnableFastISel = options.EnableFastISel;
  66. std::unique_ptr<Module> Mod(unwrap(M));
  67. if (Mod) {
  68. // Set function attribute "frame-pointer" based on
  69. // NoFramePointerElim.
  70. for (auto &F : *Mod) {
  71. auto Attrs = F.getAttributes();
  72. StringRef Value = options.NoFramePointerElim ? "all" : "none";
  73. Attrs =
  74. Attrs.addAttribute(F.getContext(), AttributeList::FunctionIndex,
  75. "frame-pointer", Value);
  76. F.setAttributes(Attrs);
  77. }
  78. }
  79. std::string Error;
  80. bool JIT;
  81. char *host_cpu = LLVMGetHostCPUName();
  82. if (!host_cpu) {
  83. *OutError = NULL;
  84. return false;
  85. }
  86. std::string mcpu(host_cpu);
  87. LLVMDisposeMessage(host_cpu);
  88. EngineBuilder builder(std::move(Mod));
  89. builder.setEngineKind(EngineKind::JIT)
  90. .setErrorStr(&Error)
  91. .setMCPU(mcpu)
  92. .setOptLevel((CodeGenOpt::Level)options.OptLevel)
  93. .setTargetOptions(targetOptions);
  94. if (Optional<CodeModel::Model> CM = unwrap(options.CodeModel, JIT))
  95. builder.setCodeModel(*CM);
  96. if (options.MCJMM)
  97. builder.setMCJITMemoryManager(
  98. std::unique_ptr<RTDyldMemoryManager>(unwrap(options.MCJMM)));
  99. if (ExecutionEngine *JIT = builder.create()) {
  100. *OutJIT = wrap(JIT);
  101. return 0;
  102. }
  103. *OutError = strdup(Error.c_str());
  104. return 1;
  105. }
  106. class ExpandMemoryOpPass : public llvm::ModulePass
  107. {
  108. public:
  109. static char ID;
  110. ExpandMemoryOpPass()
  111. : ModulePass(ID)
  112. {}
  113. bool runOnModule(Module &M) override;
  114. bool expandMemIntrinsicUses(Function &F);
  115. StringRef getPassName() const override
  116. {
  117. return "Expand memory operation intrinsics";
  118. }
  119. void getAnalysisUsage(AnalysisUsage &AU) const override
  120. {
  121. AU.addRequired<TargetTransformInfoWrapperPass>();
  122. }
  123. };
  124. char ExpandMemoryOpPass::ID = 0;
  125. bool
  126. ExpandMemoryOpPass::expandMemIntrinsicUses(Function &F)
  127. {
  128. Intrinsic::ID ID = F.getIntrinsicID();
  129. bool Changed = false;
  130. for (auto I = F.user_begin(), E = F.user_end(); I != E;) {
  131. Instruction *Inst = cast<Instruction>(*I);
  132. ++I;
  133. switch (ID) {
  134. case Intrinsic::memcpy:
  135. {
  136. auto *Memcpy = cast<MemCpyInst>(Inst);
  137. Function *ParentFunc = Memcpy->getParent()->getParent();
  138. const TargetTransformInfo &TTI =
  139. getAnalysis<TargetTransformInfoWrapperPass>().getTTI(
  140. *ParentFunc);
  141. expandMemCpyAsLoop(Memcpy, TTI);
  142. Changed = true;
  143. Memcpy->eraseFromParent();
  144. break;
  145. }
  146. case Intrinsic::memmove:
  147. {
  148. auto *Memmove = cast<MemMoveInst>(Inst);
  149. expandMemMoveAsLoop(Memmove);
  150. Changed = true;
  151. Memmove->eraseFromParent();
  152. break;
  153. }
  154. case Intrinsic::memset:
  155. {
  156. auto *Memset = cast<MemSetInst>(Inst);
  157. expandMemSetAsLoop(Memset);
  158. Changed = true;
  159. Memset->eraseFromParent();
  160. break;
  161. }
  162. default:
  163. break;
  164. }
  165. }
  166. return Changed;
  167. }
  168. bool
  169. ExpandMemoryOpPass::runOnModule(Module &M)
  170. {
  171. bool Changed = false;
  172. for (Function &F : M) {
  173. if (!F.isDeclaration())
  174. continue;
  175. switch (F.getIntrinsicID()) {
  176. case Intrinsic::memcpy:
  177. case Intrinsic::memmove:
  178. case Intrinsic::memset:
  179. if (expandMemIntrinsicUses(F))
  180. Changed = true;
  181. break;
  182. default:
  183. break;
  184. }
  185. }
  186. return Changed;
  187. }
  188. void
  189. aot_add_expand_memory_op_pass(LLVMPassManagerRef pass)
  190. {
  191. unwrap(pass)->add(new ExpandMemoryOpPass());
  192. }
  193. bool
  194. aot_check_simd_compatibility(const char *arch_c_str, const char *cpu_c_str)
  195. {
  196. #if WASM_ENABLE_SIMD != 0
  197. if (!arch_c_str || !cpu_c_str) {
  198. return false;
  199. }
  200. llvm::SmallVector<std::string, 1> targetAttributes;
  201. llvm::Triple targetTriple(arch_c_str, "", "");
  202. auto targetMachine =
  203. std::unique_ptr<llvm::TargetMachine>(llvm::EngineBuilder().selectTarget(
  204. targetTriple, "", std::string(cpu_c_str), targetAttributes));
  205. if (!targetMachine) {
  206. return false;
  207. }
  208. const llvm::Triple::ArchType targetArch =
  209. targetMachine->getTargetTriple().getArch();
  210. const llvm::MCSubtargetInfo *subTargetInfo =
  211. targetMachine->getMCSubtargetInfo();
  212. if (subTargetInfo == nullptr) {
  213. return false;
  214. }
  215. if (targetArch == llvm::Triple::x86_64) {
  216. return subTargetInfo->checkFeatures("+sse4.1");
  217. }
  218. else if (targetArch == llvm::Triple::aarch64) {
  219. return subTargetInfo->checkFeatures("+neon");
  220. }
  221. else {
  222. return false;
  223. }
  224. #else
  225. (void)arch_c_str;
  226. (void)cpu_c_str;
  227. return true;
  228. #endif /* WASM_ENABLE_SIMD */
  229. }
  230. void
  231. aot_func_disable_tce(LLVMValueRef func)
  232. {
  233. Function *F = unwrap<Function>(func);
  234. auto Attrs = F->getAttributes();
  235. Attrs = Attrs.addAttribute(F->getContext(), AttributeList::FunctionIndex,
  236. "disable-tail-calls", "true");
  237. F->setAttributes(Attrs);
  238. }