3 changes: 3 additions & 0 deletions llvm/lib/Target/PowerPC/PPCISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2085,6 +2085,9 @@ SDValue PPCTargetLowering::LowerGlobalTLSAddress(SDValue Op,
// large models could be added if users need it, at the cost of
// additional complexity.
GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Op);
if (DAG.getTarget().Options.EmulatedTLS)
return LowerToTLSEmulatedModel(GA, DAG);

SDLoc dl(GA);
const GlobalValue *GV = GA->getGlobal();
EVT PtrVT = getPointerTy(DAG.getDataLayout());
Expand Down
3 changes: 3 additions & 0 deletions llvm/lib/Target/Sparc/SparcISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1872,6 +1872,9 @@ SDValue SparcTargetLowering::LowerGlobalTLSAddress(SDValue Op,
SelectionDAG &DAG) const {

GlobalAddressSDNode *GA = cast<GlobalAddressSDNode>(Op);
if (DAG.getTarget().Options.EmulatedTLS)
return LowerToTLSEmulatedModel(GA, DAG);

SDLoc DL(GA);
const GlobalValue *GV = GA->getGlobal();
EVT PtrVT = getPointerTy(DAG.getDataLayout());
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/SystemZ/SystemZISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2485,6 +2485,8 @@ SDValue SystemZTargetLowering::lowerTLSGetOffset(GlobalAddressSDNode *Node,

SDValue SystemZTargetLowering::lowerGlobalTLSAddress(GlobalAddressSDNode *Node,
SelectionDAG &DAG) const {
if (DAG.getTarget().Options.EmulatedTLS)
return LowerToTLSEmulatedModel(Node, DAG);
SDLoc DL(Node);
const GlobalValue *GV = Node->getGlobal();
EVT PtrVT = getPointerTy(DAG.getDataLayout());
Expand Down
2 changes: 2 additions & 0 deletions llvm/lib/Target/X86/X86ISelLowering.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11645,6 +11645,8 @@ X86TargetLowering::LowerGlobalTLSAddress(SDValue Op, SelectionDAG &DAG) const {
auto PtrVT = getPointerTy(DAG.getDataLayout());

if (Subtarget->isTargetELF()) {
if (DAG.getTarget().Options.EmulatedTLS)
return LowerToTLSEmulatedModel(GA, DAG);
TLSModel::Model model = DAG.getTarget().getTLSModel(GV);
switch (model) {
case TLSModel::GeneralDynamic:
Expand Down
43 changes: 40 additions & 3 deletions llvm/test/CodeGen/AArch64/arm64-tls-dynamic-together.ll
Original file line number Diff line number Diff line change
@@ -1,4 +1,7 @@
; RUN: llc -O0 -mtriple=arm64-none-linux-gnu -relocation-model=pic -verify-machineinstrs < %s | FileCheck %s
; RUN: llc -O0 -mtriple=arm64-none-linux-gnu -relocation-model=pic \
; RUN: -verify-machineinstrs < %s | FileCheck -check-prefix=CHECK -check-prefix=NOEMU %s
; RUN: llc -emulated-tls -O0 -mtriple=arm64-none-linux-gnu -relocation-model=pic \
; RUN: -verify-machineinstrs < %s | FileCheck -check-prefix=CHECK -check-prefix=EMU %s

; If the .tlsdesccall and blr parts are emitted completely separately (even with
; glue) then LLVM will separate them quite happily (with a spill at O0, hence
Expand All @@ -13,6 +16,40 @@ define i32 @test_generaldynamic() {
%val = load i32, i32* @general_dynamic_var
ret i32 %val

; CHECK: .tlsdesccall general_dynamic_var
; CHECK-NEXT: blr {{x[0-9]+}}
; NOEMU: .tlsdesccall general_dynamic_var
; NOEMU-NEXT: blr {{x[0-9]+}}
; NOEMU-NOT: __emutls_v.general_dynamic_var:

; EMU: adrp{{.+}}__emutls_v.general_dynamic_var
; EMU: bl __emutls_get_address

; EMU-NOT: __emutls_v.general_dynamic_var
; EMU-NOT: __emutls_t.general_dynamic_var
}

@emulated_init_var = thread_local global i32 37, align 8

define i32 @test_emulated_init() {
; COMMON-LABEL: test_emulated_init:

%val = load i32, i32* @emulated_init_var
ret i32 %val

; EMU: adrp{{.+}}__emutls_v.emulated_init_var
; EMU: bl __emutls_get_address

; EMU-NOT: __emutls_v.general_dynamic_var:

; EMU: .align 3
; EMU-LABEL: __emutls_v.emulated_init_var:
; EMU-NEXT: .xword 4
; EMU-NEXT: .xword 8
; EMU-NEXT: .xword 0
; EMU-NEXT: .xword __emutls_t.emulated_init_var

; EMU-LABEL: __emutls_t.emulated_init_var:
; EMU-NEXT: .word 37
}

; CHECK-NOT: __emutls_v.general_dynamic_var:
; EMU-NOT: __emutls_t.general_dynamic_var
368 changes: 368 additions & 0 deletions llvm/test/CodeGen/AArch64/emutls.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,368 @@
; RUN: llc -emulated-tls -mtriple=arm-linux-android \
; RUN: -relocation-model=pic < %s | FileCheck -check-prefix=ARM32 %s
; RUN: llc -emulated-tls -mtriple=aarch64-linux-android \
; RUN: -relocation-model=pic < %s | FileCheck -check-prefix=ARM64 %s

; Copied from X86/emutls.ll

; Use my_emutls_get_address like __emutls_get_address.
@my_emutls_v_xyz = external global i8*, align 4
declare i8* @my_emutls_get_address(i8*)

define i32 @my_get_xyz() {
; ARM32-LABEL: my_get_xyz:
; ARM32: ldr r0,
; ARM32-NEXT: ldr r1,
; ARM32: add r0, pc, r0
; ARM32-NEXT: ldr r0, [r1, r0]
; ARM32-NEXT: bl my_emutls_get_address(PLT)
; ARM32-NEXT: ldr r0, [r0]
; ARM64-LABEL: my_get_xyz:
; ARM64: adrp x0, :got:my_emutls_v_xyz
; ARM64-NEXT: ldr x0, [x0, :got_lo12:my_emutls_v_xyz]
; ARM64-NEXT: bl my_emutls_get_address
; ARM64-NEXT: ldr w0, [x0]
; ARM64-NEXT: ldp x29, x30, [sp]

entry:
%call = call i8* @my_emutls_get_address(i8* bitcast (i8** @my_emutls_v_xyz to i8*))
%0 = bitcast i8* %call to i32*
%1 = load i32, i32* %0, align 4
ret i32 %1
}

@i1 = thread_local global i32 15
@i2 = external thread_local global i32
@i3 = internal thread_local global i32 15
@i4 = hidden thread_local global i32 15
@i5 = external hidden thread_local global i32
@s1 = thread_local global i16 15
@b1 = thread_local global i8 0

define i32 @f1() {
; ARM32-LABEL: f1:
; ARM32: ldr r0,
; ARM32-NEXT: ldr r1,
; ARM32: add r0, pc, r0
; ARM32-NEXT: ldr r0, [r1, r0]
; ARM32-NEXT: bl __emutls_get_address(PLT)
; ARM32-NEXT: ldr r0, [r0]
; ARM64-LABEL: f1:
; ARM64: adrp x0, :got:__emutls_v.i1
; ARM64-NEXT: ldr x0, [x0, :got_lo12:__emutls_v.i1]
; ARM64-NEXT: bl __emutls_get_address
; ARM64-NEXT: ldr w0, [x0]
; ARM64-NEXT: ldp x29, x30, [sp]

entry:
%tmp1 = load i32, i32* @i1
ret i32 %tmp1
}

define i32* @f2() {
; ARM32-LABEL: f2:
; ARM32: ldr r0,
; ARM32-NEXT: ldr r1,
; ARM32: add r0, pc, r0
; ARM32-NEXT: ldr r0, [r1, r0]
; ARM32-NEXT: bl __emutls_get_address(PLT)
; ARM32-NEXT: pop
; ARM64-LABEL: f2:
; ARM64: adrp x0, :got:__emutls_v.i1
; ARM64-NEXT: ldr x0, [x0, :got_lo12:__emutls_v.i1]
; ARM64-NEXT: bl __emutls_get_address
; ARM64-NEXT: ldp x29, x30, [sp]

entry:
ret i32* @i1
}

define i32 @f3() nounwind {
; ARM32-LABEL: f3:
; ARM32: ldr r0,
; ARM32-NEXT: ldr r1,
; ARM32: add r0, pc, r0
; ARM32-NEXT: ldr r0, [r1, r0]
; ARM32-NEXT: bl __emutls_get_address(PLT)
; ARM32-NEXT: ldr r0, [r0]

entry:
%tmp1 = load i32, i32* @i2
ret i32 %tmp1
}

define i32* @f4() {
; ARM32-LABEL: f4:
; ARM32: ldr r0,
; ARM32-NEXT: ldr r1,
; ARM32: add r0, pc, r0
; ARM32-NEXT: ldr r0, [r1, r0]
; ARM32-NEXT: bl __emutls_get_address(PLT)
; ARM32-NEXT: pop

entry:
ret i32* @i2
}

define i32 @f5() nounwind {
; ARM32-LABEL: f5:
; ARM32: ldr r0,
; ARM32-NEXT: ldr r1,
; ARM32: add r0, pc, r0
; ARM32-NEXT: ldr r0, [r1, r0]
; ARM32-NEXT: bl __emutls_get_address(PLT)
; ARM32-NEXT: ldr r0, [r0]

entry:
%tmp1 = load i32, i32* @i3
ret i32 %tmp1
}

define i32* @f6() {
; ARM32-LABEL: f6:
; ARM32: ldr r0,
; ARM32-NEXT: ldr r1,
; ARM32: add r0, pc, r0
; ARM32-NEXT: ldr r0, [r1, r0]
; ARM32-NEXT: bl __emutls_get_address(PLT)
; ARM32-NEXT: pop

entry:
ret i32* @i3
}

define i32 @f7() {
; ARM32-LABEL: f7:
; ARM32: ldr r0,
; ARM32-NEXT: ldr r1,
; ARM32: add r0, pc, r0
; ARM32-NEXT: ldr r0, [r1, r0]
; ARM32-NEXT: bl __emutls_get_address(PLT)
; ARM32-NEXT: ldr r0, [r0]

entry:
%tmp1 = load i32, i32* @i4
ret i32 %tmp1
}

define i32* @f8() {
; ARM32-LABEL: f8:
; ARM32: ldr r0,
; ARM32-NEXT: ldr r1,
; ARM32: add r0, pc, r0
; ARM32-NEXT: ldr r0, [r1, r0]
; ARM32-NEXT: bl __emutls_get_address(PLT)
; ARM32-NEXT: pop

entry:
ret i32* @i4
}

define i32 @f9() {
; ARM32-LABEL: f9:
; ARM32: ldr r0,
; ARM32-NEXT: ldr r1,
; ARM32: add r0, pc, r0
; ARM32-NEXT: ldr r0, [r1, r0]
; ARM32-NEXT: bl __emutls_get_address(PLT)
; ARM32-NEXT: ldr r0, [r0]

entry:
%tmp1 = load i32, i32* @i5
ret i32 %tmp1
}

define i32* @f10() {
; ARM32-LABEL: f10:
; ARM32: ldr r0,
; ARM32-NEXT: ldr r1,
; ARM32: add r0, pc, r0
; ARM32-NEXT: ldr r0, [r1, r0]
; ARM32-NEXT: bl __emutls_get_address(PLT)
; ARM32-NEXT: pop

entry:
ret i32* @i5
}

define i16 @f11() {
; ARM32-LABEL: f11:
; ARM32: ldr r0,
; ARM32-NEXT: ldr r1,
; ARM32: add r0, pc, r0
; ARM32-NEXT: ldr r0, [r1, r0]
; ARM32-NEXT: bl __emutls_get_address(PLT)
; ARM32-NEXT: ldrh r0, [r0]

entry:
%tmp1 = load i16, i16* @s1
ret i16 %tmp1
}

define i32 @f12() {
; ARM32-LABEL: f12:
; ARM32: ldr r0,
; ARM32-NEXT: ldr r1,
; ARM32: add r0, pc, r0
; ARM32-NEXT: ldr r0, [r1, r0]
; ARM32-NEXT: bl __emutls_get_address(PLT)
; ARM32-NEXT: ldrsh r0, [r0]

entry:
%tmp1 = load i16, i16* @s1
%tmp2 = sext i16 %tmp1 to i32
ret i32 %tmp2
}

define i8 @f13() {
; ARM32-LABEL: f13:
; ARM32: ldr r0,
; ARM32-NEXT: ldr r1,
; ARM32: add r0, pc, r0
; ARM32-NEXT: ldr r0, [r1, r0]
; ARM32-NEXT: bl __emutls_get_address(PLT)
; ARM32-NEXT: ldrb r0, [r0]
; ARM32-NEXT: pop

entry:
%tmp1 = load i8, i8* @b1
ret i8 %tmp1
}

define i32 @f14() {
; ARM32-LABEL: f14:
; ARM32: ldr r0,
; ARM32-NEXT: ldr r1,
; ARM32: add r0, pc, r0
; ARM32-NEXT: ldr r0, [r1, r0]
; ARM32-NEXT: bl __emutls_get_address(PLT)
; ARM32-NEXT: ldrsb r0, [r0]
; ARM32-NEXT: pop

entry:
%tmp1 = load i8, i8* @b1
%tmp2 = sext i8 %tmp1 to i32
ret i32 %tmp2
}

;;;;;;;;;;;;;; 32-bit __emutls_v. and __emutls_t.

; ARM32 .section .data.rel.local,
; ARM32-LABEL: __emutls_v.i1:
; ARM32-NEXT: .long 4
; ARM32-NEXT: .long 4
; ARM32-NEXT: .long 0
; ARM32-NEXT: .long __emutls_t.i1

; ARM32 .section .rodata,
; ARM32-LABEL: __emutls_t.i1:
; ARM32-NEXT: .long 15

; ARM32-NOT: __emutls_v.i2

; ARM32 .section .data.rel.local,
; ARM32-LABEL: __emutls_v.i3:
; ARM32-NEXT: .long 4
; ARM32-NEXT: .long 4
; ARM32-NEXT: .long 0
; ARM32-NEXT: .long __emutls_t.i3

; ARM32 .section .rodata,
; ARM32-LABEL: __emutls_t.i3:
; ARM32-NEXT: .long 15

; ARM32 .section .data.rel.local,
; ARM32-LABEL: __emutls_v.i4:
; ARM32-NEXT: .long 4
; ARM32-NEXT: .long 4
; ARM32-NEXT: .long 0
; ARM32-NEXT: .long __emutls_t.i4

; ARM32 .section .rodata,
; ARM32-LABEL: __emutls_t.i4:
; ARM32-NEXT: .long 15

; ARM32-NOT: __emutls_v.i5:
; ARM32 .hidden __emutls_v.i5
; ARM32-NOT: __emutls_v.i5:

; ARM32 .section .data.rel.local,
; ARM32-LABEL: __emutls_v.s1:
; ARM32-NEXT: .long 2
; ARM32-NEXT: .long 2
; ARM32-NEXT: .long 0
; ARM32-NEXT: .long __emutls_t.s1

; ARM32 .section .rodata,
; ARM32-LABEL: __emutls_t.s1:
; ARM32-NEXT: .short 15

; ARM32 .section .data.rel.local,
; ARM32-LABEL: __emutls_v.b1:
; ARM32-NEXT: .long 1
; ARM32-NEXT: .long 1
; ARM32-NEXT: .long 0
; ARM32-NEXT: .long 0

; ARM32-NOT: __emutls_t.b1

;;;;;;;;;;;;;; 64-bit __emutls_v. and __emutls_t.

; ARM64 .section .data.rel.local,
; ARM64-LABEL: __emutls_v.i1:
; ARM64-NEXT: .xword 4
; ARM64-NEXT: .xword 4
; ARM64-NEXT: .xword 0
; ARM64-NEXT: .xword __emutls_t.i1

; ARM64 .section .rodata,
; ARM64-LABEL: __emutls_t.i1:
; ARM64-NEXT: .word 15

; ARM64-NOT: __emutls_v.i2

; ARM64 .section .data.rel.local,
; ARM64-LABEL: __emutls_v.i3:
; ARM64-NEXT: .xword 4
; ARM64-NEXT: .xword 4
; ARM64-NEXT: .xword 0
; ARM64-NEXT: .xword __emutls_t.i3

; ARM64 .section .rodata,
; ARM64-LABEL: __emutls_t.i3:
; ARM64-NEXT: .word 15

; ARM64 .section .data.rel.local,
; ARM64-LABEL: __emutls_v.i4:
; ARM64-NEXT: .xword 4
; ARM64-NEXT: .xword 4
; ARM64-NEXT: .xword 0
; ARM64-NEXT: .xword __emutls_t.i4

; ARM64 .section .rodata,
; ARM64-LABEL: __emutls_t.i4:
; ARM64-NEXT: .word 15

; ARM64-NOT: __emutls_v.i5:
; ARM64 .hidden __emutls_v.i5
; ARM64-NOT: __emutls_v.i5:

; ARM64 .section .data.rel.local,
; ARM64-LABEL: __emutls_v.s1:
; ARM64-NEXT: .xword 2
; ARM64-NEXT: .xword 2
; ARM64-NEXT: .xword 0
; ARM64-NEXT: .xword __emutls_t.s1

; ARM64 .section .rodata,
; ARM64-LABEL: __emutls_t.s1:
; ARM64-NEXT: .hword 15

; ARM64 .section .data.rel.local,
; ARM64-LABEL: __emutls_v.b1:
; ARM64-NEXT: .xword 1
; ARM64-NEXT: .xword 1
; ARM64-NEXT: .xword 0
; ARM64-NEXT: .xword 0

; ARM64-NOT: __emutls_t.b1
31 changes: 31 additions & 0 deletions llvm/test/CodeGen/ARM/emutls1.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
; RUN: llc < %s -emulated-tls -march=arm -mtriple=arm-linux-androideabi \
; RUN: | FileCheck %s
; RUN: llc < %s -emulated-tls -march=arm -mtriple=arm-linux-androideabi \
; RUN: -relocation-model=pic | FileCheck %s --check-prefix=PIC

; Compared with tls1.ll, emulated mode should not use __aeabi_read_tp or __tls_get_addr.

; CHECK-NOT: _aeabi_read_tp
; CHECK-NOT: _tls_get_addr
; CHECK: __emutls_get_addr
; CHECK-NOT: __aeabi_read_tp
; CHECK-NOT: _tls_get_addr

; PIC-NOT: _aeabi_read_tp
; PIC-NOT: _tls_get_addr
; PIC: __emutls_get_addr
; PIC-NOT: _aeabi_read_tp
; PIC-NOT: _tls_get_addr

@i = thread_local global i32 15 ; <i32*> [#uses=2]

define i32 @f() {
entry:
%tmp1 = load i32, i32* @i ; <i32> [#uses=1]
ret i32 %tmp1
}

define i32* @g() {
entry:
ret i32* @i
}
74 changes: 56 additions & 18 deletions llvm/test/CodeGen/ARM/tls-models.ll
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
; RUN: llc -march=arm -mtriple=arm-linux-gnueabi < %s | FileCheck -check-prefix=CHECK-NONPIC %s
; RUN: llc -march=arm -mtriple=arm-linux-gnueabi -relocation-model=pic < %s | FileCheck -check-prefix=CHECK-PIC %s
; RUN: llc -march=arm -mtriple=arm-linux-gnueabi < %s \
; RUN: | FileCheck -check-prefix=CHECK-NONPIC -check-prefix=COMMON %s
; RUN: llc -march=arm -mtriple=arm-linux-gnueabi -relocation-model=pic < %s \
; RUN: | FileCheck -check-prefix=CHECK-PIC -check-prefix=COMMON %s
; RUN: llc -emulated-tls -march=arm -mtriple=arm-linux-gnueabi < %s \
; RUN: | FileCheck -check-prefix=EMUNONPIC -check-prefix=EMU -check-prefix=COMMON %s
; RUN: llc -emulated-tls -march=arm -mtriple=arm-linux-gnueabi -relocation-model=pic < %s \
; RUN: | FileCheck -check-prefix=EMUPIC -check-prefix=EMU -check-prefix=COMMON %s


@external_gd = external thread_local global i32
Expand All @@ -20,23 +26,23 @@ define i32* @f1() {
entry:
ret i32* @external_gd

; COMMON-LABEL: f1:
; Non-PIC code can use initial-exec, PIC code has to use general dynamic.
; CHECK-NONPIC-LABEL: f1:
; CHECK-NONPIC: external_gd(GOTTPOFF)
; CHECK-PIC-LABEL: f1:
; CHECK-PIC: external_gd(TLSGD)
; EMU: __emutls_get_address
}

define i32* @f2() {
entry:
ret i32* @internal_gd

; COMMON-LABEL: f2:
; Non-PIC code can use local exec, PIC code can use local dynamic,
; but that is not implemented, so falls back to general dynamic.
; CHECK-NONPIC-LABEL: f2:
; CHECK-NONPIC: internal_gd(TPOFF)
; CHECK-PIC-LABEL: f2:
; CHECK-PIC: internal_gd(TLSGD)
; EMU: __emutls_get_address
}


Expand All @@ -46,24 +52,24 @@ define i32* @f3() {
entry:
ret i32* @external_ld

; COMMON-LABEL: f3:
; Non-PIC code can use initial exec, PIC should use local dynamic,
; but that is not implemented, so falls back to general dynamic.
; CHECK-NONPIC-LABEL: f3:
; CHECK-NONPIC: external_ld(GOTTPOFF)
; CHECK-PIC-LABEL: f3:
; CHECK-PIC: external_ld(TLSGD)
; EMU: __emutls_get_address
}

define i32* @f4() {
entry:
ret i32* @internal_ld

; COMMON-LABEL: f4:
; Non-PIC code can use local exec, PIC code can use local dynamic,
; but that is not implemented, so it falls back to general dynamic.
; CHECK-NONPIC-LABEL: f4:
; CHECK-NONPIC: internal_ld(TPOFF)
; CHECK-PIC-LABEL: f4:
; CHECK-PIC: internal_ld(TLSGD)
; EMU: __emutls_get_address
}


Expand All @@ -73,22 +79,22 @@ define i32* @f5() {
entry:
ret i32* @external_ie

; COMMON-LABEL: f5:
; Non-PIC and PIC code will use initial exec as specified.
; CHECK-NONPIC-LABEL: f5:
; CHECK-NONPIC: external_ie(GOTTPOFF)
; CHECK-PIC-LABEL: f5:
; CHECK-PIC: external_ie(GOTTPOFF)
; EMU: __emutls_get_address
}

define i32* @f6() {
entry:
ret i32* @internal_ie

; COMMON-LABEL: f6:
; Non-PIC code can use local exec, PIC code use initial exec as specified.
; CHECK-NONPIC-LABEL: f6:
; CHECK-NONPIC: internal_ie(TPOFF)
; CHECK-PIC-LABEL: f6:
; CHECK-PIC: internal_ie(GOTTPOFF)
; EMU: __emutls_get_address
}


Expand All @@ -98,20 +104,52 @@ define i32* @f7() {
entry:
ret i32* @external_le

; COMMON-LABEL: f7:
; Non-PIC and PIC code will use local exec as specified.
; CHECK-NONPIC-LABEL: f7:
; CHECK-NONPIC: external_le(TPOFF)
; CHECK-PIC-LABEL: f7:
; CHECK-PIC: external_le(TPOFF)
; EMU: __emutls_get_address
}

define i32* @f8() {
entry:
ret i32* @internal_le

; COMMON-LABEL: f8:
; Non-PIC and PIC code will use local exec as specified.
; CHECK-NONPIC-LABEL: f8:
; CHECK-NONPIC: internal_le(TPOFF)
; CHECK-PIC-LABEL: f8:
; CHECK-PIC: internal_le(TPOFF)
; EMU: __emutls_get_address
}


; ----- emulated specified -----

; External declaration has no initializer.
; Internal definition has initializer.

; EMU-NOT: __emutls_t.external_gd
; EMU-NOT: __emutls_v.external_gd
; EMU: .align 2
; EMU-LABEL: __emutls_v.internal_gd:
; EMU-NEXT: .long 4
; EMU-NEXT: .long 4
; EMU-NEXT: .long 0
; EMU-NEXT: .long __emutls_t.internal_gd
; EMU-LABEL: __emutls_t.internal_gd:
; EMU-NEXT: .long 42
; EMU-NOT: __emutls_t.external_gd

; __emutls_t and __emutls_v are the same for PIC and non-PIC modes.

; EMU-NOT: __emutls_t.external_gd
; EMU-NOT: __emutls_v.external_gd
; EMU: .align 2
; EMU-LABEL: __emutls_v.internal_le:
; EMU-NEXT: .long 4
; EMU-NEXT: .long 4
; EMU-NEXT: .long 0
; EMU-NEXT: .long __emutls_t.internal_le
; EMU-LABEL: __emutls_t.internal_le:
; EMU-NEXT: .long 42
; EMU-NOT: __emutls_t.external_le
29 changes: 26 additions & 3 deletions llvm/test/CodeGen/ARM/tls3.ll
Original file line number Diff line number Diff line change
@@ -1,11 +1,34 @@
; RUN: llc < %s -march=arm -mtriple=arm-linux-gnueabi | \
; RUN: grep "tbss"
; RUN: llc < %s -march=arm -mtriple=arm-linux-gnueabi | \
; RUN: FileCheck %s -check-prefix=CHECK -check-prefix=NOEMU
; RUN: llc < %s -emulated-tls -march=arm -mtriple=arm-linux-gnueabi | \
; RUN: FileCheck %s -check-prefix=CHECK -check-prefix=EMU

%struct.anon = type { i32, i32 }
@teste = internal thread_local global %struct.anon zeroinitializer ; <%struct.anon*> [#uses=1]
@teste = internal thread_local global %struct.anon zeroinitializer ; <%struct.anon*> [#uses=1]

define i32 @main() {
entry:
%tmp2 = load i32, i32* getelementptr (%struct.anon, %struct.anon* @teste, i32 0, i32 0), align 8 ; <i32> [#uses=1]
ret i32 %tmp2
%tmp2 = load i32, i32* getelementptr (%struct.anon, %struct.anon* @teste, i32 0, i32 0), align 8 ; <i32> [#uses=1]
ret i32 %tmp2
}

; CHECK-LABEL: main:
; NOEMU-NOT: __emutls_get_address

; NOEMU: .section .tbss
; NOEMU-LABEL: teste:
; NOEMU-NEXT: .zero 8

; CHECK-NOT: __emutls_t.teste

; EMU: .align 2
; EMU-LABEL: __emutls_v.teste:
; EMU-NEXT: .long 8
; EMU-NEXT: .long 4
; EMU-NEXT: .long 0
; EMU-NEXT: .long 0

; CHECK-NOT: teste:
; CHECK-NOT: __emutls_t.teste
298 changes: 298 additions & 0 deletions llvm/test/CodeGen/Generic/emutls.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,298 @@
; RUN: llc < %s -emulated-tls -mtriple=arm-linux-android -relocation-model=pic \
; RUN: | FileCheck -check-prefix=ARM_32 %s
; RUN: llc < %s -emulated-tls -mtriple=arm-linux-androidabi -relocation-model=pic \
; RUN: | FileCheck -check-prefix=ARM_32 %s
; RUN: llc < %s -emulated-tls -mtriple=aarch64-linux-android -relocation-model=pic \
; RUN: | FileCheck -check-prefix=ARM_64 %s
; RUN: llc < %s -emulated-tls -mtriple=arm-linux-androidabi -relocation-model=pic -O3 \
; RUN: | FileCheck -check-prefix=ARM_32 %s
; RUN: llc < %s -emulated-tls -mtriple=aarch64-linux-android -relocation-model=pic -O3 \
; RUN: | FileCheck -check-prefix=ARM_64 %s
; RUN: llc < %s -emulated-tls -mtriple=arm-linux-androidabi -O3 \
; RUN: | FileCheck -check-prefix=ARM_32 %s
; RUN: llc < %s -emulated-tls -mtriple=aarch64-linux-android -O3 \
; RUN: | FileCheck -check-prefix=ARM_64 %s
; RUN: llc < %s -emulated-tls -mtriple=i686-linux-android -relocation-model=pic \
; RUN: | FileCheck -check-prefix=X86_32 %s
; RUN: llc < %s -emulated-tls -mtriple=x86_64-linux-android -march=x86 -relocation-model=pic \
; RUN: | FileCheck -check-prefix=X86_32 %s
; RUN: llc < %s -emulated-tls -mtriple=x86_64-linux-android -relocation-model=pic \
; RUN: | FileCheck -check-prefix=X86_64 %s
; RUN: llc < %s -emulated-tls -mtriple=mipsel-linux-android -relocation-model=pic \
; RUN: | FileCheck -check-prefix=MIPS_32 %s
; RUN: llc < %s -emulated-tls -mtriple=mips64el-linux-android -relocation-model=pic \
; RUN: | FileCheck -check-prefix=MIPS_64 %s
; RUN: llc < %s -emulated-tls -march=ppc64 -relocation-model=pic \
; RUN: | FileCheck %s
; RUN: llc < %s -emulated-tls -march=ppc32 -relocation-model=pic \
; RUN: | FileCheck %s
; RUN: llc < %s -emulated-tls -march=x86 -mtriple=i386-linux-gnu -relocation-model=pic \
; RUN: | FileCheck %s

; Make sure that TLS symbols are emitted in expected order.

@external_x = external thread_local global i32, align 8
@external_y = thread_local global i8 7, align 2
@internal_y = internal thread_local global i64 9, align 16

define i32* @get_external_x() {
entry:
ret i32* @external_x
}

define i8* @get_external_y() {
entry:
ret i8* @external_y
}

define i64* @get_internal_y() {
entry:
ret i64* @internal_y
}

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; targets independent mode
; CHECK-LABEL: get_external_x:
; CHECK-NOT: _tls_get_address
; CHECK: __emutls_get_address
; CHECK-LABEL: get_external_y:
; CHECK: __emutls_get_address
; CHECK-NOT: _tls_get_address
; CHECK-LABEL: get_internal_y:

; CHECK-NOT: __emutls_t.external_x:
; CHECK-NOT: __emutls_v.external_x:

; CHECK-LABEL: __emutls_v.external_y:
; CHECK-LABEL: __emutls_t.external_y:
; CHECK: __emutls_t.external_y

; CHECK-LABEL: __emutls_v.internal_y:
; CHECK-LABEL: __emutls_t.internal_y:
; CHECK: __emutls_t.internal_y

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 32-bit mode
; ARM_32-LABEL: get_external_x:
; X86_32-LABEL: get_external_x:
; MIPS-LABEL: get_external_x:

; ARM_32: bl __emutls_get_address
; ARM_32: .long __emutls_v.external_x

; X86_32: movl __emutls_v.external_x
; X86_32: calll __emutls_get_address

; ARM_32-LABEL: get_external_y:
; X86_32-LABEL: get_external_y:
; MIPS_32-LABEL: get_external_y:

; ARM_32: bl __emutls_get_address
; ARM_32: .long __emutls_v.external_y

; X86_32: movl __emutls_v.external_y
; X86_32: calll __emutls_get_address

; ARM_32-LABEL: get_internal_y:
; X86_32-LABEL: get_internal_y:
; MIPS_32-LABEL: get_internal_y:

; ARM_32: bl __emutls_get_address
; ARM_32: .long __emutls_v.internal_y

; X86_32: movl __emutls_v.internal_y
; X86_32: calll __emutls_get_address

; MIPS_32: lw {{.+}}(__emutls_v.internal_y
; MIPS_32: lw {{.+}}call16(__emutls_get_address

; ARM_32-NOT: __emutls_t.external_x
; X86_32-NOT: __emutls_t.external_x
; MIPS_32-NOT: __emutls_t.external_x

; ARM_32-NOT: __emutls_v.external_x:
; X86_32-NOT: __emutls_v.external_x:
; MIPS_32-NOT: __emutls_v.external_x:

; ARM_32: .section .data.rel.local
; X86_32: .section .data.rel.local
; MIPS_32: .section .data.rel.local

; ARM_32: .align 2
; X86_32: .align 4
; MIPS_32: .align 2

; ARM_32-LABEL: __emutls_v.external_y:
; X86_32-LABEL: __emutls_v.external_y:
; MIPS_32-LABEL: __emutls_v.external_y:

; ARM_32-NEXT: .long 1
; ARM_32-NEXT: .long 2
; ARM_32-NEXT: .long 0
; ARM_32-NEXT: .long __emutls_t.external_y

; X86_32-NEXT: .long 1
; X86_32-NEXT: .long 2
; X86_32-NEXT: .long 0
; X86_32-NEXT: .long __emutls_t.external_y

; ARM_32: .section .rodata,
; X86_32: .section .rodata,
; MIPS_32: .section .rodata,

; ARM_32-LABEL: __emutls_t.external_y:
; X86_32-LABEL: __emutls_t.external_y:
; MIPS_32-LABEL: __emutls_t.external_y:

; ARM_32-NEXT: .byte 7
; X86_32-NEXT: .byte 7
; MIPS_32-NEXT: .byte 7

; ARM_32: .section .data.rel.local
; X86_32: .section .data.rel.local
; MIPS_32: .section .data.rel.local

; ARM_32: .align 2
; X86_32: .align 4
; MIPS_32: .align 2

; ARM_32-LABEL: __emutls_v.internal_y:
; X86_32-LABEL: __emutls_v.internal_y:
; MIPS_32-LABEL: __emutls_v.internal_y:

; ARM_32-NEXT: .long 8
; ARM_32-NEXT: .long 16
; ARM_32-NEXT: .long 0
; ARM_32-NEXT: .long __emutls_t.internal_y

; X86_32-NEXT: .long 8
; X86_32-NEXT: .long 16
; X86_32-NEXT: .long 0
; X86_32-NEXT: .long __emutls_t.internal_y

; MIPS_32-NEXT: .4byte 8
; MIPS_32-NEXT: .4byte 16
; MIPS_32-NEXT: .4byte 0
; MIPS_32-NEXT: .4byte __emutls_t.internal_y

; ARM_32-LABEL: __emutls_t.internal_y:
; X86_32-LABEL: __emutls_t.internal_y:
; MIPS_32-LABEL: __emutls_t.internal_y:

; ARM_32-NEXT: .long 9
; ARM_32-NEXT: .long 0
; X86_32-NEXT: .quad 9
; MIPS_32-NEXT: .8byte 9


;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 64-bit mode
; X86_64-LABEL: get_external_x:
; ARM_64-LABEL: get_external_x:
; MIPS_64-LABEL: get_external_x:

; X86_64: __emutls_v.external_x
; X86_64: __emutls_get_address

; ARM_64: __emutls_v.external_x
; ARM_64: __emutls_get_address

; X86_64-LABEL: get_external_y:
; ARM_64-LABEL: get_external_y:
; MIPS_64-LABEL: get_external_y:

; X86_64: __emutls_v.external_y
; X86_64: __emutls_get_address

; ARM_64: __emutls_v.external_y
; ARM_64: __emutls_get_address

; X86_64-LABEL: get_internal_y:
; ARM_64-LABEL: get_internal_y:
; MIPS_64-LABEL: get_internal_y:

; X86_64: __emutls_v.internal_y
; X86_64: __emutls_get_address

; ARM_64: __emutls_v.internal_y
; ARM_64: __emutls_get_address

; MIPS_64: ld {{.+}}(__emutls_v.internal_y
; MIPS_64: ld {{.+}}call16(__emutls_get_address

; ARM_64-NOT: __emutls_t.external_x
; X86_64-NOT: __emutls_t.external_x
; MIPS_64-NOT: __emutls_t.external_x

; X86_64-NOT: __emutls_v.external_x:
; ARM_64-NOT: __emutls_v.external_x:
; MIPS_64-NOT: __emutls_v.external_x:

; X86_64: .align 8
; ARM_64: .align 3

; X86_64-LABEL: __emutls_v.external_y:
; ARM_64-LABEL: __emutls_v.external_y:
; MIPS_64-LABEL: __emutls_v.external_y:

; X86_64-NEXT: .quad 1
; X86_64-NEXT: .quad 2
; X86_64-NEXT: .quad 0
; X86_64-NEXT: .quad __emutls_t.external_y

; ARM_64-NEXT: .xword 1
; ARM_64-NEXT: .xword 2
; ARM_64-NEXT: .xword 0
; ARM_64-NEXT: .xword __emutls_t.external_y

; X86_64-NOT: __emutls_v.external_x:
; ARM_64-NOT: __emutls_v.external_x:
; MIPS_64-NOT: __emutls_v.external_x:

; ARM_64: .section .rodata,
; X86_64: .section .rodata,
; MIPS_64: .section .rodata,

; X86_64-LABEL: __emutls_t.external_y:
; ARM_64-LABEL: __emutls_t.external_y:
; MIPS_64-LABEL: __emutls_t.external_y:

; X86_64-NEXT: .byte 7
; ARM_64-NEXT: .byte 7
; MIPS_64-NEXT: .byte 7

; ARM_64: .section .data.rel.local
; X86_64: .section .data.rel.local
; MIPS_64: .section .data.rel.local

; X86_64: .align 8
; ARM_64: .align 3
; MIPS_64: .align 3

; X86_64-LABEL: __emutls_v.internal_y:
; ARM_64-LABEL: __emutls_v.internal_y:
; MIPS_64-LABEL: __emutls_v.internal_y:

; X86_64-NEXT: .quad 8
; X86_64-NEXT: .quad 16
; X86_64-NEXT: .quad 0
; X86_64-NEXT: .quad __emutls_t.internal_y

; ARM_64-NEXT: .xword 8
; ARM_64-NEXT: .xword 16
; ARM_64-NEXT: .xword 0
; ARM_64-NEXT: .xword __emutls_t.internal_y

; MIPS_64-NEXT: .8byte 8
; MIPS_64-NEXT: .8byte 16
; MIPS_64-NEXT: .8byte 0
; MIPS_64-NEXT: .8byte __emutls_t.internal_y

; ARM_64: .section .rodata,
; X86_64: .section .rodata,
; MIPS_64: .section .rodata,

; X86_64-LABEL: __emutls_t.internal_y:
; ARM_64-LABEL: __emutls_t.internal_y:
; MIPS_64-LABEL: __emutls_t.internal_y:

; X86_64-NEXT: .quad 9
; ARM_64-NEXT: .xword 9
; MIPS_64-NEXT: .8byte 9
168 changes: 168 additions & 0 deletions llvm/test/CodeGen/X86/emutls-pic.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,168 @@
; RUN: llc < %s -emulated-tls -march=x86 -mtriple=i386-linux-gnu -relocation-model=pic | FileCheck -check-prefix=X32 %s
; RUN: llc < %s -emulated-tls -march=x86-64 -mtriple=x86_64-linux-gnu -relocation-model=pic | FileCheck -check-prefix=X64 %s
; RUN: llc < %s -emulated-tls -march=x86 -mtriple=i386-linux-android -relocation-model=pic | FileCheck -check-prefix=X32 %s
; RUN: llc < %s -emulated-tls -march=x86-64 -mtriple=x86_64-linux-android -relocation-model=pic | FileCheck -check-prefix=X64 %s

; Use my_emutls_get_address like __emutls_get_address.
@my_emutls_v_xyz = external global i8*, align 4
declare i8* @my_emutls_get_address(i8*)

define i32 @my_get_xyz() {
; X32-LABEL: my_get_xyz:
; X32: movl my_emutls_v_xyz@GOT(%ebx), %eax
; X32-NEXT: movl %eax, (%esp)
; X32-NEXT: calll my_emutls_get_address@PLT
; X64-LABEL: my_get_xyz:
; X64: movq my_emutls_v_xyz@GOTPCREL(%rip), %rdi
; X64-NEXT: callq my_emutls_get_address@PLT
; X64-NEXT: movl (%rax), %eax

entry:
%call = call i8* @my_emutls_get_address(i8* bitcast (i8** @my_emutls_v_xyz to i8*))
%0 = bitcast i8* %call to i32*
%1 = load i32, i32* %0, align 4
ret i32 %1
}

@i = thread_local global i32 15
@j = internal thread_local global i32 42
@k = internal thread_local global i32 0, align 8

define i32 @f1() {
entry:
%tmp1 = load i32, i32* @i
ret i32 %tmp1
}

; X32-LABEL: f1:
; X32: movl __emutls_v.i@GOT(%ebx), %eax
; X32-NEXT: movl %eax, (%esp)
; X32-NEXT: calll __emutls_get_address@PLT
; X64-LABEL: f1:
; X64: movq __emutls_v.i@GOTPCREL(%rip), %rdi
; X64-NEXT: callq __emutls_get_address@PLT
; X64-NEXT: movl (%rax), %eax

@i2 = external thread_local global i32

define i32* @f2() {
entry:
ret i32* @i
}

; X32-LABEL: f2:
; X64-LABEL: f2:


define i32 @f3() {
entry:
%tmp1 = load i32, i32* @i ; <i32> [#uses=1]
ret i32 %tmp1
}

; X32-LABEL: f3:
; X64-LABEL: f3:


define i32* @f4() nounwind {
entry:
ret i32* @i
}

; X32-LABEL: f4:
; X64-LABEL: f4:


define i32 @f5() nounwind {
entry:
%0 = load i32, i32* @j, align 4
%1 = load i32, i32* @k, align 4
%add = add nsw i32 %0, %1
ret i32 %add
}

; X32-LABEL: f5:
; X32: movl __emutls_v.j@GOT(%ebx), %eax
; X32-NEXT: movl %eax, (%esp)
; X32-NEXT: calll __emutls_get_address@PLT
; X32-NEXT: movl (%eax), %esi
; X32-NEXT: movl __emutls_v.k@GOT(%ebx), %eax
; X32-NEXT: movl %eax, (%esp)
; X32-NEXT: calll __emutls_get_address@PLT
; X32-NEXT: addl (%eax), %esi
; X32-NEXT: movl %esi, %eax

; X64-LABEL: f5:
; X64: movq __emutls_v.j@GOTPCREL(%rip), %rdi
; X64-NEXT: callq __emutls_get_address@PLT
; X64-NEXT: movl (%rax), %ebx
; X64-NEXT: movq __emutls_v.k@GOTPCREL(%rip), %rdi
; X64-NEXT: callq __emutls_get_address@PLT
; X64-NEXT: addl (%rax), %ebx
; X64-NEXT: movl %ebx, %eax

;;;;; 32-bit targets

; X32: .section .data.rel.local,
; X32-LABEL: __emutls_v.i:
; X32-NEXT: .long 4
; X32-NEXT: .long 4
; X32-NEXT: .long 0
; X32-NEXT: .long __emutls_t.i

; X32: .section .rodata,
; X32-LABEL: __emutls_t.i:
; X32-NEXT: .long 15

; X32: .section .data.rel.local,
; X32-LABEL: __emutls_v.j:
; X32-NEXT: .long 4
; X32-NEXT: .long 4
; X32-NEXT: .long 0
; X32-NEXT: .long __emutls_t.j

; X32: .section .rodata,
; X32-LABEL: __emutls_t.j:
; X32-NEXT: .long 42

; X32: .data
; X32-LABEL: __emutls_v.k:
; X32-NEXT: .long 4
; X32-NEXT: .long 8
; X32-NEXT: .long 0
; X32-NEXT: .long 0

; X32-NOT: __emutls_t.k:

;;;;; 64-bit targets

; X64: .section .data.rel.local,
; X64-LABEL: __emutls_v.i:
; X64-NEXT: .quad 4
; X64-NEXT: .quad 4
; X64-NEXT: .quad 0
; X64-NEXT: .quad __emutls_t.i

; X64: .section .rodata,
; X64-LABEL: __emutls_t.i:
; X64-NEXT: .long 15

; X64: .section .data.rel.local,
; X64-LABEL: __emutls_v.j:
; X64-NEXT: .quad 4
; X64-NEXT: .quad 4
; X64-NEXT: .quad 0
; X64-NEXT: .quad __emutls_t.j

; X64: .section .rodata,
; X64-LABEL: __emutls_t.j:
; X64-NEXT: .long 42

; X64: .data
; X64-LABEL: __emutls_v.k:
; X64-NEXT: .quad 4
; X64-NEXT: .quad 8
; X64-NEXT: .quad 0
; X64-NEXT: .quad 0

; X64-NOT: __emutls_t.k:
131 changes: 131 additions & 0 deletions llvm/test/CodeGen/X86/emutls-pie.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
; RUN: llc < %s -emulated-tls -march=x86 -mcpu=generic -mtriple=i386-linux-gnu -relocation-model=pic -enable-pie \
; RUN: | FileCheck -check-prefix=X32 %s
; RUN: llc < %s -emulated-tls -march=x86-64 -mcpu=generic -mtriple=x86_64-linux-gnu -relocation-model=pic -enable-pie \
; RUN: | FileCheck -check-prefix=X64 %s
; RUN: llc < %s -emulated-tls -march=x86 -mcpu=generic -mtriple=i386-linux-android -relocation-model=pic -enable-pie \
; RUN: | FileCheck -check-prefix=X32 %s
; RUN: llc < %s -emulated-tls -march=x86-64 -mcpu=generic -mtriple=x86_64-linux-android -relocation-model=pic -enable-pie \
; RUN: | FileCheck -check-prefix=X64 %s

; Use my_emutls_get_address like __emutls_get_address.
@my_emutls_v_xyz = external global i8*, align 4
declare i8* @my_emutls_get_address(i8*)

define i32 @my_get_xyz() {
; X32-LABEL: my_get_xyz:
; X32: movl my_emutls_v_xyz@GOT(%ebx), %eax
; X32-NEXT: movl %eax, (%esp)
; X32-NEXT: calll my_emutls_get_address@PLT
; X32-NEXT: movl (%eax), %eax
; X32-NEXT: addl $8, %esp
; X32-NEXT: popl %ebx
; X32-NEXT: retl
; X64-LABEL: my_get_xyz:
; X64: movq my_emutls_v_xyz@GOTPCREL(%rip), %rdi
; X64-NEXT: callq my_emutls_get_address@PLT
; X64-NEXT: movl (%rax), %eax
; X64-NEXT: popq %rdx
; X64-NEXT: retq

entry:
%call = call i8* @my_emutls_get_address(i8* bitcast (i8** @my_emutls_v_xyz to i8*))
%0 = bitcast i8* %call to i32*
%1 = load i32, i32* %0, align 4
ret i32 %1
}

@i = thread_local global i32 15
@i2 = external thread_local global i32

define i32 @f1() {
; X32-LABEL: f1:
; X32: movl __emutls_v.i@GOT(%ebx), %eax
; X32-NEXT: movl %eax, (%esp)
; X32-NEXT: calll __emutls_get_address@PLT
; X32-NEXT: movl (%eax), %eax
; X32-NEXT: addl $8, %esp
; X32-NEXT: popl %ebx
; X32-NEXT: retl
; X64-LABEL: f1:
; X64: movq __emutls_v.i@GOTPCREL(%rip), %rdi
; X64-NEXT: callq __emutls_get_address@PLT
; X64-NEXT: movl (%rax), %eax
; X64-NEXT: popq %rdx
; X64-NEXT: retq

entry:
%tmp1 = load i32, i32* @i
ret i32 %tmp1
}

define i32* @f2() {
; X32-LABEL: f2:
; X32: movl __emutls_v.i@GOT(%ebx), %eax
; X32-NEXT: movl %eax, (%esp)
; X32-NEXT: calll __emutls_get_address@PLT
; X64-LABEL: f2:
; X64: movq __emutls_v.i@GOTPCREL(%rip), %rdi
; X64-NEXT: callq __emutls_get_address@PLT

entry:
ret i32* @i
}

define i32 @f3() {
; X32-LABEL: f3:
; X32: movl __emutls_v.i2@GOT(%ebx), %eax
; X32-NEXT: movl %eax, (%esp)
; X32-NEXT: calll __emutls_get_address@PLT
; X64-LABEL: f3:
; X64: movq __emutls_v.i2@GOTPCREL(%rip), %rdi
; X64-NEXT: callq __emutls_get_address@PLT

entry:
%tmp1 = load i32, i32* @i2
ret i32 %tmp1
}

define i32* @f4() {
; X32-LABEL: f4:
; X32: movl __emutls_v.i2@GOT(%ebx), %eax
; X32-NEXT: movl %eax, (%esp)
; X32-NEXT: calll __emutls_get_address@PLT
; X64-LABEL: f4:
; X64: movq __emutls_v.i2@GOTPCREL(%rip), %rdi
; X64-NEXT: callq __emutls_get_address@PLT

entry:
ret i32* @i2
}

;;;;; 32-bit targets

; X32: .section .data.rel.local,
; X32-LABEL: __emutls_v.i:
; X32-NEXT: .long 4
; X32-NEXT: .long 4
; X32-NEXT: .long 0
; X32-NEXT: .long __emutls_t.i

; X32: .section .rodata,
; X32-LABEL: __emutls_t.i:
; X32-NEXT: .long 15

; X32-NOT: __emutls_v.i2
; X32-NOT: __emutls_t.i2

;;;;; 64-bit targets

; X64: .section .data.rel.local,
; X64-LABEL: __emutls_v.i:
; X64-NEXT: .quad 4
; X64-NEXT: .quad 4
; X64-NEXT: .quad 0
; X64-NEXT: .quad __emutls_t.i

; X64: .section .rodata,
; X64-LABEL: __emutls_t.i:
; X64-NEXT: .long 15

; X64-NOT: __emutls_v.i2
; X64-NOT: __emutls_t.i2
347 changes: 347 additions & 0 deletions llvm/test/CodeGen/X86/emutls.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,347 @@
; RUN: llc < %s -emulated-tls -march=x86 -mtriple=i386-linux-gnu | FileCheck -check-prefix=X32 %s
; RUN: llc < %s -emulated-tls -march=x86-64 -mtriple=x86_64-linux-gnu | FileCheck -check-prefix=X64 %s
; RUN: llc < %s -emulated-tls -march=x86 -mtriple=x86-linux-android | FileCheck -check-prefix=X32 %s
; RUN: llc < %s -emulated-tls -march=x86-64 -mtriple=x86_64-linux-android | FileCheck -check-prefix=X64 %s

; Copied from tls.ll; emulated TLS model is not implemented
; for *-pc-win32 and *-pc-winows targets yet.

; Use my_emutls_get_address like __emutls_get_address.
@my_emutls_v_xyz = external global i8*, align 4
declare i8* @my_emutls_get_address(i8*)

define i32 @my_get_xyz() {
; X32-LABEL: my_get_xyz:
; X32: movl $my_emutls_v_xyz, (%esp)
; X32-NEXT: calll my_emutls_get_address
; X32-NEXT: movl (%eax), %eax
; X32-NEXT: addl $12, %esp
; X32-NEXT: retl
; X64-LABEL: my_get_xyz:
; X64: movl $my_emutls_v_xyz, %edi
; X64-NEXT: callq my_emutls_get_address
; X64-NEXT: movl (%rax), %eax
; X64-NEXT: popq %rdx
; X64-NEXT: retq

entry:
%call = call i8* @my_emutls_get_address(i8* bitcast (i8** @my_emutls_v_xyz to i8*))
%0 = bitcast i8* %call to i32*
%1 = load i32, i32* %0, align 4
ret i32 %1
}

@i1 = thread_local global i32 15
@i2 = external thread_local global i32
@i3 = internal thread_local global i32 15
@i4 = hidden thread_local global i32 15
@i5 = external hidden thread_local global i32
@s1 = thread_local global i16 15
@b1 = thread_local global i8 0

define i32 @f1() {
; X32-LABEL: f1:
; X32: movl $__emutls_v.i1, (%esp)
; X32-NEXT: calll __emutls_get_address
; X32-NEXT: movl (%eax), %eax
; X32-NEXT: addl $12, %esp
; X32-NEXT: retl
; X64-LABEL: f1:
; X64: movl $__emutls_v.i1, %edi
; X64-NEXT: callq __emutls_get_address
; X64-NEXT: movl (%rax), %eax
; X64-NEXT: popq %rdx
; X64-NEXT: retq

entry:
%tmp1 = load i32, i32* @i1
ret i32 %tmp1
}

define i32* @f2() {
; X32-LABEL: f2:
; X32: movl $__emutls_v.i1, (%esp)
; X32-NEXT: calll __emutls_get_address
; X32-NEXT: addl $12, %esp
; X32-NEXT: retl
; X64-LABEL: f2:
; X64: movl $__emutls_v.i1, %edi
; X64-NEXT: callq __emutls_get_address
; X64-NEXT: popq %rdx
; X64-NEXT: retq

entry:
ret i32* @i1
}

define i32 @f3() nounwind {
; X32-LABEL: f3:
; X32: movl $__emutls_v.i2, (%esp)
; X32-NEXT: calll __emutls_get_address
; X32-NEXT: movl (%eax), %eax
; X32-NEXT: addl $12, %esp
; X32-NEXT: retl

entry:
%tmp1 = load i32, i32* @i2
ret i32 %tmp1
}

define i32* @f4() {
; X32-LABEL: f4:
; X32: movl $__emutls_v.i2, (%esp)
; X32-NEXT: calll __emutls_get_address
; X32-NEXT: addl $12, %esp
; X32-NEXT: retl

entry:
ret i32* @i2
}

define i32 @f5() nounwind {
; X32-LABEL: f5:
; X32: movl $__emutls_v.i3, (%esp)
; X32-NEXT: calll __emutls_get_address
; X32-NEXT: movl (%eax), %eax
; X32-NEXT: addl $12, %esp
; X32-NEXT: retl

entry:
%tmp1 = load i32, i32* @i3
ret i32 %tmp1
}

define i32* @f6() {
; X32-LABEL: f6:
; X32: movl $__emutls_v.i3, (%esp)
; X32-NEXT: calll __emutls_get_address
; X32-NEXT: addl $12, %esp
; X32-NEXT: retl

entry:
ret i32* @i3
}

define i32 @f7() {
; X32-LABEL: f7:
; X32: movl $__emutls_v.i4, (%esp)
; X32-NEXT: calll __emutls_get_address
; X32-NEXT: movl (%eax), %eax
; X32-NEXT: addl $12, %esp
; X32-NEXT: retl

entry:
%tmp1 = load i32, i32* @i4
ret i32 %tmp1
}

define i32* @f8() {
; X32-LABEL: f8:
; X32: movl $__emutls_v.i4, (%esp)
; X32-NEXT: calll __emutls_get_address
; X32-NEXT: addl $12, %esp
; X32-NEXT: retl

entry:
ret i32* @i4
}

define i32 @f9() {
; X32-LABEL: f9:
; X32: movl $__emutls_v.i5, (%esp)
; X32-NEXT: calll __emutls_get_address
; X32-NEXT: movl (%eax), %eax
; X32-NEXT: addl $12, %esp
; X32-NEXT: retl

entry:
%tmp1 = load i32, i32* @i5
ret i32 %tmp1
}

define i32* @f10() {
; X32-LABEL: f10:
; X32: movl $__emutls_v.i5, (%esp)
; X32-NEXT: calll __emutls_get_address
; X32-NEXT: addl $12, %esp
; X32-NEXT: retl

entry:
ret i32* @i5
}

define i16 @f11() {
; X32-LABEL: f11:
; X32: movl $__emutls_v.s1, (%esp)
; X32-NEXT: calll __emutls_get_address
; X32-NEXT: movzwl (%eax), %eax
; X32-NEXT: addl $12, %esp
; X32-NEXT: retl

entry:
%tmp1 = load i16, i16* @s1
ret i16 %tmp1
}

define i32 @f12() {
; X32-LABEL: f12:
; X32: movl $__emutls_v.s1, (%esp)
; X32-NEXT: calll __emutls_get_address
; X32-NEXT: movswl (%eax), %eax
; X32-NEXT: addl $12, %esp
; X32-NEXT: retl

entry:
%tmp1 = load i16, i16* @s1
%tmp2 = sext i16 %tmp1 to i32
ret i32 %tmp2
}

define i8 @f13() {
; X32-LABEL: f13:
; X32: movl $__emutls_v.b1, (%esp)
; X32-NEXT: calll __emutls_get_address
; X32-NEXT: movb (%eax), %al
; X32-NEXT: addl $12, %esp
; X32-NEXT: retl

entry:
%tmp1 = load i8, i8* @b1
ret i8 %tmp1
}

define i32 @f14() {
; X32-LABEL: f14:
; X32: movl $__emutls_v.b1, (%esp)
; X32-NEXT: calll __emutls_get_address
; X32-NEXT: movsbl (%eax), %eax
; X32-NEXT: addl $12, %esp
; X32-NEXT: retl

entry:
%tmp1 = load i8, i8* @b1
%tmp2 = sext i8 %tmp1 to i32
ret i32 %tmp2
}

;;;;;;;;;;;;;; 32-bit __emutls_v. and __emutls_t.

; X32 .section .data.rel.local,
; X32-LABEL: __emutls_v.i1:
; X32-NEXT: .long 4
; X32-NEXT: .long 4
; X32-NEXT: .long 0
; X32-NEXT: .long __emutls_t.i1

; X32 .section .rodata,
; X32-LABEL: __emutls_t.i1:
; X32-NEXT: .long 15

; X32-NOT: __emutls_v.i2

; X32 .section .data.rel.local,
; X32-LABEL: __emutls_v.i3:
; X32-NEXT: .long 4
; X32-NEXT: .long 4
; X32-NEXT: .long 0
; X32-NEXT: .long __emutls_t.i3

; X32 .section .rodata,
; X32-LABEL: __emutls_t.i3:
; X32-NEXT: .long 15

; X32 .section .data.rel.local,
; X32-LABEL: __emutls_v.i4:
; X32-NEXT: .long 4
; X32-NEXT: .long 4
; X32-NEXT: .long 0
; X32-NEXT: .long __emutls_t.i4

; X32 .section .rodata,
; X32-LABEL: __emutls_t.i4:
; X32-NEXT: .long 15

; X32-NOT: __emutls_v.i5:
; X32 .hidden __emutls_v.i5
; X32-NOT: __emutls_v.i5:

; X32 .section .data.rel.local,
; X32-LABEL: __emutls_v.s1:
; X32-NEXT: .long 2
; X32-NEXT: .long 2
; X32-NEXT: .long 0
; X32-NEXT: .long __emutls_t.s1

; X32 .section .rodata,
; X32-LABEL: __emutls_t.s1:
; X32-NEXT: .short 15

; X32 .section .data.rel.local,
; X32-LABEL: __emutls_v.b1:
; X32-NEXT: .long 1
; X32-NEXT: .long 1
; X32-NEXT: .long 0
; X32-NEXT: .long 0

; X32-NOT: __emutls_t.b1

;;;;;;;;;;;;;; 64-bit __emutls_v. and __emutls_t.

; X64 .section .data.rel.local,
; X64-LABEL: __emutls_v.i1:
; X64-NEXT: .quad 4
; X64-NEXT: .quad 4
; X64-NEXT: .quad 0
; X64-NEXT: .quad __emutls_t.i1

; X64 .section .rodata,
; X64-LABEL: __emutls_t.i1:
; X64-NEXT: .long 15

; X64-NOT: __emutls_v.i2

; X64 .section .data.rel.local,
; X64-LABEL: __emutls_v.i3:
; X64-NEXT: .quad 4
; X64-NEXT: .quad 4
; X64-NEXT: .quad 0
; X64-NEXT: .quad __emutls_t.i3

; X64 .section .rodata,
; X64-LABEL: __emutls_t.i3:
; X64-NEXT: .long 15

; X64 .section .data.rel.local,
; X64-LABEL: __emutls_v.i4:
; X64-NEXT: .quad 4
; X64-NEXT: .quad 4
; X64-NEXT: .quad 0
; X64-NEXT: .quad __emutls_t.i4

; X64 .section .rodata,
; X64-LABEL: __emutls_t.i4:
; X64-NEXT: .long 15

; X64-NOT: __emutls_v.i5:
; X64 .hidden __emutls_v.i5
; X64-NOT: __emutls_v.i5:

; X64 .section .data.rel.local,
; X64-LABEL: __emutls_v.s1:
; X64-NEXT: .quad 2
; X64-NEXT: .quad 2
; X64-NEXT: .quad 0
; X64-NEXT: .quad __emutls_t.s1

; X64 .section .rodata,
; X64-LABEL: __emutls_t.s1:
; X64-NEXT: .short 15

; X64 .section .data.rel.local,
; X64-LABEL: __emutls_v.b1:
; X64-NEXT: .quad 1
; X64-NEXT: .quad 1
; X64-NEXT: .quad 0
; X64-NEXT: .quad 0

; X64-NOT: __emutls_t.b1
48 changes: 48 additions & 0 deletions llvm/test/CodeGen/X86/fast-isel-emutls.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
; RUN: llc < %s -emulated-tls -march=x86 -relocation-model=pic -mtriple=i686-unknown-linux-gnu -fast-isel | FileCheck %s
; PR3654

@v = thread_local global i32 0
define i32 @f() nounwind {
entry:
%t = load i32, i32* @v
%s = add i32 %t, 1
ret i32 %s
}

; CHECK-LABEL: f:
; CHECK: movl __emutls_v.v@GOT(%ebx), %eax
; CHECK-NEXT: movl %eax, (%esp)
; CHECK-NEXT: calll __emutls_get_address@PLT
; CHECK-NEXT: movl (%eax), %eax

@alias = internal alias i32* @v
define i32 @f_alias() nounwind {
entry:
%t = load i32, i32* @v
%s = add i32 %t, 1
ret i32 %s
}

; CHECK-LABEL: f_alias:
; CHECK: movl __emutls_v.v@GOT(%ebx), %eax
; CHECK-NEXT: movl %eax, (%esp)
; CHECK-NEXT: calll __emutls_get_address@PLT
; CHECK-NEXT: movl (%eax), %eax

; Use my_emutls_get_address like __emutls_get_address.
@my_emutls_v_xyz = external global i8*, align 4
declare i8* @my_emutls_get_address(i8*)

define i32 @my_get_xyz() {
entry:
%call = call i8* @my_emutls_get_address(i8* bitcast (i8** @my_emutls_v_xyz to i8*))
%0 = bitcast i8* %call to i32*
%1 = load i32, i32* %0, align 4
ret i32 %1
}

; CHECK-LABEL: my_get_xyz:
; CHECK: movl my_emutls_v_xyz@GOT(%ebx), %eax
; CHECK-NEXT: movl %eax, (%esp)
; CHECK-NEXT: calll my_emutls_get_address@PLT
; CHECK-NEXT: movl (%eax), %eax
65 changes: 65 additions & 0 deletions llvm/test/CodeGen/X86/tls-android-negative.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
; RUN: llc < %s -emulated-tls -march=x86 -mtriple=x86_64-linux-android -relocation-model=pic | FileCheck %s
; RUN: llc < %s -emulated-tls -march=x86-64 -mtriple=x86_64-linux-android -relocation-model=pic | FileCheck %s

; Make sure that some symboles are not emitted in emulated TLS model.

@external_x = external thread_local global i32
@external_y = thread_local global i32 7
@internal_y = internal thread_local global i32 9
@internal_y0 = internal thread_local global i32 0

define i32* @get_external_x() {
entry:
ret i32* @external_x
}

define i32* @get_external_y() {
entry:
ret i32* @external_y
}

define i32* @get_internal_y() {
entry:
ret i32* @internal_y
}

define i32* @get_internal_y0() {
entry:
ret i32* @internal_y0
}

; no direct access to emulated TLS variables.
; no definition of emulated TLS variables.
; no initializer for external TLS variables, __emutls_t.external_x
; no initializer for 0-initialized TLS variables, __emutls_t.internal_y0
; not global linkage for __emutls_t.external_y

; CHECK-NOT: external_x@TLS
; CHECK-NOT: external_y@TLS
; CHECK-NOT: internal_y@TLS
; CHECK-NOT: .size external_x
; CHECK-NOT: .size external_y
; CHECK-NOT: .size internal_y
; CHECK-NOT: .size internal_y0
; CHECK-NOT: __emutls_v.external_x:
; CHECK-NOT: __emutls_t.external_x:
; CHECK-NOT: __emutls_t.internal_y0:
; CHECK-NOT: global __emutls_t.external_y
; CHECK-NOT: global __emutls_v.internal_y
; CHECK-NOT: global __emutls_v.internal_y0

; CHECK: __emutls_t.external_y

; CHECK-NOT: external_x@TLS
; CHECK-NOT: external_y@TLS
; CHECK-NOT: internal_y@TLS
; CHECK-NOT: .size external_x
; CHECK-NOT: .size external_y
; CHECK-NOT: .size internal_y
; CHECK-NOT: .size internal_y0
; CHECK-NOT: __emutls_v.external_x:
; CHECK-NOT: __emutls_t.external_x:
; CHECK-NOT: __emutls_t.internal_y0:
; CHECK-NOT: global __emutls_t.external_y
; CHECK-NOT: global __emutls_v.internal_y
; CHECK-NOT: global __emutls_v.internal_y0
89 changes: 89 additions & 0 deletions llvm/test/CodeGen/X86/tls-android.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
; RUN: llc < %s -emulated-tls -march=x86 -mtriple=x86_64-linux-android -relocation-model=pic | FileCheck %s
; RUN: llc < %s -emulated-tls -march=x86-64 -mtriple=x86_64-linux-android -relocation-model=pic | FileCheck -check-prefix=X64 %s

; Make sure that TLS symboles are emitted in expected order.

@external_x = external thread_local global i32
@external_y = thread_local global i32 7
@internal_y = internal thread_local global i32 9

define i32* @get_external_x() {
entry:
ret i32* @external_x
}

define i32* @get_external_y() {
entry:
ret i32* @external_y
}

define i32* @get_internal_y() {
entry:
ret i32* @internal_y
}

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 32-bit mode
; CHECK-LABEL: get_external_x:
; CHECK: __emutls_v.external_x
; CHECK: __emutls_get_address

; CHECK-LABEL: get_external_y:
; CHECK: __emutls_v.external_y
; CHECK: __emutls_get_address

; CHECK-LABEL: get_internal_y:
; CHECK: __emutls_v.internal_y
; CHECK: __emutls_get_address

; CHECK-NOT: __emutls_v.external_x:

; CHECK: .align 4
; CHECK-LABEL: __emutls_v.external_y:
; CHECK-NEXT: .long 4
; CHECK-NEXT: .long 4
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long __emutls_t.external_y
; CHECK-LABEL: __emutls_t.external_y:
; CHECK-NEXT: .long 7

; CHECK: .align 4
; CHECK-LABEL: __emutls_v.internal_y:
; CHECK-NEXT: .long 4
; CHECK-NEXT: .long 4
; CHECK-NEXT: .long 0
; CHECK-NEXT: .long __emutls_t.internal_y
; CHECK-LABEL: __emutls_t.internal_y:
; CHECK-NEXT: .long 9

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;; 64-bit mode
; X64-LABEL: get_external_x:
; X64: __emutls_v.external_x
; X64: __emutls_get_address

; X64-LABEL: get_external_y:
; X64: __emutls_v.external_y
; X64: __emutls_get_address

; X64-LABEL: get_internal_y:
; X64: __emutls_v.internal_y
; X64: __emutls_get_address

; X64-NOT: __emutls_v.external_x:

; X64: .align 8
; X64-LABEL: __emutls_v.external_y:
; X64-NEXT: .quad 4
; X64-NEXT: .quad 4
; X64-NEXT: .quad 0
; X64-NEXT: .quad __emutls_t.external_y
; X64-LABEL: __emutls_t.external_y:
; X64-NEXT: .long 7

; X64: .align 8
; X64-LABEL: __emutls_v.internal_y:
; X64-NEXT: .quad 4
; X64-NEXT: .quad 4
; X64-NEXT: .quad 0
; X64-NEXT: .quad __emutls_t.internal_y
; X64-LABEL: __emutls_t.internal_y:
; X64-NEXT: .long 9
2 changes: 2 additions & 0 deletions llvm/test/CodeGen/X86/tls-models.ll
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
@external_le = external thread_local(localexec) global i32
@internal_le = internal thread_local(localexec) global i32 42

; See test cases for emulated model in emutls.ll, emutls-pic.ll and emutls-pie.ll.

; ----- no model specified -----

define i32* @f1() {
Expand Down
10 changes: 8 additions & 2 deletions llvm/test/DebugInfo/ARM/tls.ll
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
; RUN: llc -O0 -filetype=asm -mtriple=armv7-linux-gnuehabi < %s | FileCheck %s
;
; RUN: llc -O0 -filetype=asm -mtriple=armv7-linux-gnuehabi < %s \
; RUN: | FileCheck %s --check-prefix=CHECK
; RUN: llc -O0 -filetype=asm -mtriple=armv7-linux-gnuehabi -emulated-tls < %s \
; RUN: | FileCheck %s --check-prefix=EMU

; Generated with clang with source
; __thread int x;

Expand All @@ -16,6 +19,9 @@
; The debug relocation of the address of the tls variable
; CHECK: .long x(tlsldo)

; TODO: Add expected output for -emulated-tls tests.
; EMU-NOT: .long x(tlsldo)

!0 = !DICompileUnit(language: DW_LANG_C99, producer: "clang version 3.5 ", isOptimized: false, emissionKind: 0, file: !1, enums: !2, retainedTypes: !2, subprograms: !2, globals: !3, imports: !2)
!1 = !DIFile(filename: "tls.c", directory: "/tmp")
!2 = !{}
Expand Down
22 changes: 16 additions & 6 deletions llvm/test/DebugInfo/X86/tls.ll
Original file line number Diff line number Diff line change
@@ -1,20 +1,30 @@
; RUN: llc %s -o - -filetype=asm -O0 -mtriple=x86_64-unknown-linux-gnu \
; RUN: | FileCheck --check-prefix=SINGLE --check-prefix=SINGLE-64 --check-prefix=GNUOP %s
; RUN: | FileCheck --check-prefix=NOEMU --check-prefix=SINGLE --check-prefix=SINGLE-64 --check-prefix=GNUOP %s

; RUN: llc %s -o - -filetype=asm -O0 -mtriple=i386-linux-gnu \
; RUN: | FileCheck --check-prefix=SINGLE --check-prefix=SINGLE-32 --check-prefix=GNUOP %s
; RUN: | FileCheck --check-prefix=NOEMU --check-prefix=SINGLE --check-prefix=SINGLE-32 --check-prefix=GNUOP %s

; RUN: llc %s -o - -filetype=asm -O0 -mtriple=x86_64-unknown-linux-gnu -split-dwarf=Enable \
; RUN: | FileCheck --check-prefix=FISSION --check-prefix=GNUOP %s
; RUN: | FileCheck --check-prefix=NOEMU --check-prefix=FISSION --check-prefix=GNUOP %s

; RUN: llc %s -o - -filetype=asm -O0 -mtriple=x86_64-scei-ps4 \
; RUN: | FileCheck --check-prefix=SINGLE --check-prefix=SINGLE-64 --check-prefix=STDOP %s
; RUN: | FileCheck --check-prefix=NOEMU --check-prefix=SINGLE --check-prefix=SINGLE-64 --check-prefix=STDOP %s

; RUN: llc %s -o - -filetype=asm -O0 -mtriple=x86_64-apple-darwin \
; RUN: | FileCheck --check-prefix=DARWIN --check-prefix=STDOP %s
; RUN: | FileCheck --check-prefix=NOEMU --check-prefix=DARWIN --check-prefix=STDOP %s

; RUN: llc %s -o - -filetype=asm -O0 -mtriple=x86_64-unknown-freebsd \
; RUN: | FileCheck --check-prefix=SINGLE --check-prefix=SINGLE-64 --check-prefix=STDOP %s
; RUN: | FileCheck --check-prefix=NOEMU --check-prefix=SINGLE --check-prefix=SINGLE-64 --check-prefix=STDOP %s

; RUN: llc %s -o - -filetype=asm -O0 -mtriple=x86_64-unknown-linux-gnu -emulated-tls \
; RUN: | FileCheck --check-prefix=SINGLE --check-prefix=EMUSINGLE-64 \
; RUN: --check-prefix=EMUGNUOP --check-prefix=EMU %s

; RUN: llc %s -o - -filetype=asm -O0 -mtriple=i386-linux-gnu -emulated-tls \
; RUN: | FileCheck --check-prefix=SINGLE --check-prefix=EMUSINGLE-32 \
; RUN: --check-prefix=EMUGNUOP --check-prefix=EMU %s

; TODO: Add expected output for -emulated-tls tests.

; FIXME: add relocation and DWARF expression support to llvm-dwarfdump & use
; that here instead of raw assembly printing
Expand Down
1 change: 1 addition & 0 deletions llvm/test/Transforms/GlobalOpt/tls.ll
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
; RUN: opt < %s -globalopt -S | FileCheck %s
; RUN: opt -emulated-tls < %s -globalopt -S | FileCheck %s

declare void @wait()
declare void @signal()
Expand Down