1

我正在编写一个MachineFunctionPass针对 X86 架构的代码,这会导致修改后的llc二进制文件。

为了测试我的修改版本,llc我创建了一堆.c程序,它们的 MIR 将由我的 pass 处理。

为了简洁起见,我已将包含源代码的目录直接添加到 LLVM 的源代码树中,特别是在$llvm_src_dir/lib/Target/X86/$examples_dir: 然后我通过将add_subdirectory()指令附加到$llvm_src_dir/lib/Target/X86/CMakeLists.txt.

通过这种方式,我将能够直接从 LLVM 的构建目录构建所有内容。

现在:如何在我的指定$examples_dir/CMakeLists.txt使用 LLVM 的 in-tree llc

源码树结构

这是源的目录结构。我省略了所有根目录的子目录,因为我只包含了“有趣的”。

LLVM 定义了llc目标,tools/llc而我的源在目录中的位置更深,如下图所示:

llvm_src_dir
├── bindings
├── cmake
├── docs
├── examples
├── include
├── lib
    └── Target
        └── X86
            /* 
             * My git repo is here. LLVM's and
             * my MachineFunctionPass' files
             * live here 
            */
            ├── .git
            ├── CMakeLists.txt // This is LLVM's X86 CMakeLists.txt
            └── examples
                └── CMakeLists.txt // My CMakeLists.txt
├── projects
├── resources
├── runtimes
├── test
├── tools
    └── llc
        └── CMakeLists.txt // this is where LLVM's llc target is defined
├── unittests
└── utils

lib/Target/X86/CMakeLists.txt

这就是我编辑CMakeLists.txt目标架构的方式:

set (CMAKE_CXX_STANDARD 14)
set(LLVM_TARGET_DEFINITIONS X86.td)

tablegen(LLVM X86GenAsmMatcher.inc -gen-asm-matcher)
tablegen(LLVM X86GenAsmWriter.inc -gen-asm-writer)
tablegen(LLVM X86GenAsmWriter1.inc -gen-asm-writer -asmwriternum=1)
tablegen(LLVM X86GenCallingConv.inc -gen-callingconv)
tablegen(LLVM X86GenDAGISel.inc -gen-dag-isel)
tablegen(LLVM X86GenDisassemblerTables.inc -gen-disassembler)
tablegen(LLVM X86GenEVEX2VEXTables.inc -gen-x86-EVEX2VEX-tables)
tablegen(LLVM X86GenFastISel.inc -gen-fast-isel)
tablegen(LLVM X86GenGlobalISel.inc -gen-global-isel)
tablegen(LLVM X86GenInstrInfo.inc -gen-instr-info)
tablegen(LLVM X86GenRegisterBank.inc -gen-register-bank)
tablegen(LLVM X86GenRegisterInfo.inc -gen-register-info)
tablegen(LLVM X86GenSubtargetInfo.inc -gen-subtarget)

if (X86_GEN_FOLD_TABLES)
    tablegen(LLVM X86GenFoldTables.inc -gen-x86-fold-tables)
endif ()

add_public_tablegen_target(X86CommonTableGen)

set(MY_SOURCES
        a.cpp
        b.cpp
        c.cpp
        )

set(sources
        ShadowCallStack.cpp
        X86AsmPrinter.cpp
        X86CallFrameOptimization.cpp
        X86CallingConv.cpp
        X86CallLowering.cpp
        X86CmovConversion.cpp
        X86DomainReassignment.cpp
        X86ExpandPseudo.cpp
        X86FastISel.cpp
        X86FixupBWInsts.cpp
        X86FixupLEAs.cpp
        X86AvoidStoreForwardingBlocks.cpp
        X86FixupSetCC.cpp
        X86FlagsCopyLowering.cpp
        X86FloatingPoint.cpp
        X86FrameLowering.cpp
        X86InstructionSelector.cpp
        X86ISelDAGToDAG.cpp
        X86ISelLowering.cpp
        X86IndirectBranchTracking.cpp
        X86InterleavedAccess.cpp
        X86InstrFMA3Info.cpp
        X86InstrFoldTables.cpp
        X86InstrInfo.cpp
        X86EvexToVex.cpp
        X86LegalizerInfo.cpp
        X86MCInstLower.cpp
        X86MachineFunctionInfo.cpp
        X86MacroFusion.cpp
        X86OptimizeLEAs.cpp
        X86PadShortFunction.cpp
        X86RegisterBankInfo.cpp
        X86RegisterInfo.cpp
        X86RetpolineThunks.cpp
        X86SelectionDAGInfo.cpp
        X86ShuffleDecodeConstantPool.cpp
        X86SpeculativeLoadHardening.cpp
        X86Subtarget.cpp
        X86TargetMachine.cpp
        X86TargetObjectFile.cpp
        X86TargetTransformInfo.cpp
        X86VZeroUpper.cpp
        X86WinAllocaExpander.cpp
        X86WinEHState.cpp
        ${MY_SOURCES}
        )

add_llvm_target(X86CodeGen ${sources})

add_subdirectory(AsmParser)
add_subdirectory(Disassembler)
add_subdirectory(InstPrinter)
add_subdirectory(MCTargetDesc)
add_subdirectory(TargetInfo)
add_subdirectory(Utils)
add_subdirectory(examples) // my examples directory

我已经尝试过的

我目前正在使用find_path()查找llc,但这需要llc已经编译,因此CMakeLists.txt如果我不llc事先编译,我的示例将无法通过验证。

假设路径存在,我最终在我的中使用了一个指令add_custom_command(),但在我看来这太hacky了。llcCMakeLists.txt

基本上,我需要将目标添加llc为我的目标的依赖项,然后使用llc“路径将我的示例”.bc文件编译成.s.

有任何想法吗?

非常感谢!

4

1 回答 1

1

我看到了两种可能的解决方案,现在让我介绍一个更简单的解决方案。

project(nested-toolchain C CXX)

# Assume that `llc` target is created somewhere within project
# Even if it is created in later `add_subdirectory` calls,
# We can defer evaluation to its path using generator expression $<TARGET_FILE:llc>

# This is the magic.
# It tells cmake how to produce test1.s from test1.bc using llc binary
# Also will track test1.bc changes and set test1.s as dirty when needed
add_custom_command(OUTPUT test1.s COMMAND $<TARGET_FILE:llc> test1.bc DEPENDS test1.bc)
add_custom_command(OUTPUT test2.s COMMAND $<TARGET_FILE:llc> test2.bc DEPENDS test2.bc)

# Now merge custom commands into single target which can be called by make/ninja/...
# simply call `make tests` to run two commands listed above (and compile llc before that)
add_custom_target(tests SOURCES test1.s test2.s)

总结一下:首先我们知道我们的 CMake 项目可以llc从 llvm-sources 的某个地方生成二进制文件。此二进制文件可用于生成test.s指定了魔法命令的文件。它们依赖于相应的.bc文件。这些.bc文件tests通过add_custom_target.

我曾经add_custom_target将示例保持在最小限度,它有一个缺陷:调用make tests总是会调用所有llc命令,因为自定义目标总是被认为是“过时的”。

如果您想在.s文件上使用其他工具,我建议您add_custom_command类比地链接另一个工具并使用add_custom_target来完成链接。

只要您正在测试单个二进制文件 ( llc),这种方法就应该有效。如果你想测试整个工具链,我会选择try_compile.

为了完整起见,对于llc.cpp给定的文件:

// Just print args
#include <iostream>
int main(int argc, char **argv) {
  for (int i = 0; i < argc; i++) {
    std::cout << argv[i] << ' ';
  }
  std::cout << "\n";
  return 0;
}

ninja tests导致:

$ ninja tests
[1/2] Generating test2.s
/home/stackoverflow/nested-toolchain/build/llc test2.bc 
[2/2] Generating test1.s
/home/stackoverflow/nested-toolchain/build/llc test1.bc 
于 2019-05-31T11:48:19.183 回答