在 LLVM-C API 中确定和设置主机目标三元组和指令扩展

2023-12-07

以下冗长的 C 程序生成一个简单的 LLVM 模块,其中包含一个仅调用的函数llvm.x86.sse41.round.ps。它发出位码文件,然后运行 ​​LLVM 生成的代码。我的问题是如何找到主机的目标三元组和指令扩展(例如 SSE 或 AVX),以及如何将此信息添加到 LLVM 模块,或者如何以其他方式将其告诉 LLVM 执行引擎。这就是我所做的:

$ cat ctest/avx-instruction-selection.c
#include <llvm-c/Core.h>
#include <llvm-c/Target.h>
#include <llvm-c/ExecutionEngine.h>
#include <llvm-c/BitWriter.h>
#include <llvm-c/Transforms/Scalar.h>

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

#if 1
const int vectorSize = 4;
const char* roundName = "llvm.x86.sse41.round.ps";
#else
const int vectorSize = 8;
const char* roundName = "llvm.x86.avx.round.ps.256";
#endif

int main ()
{
  LLVMModuleRef module;
  LLVMExecutionEngineRef execEngine;
  LLVMTargetDataRef targetData;
  LLVMTypeRef floatType, vectorType, ptrType, voidType, funcType, roundType, int32Type;
  LLVMValueRef func, roundFunc;
  LLVMValueRef param, loaded, const1, callRound;
  LLVMBuilderRef builder;
  LLVMBasicBlockRef block;
  const int false = 0;

  LLVMInitializeX86TargetInfo();
  LLVMInitializeX86Target();
  LLVMInitializeX86TargetMC();
  module = LLVMModuleCreateWithName("_module");
  LLVMSetTarget(module, "x86_64-unknown-linux-gnu");
  floatType = LLVMFloatType();
  vectorType = LLVMVectorType(floatType, vectorSize);
  ptrType = LLVMPointerType(vectorType, 0);
  voidType = LLVMVoidType();
  LLVMTypeRef roundParams[] = { ptrType };
  roundType = LLVMFunctionType(voidType, roundParams, 1, false);
  func = LLVMAddFunction(module, "round", roundType);
  LLVMSetLinkage(func, LLVMExternalLinkage);
  builder = LLVMCreateBuilder();
  block = LLVMAppendBasicBlock(func, "_L1");
  LLVMPositionBuilderAtEnd(builder, block);
  param = LLVMGetParam(func, 0);
  loaded = LLVMBuildLoad(builder, param, "");
  int32Type = LLVMIntType(32);
  LLVMTypeRef funcParams[] = { vectorType, int32Type } ;
  funcType = LLVMFunctionType(vectorType, funcParams, 2, false);
  roundFunc = LLVMAddFunction(module, roundName, funcType);
  LLVMSetLinkage(roundFunc, LLVMExternalLinkage);
  const1 = LLVMConstInt(int32Type, 1, false);
  LLVMValueRef callParams [] = { loaded, const1 } ;
  callRound = LLVMBuildCall(builder, roundFunc, callParams, 2, "");
  LLVMSetInstructionCallConv(callRound, 0);
  LLVMAddInstrAttribute(callRound, 0, 0);
  LLVMBuildStore(builder, callRound, param);
  LLVMBuildRetVoid(builder);
  LLVMWriteBitcodeToFile(module, "round-avx.bc");
  char *errorMsg;
  LLVMCreateExecutionEngineForModule(&execEngine, module, &errorMsg);
  targetData = LLVMGetExecutionEngineTargetData(execEngine);
  size_t vectorSize0 = LLVMStoreSizeOfType(targetData, vectorType);
  size_t vectorAlign = LLVMABIAlignmentOfType(targetData, vectorType);
  float vector[vectorSize];
  printf("%lx, size %lx, align %lx\n", (size_t)vector, vectorSize0, vectorAlign);
  LLVMGenericValueRef genericVector = LLVMCreateGenericValueOfPointer(vector);
  LLVMGenericValueRef runParams[] = { genericVector } ;
  LLVMRunFunction(execEngine, func, 1, runParams);
  return 0;
}

$ gcc -Wall -o ctest/avx-instruction-selection ctest/avx-instruction-selection.c `/usr/lib/llvm-3.4/bin/llvm-config --cflags --ldflags` -lLLVM-3.4

$ ctest/avx-instruction-selection
7fff590431c0, size 10, align 10

$ ls round-avx.bc
round-avx.bc

$ llvm-dis -o - round-avx.bc
; ModuleID = 'round-avx.bc'
target triple = "x86_64-unknown-linux-gnu"

define void @round(<4 x float>*) {
_L1:
  %1 = load <4 x float>* %0
  %2 = call <4 x float> @llvm.x86.sse41.round.ps(<4 x float> %1, i32 1)
  store <4 x float> %2, <4 x float>* %0
  ret void
}

; Function Attrs: nounwind readnone
declare <4 x float> @llvm.x86.sse41.round.ps(<4 x float>, i32) #0

attributes #0 = { nounwind readnone }

$ gcc -Wall -o ctest/avx-instruction-selection ctest/avx-instruction-selection.c `/usr/lib/llvm-3.5/bin/llvm-config --cflags --ldflags` -lLLVM-3.5

$ ctest/avx-instruction-selection
7ffed6170350, size 10, align 10
LLVM ERROR: Cannot select: intrinsic %llvm.x86.sse41.round.ps

$ gcc -Wall -o ctest/avx-instruction-selection ctest/avx-instruction-selection.c `/usr/lib/llvm-3.6/bin/llvm-config --cflags --ldflags` -lLLVM-3.6

$ ctest/avx-instruction-selection
7ffeae91eb40, size 10, align 10
LLVM ERROR: Target does not support MC emission!

$ gcc -Wall -o ctest/avx-instruction-selection ctest/avx-instruction-selection.c `/usr/lib/llvm-3.7/bin/llvm-config --cflags --ldflags` -lLLVM-3.7

$ ctest/avx-instruction-selection
7fffb6464ea0, size 10, align 10
LLVM ERROR: Target does not support MC emission!

$ gcc -Wall -o ctest/avx-instruction-selection ctest/avx-instruction-selection.c `/usr/lib/llvm-3.8/bin/llvm-config --cflags --ldflags` -lLLVM-3.8

$ ctest/avx-instruction-selection
7ffd5e233000, size 10, align 10
LLVM ERROR: Target does not support MC emission!

总结:使用 LLVM-3.4,该示例可以运行,使用 LLVM-3.5,该示例可以运行内在函数round.ps找不到LLVM-3.6,后来又说了一些我不明白的关于MC排放的事情。

据我了解,LLVM-3.5 没有找到round.ps内在的,我猜它找不到它,因为我还没有告诉它现有的 SSE 扩展。跑步时llc我可以添加选项-mattr=sse4.1但我怎样才能告诉执行引擎呢?

第二个问题:如何通过LLVM-C API了解主机可用的指令扩展(例如SSE)?在 x86 上我可以调用 CPUID 指令,但是有没有一种方法可以在所有平台上统一工作并且 LLVM 可以协助检测扩展?

第三个问题:我已将目标三元组硬编码到 C 代码中。如何通过 LLVM-C API 找到主机目标三元组?

最后一个问题:这个MC发射错误怎么办?


经过多次尝试后,我认为答案如下:

更换线路

LLVMInitializeX86TargetInfo();
LLVMInitializeX86Target();
LLVMInitializeX86TargetMC();

by

LLVMInitializeNativeTarget();
LLVMInitializeNativeAsmPrinter();
LLVMInitializeNativeAsmParser();

替换调用LLVMCreateExecutionEngineForModule通过调用自定义函数LLVMCreateExecutionEngineForModuleCPU。这是原来的实现LLVMCreateExecutionEngineForModule加上一个电话setMCPU.

#define LLVM_VERSION (LLVM_VERSION_MAJOR * 100 + LLVM_VERSION_MINOR)

LLVMBool LLVMCreateExecutionEngineForModuleCPU
    (LLVMExecutionEngineRef *OutEE,
     LLVMModuleRef M,
     char **OutError) {
  std::string Error;
#if LLVM_VERSION < 306
  EngineBuilder builder(unwrap(M));
#else
  EngineBuilder builder(std::unique_ptr<Module>(unwrap(M)));
#endif
  builder.setEngineKind(EngineKind::Either)
         .setMCPU(sys::getHostCPUName().data())
         .setErrorStr(&Error);
  if (ExecutionEngine *EE = builder.create()){
    *OutEE = wrap(EE);
    return 0;
  }
  *OutError = strdup(Error.c_str());
  return 1;
}

我还应该添加

float vector[vectorSize] __attribute__((aligned(32)));

为了对齐 AVX 向量的数组。

根据线程中的答案使用 AVX 内在函数进行崩溃 JIT LLVMRunFunction仅限于main-类似原型(显然仅在 MCJIT 中)。因此我们还应该替换LLVMRunFunction东西由

void (*funcPtr) (float *);
funcPtr = LLVMGetPointerToGlobal(execEngine, func);
funcPtr(vector);
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

在 LLVM-C API 中确定和设置主机目标三元组和指令扩展 的相关文章

  • 使用 LLVM pass 添加内在函数

    我使用 LLVM 通道向输入代码添加了一个内在函数 我能够看到内部调用 但我无法弄清楚如何将代码编译到我的目标架构 x86 64 我正在运行以下命令 clang llvm config ldflags libs all ff s o foo
  • 针对 Windows Phone ARM 目标的 Clang 交叉编译

    我想使用 Clang 为 Windows Phone ARM 目标编译一个用 C 编写的程序 有人有这方面的经验吗 什么是更好的方法 1 使用 Clang for Windows 和 MinGW 在运行 Windows 8 的主机上构建 C
  • 使用 llvm-prof 收集 LLVM 边缘分析

    我正在使用这些命令来编译下面的代码以收集 trunk llvm 中的边缘 块分析 clang emit llvm c sort c o sort bc opt insert edge profiling sort bc o sort pro
  • 对于使用块的 clang 程序,您需要链接哪些库

    我发现 如下 在编译使用块的代码时需要使用 fblocks 我需要链接哪个库才能让链接器解析 NSConcreteStackBlock 在 Ubuntu 9 10 AMD64 上 chris chris desktop clang ctes
  • 如何将 c++filt 与 llvm-cov 报告一起使用?

    我正在尝试将 demangler 与 llvm cov 报告工具一起使用 以下是我正在运行的命令 llvm cov report path to executable instr profile path to default profda
  • 如何使用 Clang 编码生成未使用的声明? [复制]

    这个问题在这里已经有答案了 我正在寻找代码生成一个llvm Module来自一些 C 代码 具体来说 我将混合 Clang 生成的代码和其他来源的代码 不幸的是 铿锵CodeGenModule如果存在使用它的定义 类似乎坚持只在模块中生成声
  • 可以从 LLVM-IR 自动生成 llvm c++ api 代码吗?

    clang 3 0 在线演示页面http llvm org demo index cgi http llvm org demo index cgi提供输出 LLVM C API 代码的选项 表示输入程序的 LLVM IR 生成 LLVM C
  • LLVM 和编译器术语

    我正在研究 LLVM 系统并且我已经阅读了入门文档 http llvm org docs GettingStarted html 然而 一些术语 以及 clang 示例中的措辞 仍然有点令人困惑 以下术语和命令都是编译过程的一部分 我想知道
  • 我可以使用 LLVM(低级虚拟机)为哪些平台编译二进制文件?

    我对使用 LLVM 的 Clang 编译器感兴趣 LLVM 声称是跨平台的 但尚不清楚可以针对哪些平台 我对此做了很多谷歌搜索 但似乎没有太多关于 LLVM 支持的平台的信息 我唯一发现的是 this http llvm org docs
  • 链接不支持异常处理的代码 (C++/LLVM)

    我正在尝试使用 llvm 作为我的软件的代码生成后端 并且刚刚意识到 llvm 的编译不支持 C 异常处理 为了提高效率 然而 在我的软件中 我广泛使用异常处理 如果我将所有回调函数包装在 try catch blocks 中 这样就不需要
  • llvm OCaml 绑定

    我正在研究 llvm OCaml 绑定 我通过 opam 安装了 llvm 包 opam install llvm 当我在 utop 中使用 llvm 时 出现以下错误 require llvm Error The external fun
  • LLVM 执行哪些优化?

    我想具体了解一下LLVM的各个优化级别分别对应什么 也就是说 我想知道当我使用 llvm 或 clang 或 opt 的 0x 选项时 哪些优化过程是准确执行的 在前端之外 以及按什么顺序执行 相应工具的 man 没有提供关于此事的太多信息
  • 使用 Clang AST 打印函数的参数

    我想将参数传递给函数 例如 如果我接到电话 printf d d i j 输出应该是 d dij 我可以使用 RecursiveASTVisitor 中的 VisitCallExpr 进行函数调用 还能够获取参数数量和参数类型 但我不知道如
  • 是否可以在 LLVM IR 代码中指定十六进制数?

    例如 error floating point constant invalid for type 3 and i8 0x80 2 从扫描的红外参考手册 http llvm org docs LangRef html simple cons
  • __attribute__ ((已弃用)) 不适用于 Objective-C 协议方法?

    我需要弃用 Objective C 协议中的单个方法 在普通的类 实例方法上我添加 attribute deprecated 声明后 看来它不适用于协议方法 如果我将它们标记为已弃用并在某个地方使用它们 则项目编译正常 不会出现预期的弃用警
  • 如何使用自定义 llc 编译 Rust 程序?

    我有一个自定义 LLVM 后端 并且想为该自定义 nostd 目标交叉编译 Rust 我想分两步编译 Rust 程序 Using rustc生成 LLVM IR 用我自己的opt and llc将 LLVM IR 转换为机器代码 我尝试使用
  • 使用 libclang 从内存中的 C 代码生成程序集

    我需要实现一个使用 LLVM Clang 作为后端将 C 代码编译为 eBPF 字节码的库 代码将从内存中读取 我也需要在内存中获取生成的汇编代码 到目前为止 我已经能够使用以下代码编译为 LLVM IR include
  • XCode 4.2 编译器错误

    当我使用 XCode 4 2 创建新项目 例如 单视图 iOS 应用程序 时 支持文件 文件夹中的 main m 文件如下所示 import
  • 如何检查 Xcode 使用的 LLVM 编译器版本?

    我在 OS X 10 8 2 上使用 Xcode 4 5 2 我如何知道 Xcode 使用的是哪个版本的 LLVM 编译器 从命令行 07 40 35 andrew iMac SalesIQ siq 303 llvm gcc v Using
  • 未生成隐式移动函数

    我有以下课程 class Blub public Blub int value Not a copy constructor Blub Blub default This line is necessary because move con

随机推荐