Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to emulate thread_local in llvm-ir?

The following code is currently does not work in 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()

It causes the following error:

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

Is there a way to emulate TLS and transform the llvm-ir to make this work ?

Would it be feasible to use a global map from thread_id to pointers and replace every occurrence of thread-local with allocator/deallocator/getter/setter ?

Are -femulated-tls and -ftls-model of any use ?

related questions:

how to perform TargetLowering in a IR-trasformation pass?

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

like image 448
Gaetano Avatar asked Feb 07 '17 16:02

Gaetano


1 Answers

Since you haven't said what the error is that you're seeing I'm assuming it's something of the form LLVM ERROR: Program used external function '_ZTH3tls' which could not be resolved!

This is a linking error, which is actually referring to the fact that tls is declared as having external linkage, but there isn't another definition to link to (at least that you've posted).

Replace

extern thread_local int tls;

with

thread_local int tls;

The compiler will then generate the following IR

@tls = thread_local global i32 0, align 4

If you actually need to have external linkage and use lli, you'll need to link the llvm files with llvm-link first since lli doesn't have the ability to link for itself.

e.g.

ext.cpp

thread_local int tls = 0;

main.cpp

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

Compiling this will generate ext.ll and main.ll. Run llvm-link -S ext.ll main.ll > output.ll to get the linked file and then lli output.ll should also work.

Let me know if that settles it.

like image 90
Evan Avatar answered Oct 20 '22 03:10

Evan