Compiler projects using llvm
; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc -mtriple=x86_64-unknown-unknown -O2 --relocation-model=pic --tls-load-hoist=true -o - %s | FileCheck %s --check-prefix=HOIST0
; RUN: llc -mtriple=x86_64-unknown-unknown -O2 --relocation-model=pic -o - %s | FileCheck %s --check-prefix=HOIST2

; This test has no module flag {"tls-load-hoist", i32 0}, so use --tls-load-hoist=x
; to choose the way of loading thread_local address.

; This test come from compiling clang/test/CodeGen/intel/tls_loads.cpp with:
; (clang tls_loads.cpp -fPIC -ftls-model=global-dynamic -O2 -S -emit-llvm)

$_ZTW5thl_x = comdat any

$_ZTW6thl_x2 = comdat any

@thl_x = thread_local global i32 0, align 4
@thl_x2 = thread_local global i32 0, align 4
@_ZZ2f2iE2st.0 = internal thread_local unnamed_addr global i8 0, align 4
@_ZZ2f2iE2st.1 = internal thread_local unnamed_addr global i32 0, align 4

; For HOIST0, check call __tls_get_addr@PLT only one time for each thread_local variable.
; For HOIST2, Check the default way: usually call __tls_get_addr@PLT every time when use thread_local variable.

; Function Attrs: mustprogress uwtable
define i32 @_Z2f1i(i32 %c) local_unnamed_addr #0 {
; HOIST0-LABEL: _Z2f1i:
; HOIST0:       # %bb.0: # %entry
; HOIST0-NEXT:    pushq %r15
; HOIST0-NEXT:    .cfi_def_cfa_offset 16
; HOIST0-NEXT:    pushq %r14
; HOIST0-NEXT:    .cfi_def_cfa_offset 24
; HOIST0-NEXT:    pushq %rbx
; HOIST0-NEXT:    .cfi_def_cfa_offset 32
; HOIST0-NEXT:    .cfi_offset %rbx, -32
; HOIST0-NEXT:    .cfi_offset %r14, -24
; HOIST0-NEXT:    .cfi_offset %r15, -16
; HOIST0-NEXT:    movl %edi, %ebx
; HOIST0-NEXT:    data16
; HOIST0-NEXT:    leaq thl_x@TLSGD(%rip), %rdi
; HOIST0-NEXT:    data16
; HOIST0-NEXT:    data16
; HOIST0-NEXT:    rex64
; HOIST0-NEXT:    callq __tls_get_addr@PLT
; HOIST0-NEXT:    movq %rax, %r14
; HOIST0-NEXT:    testl %ebx, %ebx
; HOIST0-NEXT:    je .LBB0_4
; HOIST0-NEXT:  # %bb.1: # %while.body.preheader
; HOIST0-NEXT:    data16
; HOIST0-NEXT:    leaq thl_x2@TLSGD(%rip), %rdi
; HOIST0-NEXT:    data16
; HOIST0-NEXT:    data16
; HOIST0-NEXT:    rex64
; HOIST0-NEXT:    callq __tls_get_addr@PLT
; HOIST0-NEXT:    movq %rax, %r15
; HOIST0-NEXT:    .p2align 4, 0x90
; HOIST0-NEXT:  .LBB0_2: # %while.body
; HOIST0-NEXT:    # =>This Inner Loop Header: Depth=1
; HOIST0-NEXT:    movl (%r15), %edi
; HOIST0-NEXT:    callq _Z6gfunc2i@PLT
; HOIST0-NEXT:    addl (%r14), %eax
; HOIST0-NEXT:    movl %eax, (%r14)
; HOIST0-NEXT:    decl %ebx
; HOIST0-NEXT:    jne .LBB0_2
; HOIST0-NEXT:    jmp .LBB0_3
; HOIST0-NEXT:  .LBB0_4: # %entry.while.end_crit_edge
; HOIST0-NEXT:    movl (%r14), %eax
; HOIST0-NEXT:  .LBB0_3: # %while.end
; HOIST0-NEXT:    popq %rbx
; HOIST0-NEXT:    .cfi_def_cfa_offset 24
; HOIST0-NEXT:    popq %r14
; HOIST0-NEXT:    .cfi_def_cfa_offset 16
; HOIST0-NEXT:    popq %r15
; HOIST0-NEXT:    .cfi_def_cfa_offset 8
; HOIST0-NEXT:    retq
;
; HOIST2-LABEL: _Z2f1i:
; HOIST2:       # %bb.0: # %entry
; HOIST2-NEXT:    pushq %rbp
; HOIST2-NEXT:    .cfi_def_cfa_offset 16
; HOIST2-NEXT:    pushq %rbx
; HOIST2-NEXT:    .cfi_def_cfa_offset 24
; HOIST2-NEXT:    pushq %rax
; HOIST2-NEXT:    .cfi_def_cfa_offset 32
; HOIST2-NEXT:    .cfi_offset %rbx, -24
; HOIST2-NEXT:    .cfi_offset %rbp, -16
; HOIST2-NEXT:    testl %edi, %edi
; HOIST2-NEXT:    je .LBB0_4
; HOIST2-NEXT:  # %bb.1:
; HOIST2-NEXT:    movl %edi, %ebx
; HOIST2-NEXT:    .p2align 4, 0x90
; HOIST2-NEXT:  .LBB0_2: # %while.body
; HOIST2-NEXT:    # =>This Inner Loop Header: Depth=1
; HOIST2-NEXT:    data16
; HOIST2-NEXT:    leaq thl_x2@TLSGD(%rip), %rdi
; HOIST2-NEXT:    data16
; HOIST2-NEXT:    data16
; HOIST2-NEXT:    rex64
; HOIST2-NEXT:    callq __tls_get_addr@PLT
; HOIST2-NEXT:    movl (%rax), %edi
; HOIST2-NEXT:    callq _Z6gfunc2i@PLT
; HOIST2-NEXT:    movl %eax, %ebp
; HOIST2-NEXT:    data16
; HOIST2-NEXT:    leaq thl_x@TLSGD(%rip), %rdi
; HOIST2-NEXT:    data16
; HOIST2-NEXT:    data16
; HOIST2-NEXT:    rex64
; HOIST2-NEXT:    callq __tls_get_addr@PLT
; HOIST2-NEXT:    addl (%rax), %ebp
; HOIST2-NEXT:    movl %ebp, (%rax)
; HOIST2-NEXT:    decl %ebx
; HOIST2-NEXT:    jne .LBB0_2
; HOIST2-NEXT:    jmp .LBB0_3
; HOIST2-NEXT:  .LBB0_4: # %entry.while.end_crit_edge
; HOIST2-NEXT:    data16
; HOIST2-NEXT:    leaq thl_x@TLSGD(%rip), %rdi
; HOIST2-NEXT:    data16
; HOIST2-NEXT:    data16
; HOIST2-NEXT:    rex64
; HOIST2-NEXT:    callq __tls_get_addr@PLT
; HOIST2-NEXT:    movl (%rax), %ebp
; HOIST2-NEXT:  .LBB0_3: # %while.end
; HOIST2-NEXT:    movl %ebp, %eax
; HOIST2-NEXT:    addq $8, %rsp
; HOIST2-NEXT:    .cfi_def_cfa_offset 24
; HOIST2-NEXT:    popq %rbx
; HOIST2-NEXT:    .cfi_def_cfa_offset 16
; HOIST2-NEXT:    popq %rbp
; HOIST2-NEXT:    .cfi_def_cfa_offset 8
; HOIST2-NEXT:    retq
entry:
  %tobool.not3 = icmp eq i32 %c, 0
  br i1 %tobool.not3, label %entry.while.end_crit_edge, label %while.body

entry.while.end_crit_edge:                        ; preds = %entry
  %.pre = load i32, ptr @thl_x, align 4
  br label %while.end

while.body:                                       ; preds = %entry, %while.body
  %c.addr.04 = phi i32 [ %dec, %while.body ], [ %c, %entry ]
  %dec = add nsw i32 %c.addr.04, -1
  %0 = load i32, ptr @thl_x2, align 4
  %call = tail call i32 @_Z6gfunc2i(i32 %0)
  %1 = load i32, ptr @thl_x, align 4
  %add = add nsw i32 %1, %call
  store i32 %add, ptr @thl_x, align 4
  %tobool.not = icmp eq i32 %dec, 0
  br i1 %tobool.not, label %while.end, label %while.body

while.end:                                        ; preds = %while.body, %entry.while.end_crit_edge
  %2 = phi i32 [ %.pre, %entry.while.end_crit_edge ], [ %add, %while.body ]
  ret i32 %2
}

declare i32 @_Z6gfunc2i(i32) local_unnamed_addr #1

; Function Attrs: mustprogress uwtable
define i32 @_Z2f2i(i32 %c) local_unnamed_addr #0 {
; HOIST0-LABEL: _Z2f2i:
; HOIST0:       # %bb.0: # %entry
; HOIST0-NEXT:    pushq %r15
; HOIST0-NEXT:    .cfi_def_cfa_offset 16
; HOIST0-NEXT:    pushq %r14
; HOIST0-NEXT:    .cfi_def_cfa_offset 24
; HOIST0-NEXT:    pushq %r12
; HOIST0-NEXT:    .cfi_def_cfa_offset 32
; HOIST0-NEXT:    pushq %rbx
; HOIST0-NEXT:    .cfi_def_cfa_offset 40
; HOIST0-NEXT:    pushq %rax
; HOIST0-NEXT:    .cfi_def_cfa_offset 48
; HOIST0-NEXT:    .cfi_offset %rbx, -40
; HOIST0-NEXT:    .cfi_offset %r12, -32
; HOIST0-NEXT:    .cfi_offset %r14, -24
; HOIST0-NEXT:    .cfi_offset %r15, -16
; HOIST0-NEXT:    movl %edi, %ebx
; HOIST0-NEXT:    data16
; HOIST0-NEXT:    leaq thl_x@TLSGD(%rip), %rdi
; HOIST0-NEXT:    data16
; HOIST0-NEXT:    data16
; HOIST0-NEXT:    rex64
; HOIST0-NEXT:    callq __tls_get_addr@PLT
; HOIST0-NEXT:    movq %rax, %r14
; HOIST0-NEXT:    testl %ebx, %ebx
; HOIST0-NEXT:    je .LBB1_3
; HOIST0-NEXT:  # %bb.1: # %while.body.preheader
; HOIST0-NEXT:    leaq _ZZ2f2iE2st.0@TLSLD(%rip), %rdi
; HOIST0-NEXT:    callq __tls_get_addr@PLT
; HOIST0-NEXT:    movq %rax, %rcx
; HOIST0-NEXT:    leaq _ZZ2f2iE2st.0@DTPOFF(%rax), %r15
; HOIST0-NEXT:    leaq _ZZ2f2iE2st.1@DTPOFF(%rax), %r12
; HOIST0-NEXT:    .p2align 4, 0x90
; HOIST0-NEXT:  .LBB1_2: # %while.body
; HOIST0-NEXT:    # =>This Inner Loop Header: Depth=1
; HOIST0-NEXT:    callq _Z5gfuncv@PLT
; HOIST0-NEXT:    addl %eax, (%r14)
; HOIST0-NEXT:    callq _Z5gfuncv@PLT
; HOIST0-NEXT:    addb %al, (%r15)
; HOIST0-NEXT:    callq _Z5gfuncv@PLT
; HOIST0-NEXT:    addl %eax, (%r12)
; HOIST0-NEXT:    decl %ebx
; HOIST0-NEXT:    jne .LBB1_2
; HOIST0-NEXT:  .LBB1_3: # %while.end
; HOIST0-NEXT:    movl (%r14), %eax
; HOIST0-NEXT:    addq $8, %rsp
; HOIST0-NEXT:    .cfi_def_cfa_offset 40
; HOIST0-NEXT:    popq %rbx
; HOIST0-NEXT:    .cfi_def_cfa_offset 32
; HOIST0-NEXT:    popq %r12
; HOIST0-NEXT:    .cfi_def_cfa_offset 24
; HOIST0-NEXT:    popq %r14
; HOIST0-NEXT:    .cfi_def_cfa_offset 16
; HOIST0-NEXT:    popq %r15
; HOIST0-NEXT:    .cfi_def_cfa_offset 8
; HOIST0-NEXT:    retq
;
; HOIST2-LABEL: _Z2f2i:
; HOIST2:       # %bb.0: # %entry
; HOIST2-NEXT:    pushq %rbp
; HOIST2-NEXT:    .cfi_def_cfa_offset 16
; HOIST2-NEXT:    pushq %r14
; HOIST2-NEXT:    .cfi_def_cfa_offset 24
; HOIST2-NEXT:    pushq %rbx
; HOIST2-NEXT:    .cfi_def_cfa_offset 32
; HOIST2-NEXT:    .cfi_offset %rbx, -32
; HOIST2-NEXT:    .cfi_offset %r14, -24
; HOIST2-NEXT:    .cfi_offset %rbp, -16
; HOIST2-NEXT:    testl %edi, %edi
; HOIST2-NEXT:    je .LBB1_3
; HOIST2-NEXT:  # %bb.1: # %while.body.preheader
; HOIST2-NEXT:    movl %edi, %ebx
; HOIST2-NEXT:    .p2align 4, 0x90
; HOIST2-NEXT:  .LBB1_2: # %while.body
; HOIST2-NEXT:    # =>This Inner Loop Header: Depth=1
; HOIST2-NEXT:    callq _Z5gfuncv@PLT
; HOIST2-NEXT:    movl %eax, %ebp
; HOIST2-NEXT:    data16
; HOIST2-NEXT:    leaq thl_x@TLSGD(%rip), %rdi
; HOIST2-NEXT:    data16
; HOIST2-NEXT:    data16
; HOIST2-NEXT:    rex64
; HOIST2-NEXT:    callq __tls_get_addr@PLT
; HOIST2-NEXT:    addl %ebp, (%rax)
; HOIST2-NEXT:    callq _Z5gfuncv@PLT
; HOIST2-NEXT:    movl %eax, %ebp
; HOIST2-NEXT:    leaq _ZZ2f2iE2st.0@TLSLD(%rip), %rdi
; HOIST2-NEXT:    callq __tls_get_addr@PLT
; HOIST2-NEXT:    movq %rax, %r14
; HOIST2-NEXT:    addb %bpl, _ZZ2f2iE2st.0@DTPOFF(%rax)
; HOIST2-NEXT:    callq _Z5gfuncv@PLT
; HOIST2-NEXT:    movl %eax, %ecx
; HOIST2-NEXT:    movq %r14, %rax
; HOIST2-NEXT:    addl %ecx, _ZZ2f2iE2st.1@DTPOFF(%r14)
; HOIST2-NEXT:    decl %ebx
; HOIST2-NEXT:    jne .LBB1_2
; HOIST2-NEXT:  .LBB1_3: # %while.end
; HOIST2-NEXT:    data16
; HOIST2-NEXT:    leaq thl_x@TLSGD(%rip), %rdi
; HOIST2-NEXT:    data16
; HOIST2-NEXT:    data16
; HOIST2-NEXT:    rex64
; HOIST2-NEXT:    callq __tls_get_addr@PLT
; HOIST2-NEXT:    movl (%rax), %eax
; HOIST2-NEXT:    popq %rbx
; HOIST2-NEXT:    .cfi_def_cfa_offset 24
; HOIST2-NEXT:    popq %r14
; HOIST2-NEXT:    .cfi_def_cfa_offset 16
; HOIST2-NEXT:    popq %rbp
; HOIST2-NEXT:    .cfi_def_cfa_offset 8
; HOIST2-NEXT:    retq
entry:
  %tobool.not9 = icmp eq i32 %c, 0
  br i1 %tobool.not9, label %while.end, label %while.body

while.body:                                       ; preds = %entry, %while.body
  %c.addr.010 = phi i32 [ %dec, %while.body ], [ %c, %entry ]
  %dec = add nsw i32 %c.addr.010, -1
  %call = tail call i32 @_Z5gfuncv()
  %0 = load i32, ptr @thl_x, align 4
  %add = add nsw i32 %0, %call
  store i32 %add, ptr @thl_x, align 4
  %call1 = tail call i32 @_Z5gfuncv()
  %1 = load i8, ptr @_ZZ2f2iE2st.0, align 4
  %2 = trunc i32 %call1 to i8
  %conv5 = add i8 %1, %2
  store i8 %conv5, ptr @_ZZ2f2iE2st.0, align 4
  %call6 = tail call i32 @_Z5gfuncv()
  %3 = load i32, ptr @_ZZ2f2iE2st.1, align 4
  %add7 = add nsw i32 %3, %call6
  store i32 %add7, ptr @_ZZ2f2iE2st.1, align 4
  %tobool.not = icmp eq i32 %dec, 0
  br i1 %tobool.not, label %while.end, label %while.body

while.end:                                        ; preds = %while.body, %entry
  %4 = load i32, ptr @thl_x, align 4
  ret i32 %4
}

declare i32 @_Z5gfuncv() local_unnamed_addr #1

; Function Attrs: mustprogress uwtable
define i32 @_Z2f3i(i32 %c) local_unnamed_addr #0 {
; HOIST0-LABEL: _Z2f3i:
; HOIST0:       # %bb.0: # %entry
; HOIST0-NEXT:    pushq %rbx
; HOIST0-NEXT:    .cfi_def_cfa_offset 16
; HOIST0-NEXT:    .cfi_offset %rbx, -16
; HOIST0-NEXT:    data16
; HOIST0-NEXT:    leaq thl_x@TLSGD(%rip), %rdi
; HOIST0-NEXT:    data16
; HOIST0-NEXT:    data16
; HOIST0-NEXT:    rex64
; HOIST0-NEXT:    callq __tls_get_addr@PLT
; HOIST0-NEXT:    movq %rax, %rbx
; HOIST0-NEXT:    movl (%rax), %edi
; HOIST0-NEXT:    callq _Z6gfunc2i@PLT
; HOIST0-NEXT:    movl (%rbx), %edi
; HOIST0-NEXT:    callq _Z6gfunc2i@PLT
; HOIST0-NEXT:    movl $1, %eax
; HOIST0-NEXT:    popq %rbx
; HOIST0-NEXT:    .cfi_def_cfa_offset 8
; HOIST0-NEXT:    retq
;
; HOIST2-LABEL: _Z2f3i:
; HOIST2:       # %bb.0: # %entry
; HOIST2-NEXT:    pushq %rbx
; HOIST2-NEXT:    .cfi_def_cfa_offset 16
; HOIST2-NEXT:    .cfi_offset %rbx, -16
; HOIST2-NEXT:    data16
; HOIST2-NEXT:    leaq thl_x@TLSGD(%rip), %rdi
; HOIST2-NEXT:    data16
; HOIST2-NEXT:    data16
; HOIST2-NEXT:    rex64
; HOIST2-NEXT:    callq __tls_get_addr@PLT
; HOIST2-NEXT:    movq %rax, %rbx
; HOIST2-NEXT:    movl (%rax), %edi
; HOIST2-NEXT:    callq _Z6gfunc2i@PLT
; HOIST2-NEXT:    movl (%rbx), %edi
; HOIST2-NEXT:    callq _Z6gfunc2i@PLT
; HOIST2-NEXT:    movl $1, %eax
; HOIST2-NEXT:    popq %rbx
; HOIST2-NEXT:    .cfi_def_cfa_offset 8
; HOIST2-NEXT:    retq
entry:
  %0 = load i32, ptr @thl_x, align 4
  %call = tail call i32 @_Z6gfunc2i(i32 %0)
  %1 = load i32, ptr @thl_x, align 4
  %call1 = tail call i32 @_Z6gfunc2i(i32 %1)
  ret i32 1
}

attributes #0 = { nounwind mustprogress uwtable "frame-pointer"="none" "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #1 = { "frame-pointer"="none" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
attributes #2 = { uwtable "frame-pointer"="none" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }

!llvm.module.flags = !{!0, !1, !2}

!0 = !{i32 1, !"wchar_size", i32 4}
!1 = !{i32 7, !"PIC Level", i32 2}
!2 = !{i32 7, !"uwtable", i32 1}