如何在llvm-ir中模拟thread_local?

26
以下代码目前在lli中无法正常工作:
//main.cpp 
extern thread_local int tls;
int main() {
    tls = 42;
    return 0;
}

//clang++ -S -emit-llvm main.cpp && lli main.ll

llvm-ir:

; ModuleID = 'main.cpp'
target datalayout = "e-m:e-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-linux-gnu"

@tls = external thread_local global i32, align 4

; Function Attrs: norecurse uwtable
define i32 @main() #0 {
  %1 = alloca i32, align 4
  store i32 0, i32* %1, align 4
  %2 = call i32* @_ZTW3tls()
  store i32 42, i32* %2, align 4
  ret i32 0
}

define weak_odr hidden i32* @_ZTW3tls() {
  br i1 icmp ne (void ()* @_ZTH3tls, void ()* null), label %1, label %2

; <label>:1                                       ; preds = %0
  call void @_ZTH3tls()
  br label %2

; <label>:2                                       ; preds = %1, %0
  ret i32* @tls
}

declare extern_weak void @_ZTH3tls()

它导致以下错误:

LLVM ERROR: Cannot select: 0x55ec0e9c3a60: i64 = X86ISD::WrapperRIP 
TargetGlobalTLSAddress:i64<i32* @tls> 0 [TF=10]
   0x55ec0e9c3858: i64 = TargetGlobalTLSAddress<i32* @tls> 0 [TF=10]
In function: _ZTW3tls

有没有一种方法可以模拟TLS并转换llvm-ir以使其工作?

是否可行使用全局映射从线程ID到指针,并将每个线程本地的出现替换为分配器/释放器/获取器/设置器?

-femulated-tls-ftls-model有用吗?

相关问题:

如何在IR转换通道中执行TargetLowering?

http://lists.llvm.org/pipermail/llvm-dev/2017-February/109947.html


据我所了解,-femulated-tls 标志基本上确实可以做到你所说的,使用与 GCC 相同的模型来模拟 TLS,以避免显式的链接器和系统支持。 - Vality
1
不幸的是,这不会影响IR。当生成二进制代码时,-femulated-tls会影响目标低层次转换(targetlowering)的代码生成阶段。 我需要对我的IR应用目标低层次转换,而不是我的机器代码。 - Gaetano
1
很不幸,LLVM似乎只在TargetLowering pass中实现了TLS仿真。该pass从IR创建汇编代码,似乎无法作为IR转换可用。相关问题: https://stackoverflow.com/questions/42163796/how-to-perform-targetlowering-in-a-ir-trasformation-pass?rq=1 - Gaetano
嗯,我似乎无法重现这个错误。这是哪个版本的LLVM? - Evan
我已经测试过它,包括在X86_64 Debian上运行的6.0.0版本和其他各种版本。 - Gaetano
显示剩余4条评论
1个回答

1

由于您没有说明看到的错误是什么,我假设它是以下形式的东西 LLVM ERROR: Program used external function '_ZTH3tls' which could not be resolved!

这是一个链接错误,实际上是指 tls 被声明为具有外部链接,但没有其他定义可供链接(至少您没有发布)。

替换

extern thread_local int tls;

使用

thread_local int tls;

编译器将生成以下IR。
@tls = thread_local global i32 0, align 4

如果你需要使用外部链接并使用 lli,你需要先使用 llvm-link 链接 llvm 文件,因为 lli 本身没有链接的能力。例如:

ext.cpp

thread_local int tls = 0;

main.cpp

extern thread_local int tls;
int main() {
  tls = 42;
  return 0;
}

编译这个将生成ext.llmain.ll。运行llvm-link -S ext.ll main.ll > output.ll获取链接文件,然后lli output.ll也应该可以工作。
如果有问题请告诉我。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接