1; RUN: llc -mtriple x86_64-apple-darwin -O0 < %s -o - | FileCheck %s 2; 3; During X86 fastisel, the address of indirect call was resolved 4; through bitcast, ptrtoint, and inttoptr instructions. This is valid 5; only if the related instructions are in that same basic block, otherwise 6; we may reference variables that were not live across basic blocks 7; resulting in undefined virtual registers. 8; 9; In this example, this is illustrated by a spill/reload of the 10; LOADED_PTR_SLOT. 11; 12; Before this patch, the compiler was accessing two different spill 13; slots. 14; <rdar://problem/15192473> 15 16; CHECK-LABEL: @test_bitcast 17; Load the value of the function pointer: %loaded_ptr 18; Spill %arg2. 19; CHECK: movq %rdx, [[ARG2_SLOT:[0-9]*\(%[a-z]+\)]] 20; CHECK: movq (%rdi), [[LOADED_PTR:%[a-z]+]] 21; Spill %loaded_ptr. 22; CHECK: movq [[LOADED_PTR]], [[LOADED_PTR_SLOT:[0-9]*\(%[a-z]+\)]] 23; Perform the indirect call. 24; Load the function pointer. 25; CHECK: movq [[LOADED_PTR_SLOT]], [[FCT_PTR:%[a-z]+]] 26; Load the third argument 27; CHECK: movq [[ARG2_SLOT]], %rdx 28; Load the first argument 29; CHECK: movq %rdx, %rdi 30; Load the second argument 31; CHECK: movq %rdx, %rsi 32; Call. 33; CHECK: callq *[[FCT_PTR]] 34; CHECK: ret 35define i64 @test_bitcast(ptr %arg, i1 %bool, i64 %arg2) { 36entry: 37 %loaded_ptr = load ptr, ptr %arg, align 8 38 switch i1 %bool, label %default [ 39 i1 true, label %label_true 40 i1 false, label %label_end 41 ] 42default: 43 br label %label_end 44 45label_true: 46 br label %label_end 47 48label_end: 49 %res = call i64 %loaded_ptr(i64 %arg2, i64 %arg2, i64 %arg2) 50 ret i64 %res 51} 52 53; CHECK-LABEL: @test_inttoptr 54; Load the value of the function pointer: %loaded_ptr 55; CHECK: movq %rdx, [[ARG2_SLOT:[0-9]*\(%[a-z]+\)]] 56; Spill %loaded_ptr. 57; CHECK: movq (%rdi), [[LOADED_PTR:%[a-z]+]] 58; Spill %arg2. 59; CHECK: movq [[LOADED_PTR]], [[LOADED_PTR_SLOT:[0-9]*\(%[a-z]+\)]] 60; Perform the indirect call. 61; Load the function pointer. 62; CHECK: movq [[LOADED_PTR_SLOT]], [[FCT_PTR:%[a-z]+]] 63; Load the third argument 64; CHECK: movq [[ARG2_SLOT]], %rdx 65; Load the first argument 66; CHECK: movq %rdx, %rdi 67; Load the second argument 68; CHECK: movq %rdx, %rsi 69; Call. 70; CHECK: callq *[[FCT_PTR]] 71; CHECK: ret 72define i64 @test_inttoptr(ptr %arg, i1 %bool, i64 %arg2) { 73entry: 74 %loaded_ptr = load ptr, ptr %arg, align 8 75 %raw = ptrtoint ptr %loaded_ptr to i64 76 switch i1 %bool, label %default [ 77 i1 true, label %label_true 78 i1 false, label %label_end 79 ] 80default: 81 br label %label_end 82 83label_true: 84 br label %label_end 85 86label_end: 87 %fct_ptr = inttoptr i64 %raw to ptr 88 %res = call i64 %fct_ptr(i64 %arg2, i64 %arg2, i64 %arg2) 89 ret i64 %res 90} 91 92; CHECK-LABEL: @test_ptrtoint 93; Spill %arg2. 94; CHECK: movq %rdx, [[ARG2_SLOT:[0-9]*\(%[a-z]+\)]] 95; Load the value of the function pointer: %loaded_ptr 96; CHECK: movq (%rdi), [[LOADED_PTR:%[a-z]+]] 97; Spill %loaded_ptr. 98; CHECK: movq [[LOADED_PTR]], [[LOADED_PTR_SLOT:[0-9]*\(%[a-z]+\)]] 99; Perform the indirect call. 100; Load the function pointer. 101; CHECK: movq [[LOADED_PTR_SLOT]], [[FCT_PTR:%[a-z]+]] 102; Load the third argument 103; CHECK: movq [[ARG2_SLOT]], %rdx 104; Load the first argument 105; CHECK: movq %rdx, %rdi 106; Load the second argument 107; CHECK: movq %rdx, %rsi 108; Call. 109; CHECK: callq *[[FCT_PTR]] 110; CHECK: ret 111define i64 @test_ptrtoint(ptr %arg, i1 %bool, i64 %arg2) { 112entry: 113 %loaded_ptr = load ptr, ptr %arg, align 8 114 switch i1 %bool, label %default [ 115 i1 true, label %label_true 116 i1 false, label %label_end 117 ] 118default: 119 br label %label_end 120 121label_true: 122 br label %label_end 123 124label_end: 125 %fct_int = ptrtoint ptr %loaded_ptr to i64 126 %fct_ptr = inttoptr i64 %fct_int to ptr 127 %res = call i64 %fct_ptr(i64 %arg2, i64 %arg2, i64 %arg2) 128 ret i64 %res 129} 130