LLVM(5)ORC实例分析

ORC实例总结

总结

  1. 因为API茫茫多,逻辑上的一些概念需要搞清,编码时会容易很多。
  2. JIT的运行实体使用LLVMOrcCreateLLJIT可以创建出来,逻辑上的JIT实例。
  3. JIT实例需要加入运行库(依赖库)和用户定义的context(运行内容)才能运行,LLVMOrcLLJITAddLLVMIRModule函数负责将运行库和ctx加入JIT实例。
  4. context相当于给用户自定义代码的上下文,其中可以加入多个module,每个module中又可以加入多个function。可以理解为一个工程(context)里面加入多个文件,每个文件(module)中又包含多个函数(function)。

注释

c 复制代码
LLVMOrcThreadSafeModuleRef createDemoModule(void) {
// 创建一个新的ThreadSafeContext和底层的LLVMContext。
LLVMOrcThreadSafeContextRef TSCtx = LLVMOrcCreateNewThreadSafeContext();

// 获取底层的LLVMContext的引用。
LLVMContextRef Ctx = LLVMOrcThreadSafeContextGetContext(TSCtx);

// 创建一个新的LLVM模块。
LLVMModuleRef M = LLVMModuleCreateWithNameInContext("demo", Ctx);

// 添加一个名为"sum"的函数:
// - 创建函数类型和函数实例。
LLVMTypeRef ParamTypes[] = {LLVMInt32Type(), LLVMInt32Type()};
LLVMTypeRef SumFunctionType =
LLVMFunctionType(LLVMInt32Type(), ParamTypes, 2, 0);
LLVMValueRef SumFunction = LLVMAddFunction(M, "sum", SumFunctionType);

// - 向函数添加一个基本块。
LLVMBasicBlockRef EntryBB = LLVMAppendBasicBlock(SumFunction, "entry");

// - 创建一个IR构建器并将其定位到基本块的末尾。
LLVMBuilderRef Builder = LLVMCreateBuilder();
LLVMPositionBuilderAtEnd(Builder, EntryBB);

// - 获取两个函数参数,并使用它们构造一个"add"指令。
LLVMValueRef SumArg0 = LLVMGetParam(SumFunction, 0);
LLVMValueRef SumArg1 = LLVMGetParam(SumFunction, 1);
LLVMValueRef Result = LLVMBuildAdd(Builder, SumArg0, SumArg1, "result");

// - 构建返回指令。
LLVMBuildRet(Builder, Result);

// 演示模块现在已经完成。将其和ThreadSafeContext封装到ThreadSafeModule中。
LLVMOrcThreadSafeModuleRef TSM = LLVMOrcCreateNewThreadSafeModule(M, TSCtx);

// 释放本地的ThreadSafeContext值。底层的LLVMContext将由ThreadSafeModule TSM保持活动状态。
LLVMOrcDisposeThreadSafeContext(TSCtx);

// 返回结果。
return TSM;
}

int main(int argc, char *argv[]) {
int MainResult = 0;

// 解析命令行参数并初始化LLVM Core。
LLVMParseCommandLineOptions(argc, (const char **)argv, "");
LLVMInitializeCore(LLVMGetGlobalPassRegistry());

// 初始化本地目标代码生成和汇编打印器。
LLVMInitializeNativeTarget();
LLVMInitializeNativeAsmPrinter();

// 创建LLJIT实例。
LLVMOrcLLJITRef J;
{
LLVMErrorRef Err;
if ((Err = LLVMOrcCreateLLJIT(&J, 0))) {
MainResult = handleError(Err);
goto llvm_shutdown;
}
}

// 创建演示模块。
LLVMOrcThreadSafeModuleRef TSM = createDemoModule();

// 将演示模块添加到JIT中。
{
LLVMOrcJITDylibRef MainJD = LLVMOrcLLJITGetMainJITDylib(J);
LLVMErrorRef Err;
if ((Err = LLVMOrcLLJITAddLLVMIRModule(J, MainJD, TSM))) {
// 如果添加ThreadSafeModule失败,我们需要自己清理它。
// 如果添加成功,JIT将管理内存。
LLVMOrcDisposeThreadSafeModule(TSM);
MainResult = handleError(Err);
goto jit_cleanup;
}
}

// 查找演示入口点的地址。
LLVMOrcJITTargetAddress SumAddr;
{
LLVMErrorRef Err;
if ((Err = LLVMOrcLLJITLookup(J, &SumAddr, "sum"))) {
MainResult = handleError(Err);
goto jit_cleanup;
}
}

// 如果程序执行到这里,说明一切顺利。执行JIT生成的代码。
int32_t (Sum)(int32_t, int32_t) = (int32_t()(int32_t, int32_t))SumAddr;
int32_t Result = Sum(1, 2);

// 打印结果。
printf("1 + 2 = %i\n", Result);

jit_cleanup:
// 销毁JIT实例。这将清理JIT所拥有的任何内存。
// 这个操作是非平凡的(例如,可能需要JIT静态析构函数),也可能失败。
// 如果失败,我们希望将错误输出到stderr,但不要覆盖任何现有的返回值。
{
LLVMErrorRef Err;
if ((Err = LLVMOrcDisposeLLJIT(J))) {
int NewFailureResult = handleError(Err);
if (MainResult == 0) MainResult = NewFailureResult;
}
}

llvm_shutdown:
// 关闭LLVM。
LLVMShutdown();

return MainResult;
}

ORC完整

cpp 复制代码
//===------ OrcV2CBindingsBasicUsage.c - Basic OrcV2 C Bindings Demo ------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include <stdio.h>

#include "llvm-c/Core.h"
#include "llvm-c/Error.h"
#include "llvm-c/Initialization.h"
#include "llvm-c/LLJIT.h"
#include "llvm-c/Support.h"
#include "llvm-c/Target.h"

int handleError(LLVMErrorRef Err) {
  char *ErrMsg = LLVMGetErrorMessage(Err);
  fprintf(stderr, "Error: %s\n", ErrMsg);
  LLVMDisposeErrorMessage(ErrMsg);
  return 1;
}

LLVMOrcThreadSafeModuleRef createDemoModule(void) {
  // Create a new ThreadSafeContext and underlying LLVMContext.
  LLVMOrcThreadSafeContextRef TSCtx = LLVMOrcCreateNewThreadSafeContext();

  // Get a reference to the underlying LLVMContext.
  LLVMContextRef Ctx = LLVMOrcThreadSafeContextGetContext(TSCtx);

  // Create a new LLVM module.
  LLVMModuleRef M = LLVMModuleCreateWithNameInContext("demo", Ctx);

  // Add a "sum" function":
  //  - Create the function type and function instance.
  LLVMTypeRef ParamTypes[] = {LLVMInt32Type(), LLVMInt32Type()};
  LLVMTypeRef SumFunctionType =
      LLVMFunctionType(LLVMInt32Type(), ParamTypes, 2, 0);
  LLVMValueRef SumFunction = LLVMAddFunction(M, "sum", SumFunctionType);

  //  - Add a basic block to the function.
  LLVMBasicBlockRef EntryBB = LLVMAppendBasicBlock(SumFunction, "entry");

  //  - Add an IR builder and point it at the end of the basic block.
  LLVMBuilderRef Builder = LLVMCreateBuilder();
  LLVMPositionBuilderAtEnd(Builder, EntryBB);

  //  - Get the two function arguments and use them co construct an "add"
  //    instruction.
  LLVMValueRef SumArg0 = LLVMGetParam(SumFunction, 0);
  LLVMValueRef SumArg1 = LLVMGetParam(SumFunction, 1);
  LLVMValueRef Result = LLVMBuildAdd(Builder, SumArg0, SumArg1, "result");

  //  - Build the return instruction.
  LLVMBuildRet(Builder, Result);

  // Our demo module is now complete. Wrap it and our ThreadSafeContext in a
  // ThreadSafeModule.
  LLVMOrcThreadSafeModuleRef TSM = LLVMOrcCreateNewThreadSafeModule(M, TSCtx);

  // Dispose of our local ThreadSafeContext value. The underlying LLVMContext
  // will be kept alive by our ThreadSafeModule, TSM.
  LLVMOrcDisposeThreadSafeContext(TSCtx);

  // Return the result.
  return TSM;
}

int main(int argc, char *argv[]) {
  int MainResult = 0;

  // Parse command line arguments and initialize LLVM Core.
  LLVMParseCommandLineOptions(argc, (const char **)argv, "");
  LLVMInitializeCore(LLVMGetGlobalPassRegistry());

  // Initialize native target codegen and asm printer.
  LLVMInitializeNativeTarget();
  LLVMInitializeNativeAsmPrinter();

  // Create the JIT instance.
  LLVMOrcLLJITRef J;
  {
    LLVMErrorRef Err;
    if ((Err = LLVMOrcCreateLLJIT(&J, 0))) {
      MainResult = handleError(Err);
      goto llvm_shutdown;
    }
  }

  // Create our demo module.
  LLVMOrcThreadSafeModuleRef TSM = createDemoModule();

  // Add our demo module to the JIT.
  {
    LLVMOrcJITDylibRef MainJD = LLVMOrcLLJITGetMainJITDylib(J);
    LLVMErrorRef Err;
    if ((Err = LLVMOrcLLJITAddLLVMIRModule(J, MainJD, TSM))) {
      // If adding the ThreadSafeModule fails then we need to clean it up
      // ourselves. If adding it succeeds the JIT will manage the memory.
      LLVMOrcDisposeThreadSafeModule(TSM);
      MainResult = handleError(Err);
      goto jit_cleanup;
    }
  }

  // Look up the address of our demo entry point.
  LLVMOrcJITTargetAddress SumAddr;
  {
    LLVMErrorRef Err;
    if ((Err = LLVMOrcLLJITLookup(J, &SumAddr, "sum"))) {
      MainResult = handleError(Err);
      goto jit_cleanup;
    }
  }

  // If we made it here then everything succeeded. Execute our JIT'd code.
  int32_t (*Sum)(int32_t, int32_t) = (int32_t(*)(int32_t, int32_t))SumAddr;
  int32_t Result = Sum(1, 2);

  // Print the result.
  printf("1 + 2 = %i\n", Result);

jit_cleanup:
  // Destroy our JIT instance. This will clean up any memory that the JIT has
  // taken ownership of. This operation is non-trivial (e.g. it may need to
  // JIT static destructors) and may also fail. In that case we want to render
  // the error to stderr, but not overwrite any existing return value.
  {
    LLVMErrorRef Err;
    if ((Err = LLVMOrcDisposeLLJIT(J))) {
      int NewFailureResult = handleError(Err);
      if (MainResult == 0) MainResult = NewFailureResult;
    }
  }

llvm_shutdown:
  // Shut down LLVM.
  LLVMShutdown();

  return MainResult;
}
相关推荐
l1t9 天前
对在aarch64 Linux环境编译安装的CinderX补充测试
linux·运维·服务器·python·jit
HyperAI超神经11 天前
在线教程丨华中科大与小红书 hi lab开源dots.mocr,SOTA级OCR模型完美还原文档结构,图形也能转 SVG
人工智能·深度学习·学习·机器学习·gpu·orc·vllm
Gauss松鼠会16 天前
【GaussDB】LLVM技术在GaussDB等数据库中的应用
大数据·数据库·架构·数据库开发·gaussdb·llvm
wang090725 天前
JVM即时编译器JIT以及常见优化
jvm·jit·标量替换
lich41 个月前
个人OLLVM项目成果展示
llvm
佛祖让我来巡山1 个月前
【JVM】编译执行与解释执行的区别是什么?JVM 使用哪种方式?
编译·解释·jit
穷人小水滴1 个月前
编译 LLVM: 跨平台 npm 二进制包
npm·编译器·llvm
穷人小水滴2 个月前
LLVM IR 入门: 使用 LLVM 编译到 WebAssembly
webassembly·编译器·llvm