516 lines · plain
1; RUN: llc -verify-machineinstrs -mtriple=x86_64-unknown < %s | FileCheck %s --implicit-check-not="jmp.*\*" --implicit-check-not="call.*\*" --check-prefix=X642; RUN: llc -verify-machineinstrs -mtriple=x86_64-unknown -O0 < %s | FileCheck %s --implicit-check-not="jmp.*\*" --implicit-check-not="call.*\*" --check-prefix=X64FAST3 4; RUN: llc -verify-machineinstrs -mtriple=i686-unknown < %s | FileCheck %s --implicit-check-not="jmp.*\*" --implicit-check-not="call.*\*" --check-prefix=X865; RUN: llc -verify-machineinstrs -mtriple=i686-unknown -O0 < %s | FileCheck %s --implicit-check-not="jmp.*\*" --implicit-check-not="call.*\*" --check-prefix=X86FAST6 7declare void @bar(i32)8 9; Test a simple indirect call and tail call.10define void @icall_reg(ptr %fp, i32 %x) #0 {11entry:12 tail call void @bar(i32 %x)13 tail call void %fp(i32 %x)14 tail call void @bar(i32 %x)15 tail call void %fp(i32 %x)16 ret void17}18 19; X64-LABEL: icall_reg:20; X64-DAG: movq %rdi, %[[fp:[^ ]*]]21; X64-DAG: movl %esi, %[[x:[^ ]*]]22; X64: movl %esi, %edi23; X64: callq bar24; X64-DAG: movl %[[x]], %edi25; X64-DAG: movq %[[fp]], %r1126; X64: callq __llvm_retpoline_r1127; X64: movl %[[x]], %edi28; X64: callq bar29; X64-DAG: movl %[[x]], %edi30; X64-DAG: movq %[[fp]], %r1131; X64: jmp __llvm_retpoline_r11 # TAILCALL32 33; X64FAST-LABEL: icall_reg:34; X64FAST: callq bar35; X64FAST: callq __llvm_retpoline_r1136; X64FAST: callq bar37; X64FAST: jmp __llvm_retpoline_r11 # TAILCALL38 39; X86-LABEL: icall_reg:40; X86-DAG: movl 12(%esp), %[[fp:[^ ]*]]41; X86-DAG: movl 16(%esp), %[[x:[^ ]*]]42; X86: pushl %[[x]]43; X86: calll bar44; X86: movl %[[fp]], %eax45; X86: pushl %[[x]]46; X86: calll __llvm_retpoline_eax47; X86: pushl %[[x]]48; X86: calll bar49; X86: movl %[[fp]], %eax50; X86: pushl %[[x]]51; X86: calll __llvm_retpoline_eax52; X86-NOT: # TAILCALL53 54; X86FAST-LABEL: icall_reg:55; X86FAST: calll bar56; X86FAST: calll __llvm_retpoline_eax57; X86FAST: calll bar58; X86FAST: calll __llvm_retpoline_eax59 60 61@global_fp = external dso_local global ptr62 63; Test an indirect call through a global variable.64define void @icall_global_fp(i32 %x, ptr %fpp) #0 {65 %fp1 = load ptr, ptr @global_fp66 call void %fp1(i32 %x)67 %fp2 = load ptr, ptr @global_fp68 tail call void %fp2(i32 %x)69 ret void70}71 72; X64-LABEL: icall_global_fp:73; X64-DAG: movl %edi, %[[x:[^ ]*]]74; X64-DAG: movq global_fp(%rip), %r1175; X64: callq __llvm_retpoline_r1176; X64-DAG: movl %[[x]], %edi77; X64-DAG: movq global_fp(%rip), %r1178; X64: jmp __llvm_retpoline_r11 # TAILCALL79 80; X64FAST-LABEL: icall_global_fp:81; X64FAST: movq global_fp(%rip), %r1182; X64FAST: callq __llvm_retpoline_r1183; X64FAST: movq global_fp(%rip), %r1184; X64FAST: jmp __llvm_retpoline_r11 # TAILCALL85 86; X86-LABEL: icall_global_fp:87; X86: movl global_fp, %eax88; X86: pushl 4(%esp)89; X86: calll __llvm_retpoline_eax90; X86: addl $4, %esp91; X86: movl global_fp, %eax92; X86: jmp __llvm_retpoline_eax # TAILCALL93 94; X86FAST-LABEL: icall_global_fp:95; X86FAST: calll __llvm_retpoline_eax96; X86FAST: jmp __llvm_retpoline_eax # TAILCALL97 98 99%struct.Foo = type { ptr }100 101; Test an indirect call through a vtable.102define void @vcall(ptr %obj) #0 {103 %vptr = load ptr, ptr %obj104 %vslot = getelementptr ptr, ptr %vptr, i32 1105 %fp = load ptr, ptr %vslot106 tail call void %fp(ptr %obj)107 tail call void %fp(ptr %obj)108 ret void109}110 111; X64-LABEL: vcall:112; X64: movq %rdi, %[[obj:[^ ]*]]113; X64: movq (%rdi), %[[vptr:[^ ]*]]114; X64: movq 8(%[[vptr]]), %[[fp:[^ ]*]]115; X64: movq %[[fp]], %r11116; X64: callq __llvm_retpoline_r11117; X64-DAG: movq %[[obj]], %rdi118; X64-DAG: movq %[[fp]], %r11119; X64: jmp __llvm_retpoline_r11 # TAILCALL120 121; X64FAST-LABEL: vcall:122; X64FAST: callq __llvm_retpoline_r11123; X64FAST: jmp __llvm_retpoline_r11 # TAILCALL124 125; X86-LABEL: vcall:126; X86: movl 8(%esp), %[[obj:[^ ]*]]127; X86: movl (%[[obj]]), %[[vptr:[^ ]*]]128; X86: movl 4(%[[vptr]]), %[[fp:[^ ]*]]129; X86: movl %[[fp]], %eax130; X86: pushl %[[obj]]131; X86: calll __llvm_retpoline_eax132; X86: addl $4, %esp133; X86: movl %[[fp]], %eax134; X86: jmp __llvm_retpoline_eax # TAILCALL135 136; X86FAST-LABEL: vcall:137; X86FAST: calll __llvm_retpoline_eax138; X86FAST: jmp __llvm_retpoline_eax # TAILCALL139 140 141declare void @direct_callee()142 143define void @direct_tail() #0 {144 tail call void @direct_callee()145 ret void146}147 148; X64-LABEL: direct_tail:149; X64: jmp direct_callee@PLT # TAILCALL150; X64FAST-LABEL: direct_tail:151; X64FAST: jmp direct_callee@PLT # TAILCALL152; X86-LABEL: direct_tail:153; X86: jmp direct_callee@PLT # TAILCALL154; X86FAST-LABEL: direct_tail:155; X86FAST: jmp direct_callee@PLT # TAILCALL156 157 158declare void @nonlazybind_callee() #2159 160define void @nonlazybind_caller() #0 {161 call void @nonlazybind_callee()162 tail call void @nonlazybind_callee()163 ret void164}165 166; X64-LABEL: nonlazybind_caller:167; X64: movq nonlazybind_callee@GOTPCREL(%rip), %[[REG:.*]]168; X64: movq %[[REG]], %r11169; X64: callq __llvm_retpoline_r11170; X64: movq %[[REG]], %r11171; X64: jmp __llvm_retpoline_r11 # TAILCALL172; X64FAST-LABEL: nonlazybind_caller:173; X64FAST: movq nonlazybind_callee@GOTPCREL(%rip), %r11174; X64FAST: callq __llvm_retpoline_r11175; X64FAST: movq nonlazybind_callee@GOTPCREL(%rip), %r11176; X64FAST: jmp __llvm_retpoline_r11 # TAILCALL177; X86-LABEL: nonlazybind_caller:178; X86: calll nonlazybind_callee@PLT179; X86: jmp nonlazybind_callee@PLT # TAILCALL180; X86FAST-LABEL: nonlazybind_caller:181; X86FAST: calll nonlazybind_callee@PLT182; X86FAST: jmp nonlazybind_callee@PLT # TAILCALL183 184 185; Check that a switch gets lowered using a jump table when retpolines are only186; enabled for calls.187define void @switch_jumptable(ptr %ptr, ptr %sink) #0 {188; X64-LABEL: switch_jumptable:189; X64: jmpq *190; X86-LABEL: switch_jumptable:191; X86: jmpl *192entry:193 br label %header194 195header:196 %i = load volatile i32, ptr %ptr197 switch i32 %i, label %bb0 [198 i32 1, label %bb1199 i32 2, label %bb2200 i32 3, label %bb3201 i32 4, label %bb4202 i32 5, label %bb5203 i32 6, label %bb6204 i32 7, label %bb7205 i32 8, label %bb8206 i32 9, label %bb9207 ]208 209bb0:210 store volatile i64 0, ptr %sink211 br label %header212 213bb1:214 store volatile i64 1, ptr %sink215 br label %header216 217bb2:218 store volatile i64 2, ptr %sink219 br label %header220 221bb3:222 store volatile i64 3, ptr %sink223 br label %header224 225bb4:226 store volatile i64 4, ptr %sink227 br label %header228 229bb5:230 store volatile i64 5, ptr %sink231 br label %header232 233bb6:234 store volatile i64 6, ptr %sink235 br label %header236 237bb7:238 store volatile i64 7, ptr %sink239 br label %header240 241bb8:242 store volatile i64 8, ptr %sink243 br label %header244 245bb9:246 store volatile i64 9, ptr %sink247 br label %header248}249 250 251@indirectbr_preserved.targets = constant [10 x ptr] [ptr blockaddress(@indirectbr_preserved, %bb0),252 ptr blockaddress(@indirectbr_preserved, %bb1),253 ptr blockaddress(@indirectbr_preserved, %bb2),254 ptr blockaddress(@indirectbr_preserved, %bb3),255 ptr blockaddress(@indirectbr_preserved, %bb4),256 ptr blockaddress(@indirectbr_preserved, %bb5),257 ptr blockaddress(@indirectbr_preserved, %bb6),258 ptr blockaddress(@indirectbr_preserved, %bb7),259 ptr blockaddress(@indirectbr_preserved, %bb8),260 ptr blockaddress(@indirectbr_preserved, %bb9)]261 262; Check that we preserve indirectbr when only calls are retpolined.263define void @indirectbr_preserved(ptr readonly %p, ptr %sink) #0 {264; X64-LABEL: indirectbr_preserved:265; X64: jmpq *266; X86-LABEL: indirectbr_preserved:267; X86: jmpl *268entry:269 %i0 = load i64, ptr %p270 %target.i0 = getelementptr [10 x ptr], ptr @indirectbr_preserved.targets, i64 0, i64 %i0271 %target0 = load ptr, ptr %target.i0272 indirectbr ptr %target0, [label %bb1, label %bb3]273 274bb0:275 store volatile i64 0, ptr %sink276 br label %latch277 278bb1:279 store volatile i64 1, ptr %sink280 br label %latch281 282bb2:283 store volatile i64 2, ptr %sink284 br label %latch285 286bb3:287 store volatile i64 3, ptr %sink288 br label %latch289 290bb4:291 store volatile i64 4, ptr %sink292 br label %latch293 294bb5:295 store volatile i64 5, ptr %sink296 br label %latch297 298bb6:299 store volatile i64 6, ptr %sink300 br label %latch301 302bb7:303 store volatile i64 7, ptr %sink304 br label %latch305 306bb8:307 store volatile i64 8, ptr %sink308 br label %latch309 310bb9:311 store volatile i64 9, ptr %sink312 br label %latch313 314latch:315 %i.next = load i64, ptr %p316 %target.i.next = getelementptr [10 x ptr], ptr @indirectbr_preserved.targets, i64 0, i64 %i.next317 %target.next = load ptr, ptr %target.i.next318 ; Potentially hit a full 10 successors here so that even if we rewrite as319 ; a switch it will try to be lowered with a jump table.320 indirectbr ptr %target.next, [label %bb0,321 label %bb1,322 label %bb2,323 label %bb3,324 label %bb4,325 label %bb5,326 label %bb6,327 label %bb7,328 label %bb8,329 label %bb9]330}331 332@indirectbr_rewrite.targets = constant [10 x ptr] [ptr blockaddress(@indirectbr_rewrite, %bb0),333 ptr blockaddress(@indirectbr_rewrite, %bb1),334 ptr blockaddress(@indirectbr_rewrite, %bb2),335 ptr blockaddress(@indirectbr_rewrite, %bb3),336 ptr blockaddress(@indirectbr_rewrite, %bb4),337 ptr blockaddress(@indirectbr_rewrite, %bb5),338 ptr blockaddress(@indirectbr_rewrite, %bb6),339 ptr blockaddress(@indirectbr_rewrite, %bb7),340 ptr blockaddress(@indirectbr_rewrite, %bb8),341 ptr blockaddress(@indirectbr_rewrite, %bb9)]342 343; Check that when retpolines are enabled for indirect branches the indirectbr344; instruction gets rewritten to use switch, and that in turn doesn't get lowered345; as a jump table.346define void @indirectbr_rewrite(ptr readonly %p, ptr %sink) #1 {347; X64-LABEL: indirectbr_rewrite:348; X64-NOT: jmpq349; X86-LABEL: indirectbr_rewrite:350; X86-NOT: jmpl351entry:352 %i0 = load i64, ptr %p353 %target.i0 = getelementptr [10 x ptr], ptr @indirectbr_rewrite.targets, i64 0, i64 %i0354 %target0 = load ptr, ptr %target.i0355 indirectbr ptr %target0, [label %bb1, label %bb3]356 357bb0:358 store volatile i64 0, ptr %sink359 br label %latch360 361bb1:362 store volatile i64 1, ptr %sink363 br label %latch364 365bb2:366 store volatile i64 2, ptr %sink367 br label %latch368 369bb3:370 store volatile i64 3, ptr %sink371 br label %latch372 373bb4:374 store volatile i64 4, ptr %sink375 br label %latch376 377bb5:378 store volatile i64 5, ptr %sink379 br label %latch380 381bb6:382 store volatile i64 6, ptr %sink383 br label %latch384 385bb7:386 store volatile i64 7, ptr %sink387 br label %latch388 389bb8:390 store volatile i64 8, ptr %sink391 br label %latch392 393bb9:394 store volatile i64 9, ptr %sink395 br label %latch396 397latch:398 %i.next = load i64, ptr %p399 %target.i.next = getelementptr [10 x ptr], ptr @indirectbr_rewrite.targets, i64 0, i64 %i.next400 %target.next = load ptr, ptr %target.i.next401 ; Potentially hit a full 10 successors here so that even if we rewrite as402 ; a switch it will try to be lowered with a jump table.403 indirectbr ptr %target.next, [label %bb0,404 label %bb1,405 label %bb2,406 label %bb3,407 label %bb4,408 label %bb5,409 label %bb6,410 label %bb7,411 label %bb8,412 label %bb9]413}414 415; Lastly check that the necessary thunks were emitted.416;417; X64-LABEL: .section .text.__llvm_retpoline_r11,{{.*}},__llvm_retpoline_r11,comdat418; X64-NEXT: .hidden __llvm_retpoline_r11419; X64-NEXT: .weak __llvm_retpoline_r11420; X64: __llvm_retpoline_r11:421; X64-NEXT: # {{.*}} # %entry422; X64-NEXT: callq [[CALL_TARGET:.*]]423; X64-NEXT: [[CAPTURE_SPEC:.*]]: # Block address taken424; X64-NEXT: # %entry425; X64-NEXT: # =>This Inner Loop Header: Depth=1426; X64-NEXT: pause427; X64-NEXT: lfence428; X64-NEXT: jmp [[CAPTURE_SPEC]]429; X64-NEXT: .p2align 4430; X64-NEXT: {{.*}} # Block address taken431; X64-NEXT: # %entry432; X64-NEXT: [[CALL_TARGET]]:433; X64-NEXT: movq %r11, (%rsp)434; X64-NEXT: retq435;436; X86-LABEL: .section .text.__llvm_retpoline_eax,{{.*}},__llvm_retpoline_eax,comdat437; X86-NEXT: .hidden __llvm_retpoline_eax438; X86-NEXT: .weak __llvm_retpoline_eax439; X86: __llvm_retpoline_eax:440; X86-NEXT: # {{.*}} # %entry441; X86-NEXT: calll [[CALL_TARGET:.*]]442; X86-NEXT: [[CAPTURE_SPEC:.*]]: # Block address taken443; X86-NEXT: # %entry444; X86-NEXT: # =>This Inner Loop Header: Depth=1445; X86-NEXT: pause446; X86-NEXT: lfence447; X86-NEXT: jmp [[CAPTURE_SPEC]]448; X86-NEXT: .p2align 4449; X86-NEXT: {{.*}} # Block address taken450; X86-NEXT: # %entry451; X86-NEXT: [[CALL_TARGET]]:452; X86-NEXT: movl %eax, (%esp)453; X86-NEXT: retl454;455; X86-LABEL: .section .text.__llvm_retpoline_ecx,{{.*}},__llvm_retpoline_ecx,comdat456; X86-NEXT: .hidden __llvm_retpoline_ecx457; X86-NEXT: .weak __llvm_retpoline_ecx458; X86: __llvm_retpoline_ecx:459; X86-NEXT: # {{.*}} # %entry460; X86-NEXT: calll [[CALL_TARGET:.*]]461; X86-NEXT: [[CAPTURE_SPEC:.*]]: # Block address taken462; X86-NEXT: # %entry463; X86-NEXT: # =>This Inner Loop Header: Depth=1464; X86-NEXT: pause465; X86-NEXT: lfence466; X86-NEXT: jmp [[CAPTURE_SPEC]]467; X86-NEXT: .p2align 4468; X86-NEXT: {{.*}} # Block address taken469; X86-NEXT: # %entry470; X86-NEXT: [[CALL_TARGET]]:471; X86-NEXT: movl %ecx, (%esp)472; X86-NEXT: retl473;474; X86-LABEL: .section .text.__llvm_retpoline_edx,{{.*}},__llvm_retpoline_edx,comdat475; X86-NEXT: .hidden __llvm_retpoline_edx476; X86-NEXT: .weak __llvm_retpoline_edx477; X86: __llvm_retpoline_edx:478; X86-NEXT: # {{.*}} # %entry479; X86-NEXT: calll [[CALL_TARGET:.*]]480; X86-NEXT: [[CAPTURE_SPEC:.*]]: # Block address taken481; X86-NEXT: # %entry482; X86-NEXT: # =>This Inner Loop Header: Depth=1483; X86-NEXT: pause484; X86-NEXT: lfence485; X86-NEXT: jmp [[CAPTURE_SPEC]]486; X86-NEXT: .p2align 4487; X86-NEXT: {{.*}} # Block address taken488; X86-NEXT: # %entry489; X86-NEXT: [[CALL_TARGET]]:490; X86-NEXT: movl %edx, (%esp)491; X86-NEXT: retl492;493; X86-LABEL: .section .text.__llvm_retpoline_edi,{{.*}},__llvm_retpoline_edi,comdat494; X86-NEXT: .hidden __llvm_retpoline_edi495; X86-NEXT: .weak __llvm_retpoline_edi496; X86: __llvm_retpoline_edi:497; X86-NEXT: # {{.*}} # %entry498; X86-NEXT: calll [[CALL_TARGET:.*]]499; X86-NEXT: [[CAPTURE_SPEC:.*]]: # Block address taken500; X86-NEXT: # %entry501; X86-NEXT: # =>This Inner Loop Header: Depth=1502; X86-NEXT: pause503; X86-NEXT: lfence504; X86-NEXT: jmp [[CAPTURE_SPEC]]505; X86-NEXT: .p2align 4506; X86-NEXT: {{.*}} # Block address taken507; X86-NEXT: # %entry508; X86-NEXT: [[CALL_TARGET]]:509; X86-NEXT: movl %edi, (%esp)510; X86-NEXT: retl511 512 513attributes #0 = { "target-features"="+retpoline-indirect-calls" }514attributes #1 = { "target-features"="+retpoline-indirect-calls,+retpoline-indirect-branches" }515attributes #2 = { nonlazybind }516