1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -x86-speculative-load-hardening -data-sections | FileCheck %s --check-prefix=X64 3; RUN: llc < %s -mtriple=x86_64-unknown-linux-gnu -x86-speculative-load-hardening -data-sections -mattr=+retpoline | FileCheck %s --check-prefix=X64-RETPOLINE 4; 5; FIXME: Add support for 32-bit. 6 7@global_fnptr = external global i32 ()* 8 9@global_blockaddrs = constant [4 x i8*] [ 10 i8* blockaddress(@test_indirectbr_global, %bb0), 11 i8* blockaddress(@test_indirectbr_global, %bb1), 12 i8* blockaddress(@test_indirectbr_global, %bb2), 13 i8* blockaddress(@test_indirectbr_global, %bb3) 14] 15 16define i32 @test_indirect_call(i32 ()** %ptr) nounwind { 17; X64-LABEL: test_indirect_call: 18; X64: # %bb.0: # %entry 19; X64-NEXT: pushq %rax 20; X64-NEXT: movq %rsp, %rax 21; X64-NEXT: movq $-1, %rcx 22; X64-NEXT: sarq $63, %rax 23; X64-NEXT: movq (%rdi), %rcx 24; X64-NEXT: orq %rax, %rcx 25; X64-NEXT: shlq $47, %rax 26; X64-NEXT: orq %rax, %rsp 27; X64-NEXT: callq *%rcx 28; X64-NEXT: movq %rsp, %rcx 29; X64-NEXT: sarq $63, %rcx 30; X64-NEXT: shlq $47, %rcx 31; X64-NEXT: orq %rcx, %rsp 32; X64-NEXT: popq %rcx 33; X64-NEXT: retq 34; 35; X64-RETPOLINE-LABEL: test_indirect_call: 36; X64-RETPOLINE: # %bb.0: # %entry 37; X64-RETPOLINE-NEXT: pushq %rax 38; X64-RETPOLINE-NEXT: movq %rsp, %rax 39; X64-RETPOLINE-NEXT: movq $-1, %rcx 40; X64-RETPOLINE-NEXT: sarq $63, %rax 41; X64-RETPOLINE-NEXT: movq (%rdi), %r11 42; X64-RETPOLINE-NEXT: orq %rax, %r11 43; X64-RETPOLINE-NEXT: shlq $47, %rax 44; X64-RETPOLINE-NEXT: orq %rax, %rsp 45; X64-RETPOLINE-NEXT: callq __llvm_retpoline_r11 46; X64-RETPOLINE-NEXT: movq %rsp, %rcx 47; X64-RETPOLINE-NEXT: sarq $63, %rcx 48; X64-RETPOLINE-NEXT: shlq $47, %rcx 49; X64-RETPOLINE-NEXT: orq %rcx, %rsp 50; X64-RETPOLINE-NEXT: popq %rcx 51; X64-RETPOLINE-NEXT: retq 52entry: 53 %fp = load i32 ()*, i32 ()** %ptr 54 %v = call i32 %fp() 55 ret i32 %v 56} 57 58define i32 @test_indirect_tail_call(i32 ()** %ptr) nounwind { 59; X64-LABEL: test_indirect_tail_call: 60; X64: # %bb.0: # %entry 61; X64-NEXT: movq %rsp, %rax 62; X64-NEXT: movq $-1, %rcx 63; X64-NEXT: sarq $63, %rax 64; X64-NEXT: movq (%rdi), %rcx 65; X64-NEXT: orq %rax, %rcx 66; X64-NEXT: shlq $47, %rax 67; X64-NEXT: orq %rax, %rsp 68; X64-NEXT: jmpq *%rcx # TAILCALL 69; 70; X64-RETPOLINE-LABEL: test_indirect_tail_call: 71; X64-RETPOLINE: # %bb.0: # %entry 72; X64-RETPOLINE-NEXT: movq %rsp, %rax 73; X64-RETPOLINE-NEXT: movq $-1, %rcx 74; X64-RETPOLINE-NEXT: sarq $63, %rax 75; X64-RETPOLINE-NEXT: movq (%rdi), %r11 76; X64-RETPOLINE-NEXT: orq %rax, %r11 77; X64-RETPOLINE-NEXT: shlq $47, %rax 78; X64-RETPOLINE-NEXT: orq %rax, %rsp 79; X64-RETPOLINE-NEXT: jmp __llvm_retpoline_r11 # TAILCALL 80entry: 81 %fp = load i32 ()*, i32 ()** %ptr 82 %v = tail call i32 %fp() 83 ret i32 %v 84} 85 86define i32 @test_indirect_call_global() nounwind { 87; X64-LABEL: test_indirect_call_global: 88; X64: # %bb.0: # %entry 89; X64-NEXT: pushq %rax 90; X64-NEXT: movq %rsp, %rax 91; X64-NEXT: movq $-1, %rcx 92; X64-NEXT: sarq $63, %rax 93; X64-NEXT: movq {{.*}}(%rip), %rcx 94; X64-NEXT: orq %rax, %rcx 95; X64-NEXT: shlq $47, %rax 96; X64-NEXT: orq %rax, %rsp 97; X64-NEXT: callq *%rcx 98; X64-NEXT: movq %rsp, %rcx 99; X64-NEXT: sarq $63, %rcx 100; X64-NEXT: shlq $47, %rcx 101; X64-NEXT: orq %rcx, %rsp 102; X64-NEXT: popq %rcx 103; X64-NEXT: retq 104; 105; X64-RETPOLINE-LABEL: test_indirect_call_global: 106; X64-RETPOLINE: # %bb.0: # %entry 107; X64-RETPOLINE-NEXT: pushq %rax 108; X64-RETPOLINE-NEXT: movq %rsp, %rax 109; X64-RETPOLINE-NEXT: movq $-1, %rcx 110; X64-RETPOLINE-NEXT: sarq $63, %rax 111; X64-RETPOLINE-NEXT: movq {{.*}}(%rip), %r11 112; X64-RETPOLINE-NEXT: shlq $47, %rax 113; X64-RETPOLINE-NEXT: orq %rax, %rsp 114; X64-RETPOLINE-NEXT: callq __llvm_retpoline_r11 115; X64-RETPOLINE-NEXT: movq %rsp, %rcx 116; X64-RETPOLINE-NEXT: sarq $63, %rcx 117; X64-RETPOLINE-NEXT: shlq $47, %rcx 118; X64-RETPOLINE-NEXT: orq %rcx, %rsp 119; X64-RETPOLINE-NEXT: popq %rcx 120; X64-RETPOLINE-NEXT: retq 121entry: 122 %fp = load i32 ()*, i32 ()** @global_fnptr 123 %v = call i32 %fp() 124 ret i32 %v 125} 126 127define i32 @test_indirect_tail_call_global() nounwind { 128; X64-LABEL: test_indirect_tail_call_global: 129; X64: # %bb.0: # %entry 130; X64-NEXT: movq %rsp, %rax 131; X64-NEXT: movq $-1, %rcx 132; X64-NEXT: sarq $63, %rax 133; X64-NEXT: movq {{.*}}(%rip), %rcx 134; X64-NEXT: orq %rax, %rcx 135; X64-NEXT: shlq $47, %rax 136; X64-NEXT: orq %rax, %rsp 137; X64-NEXT: jmpq *%rcx # TAILCALL 138; 139; X64-RETPOLINE-LABEL: test_indirect_tail_call_global: 140; X64-RETPOLINE: # %bb.0: # %entry 141; X64-RETPOLINE-NEXT: movq %rsp, %rax 142; X64-RETPOLINE-NEXT: movq $-1, %rcx 143; X64-RETPOLINE-NEXT: sarq $63, %rax 144; X64-RETPOLINE-NEXT: movq {{.*}}(%rip), %r11 145; X64-RETPOLINE-NEXT: shlq $47, %rax 146; X64-RETPOLINE-NEXT: orq %rax, %rsp 147; X64-RETPOLINE-NEXT: jmp __llvm_retpoline_r11 # TAILCALL 148entry: 149 %fp = load i32 ()*, i32 ()** @global_fnptr 150 %v = tail call i32 %fp() 151 ret i32 %v 152} 153 154define i32 @test_indirectbr(i8** %ptr) nounwind { 155; X64-LABEL: test_indirectbr: 156; X64: # %bb.0: # %entry 157; X64-NEXT: movq %rsp, %rcx 158; X64-NEXT: movq $-1, %rax 159; X64-NEXT: sarq $63, %rcx 160; X64-NEXT: movq (%rdi), %rax 161; X64-NEXT: orq %rcx, %rax 162; X64-NEXT: jmpq *%rax 163; X64-NEXT: .LBB4_1: # %bb0 164; X64-NEXT: movl $2, %eax 165; X64-NEXT: jmp .LBB4_2 166; X64-NEXT: .LBB4_4: # %bb2 167; X64-NEXT: movl $13, %eax 168; X64-NEXT: jmp .LBB4_2 169; X64-NEXT: .LBB4_5: # %bb3 170; X64-NEXT: movl $42, %eax 171; X64-NEXT: jmp .LBB4_2 172; X64-NEXT: .LBB4_3: # %bb1 173; X64-NEXT: movl $7, %eax 174; X64-NEXT: .LBB4_2: # %bb0 175; X64-NEXT: shlq $47, %rcx 176; X64-NEXT: orq %rcx, %rsp 177; X64-NEXT: retq 178; 179; X64-RETPOLINE-LABEL: test_indirectbr: 180; X64-RETPOLINE: # %bb.0: # %entry 181entry: 182 %a = load i8*, i8** %ptr 183 indirectbr i8* %a, [ label %bb0, label %bb1, label %bb2, label %bb3 ] 184 185bb0: 186 ret i32 2 187 188bb1: 189 ret i32 7 190 191bb2: 192 ret i32 13 193 194bb3: 195 ret i32 42 196} 197 198define i32 @test_indirectbr_global(i32 %idx) nounwind { 199; X64-LABEL: test_indirectbr_global: 200; X64: # %bb.0: # %entry 201; X64-NEXT: movq %rsp, %rcx 202; X64-NEXT: movq $-1, %rax 203; X64-NEXT: sarq $63, %rcx 204; X64-NEXT: movslq %edi, %rax 205; X64-NEXT: movq global_blockaddrs(,%rax,8), %rax 206; X64-NEXT: orq %rcx, %rax 207; X64-NEXT: jmpq *%rax 208; X64-NEXT: .Ltmp0: # Block address taken 209; X64-NEXT: .LBB5_1: # %bb0 210; X64-NEXT: movl $2, %eax 211; X64-NEXT: jmp .LBB5_2 212; X64-NEXT: .Ltmp1: # Block address taken 213; X64-NEXT: .LBB5_4: # %bb2 214; X64-NEXT: movl $13, %eax 215; X64-NEXT: jmp .LBB5_2 216; X64-NEXT: .Ltmp2: # Block address taken 217; X64-NEXT: .LBB5_5: # %bb3 218; X64-NEXT: movl $42, %eax 219; X64-NEXT: jmp .LBB5_2 220; X64-NEXT: .Ltmp3: # Block address taken 221; X64-NEXT: .LBB5_3: # %bb1 222; X64-NEXT: movl $7, %eax 223; X64-NEXT: .LBB5_2: # %bb0 224; X64-NEXT: shlq $47, %rcx 225; X64-NEXT: orq %rcx, %rsp 226; X64-NEXT: retq 227; 228; X64-RETPOLINE-LABEL: test_indirectbr_global: 229; X64-RETPOLINE: # %bb.0: # %entry 230; X64-RETPOLINE-NEXT: movq %rsp, %rcx 231; X64-RETPOLINE-NEXT: movq $-1, %rax 232; X64-RETPOLINE-NEXT: sarq $63, %rcx 233; X64-RETPOLINE-NEXT: movslq %edi, %rdx 234; X64-RETPOLINE-NEXT: movq global_blockaddrs(,%rdx,8), %rdx 235; X64-RETPOLINE-NEXT: orq %rcx, %rdx 236; X64-RETPOLINE-NEXT: cmpq $2, %rdx 237; X64-RETPOLINE-NEXT: je .LBB6_5 238; X64-RETPOLINE-NEXT: # %bb.1: # %entry 239; X64-RETPOLINE-NEXT: cmoveq %rax, %rcx 240; X64-RETPOLINE-NEXT: cmpq $3, %rdx 241; X64-RETPOLINE-NEXT: je .LBB6_6 242; X64-RETPOLINE-NEXT: # %bb.2: # %entry 243; X64-RETPOLINE-NEXT: cmoveq %rax, %rcx 244; X64-RETPOLINE-NEXT: cmpq $4, %rdx 245; X64-RETPOLINE-NEXT: jne .LBB6_3 246; X64-RETPOLINE-NEXT: .Ltmp0: # Block address taken 247; X64-RETPOLINE-NEXT: # %bb.7: # %bb3 248; X64-RETPOLINE-NEXT: cmovneq %rax, %rcx 249; X64-RETPOLINE-NEXT: movl $42, %eax 250; X64-RETPOLINE-NEXT: jmp .LBB6_4 251; X64-RETPOLINE-NEXT: .Ltmp1: # Block address taken 252; X64-RETPOLINE-NEXT: .LBB6_5: # %bb1 253; X64-RETPOLINE-NEXT: cmovneq %rax, %rcx 254; X64-RETPOLINE-NEXT: movl $7, %eax 255; X64-RETPOLINE-NEXT: jmp .LBB6_4 256; X64-RETPOLINE-NEXT: .Ltmp2: # Block address taken 257; X64-RETPOLINE-NEXT: .LBB6_6: # %bb2 258; X64-RETPOLINE-NEXT: cmovneq %rax, %rcx 259; X64-RETPOLINE-NEXT: movl $13, %eax 260; X64-RETPOLINE-NEXT: jmp .LBB6_4 261; X64-RETPOLINE-NEXT: .Ltmp3: # Block address taken 262; X64-RETPOLINE-NEXT: .LBB6_3: # %bb0 263; X64-RETPOLINE-NEXT: cmoveq %rax, %rcx 264; X64-RETPOLINE-NEXT: movl $2, %eax 265; X64-RETPOLINE-NEXT: .LBB6_4: # %bb0 266; X64-RETPOLINE-NEXT: shlq $47, %rcx 267; X64-RETPOLINE-NEXT: orq %rcx, %rsp 268; X64-RETPOLINE-NEXT: retq 269entry: 270 %ptr = getelementptr [4 x i8*], [4 x i8*]* @global_blockaddrs, i32 0, i32 %idx 271 %a = load i8*, i8** %ptr 272 indirectbr i8* %a, [ label %bb0, label %bb1, label %bb2, label %bb3 ] 273 274bb0: 275 ret i32 2 276 277bb1: 278 ret i32 7 279 280bb2: 281 ret i32 13 282 283bb3: 284 ret i32 42 285} 286 287; This function's switch is crafted to trigger jump-table lowering in the x86 288; backend so that we can test how the exact jump table lowering behaves. 289define i32 @test_switch_jumptable(i32 %idx) nounwind { 290; X64-LABEL: test_switch_jumptable: 291; X64: # %bb.0: # %entry 292; X64-NEXT: movq %rsp, %rcx 293; X64-NEXT: movq $-1, %rax 294; X64-NEXT: sarq $63, %rcx 295; X64-NEXT: cmpl $3, %edi 296; X64-NEXT: ja .LBB6_2 297; X64-NEXT: # %bb.1: # %entry 298; X64-NEXT: cmovaq %rax, %rcx 299; X64-NEXT: movl %edi, %eax 300; X64-NEXT: movq .LJTI6_0(,%rax,8), %rax 301; X64-NEXT: orq %rcx, %rax 302; X64-NEXT: jmpq *%rax 303; X64-NEXT: .LBB6_3: # %bb1 304; X64-NEXT: movl $7, %eax 305; X64-NEXT: jmp .LBB6_4 306; X64-NEXT: .LBB6_2: # %bb0 307; X64-NEXT: cmovbeq %rax, %rcx 308; X64-NEXT: movl $2, %eax 309; X64-NEXT: jmp .LBB6_4 310; X64-NEXT: .LBB6_5: # %bb2 311; X64-NEXT: movl $13, %eax 312; X64-NEXT: jmp .LBB6_4 313; X64-NEXT: .LBB6_6: # %bb3 314; X64-NEXT: movl $42, %eax 315; X64-NEXT: jmp .LBB6_4 316; X64-NEXT: .LBB6_7: # %bb5 317; X64-NEXT: movl $11, %eax 318; X64-NEXT: .LBB6_4: # %bb1 319; X64-NEXT: shlq $47, %rcx 320; X64-NEXT: orq %rcx, %rsp 321; X64-NEXT: retq 322; 323; X64-RETPOLINE-LABEL: test_switch_jumptable: 324; X64-RETPOLINE: # %bb.0: # %entry 325; X64-RETPOLINE-NEXT: movq %rsp, %rcx 326; X64-RETPOLINE-NEXT: movq $-1, %rax 327; X64-RETPOLINE-NEXT: sarq $63, %rcx 328; X64-RETPOLINE-NEXT: cmpl $1, %edi 329; X64-RETPOLINE-NEXT: jg .LBB7_4 330; X64-RETPOLINE-NEXT: # %bb.1: # %entry 331; X64-RETPOLINE-NEXT: cmovgq %rax, %rcx 332; X64-RETPOLINE-NEXT: testl %edi, %edi 333; X64-RETPOLINE-NEXT: je .LBB7_8 334; X64-RETPOLINE-NEXT: # %bb.2: # %entry 335; X64-RETPOLINE-NEXT: cmoveq %rax, %rcx 336; X64-RETPOLINE-NEXT: cmpl $1, %edi 337; X64-RETPOLINE-NEXT: jne .LBB7_6 338; X64-RETPOLINE-NEXT: # %bb.3: # %bb2 339; X64-RETPOLINE-NEXT: cmovneq %rax, %rcx 340; X64-RETPOLINE-NEXT: movl $13, %eax 341; X64-RETPOLINE-NEXT: jmp .LBB7_7 342; X64-RETPOLINE-NEXT: .LBB7_4: # %entry 343; X64-RETPOLINE-NEXT: cmovleq %rax, %rcx 344; X64-RETPOLINE-NEXT: cmpl $2, %edi 345; X64-RETPOLINE-NEXT: je .LBB7_9 346; X64-RETPOLINE-NEXT: # %bb.5: # %entry 347; X64-RETPOLINE-NEXT: cmoveq %rax, %rcx 348; X64-RETPOLINE-NEXT: cmpl $3, %edi 349; X64-RETPOLINE-NEXT: jne .LBB7_6 350; X64-RETPOLINE-NEXT: # %bb.10: # %bb5 351; X64-RETPOLINE-NEXT: cmovneq %rax, %rcx 352; X64-RETPOLINE-NEXT: movl $11, %eax 353; X64-RETPOLINE-NEXT: jmp .LBB7_7 354; X64-RETPOLINE-NEXT: .LBB7_6: 355; X64-RETPOLINE-NEXT: cmoveq %rax, %rcx 356; X64-RETPOLINE-NEXT: movl $2, %eax 357; X64-RETPOLINE-NEXT: jmp .LBB7_7 358; X64-RETPOLINE-NEXT: .LBB7_8: # %bb1 359; X64-RETPOLINE-NEXT: cmovneq %rax, %rcx 360; X64-RETPOLINE-NEXT: movl $7, %eax 361; X64-RETPOLINE-NEXT: jmp .LBB7_7 362; X64-RETPOLINE-NEXT: .LBB7_9: # %bb3 363; X64-RETPOLINE-NEXT: cmovneq %rax, %rcx 364; X64-RETPOLINE-NEXT: movl $42, %eax 365; X64-RETPOLINE-NEXT: .LBB7_7: # %bb0 366; X64-RETPOLINE-NEXT: shlq $47, %rcx 367; X64-RETPOLINE-NEXT: orq %rcx, %rsp 368; X64-RETPOLINE-NEXT: retq 369entry: 370 switch i32 %idx, label %bb0 [ 371 i32 0, label %bb1 372 i32 1, label %bb2 373 i32 2, label %bb3 374 i32 3, label %bb5 375 ] 376 377bb0: 378 ret i32 2 379 380bb1: 381 ret i32 7 382 383bb2: 384 ret i32 13 385 386bb3: 387 ret i32 42 388 389bb5: 390 ret i32 11 391} 392