; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu | FileCheck %s --check-prefix=X64
; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -x86-slh-lfence | FileCheck %s --check-prefix=X64-LFENCE
;
; FIXME: Add support for 32-bit and other EH ABIs.
declare void @leak(i32 %v1, i32 %v2)
declare void @sink(i32)
define i32 @test_trivial_entry_load(ptr %ptr) speculative_load_hardening {
; X64-LABEL: test_trivial_entry_load:
; X64: # %bb.0: # %entry
; X64-NEXT: movq %rsp, %rcx
; X64-NEXT: movq $-1, %rax
; X64-NEXT: sarq $63, %rcx
; X64-NEXT: movl (%rdi), %eax
; X64-NEXT: orl %ecx, %eax
; X64-NEXT: shlq $47, %rcx
; X64-NEXT: orq %rcx, %rsp
; X64-NEXT: retq
;
; X64-LFENCE-LABEL: test_trivial_entry_load:
; X64-LFENCE: # %bb.0: # %entry
; X64-LFENCE-NEXT: movl (%rdi), %eax
; X64-LFENCE-NEXT: retq
entry:
%v = load i32, ptr %ptr
ret i32 %v
}
define void @test_basic_conditions(i32 %a, i32 %b, i32 %c, ptr %ptr1, ptr %ptr2, ptr %ptr3) speculative_load_hardening {
; X64-LABEL: test_basic_conditions:
; X64: # %bb.0: # %entry
; X64-NEXT: pushq %r15
; X64-NEXT: .cfi_def_cfa_offset 16
; X64-NEXT: pushq %r14
; X64-NEXT: .cfi_def_cfa_offset 24
; X64-NEXT: pushq %rbx
; X64-NEXT: .cfi_def_cfa_offset 32
; X64-NEXT: .cfi_offset %rbx, -32
; X64-NEXT: .cfi_offset %r14, -24
; X64-NEXT: .cfi_offset %r15, -16
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq $-1, %rbx
; X64-NEXT: sarq $63, %rax
; X64-NEXT: testl %edi, %edi
; X64-NEXT: jne .LBB1_1
; X64-NEXT: # %bb.2: # %then1
; X64-NEXT: cmovneq %rbx, %rax
; X64-NEXT: testl %esi, %esi
; X64-NEXT: je .LBB1_4
; X64-NEXT: .LBB1_1:
; X64-NEXT: cmoveq %rbx, %rax
; X64-NEXT: .LBB1_8: # %exit
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: popq %rbx
; X64-NEXT: .cfi_def_cfa_offset 24
; X64-NEXT: popq %r14
; X64-NEXT: .cfi_def_cfa_offset 16
; X64-NEXT: popq %r15
; X64-NEXT: .cfi_def_cfa_offset 8
; X64-NEXT: retq
; X64-NEXT: .LBB1_4: # %then2
; X64-NEXT: .cfi_def_cfa_offset 32
; X64-NEXT: cmovneq %rbx, %rax
; X64-NEXT: testl %edx, %edx
; X64-NEXT: je .LBB1_6
; X64-NEXT: # %bb.5: # %else3
; X64-NEXT: cmoveq %rbx, %rax
; X64-NEXT: movslq (%r9), %rcx
; X64-NEXT: orq %rax, %rcx
; X64-NEXT: leaq (%r8,%rcx,4), %r14
; X64-NEXT: movl %ecx, (%r8,%rcx,4)
; X64-NEXT: jmp .LBB1_7
; X64-NEXT: .LBB1_6: # %then3
; X64-NEXT: cmovneq %rbx, %rax
; X64-NEXT: movl (%rcx), %ecx
; X64-NEXT: addl (%r8), %ecx
; X64-NEXT: movslq %ecx, %rdi
; X64-NEXT: orq %rax, %rdi
; X64-NEXT: movl (%r8,%rdi,4), %esi
; X64-NEXT: orl %eax, %esi
; X64-NEXT: movq (%r9), %r14
; X64-NEXT: orq %rax, %r14
; X64-NEXT: addl (%r14), %esi
; X64-NEXT: shlq $47, %rax
; X64-NEXT: # kill: def $edi killed $edi killed $rdi
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: movq %r8, %r15
; X64-NEXT: callq leak@PLT
; X64-NEXT: .Lslh_ret_addr0:
; X64-NEXT: movq %r15, %r8
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rcx
; X64-NEXT: sarq $63, %rax
; X64-NEXT: cmpq $.Lslh_ret_addr0, %rcx
; X64-NEXT: cmovneq %rbx, %rax
; X64-NEXT: .LBB1_7: # %merge
; X64-NEXT: movslq (%r14), %rcx
; X64-NEXT: orq %rax, %rcx
; X64-NEXT: movl $0, (%r8,%rcx,4)
; X64-NEXT: jmp .LBB1_8
;
; X64-LFENCE-LABEL: test_basic_conditions:
; X64-LFENCE: # %bb.0: # %entry
; X64-LFENCE-NEXT: pushq %r14
; X64-LFENCE-NEXT: .cfi_def_cfa_offset 16
; X64-LFENCE-NEXT: pushq %rbx
; X64-LFENCE-NEXT: .cfi_def_cfa_offset 24
; X64-LFENCE-NEXT: pushq %rax
; X64-LFENCE-NEXT: .cfi_def_cfa_offset 32
; X64-LFENCE-NEXT: .cfi_offset %rbx, -24
; X64-LFENCE-NEXT: .cfi_offset %r14, -16
; X64-LFENCE-NEXT: testl %edi, %edi
; X64-LFENCE-NEXT: jne .LBB1_6
; X64-LFENCE-NEXT: # %bb.1: # %then1
; X64-LFENCE-NEXT: lfence
; X64-LFENCE-NEXT: testl %esi, %esi
; X64-LFENCE-NEXT: jne .LBB1_6
; X64-LFENCE-NEXT: # %bb.2: # %then2
; X64-LFENCE-NEXT: lfence
; X64-LFENCE-NEXT: testl %edx, %edx
; X64-LFENCE-NEXT: je .LBB1_3
; X64-LFENCE-NEXT: # %bb.4: # %else3
; X64-LFENCE-NEXT: lfence
; X64-LFENCE-NEXT: movslq (%r9), %rax
; X64-LFENCE-NEXT: leaq (%r8,%rax,4), %rbx
; X64-LFENCE-NEXT: movl %eax, (%r8,%rax,4)
; X64-LFENCE-NEXT: jmp .LBB1_5
; X64-LFENCE-NEXT: .LBB1_3: # %then3
; X64-LFENCE-NEXT: lfence
; X64-LFENCE-NEXT: movl (%rcx), %eax
; X64-LFENCE-NEXT: addl (%r8), %eax
; X64-LFENCE-NEXT: movslq %eax, %rdi
; X64-LFENCE-NEXT: movl (%r8,%rdi,4), %esi
; X64-LFENCE-NEXT: movq (%r9), %rbx
; X64-LFENCE-NEXT: addl (%rbx), %esi
; X64-LFENCE-NEXT: # kill: def $edi killed $edi killed $rdi
; X64-LFENCE-NEXT: movq %r8, %r14
; X64-LFENCE-NEXT: callq leak@PLT
; X64-LFENCE-NEXT: movq %r14, %r8
; X64-LFENCE-NEXT: .LBB1_5: # %merge
; X64-LFENCE-NEXT: movslq (%rbx), %rax
; X64-LFENCE-NEXT: movl $0, (%r8,%rax,4)
; X64-LFENCE-NEXT: .LBB1_6: # %exit
; X64-LFENCE-NEXT: lfence
; X64-LFENCE-NEXT: addq $8, %rsp
; X64-LFENCE-NEXT: .cfi_def_cfa_offset 24
; X64-LFENCE-NEXT: popq %rbx
; X64-LFENCE-NEXT: .cfi_def_cfa_offset 16
; X64-LFENCE-NEXT: popq %r14
; X64-LFENCE-NEXT: .cfi_def_cfa_offset 8
; X64-LFENCE-NEXT: retq
entry:
%a.cmp = icmp eq i32 %a, 0
br i1 %a.cmp, label %then1, label %exit
then1:
%b.cmp = icmp eq i32 %b, 0
br i1 %b.cmp, label %then2, label %exit
then2:
%c.cmp = icmp eq i32 %c, 0
br i1 %c.cmp, label %then3, label %else3
then3:
%secret1 = load i32, ptr %ptr1
%secret2 = load i32, ptr %ptr2
%secret.sum1 = add i32 %secret1, %secret2
%ptr2.idx = getelementptr i32, ptr %ptr2, i32 %secret.sum1
%secret3 = load i32, ptr %ptr2.idx
%secret4 = load ptr, ptr %ptr3
%secret5 = load i32, ptr %secret4
%secret.sum2 = add i32 %secret3, %secret5
call void @leak(i32 %secret.sum1, i32 %secret.sum2)
br label %merge
else3:
%secret6 = load ptr, ptr %ptr3
%cast = ptrtoint ptr %secret6 to i32
%ptr2.idx2 = getelementptr i32, ptr %ptr2, i32 %cast
store i32 %cast, ptr %ptr2.idx2
br label %merge
merge:
%phi = phi ptr [ %secret4, %then3 ], [ %ptr2.idx2, %else3 ]
%secret7 = load i32, ptr %phi
%ptr2.idx3 = getelementptr i32, ptr %ptr2, i32 %secret7
store i32 0, ptr %ptr2.idx3
br label %exit
exit:
ret void
}
define void @test_basic_loop(i32 %a, i32 %b, ptr %ptr1, ptr %ptr2) nounwind speculative_load_hardening {
; X64-LABEL: test_basic_loop:
; X64: # %bb.0: # %entry
; X64-NEXT: pushq %rbp
; X64-NEXT: pushq %r15
; X64-NEXT: pushq %r14
; X64-NEXT: pushq %r12
; X64-NEXT: pushq %rbx
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq $-1, %r15
; X64-NEXT: sarq $63, %rax
; X64-NEXT: testl %edi, %edi
; X64-NEXT: je .LBB2_2
; X64-NEXT: # %bb.1:
; X64-NEXT: cmoveq %r15, %rax
; X64-NEXT: jmp .LBB2_5
; X64-NEXT: .LBB2_2: # %l.header.preheader
; X64-NEXT: movq %rcx, %rbx
; X64-NEXT: movq %rdx, %r14
; X64-NEXT: movl %esi, %ebp
; X64-NEXT: cmovneq %r15, %rax
; X64-NEXT: xorl %r12d, %r12d
; X64-NEXT: .p2align 4
; X64-NEXT: .LBB2_3: # %l.header
; X64-NEXT: # =>This Inner Loop Header: Depth=1
; X64-NEXT: movslq (%r14), %rcx
; X64-NEXT: orq %rax, %rcx
; X64-NEXT: movq %rax, %rdx
; X64-NEXT: orq %rbx, %rdx
; X64-NEXT: movl (%rdx,%rcx,4), %edi
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: callq sink@PLT
; X64-NEXT: .Lslh_ret_addr1:
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rcx
; X64-NEXT: sarq $63, %rax
; X64-NEXT: cmpq $.Lslh_ret_addr1, %rcx
; X64-NEXT: cmovneq %r15, %rax
; X64-NEXT: incl %r12d
; X64-NEXT: cmpl %ebp, %r12d
; X64-NEXT: jge .LBB2_4
; X64-NEXT: # %bb.6: # in Loop: Header=BB2_3 Depth=1
; X64-NEXT: cmovgeq %r15, %rax
; X64-NEXT: jmp .LBB2_3
; X64-NEXT: .LBB2_4:
; X64-NEXT: cmovlq %r15, %rax
; X64-NEXT: .LBB2_5: # %exit
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: popq %rbx
; X64-NEXT: popq %r12
; X64-NEXT: popq %r14
; X64-NEXT: popq %r15
; X64-NEXT: popq %rbp
; X64-NEXT: retq
;
; X64-LFENCE-LABEL: test_basic_loop:
; X64-LFENCE: # %bb.0: # %entry
; X64-LFENCE-NEXT: pushq %rbp
; X64-LFENCE-NEXT: pushq %r15
; X64-LFENCE-NEXT: pushq %r14
; X64-LFENCE-NEXT: pushq %rbx
; X64-LFENCE-NEXT: pushq %rax
; X64-LFENCE-NEXT: testl %edi, %edi
; X64-LFENCE-NEXT: jne .LBB2_3
; X64-LFENCE-NEXT: # %bb.1: # %l.header.preheader
; X64-LFENCE-NEXT: movq %rcx, %rbx
; X64-LFENCE-NEXT: movq %rdx, %r14
; X64-LFENCE-NEXT: movl %esi, %ebp
; X64-LFENCE-NEXT: lfence
; X64-LFENCE-NEXT: xorl %r15d, %r15d
; X64-LFENCE-NEXT: .p2align 4
; X64-LFENCE-NEXT: .LBB2_2: # %l.header
; X64-LFENCE-NEXT: # =>This Inner Loop Header: Depth=1
; X64-LFENCE-NEXT: lfence
; X64-LFENCE-NEXT: movslq (%r14), %rax
; X64-LFENCE-NEXT: movl (%rbx,%rax,4), %edi
; X64-LFENCE-NEXT: callq sink@PLT
; X64-LFENCE-NEXT: incl %r15d
; X64-LFENCE-NEXT: cmpl %ebp, %r15d
; X64-LFENCE-NEXT: jl .LBB2_2
; X64-LFENCE-NEXT: .LBB2_3: # %exit
; X64-LFENCE-NEXT: lfence
; X64-LFENCE-NEXT: addq $8, %rsp
; X64-LFENCE-NEXT: popq %rbx
; X64-LFENCE-NEXT: popq %r14
; X64-LFENCE-NEXT: popq %r15
; X64-LFENCE-NEXT: popq %rbp
; X64-LFENCE-NEXT: retq
entry:
%a.cmp = icmp eq i32 %a, 0
br i1 %a.cmp, label %l.header, label %exit
l.header:
%i = phi i32 [ 0, %entry ], [ %i.next, %l.header ]
%secret = load i32, ptr %ptr1
%ptr2.idx = getelementptr i32, ptr %ptr2, i32 %secret
%leak = load i32, ptr %ptr2.idx
call void @sink(i32 %leak)
%i.next = add i32 %i, 1
%i.cmp = icmp slt i32 %i.next, %b
br i1 %i.cmp, label %l.header, label %exit
exit:
ret void
}
define void @test_basic_nested_loop(i32 %a, i32 %b, i32 %c, ptr %ptr1, ptr %ptr2) nounwind speculative_load_hardening {
; X64-LABEL: test_basic_nested_loop:
; X64: # %bb.0: # %entry
; X64-NEXT: pushq %rbp
; X64-NEXT: pushq %r15
; X64-NEXT: pushq %r14
; X64-NEXT: pushq %r13
; X64-NEXT: pushq %r12
; X64-NEXT: pushq %rbx
; X64-NEXT: pushq %rax
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq $-1, %r12
; X64-NEXT: sarq $63, %rax
; X64-NEXT: testl %edi, %edi
; X64-NEXT: je .LBB3_2
; X64-NEXT: # %bb.1:
; X64-NEXT: cmoveq %r12, %rax
; X64-NEXT: jmp .LBB3_10
; X64-NEXT: .LBB3_2: # %l1.header.preheader
; X64-NEXT: movq %r8, %rbx
; X64-NEXT: movq %rcx, %r14
; X64-NEXT: movl %edx, %ebp
; X64-NEXT: movl %esi, %r15d
; X64-NEXT: cmovneq %r12, %rax
; X64-NEXT: xorl %r13d, %r13d
; X64-NEXT: movl %esi, {{[-0-9]+}}(%r{{[sb]}}p) # 4-byte Spill
; X64-NEXT: testl %r15d, %r15d
; X64-NEXT: jle .LBB3_4
; X64-NEXT: .p2align 4
; X64-NEXT: .LBB3_5: # %l2.header.preheader
; X64-NEXT: cmovleq %r12, %rax
; X64-NEXT: xorl %r15d, %r15d
; X64-NEXT: .p2align 4
; X64-NEXT: .LBB3_6: # %l2.header
; X64-NEXT: # =>This Inner Loop Header: Depth=1
; X64-NEXT: movslq (%r14), %rcx
; X64-NEXT: orq %rax, %rcx
; X64-NEXT: movq %rax, %rdx
; X64-NEXT: orq %rbx, %rdx
; X64-NEXT: movl (%rdx,%rcx,4), %edi
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: callq sink@PLT
; X64-NEXT: .Lslh_ret_addr2:
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rcx
; X64-NEXT: sarq $63, %rax
; X64-NEXT: cmpq $.Lslh_ret_addr2, %rcx
; X64-NEXT: cmovneq %r12, %rax
; X64-NEXT: incl %r15d
; X64-NEXT: cmpl %ebp, %r15d
; X64-NEXT: jge .LBB3_7
; X64-NEXT: # %bb.11: # in Loop: Header=BB3_6 Depth=1
; X64-NEXT: cmovgeq %r12, %rax
; X64-NEXT: jmp .LBB3_6
; X64-NEXT: .p2align 4
; X64-NEXT: .LBB3_7:
; X64-NEXT: cmovlq %r12, %rax
; X64-NEXT: movl {{[-0-9]+}}(%r{{[sb]}}p), %r15d # 4-byte Reload
; X64-NEXT: jmp .LBB3_8
; X64-NEXT: .p2align 4
; X64-NEXT: .LBB3_4:
; X64-NEXT: cmovgq %r12, %rax
; X64-NEXT: .LBB3_8: # %l1.latch
; X64-NEXT: movslq (%r14), %rcx
; X64-NEXT: orq %rax, %rcx
; X64-NEXT: movq %rax, %rdx
; X64-NEXT: orq %rbx, %rdx
; X64-NEXT: movl (%rdx,%rcx,4), %edi
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: callq sink@PLT
; X64-NEXT: .Lslh_ret_addr3:
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rcx
; X64-NEXT: sarq $63, %rax
; X64-NEXT: cmpq $.Lslh_ret_addr3, %rcx
; X64-NEXT: cmovneq %r12, %rax
; X64-NEXT: incl %r13d
; X64-NEXT: cmpl %r15d, %r13d
; X64-NEXT: jge .LBB3_9
; X64-NEXT: # %bb.12:
; X64-NEXT: cmovgeq %r12, %rax
; X64-NEXT: testl %r15d, %r15d
; X64-NEXT: jg .LBB3_5
; X64-NEXT: jmp .LBB3_4
; X64-NEXT: .LBB3_9:
; X64-NEXT: cmovlq %r12, %rax
; X64-NEXT: .LBB3_10: # %exit
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: addq $8, %rsp
; X64-NEXT: popq %rbx
; X64-NEXT: popq %r12
; X64-NEXT: popq %r13
; X64-NEXT: popq %r14
; X64-NEXT: popq %r15
; X64-NEXT: popq %rbp
; X64-NEXT: retq
;
; X64-LFENCE-LABEL: test_basic_nested_loop:
; X64-LFENCE: # %bb.0: # %entry
; X64-LFENCE-NEXT: pushq %rbp
; X64-LFENCE-NEXT: pushq %r15
; X64-LFENCE-NEXT: pushq %r14
; X64-LFENCE-NEXT: pushq %r13
; X64-LFENCE-NEXT: pushq %r12
; X64-LFENCE-NEXT: pushq %rbx
; X64-LFENCE-NEXT: pushq %rax
; X64-LFENCE-NEXT: testl %edi, %edi
; X64-LFENCE-NEXT: je .LBB3_1
; X64-LFENCE-NEXT: .LBB3_6: # %exit
; X64-LFENCE-NEXT: lfence
; X64-LFENCE-NEXT: addq $8, %rsp
; X64-LFENCE-NEXT: popq %rbx
; X64-LFENCE-NEXT: popq %r12
; X64-LFENCE-NEXT: popq %r13
; X64-LFENCE-NEXT: popq %r14
; X64-LFENCE-NEXT: popq %r15
; X64-LFENCE-NEXT: popq %rbp
; X64-LFENCE-NEXT: retq
; X64-LFENCE-NEXT: .LBB3_1: # %l1.header.preheader
; X64-LFENCE-NEXT: movq %r8, %rbx
; X64-LFENCE-NEXT: movq %rcx, %r14
; X64-LFENCE-NEXT: movl %edx, %ebp
; X64-LFENCE-NEXT: movl %esi, %r15d
; X64-LFENCE-NEXT: lfence
; X64-LFENCE-NEXT: xorl %r12d, %r12d
; X64-LFENCE-NEXT: jmp .LBB3_2
; X64-LFENCE-NEXT: .p2align 4
; X64-LFENCE-NEXT: .LBB3_5: # %l1.latch
; X64-LFENCE-NEXT: # in Loop: Header=BB3_2 Depth=1
; X64-LFENCE-NEXT: lfence
; X64-LFENCE-NEXT: movslq (%r14), %rax
; X64-LFENCE-NEXT: movl (%rbx,%rax,4), %edi
; X64-LFENCE-NEXT: callq sink@PLT
; X64-LFENCE-NEXT: incl %r12d
; X64-LFENCE-NEXT: cmpl %r15d, %r12d
; X64-LFENCE-NEXT: jge .LBB3_6
; X64-LFENCE-NEXT: .LBB3_2: # %l1.header
; X64-LFENCE-NEXT: # =>This Loop Header: Depth=1
; X64-LFENCE-NEXT: # Child Loop BB3_4 Depth 2
; X64-LFENCE-NEXT: lfence
; X64-LFENCE-NEXT: testl %r15d, %r15d
; X64-LFENCE-NEXT: jle .LBB3_5
; X64-LFENCE-NEXT: # %bb.3: # %l2.header.preheader
; X64-LFENCE-NEXT: # in Loop: Header=BB3_2 Depth=1
; X64-LFENCE-NEXT: lfence
; X64-LFENCE-NEXT: xorl %r13d, %r13d
; X64-LFENCE-NEXT: .p2align 4
; X64-LFENCE-NEXT: .LBB3_4: # %l2.header
; X64-LFENCE-NEXT: # Parent Loop BB3_2 Depth=1
; X64-LFENCE-NEXT: # => This Inner Loop Header: Depth=2
; X64-LFENCE-NEXT: lfence
; X64-LFENCE-NEXT: movslq (%r14), %rax
; X64-LFENCE-NEXT: movl (%rbx,%rax,4), %edi
; X64-LFENCE-NEXT: callq sink@PLT
; X64-LFENCE-NEXT: incl %r13d
; X64-LFENCE-NEXT: cmpl %ebp, %r13d
; X64-LFENCE-NEXT: jl .LBB3_4
; X64-LFENCE-NEXT: jmp .LBB3_5
entry:
%a.cmp = icmp eq i32 %a, 0
br i1 %a.cmp, label %l1.header, label %exit
l1.header:
%i = phi i32 [ 0, %entry ], [ %i.next, %l1.latch ]
%b.cmp = icmp sgt i32 %b, 0
br i1 %b.cmp, label %l2.header, label %l1.latch
l2.header:
%j = phi i32 [ 0, %l1.header ], [ %j.next, %l2.header ]
%secret = load i32, ptr %ptr1
%ptr2.idx = getelementptr i32, ptr %ptr2, i32 %secret
%leak = load i32, ptr %ptr2.idx
call void @sink(i32 %leak)
%j.next = add i32 %j, 1
%j.cmp = icmp slt i32 %j.next, %c
br i1 %j.cmp, label %l2.header, label %l1.latch
l1.latch:
%secret2 = load i32, ptr %ptr1
%ptr2.idx2 = getelementptr i32, ptr %ptr2, i32 %secret2
%leak2 = load i32, ptr %ptr2.idx2
call void @sink(i32 %leak2)
%i.next = add i32 %i, 1
%i.cmp = icmp slt i32 %i.next, %b
br i1 %i.cmp, label %l1.header, label %exit
exit:
ret void
}
declare i32 @__gxx_personality_v0(...)
declare ptr @__cxa_allocate_exception(i64) local_unnamed_addr
declare void @__cxa_throw(ptr, ptr, ptr) local_unnamed_addr
define void @test_basic_eh(i32 %a, ptr %ptr1, ptr %ptr2) speculative_load_hardening personality ptr @__gxx_personality_v0 {
; X64-LABEL: test_basic_eh:
; X64: # %bb.0: # %entry
; X64-NEXT: pushq %rbp
; X64-NEXT: .cfi_def_cfa_offset 16
; X64-NEXT: pushq %r15
; X64-NEXT: .cfi_def_cfa_offset 24
; X64-NEXT: pushq %r14
; X64-NEXT: .cfi_def_cfa_offset 32
; X64-NEXT: pushq %rbx
; X64-NEXT: .cfi_def_cfa_offset 40
; X64-NEXT: pushq %rax
; X64-NEXT: .cfi_def_cfa_offset 48
; X64-NEXT: .cfi_offset %rbx, -40
; X64-NEXT: .cfi_offset %r14, -32
; X64-NEXT: .cfi_offset %r15, -24
; X64-NEXT: .cfi_offset %rbp, -16
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq $-1, %rbx
; X64-NEXT: sarq $63, %rax
; X64-NEXT: cmpl $41, %edi
; X64-NEXT: jg .LBB4_1
; X64-NEXT: # %bb.2: # %thrower
; X64-NEXT: movq %rdx, %r14
; X64-NEXT: cmovgq %rbx, %rax
; X64-NEXT: movslq %edi, %rcx
; X64-NEXT: movq %rsi, %r15
; X64-NEXT: movl (%rsi,%rcx,4), %ebp
; X64-NEXT: orl %eax, %ebp
; X64-NEXT: movl $4, %edi
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: callq __cxa_allocate_exception@PLT
; X64-NEXT: .Lslh_ret_addr4:
; X64-NEXT: movq %rsp, %rcx
; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rdx
; X64-NEXT: sarq $63, %rcx
; X64-NEXT: cmpq $.Lslh_ret_addr4, %rdx
; X64-NEXT: cmovneq %rbx, %rcx
; X64-NEXT: movl %ebp, (%rax)
; X64-NEXT: .Ltmp0:
; X64-NEXT: shlq $47, %rcx
; X64-NEXT: movq %rax, %rdi
; X64-NEXT: xorl %esi, %esi
; X64-NEXT: xorl %edx, %edx
; X64-NEXT: orq %rcx, %rsp
; X64-NEXT: callq __cxa_throw@PLT
; X64-NEXT: .Lslh_ret_addr5:
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rcx
; X64-NEXT: sarq $63, %rax
; X64-NEXT: cmpq $.Lslh_ret_addr5, %rcx
; X64-NEXT: cmovneq %rbx, %rax
; X64-NEXT: .Ltmp1:
; X64-NEXT: jmp .LBB4_3
; X64-NEXT: .LBB4_1:
; X64-NEXT: cmovleq %rbx, %rax
; X64-NEXT: .LBB4_3: # %exit
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: addq $8, %rsp
; X64-NEXT: .cfi_def_cfa_offset 40
; X64-NEXT: popq %rbx
; X64-NEXT: .cfi_def_cfa_offset 32
; X64-NEXT: popq %r14
; X64-NEXT: .cfi_def_cfa_offset 24
; X64-NEXT: popq %r15
; X64-NEXT: .cfi_def_cfa_offset 16
; X64-NEXT: popq %rbp
; X64-NEXT: .cfi_def_cfa_offset 8
; X64-NEXT: retq
; X64-NEXT: .LBB4_4: # %lpad
; X64-NEXT: .cfi_def_cfa_offset 48
; X64-NEXT: .Ltmp2:
; X64-NEXT: movq %rsp, %rcx
; X64-NEXT: sarq $63, %rcx
; X64-NEXT: movl (%rax), %eax
; X64-NEXT: addl (%r15), %eax
; X64-NEXT: cltq
; X64-NEXT: orq %rcx, %rax
; X64-NEXT: movl (%r14,%rax,4), %edi
; X64-NEXT: orl %ecx, %edi
; X64-NEXT: shlq $47, %rcx
; X64-NEXT: orq %rcx, %rsp
; X64-NEXT: callq sink@PLT
; X64-NEXT: .Lslh_ret_addr6:
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rcx
; X64-NEXT: sarq $63, %rax
; X64-NEXT: cmpq $.Lslh_ret_addr6, %rcx
; X64-NEXT: cmovneq %rbx, %rax
;
; X64-LFENCE-LABEL: test_basic_eh:
; X64-LFENCE: # %bb.0: # %entry
; X64-LFENCE-NEXT: pushq %rbp
; X64-LFENCE-NEXT: .cfi_def_cfa_offset 16
; X64-LFENCE-NEXT: pushq %r14
; X64-LFENCE-NEXT: .cfi_def_cfa_offset 24
; X64-LFENCE-NEXT: pushq %rbx
; X64-LFENCE-NEXT: .cfi_def_cfa_offset 32
; X64-LFENCE-NEXT: .cfi_offset %rbx, -32
; X64-LFENCE-NEXT: .cfi_offset %r14, -24
; X64-LFENCE-NEXT: .cfi_offset %rbp, -16
; X64-LFENCE-NEXT: cmpl $41, %edi
; X64-LFENCE-NEXT: jg .LBB4_2
; X64-LFENCE-NEXT: # %bb.1: # %thrower
; X64-LFENCE-NEXT: movq %rdx, %rbx
; X64-LFENCE-NEXT: movq %rsi, %r14
; X64-LFENCE-NEXT: lfence
; X64-LFENCE-NEXT: movslq %edi, %rax
; X64-LFENCE-NEXT: movl (%rsi,%rax,4), %ebp
; X64-LFENCE-NEXT: movl $4, %edi
; X64-LFENCE-NEXT: callq __cxa_allocate_exception@PLT
; X64-LFENCE-NEXT: movl %ebp, (%rax)
; X64-LFENCE-NEXT: .Ltmp0:
; X64-LFENCE-NEXT: movq %rax, %rdi
; X64-LFENCE-NEXT: xorl %esi, %esi
; X64-LFENCE-NEXT: xorl %edx, %edx
; X64-LFENCE-NEXT: callq __cxa_throw@PLT
; X64-LFENCE-NEXT: .Ltmp1:
; X64-LFENCE-NEXT: .LBB4_2: # %exit
; X64-LFENCE-NEXT: lfence
; X64-LFENCE-NEXT: popq %rbx
; X64-LFENCE-NEXT: .cfi_def_cfa_offset 24
; X64-LFENCE-NEXT: popq %r14
; X64-LFENCE-NEXT: .cfi_def_cfa_offset 16
; X64-LFENCE-NEXT: popq %rbp
; X64-LFENCE-NEXT: .cfi_def_cfa_offset 8
; X64-LFENCE-NEXT: retq
; X64-LFENCE-NEXT: .LBB4_3: # %lpad
; X64-LFENCE-NEXT: .cfi_def_cfa_offset 32
; X64-LFENCE-NEXT: .Ltmp2:
; X64-LFENCE-NEXT: movl (%rax), %eax
; X64-LFENCE-NEXT: addl (%r14), %eax
; X64-LFENCE-NEXT: cltq
; X64-LFENCE-NEXT: movl (%rbx,%rax,4), %edi
; X64-LFENCE-NEXT: callq sink@PLT
entry:
%a.cmp = icmp slt i32 %a, 42
br i1 %a.cmp, label %thrower, label %exit
thrower:
%badidx = getelementptr i32, ptr %ptr1, i32 %a
%secret1 = load i32, ptr %badidx
%e.ptr = call ptr @__cxa_allocate_exception(i64 4)
store i32 %secret1, ptr %e.ptr
invoke void @__cxa_throw(ptr %e.ptr, ptr null, ptr null)
to label %exit unwind label %lpad
exit:
ret void
lpad:
%e = landingpad { ptr, i32 }
catch ptr null
%e.catch.ptr = extractvalue { ptr, i32 } %e, 0
%secret1.catch = load i32, ptr %e.catch.ptr
%secret2 = load i32, ptr %ptr1
%secret.sum = add i32 %secret1.catch, %secret2
%ptr2.idx = getelementptr i32, ptr %ptr2, i32 %secret.sum
%leak = load i32, ptr %ptr2.idx
call void @sink(i32 %leak)
unreachable
}
declare void @sink_float(float)
declare void @sink_double(double)
; Test direct and converting loads of floating point values.
define void @test_fp_loads(ptr %fptr, ptr %dptr, ptr %i32ptr, ptr %i64ptr) nounwind speculative_load_hardening {
; X64-LABEL: test_fp_loads:
; X64: # %bb.0: # %entry
; X64-NEXT: pushq %r15
; X64-NEXT: pushq %r14
; X64-NEXT: pushq %r13
; X64-NEXT: pushq %r12
; X64-NEXT: pushq %rbx
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq %rcx, %r14
; X64-NEXT: movq %rdx, %rbx
; X64-NEXT: movq %rsi, %r12
; X64-NEXT: movq %rdi, %r15
; X64-NEXT: movq $-1, %r13
; X64-NEXT: sarq $63, %rax
; X64-NEXT: orq %rax, %r15
; X64-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: callq sink_float@PLT
; X64-NEXT: .Lslh_ret_addr7:
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rcx
; X64-NEXT: sarq $63, %rax
; X64-NEXT: cmpq $.Lslh_ret_addr7, %rcx
; X64-NEXT: cmovneq %r13, %rax
; X64-NEXT: orq %rax, %r12
; X64-NEXT: movsd {{.*#+}} xmm0 = mem[0],zero
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: callq sink_double@PLT
; X64-NEXT: .Lslh_ret_addr8:
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rcx
; X64-NEXT: sarq $63, %rax
; X64-NEXT: cmpq $.Lslh_ret_addr8, %rcx
; X64-NEXT: cmovneq %r13, %rax
; X64-NEXT: movsd {{.*#+}} xmm0 = mem[0],zero
; X64-NEXT: cvtsd2ss %xmm0, %xmm0
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: callq sink_float@PLT
; X64-NEXT: .Lslh_ret_addr9:
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rcx
; X64-NEXT: sarq $63, %rax
; X64-NEXT: cmpq $.Lslh_ret_addr9, %rcx
; X64-NEXT: cmovneq %r13, %rax
; X64-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero
; X64-NEXT: cvtss2sd %xmm0, %xmm0
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: callq sink_double@PLT
; X64-NEXT: .Lslh_ret_addr10:
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rcx
; X64-NEXT: sarq $63, %rax
; X64-NEXT: cmpq $.Lslh_ret_addr10, %rcx
; X64-NEXT: cmovneq %r13, %rax
; X64-NEXT: orq %rax, %rbx
; X64-NEXT: xorps %xmm0, %xmm0
; X64-NEXT: cvtsi2ssl (%rbx), %xmm0
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: callq sink_float@PLT
; X64-NEXT: .Lslh_ret_addr11:
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rcx
; X64-NEXT: sarq $63, %rax
; X64-NEXT: cmpq $.Lslh_ret_addr11, %rcx
; X64-NEXT: cmovneq %r13, %rax
; X64-NEXT: orq %rax, %r14
; X64-NEXT: xorps %xmm0, %xmm0
; X64-NEXT: cvtsi2sdq (%r14), %xmm0
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: callq sink_double@PLT
; X64-NEXT: .Lslh_ret_addr12:
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rcx
; X64-NEXT: sarq $63, %rax
; X64-NEXT: cmpq $.Lslh_ret_addr12, %rcx
; X64-NEXT: cmovneq %r13, %rax
; X64-NEXT: xorps %xmm0, %xmm0
; X64-NEXT: cvtsi2ssq (%r14), %xmm0
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: callq sink_float@PLT
; X64-NEXT: .Lslh_ret_addr13:
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rcx
; X64-NEXT: sarq $63, %rax
; X64-NEXT: cmpq $.Lslh_ret_addr13, %rcx
; X64-NEXT: cmovneq %r13, %rax
; X64-NEXT: xorps %xmm0, %xmm0
; X64-NEXT: cvtsi2sdl (%rbx), %xmm0
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: callq sink_double@PLT
; X64-NEXT: .Lslh_ret_addr14:
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rcx
; X64-NEXT: sarq $63, %rax
; X64-NEXT: cmpq $.Lslh_ret_addr14, %rcx
; X64-NEXT: cmovneq %r13, %rax
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: popq %rbx
; X64-NEXT: popq %r12
; X64-NEXT: popq %r13
; X64-NEXT: popq %r14
; X64-NEXT: popq %r15
; X64-NEXT: retq
;
; X64-LFENCE-LABEL: test_fp_loads:
; X64-LFENCE: # %bb.0: # %entry
; X64-LFENCE-NEXT: pushq %r15
; X64-LFENCE-NEXT: pushq %r14
; X64-LFENCE-NEXT: pushq %r12
; X64-LFENCE-NEXT: pushq %rbx
; X64-LFENCE-NEXT: pushq %rax
; X64-LFENCE-NEXT: movq %rcx, %r14
; X64-LFENCE-NEXT: movq %rdx, %rbx
; X64-LFENCE-NEXT: movq %rsi, %r15
; X64-LFENCE-NEXT: movq %rdi, %r12
; X64-LFENCE-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero
; X64-LFENCE-NEXT: callq sink_float@PLT
; X64-LFENCE-NEXT: movsd {{.*#+}} xmm0 = mem[0],zero
; X64-LFENCE-NEXT: callq sink_double@PLT
; X64-LFENCE-NEXT: movsd {{.*#+}} xmm0 = mem[0],zero
; X64-LFENCE-NEXT: cvtsd2ss %xmm0, %xmm0
; X64-LFENCE-NEXT: callq sink_float@PLT
; X64-LFENCE-NEXT: movss {{.*#+}} xmm0 = mem[0],zero,zero,zero
; X64-LFENCE-NEXT: cvtss2sd %xmm0, %xmm0
; X64-LFENCE-NEXT: callq sink_double@PLT
; X64-LFENCE-NEXT: xorps %xmm0, %xmm0
; X64-LFENCE-NEXT: cvtsi2ssl (%rbx), %xmm0
; X64-LFENCE-NEXT: callq sink_float@PLT
; X64-LFENCE-NEXT: xorps %xmm0, %xmm0
; X64-LFENCE-NEXT: cvtsi2sdq (%r14), %xmm0
; X64-LFENCE-NEXT: callq sink_double@PLT
; X64-LFENCE-NEXT: xorps %xmm0, %xmm0
; X64-LFENCE-NEXT: cvtsi2ssq (%r14), %xmm0
; X64-LFENCE-NEXT: callq sink_float@PLT
; X64-LFENCE-NEXT: xorps %xmm0, %xmm0
; X64-LFENCE-NEXT: cvtsi2sdl (%rbx), %xmm0
; X64-LFENCE-NEXT: callq sink_double@PLT
; X64-LFENCE-NEXT: addq $8, %rsp
; X64-LFENCE-NEXT: popq %rbx
; X64-LFENCE-NEXT: popq %r12
; X64-LFENCE-NEXT: popq %r14
; X64-LFENCE-NEXT: popq %r15
; X64-LFENCE-NEXT: retq
entry:
%f1 = load float, ptr %fptr
call void @sink_float(float %f1)
%d1 = load double, ptr %dptr
call void @sink_double(double %d1)
%f2.d = load double, ptr %dptr
%f2 = fptrunc double %f2.d to float
call void @sink_float(float %f2)
%d2.f = load float, ptr %fptr
%d2 = fpext float %d2.f to double
call void @sink_double(double %d2)
%f3.i = load i32, ptr %i32ptr
%f3 = sitofp i32 %f3.i to float
call void @sink_float(float %f3)
%d3.i = load i64, ptr %i64ptr
%d3 = sitofp i64 %d3.i to double
call void @sink_double(double %d3)
%f4.i = load i64, ptr %i64ptr
%f4 = sitofp i64 %f4.i to float
call void @sink_float(float %f4)
%d4.i = load i32, ptr %i32ptr
%d4 = sitofp i32 %d4.i to double
call void @sink_double(double %d4)
ret void
}
declare void @sink_v4f32(<4 x float>)
declare void @sink_v2f64(<2 x double>)
declare void @sink_v16i8(<16 x i8>)
declare void @sink_v8i16(<8 x i16>)
declare void @sink_v4i32(<4 x i32>)
declare void @sink_v2i64(<2 x i64>)
; Test loads of vectors.
define void @test_vec_loads(ptr %v4f32ptr, ptr %v2f64ptr, ptr %v16i8ptr, ptr %v8i16ptr, ptr %v4i32ptr, ptr %v2i64ptr) nounwind speculative_load_hardening {
; X64-LABEL: test_vec_loads:
; X64: # %bb.0: # %entry
; X64-NEXT: pushq %rbp
; X64-NEXT: pushq %r15
; X64-NEXT: pushq %r14
; X64-NEXT: pushq %r13
; X64-NEXT: pushq %r12
; X64-NEXT: pushq %rbx
; X64-NEXT: pushq %rax
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq %r9, %rbx
; X64-NEXT: movq %r8, %r14
; X64-NEXT: movq %rcx, %r15
; X64-NEXT: movq %rdx, %r12
; X64-NEXT: movq %rsi, %r13
; X64-NEXT: movq $-1, %rbp
; X64-NEXT: sarq $63, %rax
; X64-NEXT: orq %rax, %rdi
; X64-NEXT: movaps (%rdi), %xmm0
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: callq sink_v4f32@PLT
; X64-NEXT: .Lslh_ret_addr15:
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rcx
; X64-NEXT: sarq $63, %rax
; X64-NEXT: cmpq $.Lslh_ret_addr15, %rcx
; X64-NEXT: cmovneq %rbp, %rax
; X64-NEXT: orq %rax, %r13
; X64-NEXT: movaps (%r13), %xmm0
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: callq sink_v2f64@PLT
; X64-NEXT: .Lslh_ret_addr16:
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rcx
; X64-NEXT: sarq $63, %rax
; X64-NEXT: cmpq $.Lslh_ret_addr16, %rcx
; X64-NEXT: cmovneq %rbp, %rax
; X64-NEXT: orq %rax, %r12
; X64-NEXT: movaps (%r12), %xmm0
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: callq sink_v16i8@PLT
; X64-NEXT: .Lslh_ret_addr17:
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rcx
; X64-NEXT: sarq $63, %rax
; X64-NEXT: cmpq $.Lslh_ret_addr17, %rcx
; X64-NEXT: cmovneq %rbp, %rax
; X64-NEXT: orq %rax, %r15
; X64-NEXT: movaps (%r15), %xmm0
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: callq sink_v8i16@PLT
; X64-NEXT: .Lslh_ret_addr18:
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rcx
; X64-NEXT: sarq $63, %rax
; X64-NEXT: cmpq $.Lslh_ret_addr18, %rcx
; X64-NEXT: cmovneq %rbp, %rax
; X64-NEXT: orq %rax, %r14
; X64-NEXT: movaps (%r14), %xmm0
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: callq sink_v4i32@PLT
; X64-NEXT: .Lslh_ret_addr19:
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rcx
; X64-NEXT: sarq $63, %rax
; X64-NEXT: cmpq $.Lslh_ret_addr19, %rcx
; X64-NEXT: cmovneq %rbp, %rax
; X64-NEXT: orq %rax, %rbx
; X64-NEXT: movaps (%rbx), %xmm0
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: callq sink_v2i64@PLT
; X64-NEXT: .Lslh_ret_addr20:
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rcx
; X64-NEXT: sarq $63, %rax
; X64-NEXT: cmpq $.Lslh_ret_addr20, %rcx
; X64-NEXT: cmovneq %rbp, %rax
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: addq $8, %rsp
; X64-NEXT: popq %rbx
; X64-NEXT: popq %r12
; X64-NEXT: popq %r13
; X64-NEXT: popq %r14
; X64-NEXT: popq %r15
; X64-NEXT: popq %rbp
; X64-NEXT: retq
;
; X64-LFENCE-LABEL: test_vec_loads:
; X64-LFENCE: # %bb.0: # %entry
; X64-LFENCE-NEXT: pushq %r15
; X64-LFENCE-NEXT: pushq %r14
; X64-LFENCE-NEXT: pushq %r13
; X64-LFENCE-NEXT: pushq %r12
; X64-LFENCE-NEXT: pushq %rbx
; X64-LFENCE-NEXT: movq %r9, %rbx
; X64-LFENCE-NEXT: movq %r8, %r14
; X64-LFENCE-NEXT: movq %rcx, %r15
; X64-LFENCE-NEXT: movq %rdx, %r12
; X64-LFENCE-NEXT: movq %rsi, %r13
; X64-LFENCE-NEXT: movaps (%rdi), %xmm0
; X64-LFENCE-NEXT: callq sink_v4f32@PLT
; X64-LFENCE-NEXT: movaps (%r13), %xmm0
; X64-LFENCE-NEXT: callq sink_v2f64@PLT
; X64-LFENCE-NEXT: movaps (%r12), %xmm0
; X64-LFENCE-NEXT: callq sink_v16i8@PLT
; X64-LFENCE-NEXT: movaps (%r15), %xmm0
; X64-LFENCE-NEXT: callq sink_v8i16@PLT
; X64-LFENCE-NEXT: movaps (%r14), %xmm0
; X64-LFENCE-NEXT: callq sink_v4i32@PLT
; X64-LFENCE-NEXT: movaps (%rbx), %xmm0
; X64-LFENCE-NEXT: callq sink_v2i64@PLT
; X64-LFENCE-NEXT: popq %rbx
; X64-LFENCE-NEXT: popq %r12
; X64-LFENCE-NEXT: popq %r13
; X64-LFENCE-NEXT: popq %r14
; X64-LFENCE-NEXT: popq %r15
; X64-LFENCE-NEXT: retq
entry:
%x1 = load <4 x float>, ptr %v4f32ptr
call void @sink_v4f32(<4 x float> %x1)
%x2 = load <2 x double>, ptr %v2f64ptr
call void @sink_v2f64(<2 x double> %x2)
%x3 = load <16 x i8>, ptr %v16i8ptr
call void @sink_v16i8(<16 x i8> %x3)
%x4 = load <8 x i16>, ptr %v8i16ptr
call void @sink_v8i16(<8 x i16> %x4)
%x5 = load <4 x i32>, ptr %v4i32ptr
call void @sink_v4i32(<4 x i32> %x5)
%x6 = load <2 x i64>, ptr %v2i64ptr
call void @sink_v2i64(<2 x i64> %x6)
ret void
}
define void @test_deferred_hardening(ptr %ptr1, ptr %ptr2, i32 %x) nounwind speculative_load_hardening {
; X64-LABEL: test_deferred_hardening:
; X64: # %bb.0: # %entry
; X64-NEXT: pushq %r15
; X64-NEXT: pushq %r14
; X64-NEXT: pushq %rbx
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq %rsi, %r14
; X64-NEXT: movq %rdi, %rbx
; X64-NEXT: movq $-1, %r15
; X64-NEXT: sarq $63, %rax
; X64-NEXT: movl (%rdi), %edi
; X64-NEXT: incl %edi
; X64-NEXT: imull %edx, %edi
; X64-NEXT: orl %eax, %edi
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: callq sink@PLT
; X64-NEXT: .Lslh_ret_addr21:
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rcx
; X64-NEXT: sarq $63, %rax
; X64-NEXT: cmpq $.Lslh_ret_addr21, %rcx
; X64-NEXT: cmovneq %r15, %rax
; X64-NEXT: movl (%rbx), %ecx
; X64-NEXT: movl (%r14), %edx
; X64-NEXT: leal 1(%rcx,%rdx), %edi
; X64-NEXT: orl %eax, %edi
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: callq sink@PLT
; X64-NEXT: .Lslh_ret_addr22:
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rcx
; X64-NEXT: sarq $63, %rax
; X64-NEXT: cmpq $.Lslh_ret_addr22, %rcx
; X64-NEXT: cmovneq %r15, %rax
; X64-NEXT: movl (%rbx), %edi
; X64-NEXT: shll $7, %edi
; X64-NEXT: orl %eax, %edi
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: callq sink@PLT
; X64-NEXT: .Lslh_ret_addr23:
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rcx
; X64-NEXT: sarq $63, %rax
; X64-NEXT: cmpq $.Lslh_ret_addr23, %rcx
; X64-NEXT: cmovneq %r15, %rax
; X64-NEXT: movswl (%rbx), %edi
; X64-NEXT: notl %edi
; X64-NEXT: shrl $7, %edi
; X64-NEXT: orl $-65536, %edi # imm = 0xFFFF0000
; X64-NEXT: orl %eax, %edi
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: callq sink@PLT
; X64-NEXT: .Lslh_ret_addr24:
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rcx
; X64-NEXT: sarq $63, %rax
; X64-NEXT: cmpq $.Lslh_ret_addr24, %rcx
; X64-NEXT: cmovneq %r15, %rax
; X64-NEXT: movzwl (%rbx), %ecx
; X64-NEXT: rolw $9, %cx
; X64-NEXT: movswl %cx, %edi
; X64-NEXT: negl %edi
; X64-NEXT: orl %eax, %edi
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: callq sink@PLT
; X64-NEXT: .Lslh_ret_addr25:
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq -{{[0-9]+}}(%rsp), %rcx
; X64-NEXT: sarq $63, %rax
; X64-NEXT: cmpq $.Lslh_ret_addr25, %rcx
; X64-NEXT: cmovneq %r15, %rax
; X64-NEXT: shlq $47, %rax
; X64-NEXT: orq %rax, %rsp
; X64-NEXT: popq %rbx
; X64-NEXT: popq %r14
; X64-NEXT: popq %r15
; X64-NEXT: retq
;
; X64-LFENCE-LABEL: test_deferred_hardening:
; X64-LFENCE: # %bb.0: # %entry
; X64-LFENCE-NEXT: pushq %r14
; X64-LFENCE-NEXT: pushq %rbx
; X64-LFENCE-NEXT: pushq %rax
; X64-LFENCE-NEXT: movq %rsi, %r14
; X64-LFENCE-NEXT: movq %rdi, %rbx
; X64-LFENCE-NEXT: movl (%rdi), %edi
; X64-LFENCE-NEXT: incl %edi
; X64-LFENCE-NEXT: imull %edx, %edi
; X64-LFENCE-NEXT: callq sink@PLT
; X64-LFENCE-NEXT: movl (%rbx), %eax
; X64-LFENCE-NEXT: movl (%r14), %ecx
; X64-LFENCE-NEXT: leal 1(%rax,%rcx), %edi
; X64-LFENCE-NEXT: callq sink@PLT
; X64-LFENCE-NEXT: movl (%rbx), %edi
; X64-LFENCE-NEXT: shll $7, %edi
; X64-LFENCE-NEXT: callq sink@PLT
; X64-LFENCE-NEXT: movswl (%rbx), %edi
; X64-LFENCE-NEXT: notl %edi
; X64-LFENCE-NEXT: shrl $7, %edi
; X64-LFENCE-NEXT: orl $-65536, %edi # imm = 0xFFFF0000
; X64-LFENCE-NEXT: callq sink@PLT
; X64-LFENCE-NEXT: movzwl (%rbx), %eax
; X64-LFENCE-NEXT: rolw $9, %ax
; X64-LFENCE-NEXT: movswl %ax, %edi
; X64-LFENCE-NEXT: negl %edi
; X64-LFENCE-NEXT: callq sink@PLT
; X64-LFENCE-NEXT: addq $8, %rsp
; X64-LFENCE-NEXT: popq %rbx
; X64-LFENCE-NEXT: popq %r14
; X64-LFENCE-NEXT: retq
entry:
%a1 = load i32, ptr %ptr1
%a2 = add i32 %a1, 1
%a3 = mul i32 %a2, %x
call void @sink(i32 %a3)
%b1 = load i32, ptr %ptr1
%b2 = add i32 %b1, 1
%b3 = load i32, ptr %ptr2
%b4 = add i32 %b2, %b3
call void @sink(i32 %b4)
%c1 = load i32, ptr %ptr1
%c2 = shl i32 %c1, 7
call void @sink(i32 %c2)
%d1 = load i32, ptr %ptr1
; Check trunc and integer ops narrower than i32.
%d2 = trunc i32 %d1 to i16
%d3 = ashr i16 %d2, 7
%d4 = zext i16 %d3 to i32
%d5 = xor i32 %d4, -1
call void @sink(i32 %d5)
%e1 = load i32, ptr %ptr1
%e2 = trunc i32 %e1 to i16
%e3 = lshr i16 %e2, 7
%e4 = shl i16 %e2, 9
%e5 = or i16 %e3, %e4
%e6 = sext i16 %e5 to i32
%e7 = sub i32 0, %e6
call void @sink(i32 %e7)
ret void
}
; Make sure we don't crash on idempotent atomic operations which have a
; hardcoded reference to RSP+offset.
define void @idempotent_atomic(ptr %x) speculative_load_hardening {
; X64-LABEL: idempotent_atomic:
; X64: # %bb.0:
; X64-NEXT: lock orl $0, -{{[0-9]+}}(%rsp)
; X64-NEXT: retq
;
; X64-LFENCE-LABEL: idempotent_atomic:
; X64-LFENCE: # %bb.0:
; X64-LFENCE-NEXT: lock orl $0, -{{[0-9]+}}(%rsp)
; X64-LFENCE-NEXT: retq
%tmp = atomicrmw or ptr %x, i32 0 seq_cst
ret void
}
; Make sure we don't crash on longjmps (PR60081).
declare void @llvm.eh.sjlj.longjmp(ptr)
define void @test_longjmp(ptr %env) speculative_load_hardening {
; X64-LABEL: test_longjmp:
; X64: # %bb.0:
; X64-NEXT: pushq %rbp
; X64-NEXT: .cfi_def_cfa_offset 16
; X64-NEXT: .cfi_offset %rbp, -16
; X64-NEXT: movq %rsp, %rax
; X64-NEXT: movq $-1, %rcx
; X64-NEXT: sarq $63, %rax
; X64-NEXT: orq %rax, %rdi
; X64-NEXT: movq (%rdi), %rbp
; X64-NEXT: movq 8(%rdi), %rcx
; X64-NEXT: movq 16(%rdi), %rsp
; X64-NEXT: orq %rax, %rcx
; X64-NEXT: jmpq *%rcx
;
; X64-LFENCE-LABEL: test_longjmp:
; X64-LFENCE: # %bb.0:
; X64-LFENCE-NEXT: pushq %rbp
; X64-LFENCE-NEXT: .cfi_def_cfa_offset 16
; X64-LFENCE-NEXT: .cfi_offset %rbp, -16
; X64-LFENCE-NEXT: movq (%rdi), %rbp
; X64-LFENCE-NEXT: movq 8(%rdi), %rax
; X64-LFENCE-NEXT: movq 16(%rdi), %rsp
; X64-LFENCE-NEXT: jmpq *%rax
call void @llvm.eh.sjlj.longjmp(ptr %env)
unreachable
}