通过 Clang/LLVM 强制使用特定寄存器的全局变量

Force a global variable using a specific register by Clang/LLVM

我有如下代码:

// global.cpp
int a = 5;
register unsigned b __asm("r9");

int test()
{
   b = 4;
   a++;
   b = b + 7;
   int c = a + b;

   return c;
}

我 运行 clang -target arm -c global.cpp -emit-llvm -o global.bc & llc -march=arm -filetype=asm global.bc -o -,但我得到以下错误:

        .text
        .syntax unified
        .eabi_attribute 67, "2.09"      @ Tag_conformance
        .eabi_attribute 6, 1    @ Tag_CPU_arch
        .eabi_attribute 8, 1    @ Tag_ARM_ISA_use
        .eabi_attribute 34, 1   @ Tag_CPU_unaligned_access
        .eabi_attribute 17, 1   @ Tag_ABI_PCS_GOT_use
        .eabi_attribute 20, 1   @ Tag_ABI_FP_denormal
        .eabi_attribute 21, 1   @ Tag_ABI_FP_exceptions
        .eabi_attribute 23, 3   @ Tag_ABI_FP_number_model
        .eabi_attribute 24, 1   @ Tag_ABI_align_needed
        .eabi_attribute 25, 1   @ Tag_ABI_align_preserved
        .eabi_attribute 38, 1   @ Tag_ABI_FP_16bit_format
        .eabi_attribute 18, 4   @ Tag_ABI_PCS_wchar_t
        .eabi_attribute 26, 2   @ Tag_ABI_enum_size
        .eabi_attribute 14, 0   @ Tag_ABI_PCS_R9_use
        .file   "global.cpp"
LLVM ERROR: Invalid register name "r9".
PLEASE submit a bug report to https://bugs.llvm.org/ and include the crash backtrace.
Stack dump:
0.      Program arguments: llc -march=arm -filetype=asm global.bc -o - 
1.      Running pass 'Function Pass Manager' on module 'global.bc'.
2.      Running pass 'ARM Instruction Selection' on function '@_Z4testv'
 #0 0x00007f345d2fea1a llvm::sys::PrintStackTrace(llvm::raw_ostream&) (/usr/lib/llvm/11/bin/../lib64/libLLVM-11.so+0xb12a1a)
 #1 0x00007f345d2fc7a4 llvm::sys::RunSignalHandlers() (/usr/lib/llvm/11/bin/../lib64/libLLVM-11.so+0xb107a4)
 #2 0x00007f345d2fc8f8 (/usr/lib/llvm/11/bin/../lib64/libLLVM-11.so+0xb108f8)
 #3 0x00007f345c39fde0 (/lib64/libc.so.6+0x38de0)
 #4 0x00007f345c39fd61 raise (/lib64/libc.so.6+0x38d61)
 #5 0x00007f345c389536 abort (/lib64/libc.so.6+0x22536)
 #6 0x00007f345d2165e6 llvm::report_fatal_error(llvm::Twine const&, bool) (/usr/lib/llvm/11/bin/../lib64/libLLVM-11.so+0xa2a5e6)
 #7 0x00007f345f40b269 (/usr/lib/llvm/11/bin/../lib64/libLLVM-11.so+0x2c1f269)
 #8 0x00007f345dbb9000 llvm::SelectionDAGISel::Select_READ_REGISTER(llvm::SDNode*) (/usr/lib/llvm/11/bin/../lib64/libLLVM-11.so+0x13cd000)
 #9 0x00007f345dbbc52b llvm::SelectionDAGISel::SelectCodeCommon(llvm::SDNode*, unsigned char const*, unsigned int) (/usr/lib/llvm/11/bin/../lib64/libLLVM-11.so+0x13d052b)
#10 0x00007f345f3fcf21 (/usr/lib/llvm/11/bin/../lib64/libLLVM-11.so+0x2c10f21)
#11 0x00007f345dbb85e8 llvm::SelectionDAGISel::DoInstructionSelection() (/usr/lib/llvm/11/bin/../lib64/libLLVM-11.so+0x13cc5e8)
#12 0x00007f345dbc11b5 llvm::SelectionDAGISel::CodeGenAndEmitDAG() (/usr/lib/llvm/11/bin/../lib64/libLLVM-11.so+0x13d51b5)
#13 0x00007f345dbc4560 llvm::SelectionDAGISel::SelectAllBasicBlocks(llvm::Function const&) (/usr/lib/llvm/11/bin/../lib64/libLLVM-11.so+0x13d8560)
#14 0x00007f345dbc7501 llvm::SelectionDAGISel::runOnMachineFunction(llvm::MachineFunction&) (/usr/lib/llvm/11/bin/../lib64/libLLVM-11.so+0x13db501)
#15 0x00007f345f406014 (/usr/lib/llvm/11/bin/../lib64/libLLVM-11.so+0x2c1a014)
#16 0x00007f345d6c949d (/usr/lib/llvm/11/bin/../lib64/libLLVM-11.so+0xedd49d)
#17 0x00007f345d4503f8 llvm::FPPassManager::runOnFunction(llvm::Function&) (/usr/lib/llvm/11/bin/../lib64/libLLVM-11.so+0xc643f8)
#18 0x00007f345d451971 llvm::FPPassManager::runOnModule(llvm::Module&) (/usr/lib/llvm/11/bin/../lib64/libLLVM-11.so+0xc65971)
#19 0x00007f345d44f70b llvm::legacy::PassManagerImpl::run(llvm::Module&) (/usr/lib/llvm/11/bin/../lib64/libLLVM-11.so+0xc6370b)
#20 0x000056232e849ef6 main (/usr/lib/llvm/11/bin/llc+0xeef6)
#21 0x00007f345c38ae6b __libc_start_main (/lib64/libc.so.6+0x23e6b)
#22 0x000056232e84a6ca _start (/usr/lib/llvm/11/bin/llc+0xf6ca)

谁能给我提示如何强制将全局变量 b 存储在寄存器 r9 中?

我的 LLVM 和 Clang 版本:11.0.0

更新: 我想将全局变量放入特定寄存器(本例中为 R9),因为我计划将全局寄存器变量功能从 ARM 移植到我自己的后端(由于没有堆栈,我需要在寄存器中分配全局变量 space 这样做)。我只是想确认这个功能是否可以在 ARM 上使用,所以我可以将这个功能移植到我的后端。

“寄存器中的全局变量”仅支持 ARM 上的 SP 寄存器。欢迎补丁:)

这个post可能与问题没有直接关系。但是由于我想在我自己的支持下将一些全局变量固定到相应的寄存器,我最终通过操纵 IR 和编写后端来修改 LLVM 使其工作。详情如下:

  • 关于后端,我参考了教程:为 Cpu0 Architecture 并记得在 XXXISelLowering.cpp.
  • 中定义 getRegisterByName 函数
  • 对于 IR 操作,我创建了一个通行证来做到这一点。主要有3个步骤:
    • 获取全局变量及其对应寄存器的列表(通过cl:opt
    • 遍历每个全局变量:
      • 正在创建相应的元数据(MDNode, NamedMDNode
      • 正在通过模块级内联汇编进行初始化(appendModuleInlineAsm
      • 正在使用相应的元数据创建新指令,用于替换全局变量的原始用户。使用 IRBuilder 可能更容易创建新指令来替换原来的指令。
    • 用相应的元数据替换原来的全局变量。请注意,此步骤应在迭代之外完成,因为替换可能会破坏迭代。

我还发现以下参考资料可以帮助我学习 LLVM:

  1. 开始使用 LLVM 核心库
  2. LLVM doxygen(找到你感兴趣的class看看都有什么功能)
  3. 直接grep源码学习class、函数等
  4. 的使用方法