1; RUN: llc -mtriple=x86_64-unknown-unknown < %s | FileCheck %s 2; RUN: llc -mtriple=x86_64-unknown-unknown -O0 < %s | FileCheck %s -check-prefix=CHECK0 3 4%struct.interrupt_frame = type { i64, i64, i64, i64, i64 } 5 6@sink_address = dso_local global ptr null 7@sink_i32 = dso_local global i64 0 8 9; Spills rax, putting original esp at +8. 10; No stack adjustment if declared with no error code 11define x86_intrcc void @test_isr_no_ecode(ptr byval(%struct.interrupt_frame) %frame) { 12 ; CHECK-LABEL: test_isr_no_ecode: 13 ; CHECK: pushq %rax 14 ; CHECK: movq 24(%rsp), %rax 15 ; CHECK: popq %rax 16 ; CHECK: iretq 17 ; CHECK0-LABEL: test_isr_no_ecode: 18 ; CHECK0: pushq %rax 19 ; CHECK0: leaq 8(%rsp), %rax 20 ; CHECK0: movq 16(%rax), %rax 21 ; CHECK0: popq %rax 22 ; CHECK0: iretq 23 %pflags = getelementptr inbounds %struct.interrupt_frame, ptr %frame, i32 0, i32 2 24 %flags = load i64, ptr %pflags, align 4 25 call void asm sideeffect "", "r"(i64 %flags) 26 ret void 27} 28 29; Spills rax and rcx, putting original rsp at +16. Stack is adjusted up another 8 bytes 30; before return, popping the error code. 31define x86_intrcc void @test_isr_ecode(ptr byval(%struct.interrupt_frame) %frame, i64 %ecode) { 32 ; CHECK-LABEL: test_isr_ecode 33 ; CHECK: pushq %rax 34 ; CHECK: pushq %rax 35 ; CHECK: pushq %rcx 36 ; CHECK: movq 24(%rsp), %rax 37 ; CHECK: movq 48(%rsp), %rcx 38 ; CHECK: popq %rcx 39 ; CHECK: popq %rax 40 ; CHECK: addq $16, %rsp 41 ; CHECK: iretq 42 ; CHECK0-LABEL: test_isr_ecode 43 ; CHECK0: pushq %rax 44 ; CHECK0: pushq %rax 45 ; CHECK0: pushq %rcx 46 ; CHECK0: movq 24(%rsp), %rcx 47 ; CHECK0: leaq 32(%rsp), %rax 48 ; CHECK0: movq 16(%rax), %rax 49 ; CHECK0: popq %rcx 50 ; CHECK0: popq %rax 51 ; CHECK0: addq $16, %rsp 52 ; CHECK0: iretq 53 %pflags = getelementptr inbounds %struct.interrupt_frame, ptr %frame, i32 0, i32 2 54 %flags = load i64, ptr %pflags, align 4 55 call void asm sideeffect "", "r,r"(i64 %flags, i64 %ecode) 56 ret void 57} 58 59; All clobbered registers must be saved 60define x86_intrcc void @test_isr_clobbers(ptr byval(%struct.interrupt_frame) %frame, i64 %ecode) { 61 call void asm sideeffect "", "~{rax},~{rbx},~{rbp},~{r11},~{xmm0}"() 62 ; CHECK-LABEL: test_isr_clobbers 63 64 ; CHECK: pushq %rax 65 ; CHECK: pushq %rbp 66 ; CHECK: pushq %r11 67 ; CHECK: pushq %rbx 68 ; CHECK: movaps %xmm0 69 ; CHECK: movaps {{.*}}, %xmm0 70 ; CHECK: popq %rbx 71 ; CHECK: popq %r11 72 ; CHECK: popq %rbp 73 ; CHECK: popq %rax 74 ; CHECK: addq $16, %rsp 75 ; CHECK: iretq 76 ; CHECK0-LABEL: test_isr_clobbers 77 78 ; CHECK0: pushq %rax 79 ; CHECK0: pushq %rbp 80 ; CHECK0: pushq %r11 81 ; CHECK0: pushq %rbx 82 ; CHECK0: movaps %xmm0 83 ; CHECK0: movaps {{.*}}, %xmm0 84 ; CHECK0: popq %rbx 85 ; CHECK0: popq %r11 86 ; CHECK0: popq %rbp 87 ; CHECK0: popq %rax 88 ; CHECK0: addq $16, %rsp 89 ; CHECK0: iretq 90 ret void 91} 92 93@f80 = common dso_local global x86_fp80 0xK00000000000000000000, align 4 94 95; Test that the presence of x87 does not crash the FP stackifier 96define x86_intrcc void @test_isr_x87(ptr byval(%struct.interrupt_frame) %frame) { 97 ; CHECK-LABEL: test_isr_x87 98 ; CHECK-DAG: fldt f80 99 ; CHECK-DAG: fld1 100 ; CHECK: faddp 101 ; CHECK-NEXT: fstpt f80 102 ; CHECK-NEXT: iretq 103entry: 104 %ld = load x86_fp80, ptr @f80, align 4 105 %add = fadd x86_fp80 %ld, 0xK3FFF8000000000000000 106 store x86_fp80 %add, ptr @f80, align 4 107 ret void 108} 109 110; Use a frame pointer to check the offsets. No return address, arguments start 111; at RBP+4. 112define dso_local x86_intrcc void @test_fp_1(ptr byval(%struct.interrupt_frame) %p) #0 { 113 ; CHECK-LABEL: test_fp_1: 114 ; CHECK: # %bb.0: # %entry 115 ; CHECK-NEXT: pushq %rbp 116 ; CHECK-NEXT: movq %rsp, %rbp 117 ; CHECK-DAG: leaq 8(%rbp), %[[R1:[^ ]*]] 118 ; CHECK-DAG: leaq 40(%rbp), %[[R2:[^ ]*]] 119 ; CHECK: movq %[[R1]], sink_address 120 ; CHECK: movq %[[R2]], sink_address 121 ; CHECK: popq %rbp 122 ; CHECK: iretq 123entry: 124 %arrayidx2 = getelementptr inbounds %struct.interrupt_frame, ptr %p, i64 0, i32 4 125 store volatile ptr %p, ptr @sink_address 126 store volatile ptr %arrayidx2, ptr @sink_address 127 ret void 128} 129 130; The error code is between RBP and the interrupt_frame. 131define dso_local x86_intrcc void @test_fp_2(ptr byval(%struct.interrupt_frame) %p, i64 %err) #0 { 132 ; CHECK-LABEL: test_fp_2: 133 ; CHECK: # %bb.0: # %entry 134 ; This RAX push is just to align the stack. 135 ; CHECK-NEXT: pushq %rax 136 ; CHECK-NEXT: pushq %rbp 137 ; CHECK-NEXT: movq %rsp, %rbp 138 ; CHECK-DAG: movq 16(%rbp), %[[R3:[^ ]*]] 139 ; CHECK-DAG: leaq 24(%rbp), %[[R1:[^ ]*]] 140 ; CHECK-DAG: leaq 56(%rbp), %[[R2:[^ ]*]] 141 ; CHECK: movq %[[R1]], sink_address(%rip) 142 ; CHECK: movq %[[R2]], sink_address(%rip) 143 ; CHECK: movq %[[R3]], sink_i32(%rip) 144 ; CHECK: popq %rbp 145 ; Pop off both the error code and the 8 byte alignment adjustment from the 146 ; prologue. 147 ; CHECK: addq $16, %rsp 148 ; CHECK: iretq 149entry: 150 %arrayidx2 = getelementptr inbounds %struct.interrupt_frame, ptr %p, i64 0, i32 4 151 store volatile ptr %p, ptr @sink_address 152 store volatile ptr %arrayidx2, ptr @sink_address 153 store volatile i64 %err, ptr @sink_i32 154 ret void 155} 156 157; Test argument copy elision when copied to a local alloca. 158define x86_intrcc void @test_copy_elide(ptr byval(%struct.interrupt_frame) %frame, i64 %err) #0 { 159 ; CHECK-LABEL: test_copy_elide: 160 ; CHECK: # %bb.0: # %entry 161 ; This RAX push is just to align the stack. 162 ; CHECK-NEXT: pushq %rax 163 ; CHECK-NEXT: pushq %rbp 164 ; CHECK-NEXT: movq %rsp, %rbp 165 ; CHECK: leaq 16(%rbp), %[[R1:[^ ]*]] 166 ; CHECK: movq %[[R1]], sink_address(%rip) 167entry: 168 %err.addr = alloca i64, align 4 169 store i64 %err, ptr %err.addr, align 4 170 store volatile ptr %err.addr, ptr @sink_address 171 ret void 172} 173 174define x86_intrcc void @test_stack_allocation(ptr byval(%struct.interrupt_frame) %frame, i64 %err) #1 { 175 ; CHECK-LABEL: test_stack_allocation: 176 ; CHECK: # %bb.0: # %entry 177 178 ;; Ensure that STACKALLOC_W_PROBING isn't emitted. 179 ; CHECK-NOT: # fixed size alloca with probing 180 ;; Ensure that stack space is allocated. 181 ; CHECK: subq $280, %rsp 182entry: 183 %some_allocation = alloca i64 184 ;; Call a un-inlineable function to ensure the allocation isn't put in the red zone. 185 call void @external_function(ptr %some_allocation) 186 ret void 187} 188 189declare void @external_function(ptr) 190 191attributes #0 = { nounwind "frame-pointer"="all" } 192attributes #1 = { nounwind "probe-stack"="inline-asm" } 193