在LLVM-CAPI中确定和设置主机目标和指令扩展

在LLVM-CAPI中确定和设置主机目标和指令扩展,llvm,Llvm,下面冗长的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/

下面冗长的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!
$cat ctest/avx指令选择.c
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#包括
#如果1
const int vectorSize=4;
const char*roundName=“llvm.x86.sse41.round.ps”;
#否则
const int vectorSize=8;
const char*roundName=“llvm.x86.avx.round.ps.256”;
#恩迪夫
int main()
{
LLVMModuleRef模块;
LLVMExecutionEngineRef ExecutionEngine;
LLVMTargetDataRef targetData;
LLVMTypeRef floatType、vectorType、ptrType、voidType、funcType、roundType、int32Type;
LLVMValueRef func、roundFunc;
LLVMValueRef参数,已加载,常量1,调用轮;
LLVMBuilderRef生成器;
LLVMBasicBlockRef区块;
常数int false=0;
LLVMInitializeX86TargetInfo();
LLVMInitializeX86Target();
LLVMInitializeX86TargetMC();
module=LLVMModuleCreateWithName(“_module”);
LLVMSetTarget(模块,“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(模块“圆形”,圆形类型);
LLVMSetLinkage(func,LLVMExternalLinkage);
builder=LLVMCreateBuilder();
block=LLVMAppendBasicBlock(func,“_L1”);
LLVMPositionBuilderEnd(建筑商、区块);
param=LLVMGetParam(func,0);
loaded=LLVMBuildLoad(生成器,参数“”);
int32Type=LLVMIntType(32);
LLVMTypeRef函数参数[]={vectorType,int32Type};
funcType=LLVMFunctionType(vectorType,funcParams,2,false);
roundFunc=LLVMAddFunction(模块、roundName、funcType);
LLVMSetLinkage(roundFunc,LLVMExternalLinkage);
const1=llvmconstant(int32Type,1,false);
LLVMValueRef调用参数[]={loaded,const1};
callRound=LLVMBuildCall(builder,roundFunc,callParams,2,“”;
LLVMSetInstructionCallConv(callRound,0);
LLVMAddInstrAttribute(callRound,0,0);
LLVMBuildStore(builder、callRound、param);
LLVMBuildRetVoid(建筑商);
LLVMWriteBitCodeFile(模块,“round avx.bc”);
char*errorMsg;
LLVMCreateExecutionEngineForModule(&ExecutEngine,module,&errorMsg);
targetData=LLVMGetExecutionEngineTargetData(ExecuteEngine);
size_t vectorSize0=LLVMStoreSizeOfType(targetData,vectorType);
size_t vectorAlign=LLVMABIAlignmentOfType(targetData,vectorType);
浮点向量[向量大小];
printf(“%lx,大小%lx,对齐%lx\n”,(大小)向量,向量大小0,向量对齐);
LLVMGenericValueRef genericVector=LLVMCreateGenericValueOfPointer(向量);
LLVMGenericValueRef运行参数[]={genericVector};
LLVMRunFunction(execEngine,func,1,runParams);
返回0;
}
$gcc-Wall-o ctest/avx指令选择ctest/avx指令选择.c`/usr/lib/llvm-3.4/bin/llvm-config--cflags--ldflags`-lLLVM-3.4
$ctest/avx指令选择
7fff590431c0,尺寸10,对齐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”
在圆形(*)处定义void{
_L1:
%1=加载*%0
%2=调用@llvm.x86.sse41.round.ps(%1,i32 1)
存储%2,*%0
ret void
}
; 函数属性:nounwind readnone
声明@llvm.x86.sse41.round.ps(,i32)#0
属性#0={none}
$gcc-Wall-o ctest/avx指令选择ctest/avx指令选择.c`/usr/lib/llvm-3.5/bin/llvm-config--cflags--ldflags`-lLLVM-3.5
$ctest/avx指令选择
7ffed6170350,尺寸10,对齐10
LLVM错误:无法选择:内在%LLVM.x86.sse41.round.ps
$gcc-Wall-o ctest/avx指令选择ctest/avx指令选择.c`/usr/lib/llvm-3.6/bin/llvm-config--cflags--ldflags`-lLLVM-3.6
$ctest/avx指令选择
7ffeae91eb40,尺寸10,对齐10
LLVM错误:目标不支持MC发射!
$gcc-Wall-o ctest/avx指令选择ctest/avx指令选择.c`/usr/lib/llvm-3.7/bin/llvm-config--cflags--ldflags`-lLLVM-3.7
$ctest/avx指令选择
7fffb6464ea0,尺寸10,对齐10
LLVM错误:目标不支持MC发射!
$gcc-Wall-o ctest/avx指令选择ctest/avx指令选择.c`/usr/lib/llvm-3.8/bin/llvm-config--cflags--ldflags`-lLLVM-3.8
$ctest/avx指令选择
7ffd5e233000,尺寸10,对齐10
LLVM错误:目标不支持MC发射!
总结:对于LLVM-3.4,示例有效;对于LLVM-3.5,内部函数
round.ps
无法找到;对于LLVM-3.6,以及后来提到的MC排放,我不理解

据我所知,LLVM-3.5没有找到
round.ps
的内在特性,我猜它找不到它,因为我没有告诉它现有的SSE扩展。当运行
llc
时,我可以添加选项
-mattr=sse4.1
,但我如何将其告知执行引擎

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

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


最后一个问题:MC排放错误如何?

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

更换管路

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

替换对
LLVMCreateExecutionEngineForModule的调用
LLVMInitializeNativeTarget();
LLVMInitializeNativeAsmPrinter();
LLVMInitializeNativeAsmParser();
#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)));
void (*funcPtr) (float *);
funcPtr = LLVMGetPointerToGlobal(execEngine, func);
funcPtr(vector);