; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py ; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -x86-speculative-load-hardening -data-sections | FileCheck %s --check-prefix=X64 ; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -x86-speculative-load-hardening -data-sections -mattr=+retpoline | FileCheck %s --check-prefix=X64-RETPOLINE ; ; FIXME: Add support for 32-bit. @global_fnptr = external global i32 ()* @global_blockaddrs = constant [4 x i8*] [ i8* blockaddress(@test_indirectbr_global, %bb0), i8* blockaddress(@test_indirectbr_global, %bb1), i8* blockaddress(@test_indirectbr_global, %bb2), i8* blockaddress(@test_indirectbr_global, %bb3) ] define i32 @test_indirect_call(i32 ()** %ptr) nounwind { ; X64-LABEL: test_indirect_call: ; X64: # %bb.0: # %entry ; X64-NEXT: pushq %rax ; X64-NEXT: movq %rsp, %rax ; X64-NEXT: movq $-1, %rcx ; X64-NEXT: sarq $63, %rax ; X64-NEXT: movq (%rdi), %rcx ; X64-NEXT: orq %rax, %rcx ; X64-NEXT: shlq $47, %rax ; X64-NEXT: orq %rax, %rsp ; X64-NEXT: callq *%rcx ; X64-NEXT: movq %rsp, %rcx ; X64-NEXT: sarq $63, %rcx ; X64-NEXT: shlq $47, %rcx ; X64-NEXT: orq %rcx, %rsp ; X64-NEXT: popq %rcx ; X64-NEXT: retq ; ; X64-RETPOLINE-LABEL: test_indirect_call: ; X64-RETPOLINE: # %bb.0: # %entry ; X64-RETPOLINE-NEXT: pushq %rax ; X64-RETPOLINE-NEXT: movq %rsp, %rax ; X64-RETPOLINE-NEXT: movq $-1, %rcx ; X64-RETPOLINE-NEXT: sarq $63, %rax ; X64-RETPOLINE-NEXT: movq (%rdi), %r11 ; X64-RETPOLINE-NEXT: orq %rax, %r11 ; X64-RETPOLINE-NEXT: shlq $47, %rax ; X64-RETPOLINE-NEXT: orq %rax, %rsp ; X64-RETPOLINE-NEXT: callq __llvm_retpoline_r11 ; X64-RETPOLINE-NEXT: movq %rsp, %rcx ; X64-RETPOLINE-NEXT: sarq $63, %rcx ; X64-RETPOLINE-NEXT: shlq $47, %rcx ; X64-RETPOLINE-NEXT: orq %rcx, %rsp ; X64-RETPOLINE-NEXT: popq %rcx ; X64-RETPOLINE-NEXT: retq entry: %fp = load i32 ()*, i32 ()** %ptr %v = call i32 %fp() ret i32 %v } define i32 @test_indirect_tail_call(i32 ()** %ptr) nounwind { ; X64-LABEL: test_indirect_tail_call: ; X64: # %bb.0: # %entry ; X64-NEXT: movq %rsp, %rax ; X64-NEXT: movq $-1, %rcx ; X64-NEXT: sarq $63, %rax ; X64-NEXT: movq (%rdi), %rcx ; X64-NEXT: orq %rax, %rcx ; X64-NEXT: shlq $47, %rax ; X64-NEXT: orq %rax, %rsp ; X64-NEXT: jmpq *%rcx # TAILCALL ; ; X64-RETPOLINE-LABEL: test_indirect_tail_call: ; X64-RETPOLINE: # %bb.0: # %entry ; X64-RETPOLINE-NEXT: movq %rsp, %rax ; X64-RETPOLINE-NEXT: movq $-1, %rcx ; X64-RETPOLINE-NEXT: sarq $63, %rax ; X64-RETPOLINE-NEXT: movq (%rdi), %r11 ; X64-RETPOLINE-NEXT: orq %rax, %r11 ; X64-RETPOLINE-NEXT: shlq $47, %rax ; X64-RETPOLINE-NEXT: orq %rax, %rsp ; X64-RETPOLINE-NEXT: jmp __llvm_retpoline_r11 # TAILCALL entry: %fp = load i32 ()*, i32 ()** %ptr %v = tail call i32 %fp() ret i32 %v } define i32 @test_indirect_call_global() nounwind { ; X64-LABEL: test_indirect_call_global: ; X64: # %bb.0: # %entry ; X64-NEXT: pushq %rax ; X64-NEXT: movq %rsp, %rax ; X64-NEXT: movq $-1, %rcx ; X64-NEXT: sarq $63, %rax ; X64-NEXT: movq {{.*}}(%rip), %rcx ; X64-NEXT: orq %rax, %rcx ; X64-NEXT: shlq $47, %rax ; X64-NEXT: orq %rax, %rsp ; X64-NEXT: callq *%rcx ; X64-NEXT: movq %rsp, %rcx ; X64-NEXT: sarq $63, %rcx ; X64-NEXT: shlq $47, %rcx ; X64-NEXT: orq %rcx, %rsp ; X64-NEXT: popq %rcx ; X64-NEXT: retq ; ; X64-RETPOLINE-LABEL: test_indirect_call_global: ; X64-RETPOLINE: # %bb.0: # %entry ; X64-RETPOLINE-NEXT: pushq %rax ; X64-RETPOLINE-NEXT: movq %rsp, %rax ; X64-RETPOLINE-NEXT: movq $-1, %rcx ; X64-RETPOLINE-NEXT: sarq $63, %rax ; X64-RETPOLINE-NEXT: movq {{.*}}(%rip), %r11 ; X64-RETPOLINE-NEXT: shlq $47, %rax ; X64-RETPOLINE-NEXT: orq %rax, %rsp ; X64-RETPOLINE-NEXT: callq __llvm_retpoline_r11 ; X64-RETPOLINE-NEXT: movq %rsp, %rcx ; X64-RETPOLINE-NEXT: sarq $63, %rcx ; X64-RETPOLINE-NEXT: shlq $47, %rcx ; X64-RETPOLINE-NEXT: orq %rcx, %rsp ; X64-RETPOLINE-NEXT: popq %rcx ; X64-RETPOLINE-NEXT: retq entry: %fp = load i32 ()*, i32 ()** @global_fnptr %v = call i32 %fp() ret i32 %v } define i32 @test_indirect_tail_call_global() nounwind { ; X64-LABEL: test_indirect_tail_call_global: ; X64: # %bb.0: # %entry ; X64-NEXT: movq %rsp, %rax ; X64-NEXT: movq $-1, %rcx ; X64-NEXT: sarq $63, %rax ; X64-NEXT: movq {{.*}}(%rip), %rcx ; X64-NEXT: orq %rax, %rcx ; X64-NEXT: shlq $47, %rax ; X64-NEXT: orq %rax, %rsp ; X64-NEXT: jmpq *%rcx # TAILCALL ; ; X64-RETPOLINE-LABEL: test_indirect_tail_call_global: ; X64-RETPOLINE: # %bb.0: # %entry ; X64-RETPOLINE-NEXT: movq %rsp, %rax ; X64-RETPOLINE-NEXT: movq $-1, %rcx ; X64-RETPOLINE-NEXT: sarq $63, %rax ; X64-RETPOLINE-NEXT: movq {{.*}}(%rip), %r11 ; X64-RETPOLINE-NEXT: shlq $47, %rax ; X64-RETPOLINE-NEXT: orq %rax, %rsp ; X64-RETPOLINE-NEXT: jmp __llvm_retpoline_r11 # TAILCALL entry: %fp = load i32 ()*, i32 ()** @global_fnptr %v = tail call i32 %fp() ret i32 %v } define i32 @test_indirectbr(i8** %ptr) nounwind { ; X64-LABEL: test_indirectbr: ; X64: # %bb.0: # %entry ; X64-NEXT: movq %rsp, %rcx ; X64-NEXT: movq $-1, %rax ; X64-NEXT: sarq $63, %rcx ; X64-NEXT: movq (%rdi), %rax ; X64-NEXT: orq %rcx, %rax ; X64-NEXT: jmpq *%rax ; X64-NEXT: .LBB4_1: # %bb0 ; X64-NEXT: movl $2, %eax ; X64-NEXT: jmp .LBB4_2 ; X64-NEXT: .LBB4_4: # %bb2 ; X64-NEXT: movl $13, %eax ; X64-NEXT: jmp .LBB4_2 ; X64-NEXT: .LBB4_5: # %bb3 ; X64-NEXT: movl $42, %eax ; X64-NEXT: jmp .LBB4_2 ; X64-NEXT: .LBB4_3: # %bb1 ; X64-NEXT: movl $7, %eax ; X64-NEXT: .LBB4_2: # %bb0 ; X64-NEXT: shlq $47, %rcx ; X64-NEXT: orq %rcx, %rsp ; X64-NEXT: retq ; ; X64-RETPOLINE-LABEL: test_indirectbr: ; X64-RETPOLINE: # %bb.0: # %entry entry: %a = load i8*, i8** %ptr indirectbr i8* %a, [ label %bb0, label %bb1, label %bb2, label %bb3 ] bb0: ret i32 2 bb1: ret i32 7 bb2: ret i32 13 bb3: ret i32 42 } define i32 @test_indirectbr_global(i32 %idx) nounwind { ; X64-LABEL: test_indirectbr_global: ; X64: # %bb.0: # %entry ; X64-NEXT: movq %rsp, %rcx ; X64-NEXT: movq $-1, %rax ; X64-NEXT: sarq $63, %rcx ; X64-NEXT: movslq %edi, %rax ; X64-NEXT: movq global_blockaddrs(,%rax,8), %rax ; X64-NEXT: orq %rcx, %rax ; X64-NEXT: jmpq *%rax ; X64-NEXT: .Ltmp0: # Block address taken ; X64-NEXT: .LBB5_1: # %bb0 ; X64-NEXT: movl $2, %eax ; X64-NEXT: jmp .LBB5_2 ; X64-NEXT: .Ltmp1: # Block address taken ; X64-NEXT: .LBB5_4: # %bb2 ; X64-NEXT: movl $13, %eax ; X64-NEXT: jmp .LBB5_2 ; X64-NEXT: .Ltmp2: # Block address taken ; X64-NEXT: .LBB5_5: # %bb3 ; X64-NEXT: movl $42, %eax ; X64-NEXT: jmp .LBB5_2 ; X64-NEXT: .Ltmp3: # Block address taken ; X64-NEXT: .LBB5_3: # %bb1 ; X64-NEXT: movl $7, %eax ; X64-NEXT: .LBB5_2: # %bb0 ; X64-NEXT: shlq $47, %rcx ; X64-NEXT: orq %rcx, %rsp ; X64-NEXT: retq ; ; X64-RETPOLINE-LABEL: test_indirectbr_global: ; X64-RETPOLINE: # %bb.0: # %entry ; X64-RETPOLINE-NEXT: movq %rsp, %rcx ; X64-RETPOLINE-NEXT: movq $-1, %rax ; X64-RETPOLINE-NEXT: sarq $63, %rcx ; X64-RETPOLINE-NEXT: movslq %edi, %rdx ; X64-RETPOLINE-NEXT: movq global_blockaddrs(,%rdx,8), %rdx ; X64-RETPOLINE-NEXT: orq %rcx, %rdx ; X64-RETPOLINE-NEXT: cmpq $2, %rdx ; X64-RETPOLINE-NEXT: je .LBB6_5 ; X64-RETPOLINE-NEXT: # %bb.1: # %entry ; X64-RETPOLINE-NEXT: cmoveq %rax, %rcx ; X64-RETPOLINE-NEXT: cmpq $3, %rdx ; X64-RETPOLINE-NEXT: je .LBB6_6 ; X64-RETPOLINE-NEXT: # %bb.2: # %entry ; X64-RETPOLINE-NEXT: cmoveq %rax, %rcx ; X64-RETPOLINE-NEXT: cmpq $4, %rdx ; X64-RETPOLINE-NEXT: jne .LBB6_3 ; X64-RETPOLINE-NEXT: .Ltmp0: # Block address taken ; X64-RETPOLINE-NEXT: # %bb.7: # %bb3 ; X64-RETPOLINE-NEXT: cmovneq %rax, %rcx ; X64-RETPOLINE-NEXT: movl $42, %eax ; X64-RETPOLINE-NEXT: jmp .LBB6_4 ; X64-RETPOLINE-NEXT: .Ltmp1: # Block address taken ; X64-RETPOLINE-NEXT: .LBB6_5: # %bb1 ; X64-RETPOLINE-NEXT: cmovneq %rax, %rcx ; X64-RETPOLINE-NEXT: movl $7, %eax ; X64-RETPOLINE-NEXT: jmp .LBB6_4 ; X64-RETPOLINE-NEXT: .Ltmp2: # Block address taken ; X64-RETPOLINE-NEXT: .LBB6_6: # %bb2 ; X64-RETPOLINE-NEXT: cmovneq %rax, %rcx ; X64-RETPOLINE-NEXT: movl $13, %eax ; X64-RETPOLINE-NEXT: jmp .LBB6_4 ; X64-RETPOLINE-NEXT: .Ltmp3: # Block address taken ; X64-RETPOLINE-NEXT: .LBB6_3: # %bb0 ; X64-RETPOLINE-NEXT: cmoveq %rax, %rcx ; X64-RETPOLINE-NEXT: movl $2, %eax ; X64-RETPOLINE-NEXT: .LBB6_4: # %bb0 ; X64-RETPOLINE-NEXT: shlq $47, %rcx ; X64-RETPOLINE-NEXT: orq %rcx, %rsp ; X64-RETPOLINE-NEXT: retq entry: %ptr = getelementptr [4 x i8*], [4 x i8*]* @global_blockaddrs, i32 0, i32 %idx %a = load i8*, i8** %ptr indirectbr i8* %a, [ label %bb0, label %bb1, label %bb2, label %bb3 ] bb0: ret i32 2 bb1: ret i32 7 bb2: ret i32 13 bb3: ret i32 42 } ; This function's switch is crafted to trigger jump-table lowering in the x86 ; backend so that we can test how the exact jump table lowering behaves. define i32 @test_switch_jumptable(i32 %idx) nounwind { ; X64-LABEL: test_switch_jumptable: ; X64: # %bb.0: # %entry ; X64-NEXT: movq %rsp, %rcx ; X64-NEXT: movq $-1, %rax ; X64-NEXT: sarq $63, %rcx ; X64-NEXT: cmpl $3, %edi ; X64-NEXT: ja .LBB6_2 ; X64-NEXT: # %bb.1: # %entry ; X64-NEXT: cmovaq %rax, %rcx ; X64-NEXT: movl %edi, %eax ; X64-NEXT: movq .LJTI6_0(,%rax,8), %rax ; X64-NEXT: orq %rcx, %rax ; X64-NEXT: jmpq *%rax ; X64-NEXT: .LBB6_3: # %bb1 ; X64-NEXT: movl $7, %eax ; X64-NEXT: jmp .LBB6_4 ; X64-NEXT: .LBB6_2: # %bb0 ; X64-NEXT: cmovbeq %rax, %rcx ; X64-NEXT: movl $2, %eax ; X64-NEXT: jmp .LBB6_4 ; X64-NEXT: .LBB6_5: # %bb2 ; X64-NEXT: movl $13, %eax ; X64-NEXT: jmp .LBB6_4 ; X64-NEXT: .LBB6_6: # %bb3 ; X64-NEXT: movl $42, %eax ; X64-NEXT: jmp .LBB6_4 ; X64-NEXT: .LBB6_7: # %bb5 ; X64-NEXT: movl $11, %eax ; X64-NEXT: .LBB6_4: # %bb1 ; X64-NEXT: shlq $47, %rcx ; X64-NEXT: orq %rcx, %rsp ; X64-NEXT: retq ; ; X64-RETPOLINE-LABEL: test_switch_jumptable: ; X64-RETPOLINE: # %bb.0: # %entry ; X64-RETPOLINE-NEXT: movq %rsp, %rcx ; X64-RETPOLINE-NEXT: movq $-1, %rax ; X64-RETPOLINE-NEXT: sarq $63, %rcx ; X64-RETPOLINE-NEXT: cmpl $1, %edi ; X64-RETPOLINE-NEXT: jg .LBB7_4 ; X64-RETPOLINE-NEXT: # %bb.1: # %entry ; X64-RETPOLINE-NEXT: cmovgq %rax, %rcx ; X64-RETPOLINE-NEXT: testl %edi, %edi ; X64-RETPOLINE-NEXT: je .LBB7_8 ; X64-RETPOLINE-NEXT: # %bb.2: # %entry ; X64-RETPOLINE-NEXT: cmoveq %rax, %rcx ; X64-RETPOLINE-NEXT: cmpl $1, %edi ; X64-RETPOLINE-NEXT: jne .LBB7_6 ; X64-RETPOLINE-NEXT: # %bb.3: # %bb2 ; X64-RETPOLINE-NEXT: cmovneq %rax, %rcx ; X64-RETPOLINE-NEXT: movl $13, %eax ; X64-RETPOLINE-NEXT: jmp .LBB7_7 ; X64-RETPOLINE-NEXT: .LBB7_4: # %entry ; X64-RETPOLINE-NEXT: cmovleq %rax, %rcx ; X64-RETPOLINE-NEXT: cmpl $2, %edi ; X64-RETPOLINE-NEXT: je .LBB7_9 ; X64-RETPOLINE-NEXT: # %bb.5: # %entry ; X64-RETPOLINE-NEXT: cmoveq %rax, %rcx ; X64-RETPOLINE-NEXT: cmpl $3, %edi ; X64-RETPOLINE-NEXT: jne .LBB7_6 ; X64-RETPOLINE-NEXT: # %bb.10: # %bb5 ; X64-RETPOLINE-NEXT: cmovneq %rax, %rcx ; X64-RETPOLINE-NEXT: movl $11, %eax ; X64-RETPOLINE-NEXT: jmp .LBB7_7 ; X64-RETPOLINE-NEXT: .LBB7_6: ; X64-RETPOLINE-NEXT: cmoveq %rax, %rcx ; X64-RETPOLINE-NEXT: movl $2, %eax ; X64-RETPOLINE-NEXT: jmp .LBB7_7 ; X64-RETPOLINE-NEXT: .LBB7_8: # %bb1 ; X64-RETPOLINE-NEXT: cmovneq %rax, %rcx ; X64-RETPOLINE-NEXT: movl $7, %eax ; X64-RETPOLINE-NEXT: jmp .LBB7_7 ; X64-RETPOLINE-NEXT: .LBB7_9: # %bb3 ; X64-RETPOLINE-NEXT: cmovneq %rax, %rcx ; X64-RETPOLINE-NEXT: movl $42, %eax ; X64-RETPOLINE-NEXT: .LBB7_7: # %bb0 ; X64-RETPOLINE-NEXT: shlq $47, %rcx ; X64-RETPOLINE-NEXT: orq %rcx, %rsp ; X64-RETPOLINE-NEXT: retq entry: switch i32 %idx, label %bb0 [ i32 0, label %bb1 i32 1, label %bb2 i32 2, label %bb3 i32 3, label %bb5 ] bb0: ret i32 2 bb1: ret i32 7 bb2: ret i32 13 bb3: ret i32 42 bb5: ret i32 11 }