LLVM-C 创建目标文件导致:"TargetMachine can't emit a file of this type"

LLVM-C creating object file results in: "TargetMachine can't emit a file of this type"

尝试用 LLVM-C 生成一个非常简单的目标文件。不幸的是,我仍然坚持 "TargetMachine can't emit a file of this type" 尝试重新排序代码和 CPU 的各种东西(x64-64,通用和 LLVMGetHostCPUName())。显然这里缺少一些东西(希望很明显)。

下面的代码是用clang -Wall -O2 test.c LLVM-C.dll -o test

编译的

输出:

target: x86-64, [64-bit X86: EM64T and AMD64], 1, 1
triple: x86_64-pc-windows-msvc
features: +sse2,+cx16,+sahf,-tbm,-avx512ifma,+sha,-gfni,-fma4,-vpclmulqdq,+prfchw,+bmi2,-cldemote,+fsgsbase,-ptwrite,+xsavec,+popcnt,+aes,-avx512bitalg,-movdiri,+xsaves,-avx512er,-avx512vnni,-avx512vpopcntdq,-pconfig,-clwb,-avx512f,+clzero,-pku,+mmx,-lwp,-rdpid,-xop,+rdseed,-waitpkg,-movdir64b,+sse4a,-avx512bw,+clflushopt,+xsave,-avx512vbmi2,+64bit,-avx512vl,-invpcid,-avx512cd,+avx,-vaes,+cx8,+fma,-rtm,+bmi,-enqcmd,+rdrnd,+mwaitx,+sse4.1,+sse4.2,+avx2,+fxsr,-wbnoinvd,+sse,+lzcnt,+pclmul,-prefetchwt1,+f16c,+ssse3,-sgx,-shstk,+cmov,-avx512vbmi,-avx512bf16,+movbe,+xsaveopt,-avx512dq,+adx,-avx512pf,+sse3
datalayout: e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128
error: (null)
error: TargetMachine can't emit a file of this type

Module.txt:

; ModuleID = 'test'
source_filename = "test"
target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc"

define float @ftest() {
ftest:
  ret float 0x401B333340000000
}

代码(test.c):

#include <llvm-c/Core.h>
#include <llvm-c/Analysis.h>
#include <llvm-c/TargetMachine.h>

#include <stdio.h>

int main(){
    LLVMInitializeNativeTarget();
    LLVMTargetRef target = LLVMGetFirstTarget();
    printf("target: %s, [%s], %d, %d\n", LLVMGetTargetName(target), LLVMGetTargetDescription(target), LLVMTargetHasJIT(target), LLVMTargetHasTargetMachine(target));
    printf("triple: %s\n", LLVMGetDefaultTargetTriple());
    printf("features: %s\n", LLVMGetHostCPUFeatures());
    LLVMTargetMachineRef machine = LLVMCreateTargetMachine(target, LLVMGetDefaultTargetTriple(), "generic", LLVMGetHostCPUFeatures(), LLVMCodeGenLevelDefault, LLVMRelocDefault, LLVMCodeModelDefault);

    LLVMContextRef context = LLVMContextCreate();
    LLVMModuleRef module = LLVMModuleCreateWithNameInContext("test", context);

    LLVMSetTarget(module, LLVMGetDefaultTargetTriple());
    LLVMTargetDataRef datalayout = LLVMCreateTargetDataLayout(machine);
    char* datalayout_str = LLVMCopyStringRepOfTargetData(datalayout);
    printf("datalayout: %s\n", datalayout_str);
    LLVMSetDataLayout(module, datalayout_str);
    LLVMDisposeMessage(datalayout_str);

    LLVMTypeRef f32 = LLVMFloatTypeInContext(context);
    LLVMTypeRef ftype = LLVMFunctionType(f32, 0, 0, 0);
    LLVMValueRef ftest = LLVMAddFunction(module, "ftest", ftype);
    LLVMBasicBlockRef bb = LLVMAppendBasicBlockInContext(context, ftest, "ftest");
    LLVMBuilderRef builder = LLVMCreateBuilderInContext(context);
    LLVMPositionBuilderAtEnd(builder, bb);
    LLVMValueRef v1 = LLVMConstReal(f32, 2.5);
    LLVMValueRef v2 = LLVMConstReal(f32, 4.3);
    LLVMValueRef result = LLVMBuildFAdd(builder, v1, v2, "f-add");
    LLVMBuildRet(builder, result);
    LLVMVerifyFunction(ftest, LLVMPrintMessageAction);

    char* errors = 0;
    LLVMPrintModuleToFile(module, "module.txt", &errors);
    printf("error: %s\n", errors);
    LLVMDisposeMessage(errors);

    LLVMTargetMachineEmitToFile(machine, module, "result.o", LLVMObjectFile, &errors);
    printf("error: %s\n", errors);
    LLVMDisposeMessage(errors);
    return 0;
}

好吧,经过更多的挖掘,我解决了这个问题。工作代码如下:

#include <llvm-c/Core.h>
#include <llvm-c/Transforms/PassManagerBuilder.h>
#include <llvm-c/Analysis.h>
#include <llvm-c/TargetMachine.h>
#include <llvm-c/BitWriter.h>

#include <stdio.h>

int main(){
    LLVMContextRef context = LLVMContextCreate();
    LLVMModuleRef module = LLVMModuleCreateWithNameInContext("test", context);

    LLVMTypeRef f32 = LLVMFloatTypeInContext(context);
    LLVMTypeRef ftype = LLVMFunctionType(f32, 0, 0, 0);
    LLVMValueRef ftest = LLVMAddFunction(module, "ftest", ftype);
    LLVMBasicBlockRef bb = LLVMAppendBasicBlockInContext(context, ftest, "ftest");
    LLVMBuilderRef builder = LLVMCreateBuilderInContext(context);
    LLVMPositionBuilderAtEnd(builder, bb);
    LLVMValueRef v1 = LLVMConstReal(f32, 2.5);
    LLVMValueRef v2 = LLVMConstReal(f32, 4.3);
    LLVMValueRef result = LLVMBuildFAdd(builder, v1, v2, "f-add");
    LLVMBuildRet(builder, result);
    LLVMVerifyFunction(ftest, LLVMPrintMessageAction);

    char* errors = 0;
    LLVMPrintModuleToFile(module, "module.txt", &errors);
    printf("error: %s\n", errors);
    LLVMDisposeMessage(errors);

    LLVMInitializeAllTargetInfos();
    LLVMInitializeAllTargets();
    LLVMInitializeAllTargetMCs();
    LLVMInitializeAllAsmParsers();
    LLVMInitializeAllAsmPrinters();

    LLVMTargetRef target;
    LLVMGetTargetFromTriple(LLVMGetDefaultTargetTriple(), &target, &errors);
    printf("error: %s\n", errors);
    LLVMDisposeMessage(errors);
    printf("target: %s, [%s], %d, %d\n", LLVMGetTargetName(target), LLVMGetTargetDescription(target), LLVMTargetHasJIT(target), LLVMTargetHasTargetMachine(target));
    printf("triple: %s\n", LLVMGetDefaultTargetTriple());
    printf("features: %s\n", LLVMGetHostCPUFeatures());
    LLVMTargetMachineRef machine = LLVMCreateTargetMachine(target, LLVMGetDefaultTargetTriple(), "generic", LLVMGetHostCPUFeatures(), LLVMCodeGenLevelDefault, LLVMRelocDefault, LLVMCodeModelDefault);

    LLVMSetTarget(module, LLVMGetDefaultTargetTriple());
    LLVMTargetDataRef datalayout = LLVMCreateTargetDataLayout(machine);
    char* datalayout_str = LLVMCopyStringRepOfTargetData(datalayout);
    printf("datalayout: %s\n", datalayout_str);
    LLVMSetDataLayout(module, datalayout_str);
    LLVMDisposeMessage(datalayout_str);

    LLVMTargetMachineEmitToFile(machine, module, "result.o", LLVMObjectFile, &errors);
    printf("error: %s\n", errors);
    LLVMDisposeMessage(errors);
    return 0;
}