Как использовать только что скомпилированный инструмент LLVM непосредственно из дерева исходных текстов LLVM? - PullRequest
1 голос
/ 31 мая 2019

Я пишу MachineFunctionPass, ориентируясь на архитектуру X86, что приводит к измененному двоичному файлу llc.

Для тестирования моей модифицированной версии llc я создал группу .c программ, MIR которых будет обработан моим пропуском.

Ради чистоты я добавил каталог, включая источники, непосредственно в дерево исходных текстов LLVM, в частности, в $llvm_src_dir/lib/Target/X86/$examples_dir: затем я подключил его к системе сборки LLVM, добавив директиву add_subdirectory() к $llvm_src_dir/lib/Target/X86/CMakeLists.txt.

Таким образом, я смогу собрать все непосредственно из директории сборки LLVM.

Теперь: как мне указать в моем $examples_dir/CMakeLists.txt использование внутреннего дерева LLVM llc?

Исходная древовидная структура

Это структура каталогов источников. Я опустил все дочерние каталоги root, так как я включил только "интересные".

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(), чтобы использовать llc в моем CMakeLists.txt, но это слишком глупо, на мой взгляд.

По сути, мне нужно добавить цель llc в качестве зависимости для моих целей, а затем использовать путь llc для компиляции файлов .bc моих примеров в .s.

Есть идеи?

Большое спасибо!

1 Ответ

1 голос
/ 31 мая 2019

Я вижу два возможных решения, а пока позвольте мне представить более простое.

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-источников.Этот двоичный файл можно использовать для создания 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 
...