1 ; RUN: llc -verify-machineinstrs < %s -mtriple=x86_64-apple-darwin | FileCheck --check-prefix=CHECK-APPLE %s 2 ; RUN: llc -verify-machineinstrs -O0 < %s -mtriple=x86_64-apple-darwin | FileCheck --check-prefix=CHECK-O0 %s 3 4 declare i8* @malloc(i64) 5 declare void @free(i8*) 6 %swift_error = type {i64, i8} 7 8 ; This tests the basic usage of a swifterror parameter. "foo" is the function 9 ; that takes a swifterror parameter and "caller" is the caller of "foo". 10 define float @foo(%swift_error** swifterror %error_ptr_ref) { 11 ; CHECK-APPLE-LABEL: foo: 12 ; CHECK-APPLE: movl $16, %edi 13 ; CHECK-APPLE: malloc 14 ; CHECK-APPLE: movb $1, 8(%rax) 15 ; CHECK-APPLE: movq %rax, %r12 16 17 ; CHECK-O0-LABEL: foo: 18 ; CHECK-O0: movl $16 19 ; CHECK-O0: malloc 20 ; CHECK-O0: movb $1, 8(%rax) 21 ; CHECK-O0: movq %{{.*}}, %r12 22 entry: 23 %call = call i8* @malloc(i64 16) 24 %call.0 = bitcast i8* %call to %swift_error* 25 store %swift_error* %call.0, %swift_error** %error_ptr_ref 26 %tmp = getelementptr inbounds i8, i8* %call, i64 8 27 store i8 1, i8* %tmp 28 ret float 1.0 29 } 30 31 ; "caller" calls "foo" that takes a swifterror parameter. 32 define float @caller(i8* %error_ref) { 33 ; CHECK-APPLE-LABEL: caller: 34 ; CHECK-APPLE: xorl %r12d, %r12d 35 ; CHECK-APPLE: callq {{.*}}foo 36 ; CHECK-APPLE: testq %r12, %r12 37 ; CHECK-APPLE: jne 38 ; Access part of the error object and save it to error_ref 39 ; CHECK-APPLE: movb 8(%r12) 40 ; CHECK-APPLE: movq %r12, %rdi 41 ; CHECK_APPLE: callq {{.*}}free 42 43 ; CHECK-O0-LABEL: caller: 44 ; CHECK-O0: xorl 45 ; CHECK-O0: movl %{{.*}}, %r12d 46 ; CHECK-O0: callq {{.*}}foo 47 ; CHECK-O0: jne 48 entry: 49 %error_ptr_ref = alloca swifterror %swift_error* 50 store %swift_error* null, %swift_error** %error_ptr_ref 51 %call = call float @foo(%swift_error** swifterror %error_ptr_ref) 52 %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref 53 %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null 54 %tmp = bitcast %swift_error* %error_from_foo to i8* 55 br i1 %had_error_from_foo, label %handler, label %cont 56 cont: 57 %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1 58 %t = load i8, i8* %v1 59 store i8 %t, i8* %error_ref 60 br label %handler 61 handler: 62 call void @free(i8* %tmp) 63 ret float 1.0 64 } 65 66 ; "caller2" is the caller of "foo", it calls "foo" inside a loop. 67 define float @caller2(i8* %error_ref) { 68 ; CHECK-APPLE-LABEL: caller2: 69 ; CHECK-APPLE: xorl %r12d, %r12d 70 ; CHECK-APPLE: callq {{.*}}foo 71 ; CHECK-APPLE: testq %r12, %r12 72 ; CHECK-APPLE: jne 73 ; CHECK-APPLE: ucomiss 74 ; CHECK-APPLE: jbe 75 ; Access part of the error object and save it to error_ref 76 ; CHECK-APPLE: movb 8(%r12) 77 ; CHECK-APPLE: movq %r12, %rdi 78 ; CHECK_APPLE: callq {{.*}}free 79 80 ; CHECK-O0-LABEL: caller2: 81 ; CHECK-O0: xorl 82 ; CHECK-O0: movl %{{.*}}, %r12d 83 ; CHECK-O0: callq {{.*}}foo 84 ; CHECK-O0: movq %r12, [[ID:%[a-z]+]] 85 ; CHECK-O0: cmpq $0, [[ID]] 86 ; CHECK-O0: jne 87 entry: 88 %error_ptr_ref = alloca swifterror %swift_error* 89 br label %bb_loop 90 bb_loop: 91 store %swift_error* null, %swift_error** %error_ptr_ref 92 %call = call float @foo(%swift_error** swifterror %error_ptr_ref) 93 %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref 94 %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null 95 %tmp = bitcast %swift_error* %error_from_foo to i8* 96 br i1 %had_error_from_foo, label %handler, label %cont 97 cont: 98 %cmp = fcmp ogt float %call, 1.000000e+00 99 br i1 %cmp, label %bb_end, label %bb_loop 100 bb_end: 101 %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1 102 %t = load i8, i8* %v1 103 store i8 %t, i8* %error_ref 104 br label %handler 105 handler: 106 call void @free(i8* %tmp) 107 ret float 1.0 108 } 109 110 ; "foo_if" is a function that takes a swifterror parameter, it sets swifterror 111 ; under a certain condition. 112 define float @foo_if(%swift_error** swifterror %error_ptr_ref, i32 %cc) { 113 ; CHECK-APPLE-LABEL: foo_if: 114 ; CHECK-APPLE: testl %edi, %edi 115 ; CHECK-APPLE: je 116 ; CHECK-APPLE: movl $16, %edi 117 ; CHECK-APPLE: malloc 118 ; CHECK-APPLE: movb $1, 8(%rax) 119 ; CHECK-APPLE: movq %rax, %r12 120 ; CHECK-APPLE-NOT: %r12 121 ; CHECK-APPLE: ret 122 123 ; CHECK-O0-LABEL: foo_if: 124 ; CHECK-O0: cmpl $0 125 ; spill to stack 126 ; CHECK-O0: movq %r12, {{.*}}(%rsp) 127 ; CHECK-O0: je 128 ; CHECK-O0: movl $16, 129 ; CHECK-O0: malloc 130 ; CHECK-O0: movq %rax, [[ID:%[a-z]+]] 131 ; CHECK-O0-DAG: movb $1, 8(%rax) 132 ; CHECK-O0-DAG: movq [[ID]], %r12 133 ; CHECK-O0: ret 134 ; reload from stack 135 ; CHECK-O0: movq {{.*}}(%rsp), %r12 136 ; CHECK-O0: ret 137 entry: 138 %cond = icmp ne i32 %cc, 0 139 br i1 %cond, label %gen_error, label %normal 140 141 gen_error: 142 %call = call i8* @malloc(i64 16) 143 %call.0 = bitcast i8* %call to %swift_error* 144 store %swift_error* %call.0, %swift_error** %error_ptr_ref 145 %tmp = getelementptr inbounds i8, i8* %call, i64 8 146 store i8 1, i8* %tmp 147 ret float 1.0 148 149 normal: 150 ret float 0.0 151 } 152 153 ; "foo_loop" is a function that takes a swifterror parameter, it sets swifterror 154 ; under a certain condition inside a loop. 155 define float @foo_loop(%swift_error** swifterror %error_ptr_ref, i32 %cc, float %cc2) { 156 ; CHECK-APPLE-LABEL: foo_loop: 157 ; CHECK-APPLE: movq %r12, %rax 158 ; CHECK-APPLE: testl 159 ; CHECK-APPLE: je 160 ; CHECK-APPLE: movl $16, %edi 161 ; CHECK-APPLE: malloc 162 ; CHECK-APPLE: movb $1, 8(%rax) 163 ; CHECK-APPLE: ucomiss 164 ; CHECK-APPLE: jbe 165 ; CHECK-APPLE: movq %rax, %r12 166 ; CHECK-APPLE: ret 167 168 ; CHECK-O0-LABEL: foo_loop: 169 ; spill to stack 170 ; CHECK-O0: movq %r12, {{.*}}(%rsp) 171 ; CHECK-O0: cmpl $0 172 ; CHECK-O0: je 173 ; CHECK-O0: movl $16, 174 ; CHECK-O0: malloc 175 ; CHECK-O0: movq %rax, [[ID:%[a-z]+]] 176 ; CHECK-O0: movb $1, 8([[ID]]) 177 ; CHECK-O0: jbe 178 ; reload from stack 179 ; CHECK-O0: movq {{.*}}(%rsp), %r12 180 ; CHECK-O0: ret 181 entry: 182 br label %bb_loop 183 184 bb_loop: 185 %cond = icmp ne i32 %cc, 0 186 br i1 %cond, label %gen_error, label %bb_cont 187 188 gen_error: 189 %call = call i8* @malloc(i64 16) 190 %call.0 = bitcast i8* %call to %swift_error* 191 store %swift_error* %call.0, %swift_error** %error_ptr_ref 192 %tmp = getelementptr inbounds i8, i8* %call, i64 8 193 store i8 1, i8* %tmp 194 br label %bb_cont 195 196 bb_cont: 197 %cmp = fcmp ogt float %cc2, 1.000000e+00 198 br i1 %cmp, label %bb_end, label %bb_loop 199 bb_end: 200 ret float 0.0 201 } 202 203 %struct.S = type { i32, i32, i32, i32, i32, i32 } 204 205 ; "foo_sret" is a function that takes a swifterror parameter, it also has a sret 206 ; parameter. 207 define void @foo_sret(%struct.S* sret %agg.result, i32 %val1, %swift_error** swifterror %error_ptr_ref) { 208 ; CHECK-APPLE-LABEL: foo_sret: 209 ; CHECK-APPLE: movq %rdi, %{{.*}} 210 ; CHECK-APPLE: movl $16, %edi 211 ; CHECK-APPLE: malloc 212 ; CHECK-APPLE: movb $1, 8(%rax) 213 ; CHECK-APPLE: movl %{{.*}}, 4(%{{.*}}) 214 ; CHECK-APPLE: movq %rax, %r12 215 ; CHECK-APPLE: movq %{{.*}}, %rax 216 ; CHECK-APPLE-NOT: x19 217 218 ; CHECK-O0-LABEL: foo_sret: 219 ; CHECK-O0: movl $16, 220 ; spill sret to stack 221 ; CHECK-O0: movq %rdi, 222 ; CHECK-O0: movq {{.*}}, %rdi 223 ; CHECK-O0: malloc 224 ; CHECK-O0: movb $1, 8(%rax) 225 ; CHECK-O0: movl %{{.*}}, 4(%{{.*}}) 226 ; CHECK-O0: movq %{{.*}}, %r12 227 ; reload sret from stack 228 ; CHECK-O0: movq {{.*}}(%rsp), %rax 229 ; CHECK-O0: ret 230 entry: 231 %call = call i8* @malloc(i64 16) 232 %call.0 = bitcast i8* %call to %swift_error* 233 store %swift_error* %call.0, %swift_error** %error_ptr_ref 234 %tmp = getelementptr inbounds i8, i8* %call, i64 8 235 store i8 1, i8* %tmp 236 %v2 = getelementptr inbounds %struct.S, %struct.S* %agg.result, i32 0, i32 1 237 store i32 %val1, i32* %v2 238 ret void 239 } 240 241 ; "caller3" calls "foo_sret" that takes a swifterror parameter. 242 define float @caller3(i8* %error_ref) { 243 ; CHECK-APPLE-LABEL: caller3: 244 ; CHECK-APPLE: movl $1, %esi 245 ; CHECK-APPLE: xorl %r12d, %r12d 246 ; CHECK-APPLE: callq {{.*}}foo_sret 247 ; CHECK-APPLE: testq %r12, %r12 248 ; CHECK-APPLE: jne 249 ; Access part of the error object and save it to error_ref 250 ; CHECK-APPLE: movb 8(%r12), 251 ; CHECK-APPLE: movb %{{.*}}, 252 ; CHECK-APPLE: movq %r12, %rdi 253 ; CHECK_APPLE: callq {{.*}}free 254 255 ; CHECK-O0-LABEL: caller3: 256 ; CHECK-O0: xorl 257 ; CHECK-O0: movl {{.*}}, %r12d 258 ; CHECK-O0: movl $1, %esi 259 ; CHECK-O0: movq {{.*}}, %rdi 260 ; CHECK-O0: callq {{.*}}foo_sret 261 ; CHECK-O0: movq %r12, 262 ; CHECK-O0: cmpq $0 263 ; CHECK-O0: jne 264 ; Access part of the error object and save it to error_ref 265 ; CHECK-O0: movb 8(%{{.*}}), 266 ; CHECK-O0: movb %{{.*}}, 267 ; reload from stack 268 ; CHECK-O0: movq {{.*}}(%rsp), %rdi 269 ; CHECK-O0: callq {{.*}}free 270 entry: 271 %s = alloca %struct.S, align 8 272 %error_ptr_ref = alloca swifterror %swift_error* 273 store %swift_error* null, %swift_error** %error_ptr_ref 274 call void @foo_sret(%struct.S* sret %s, i32 1, %swift_error** swifterror %error_ptr_ref) 275 %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref 276 %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null 277 %tmp = bitcast %swift_error* %error_from_foo to i8* 278 br i1 %had_error_from_foo, label %handler, label %cont 279 cont: 280 %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1 281 %t = load i8, i8* %v1 282 store i8 %t, i8* %error_ref 283 br label %handler 284 handler: 285 call void @free(i8* %tmp) 286 ret float 1.0 287 } 288 289 ; This is a caller with multiple swifterror values, it calls "foo" twice, each 290 ; time with a different swifterror value, from "alloca swifterror". 291 define float @caller_with_multiple_swifterror_values(i8* %error_ref, i8* %error_ref2) { 292 ; CHECK-APPLE-LABEL: caller_with_multiple_swifterror_values: 293 294 ; The first swifterror value: 295 ; CHECK-APPLE: xorl %r12d, %r12d 296 ; CHECK-APPLE: callq {{.*}}foo 297 ; CHECK-APPLE: testq %r12, %r12 298 ; CHECK-APPLE: jne 299 ; Access part of the error object and save it to error_ref 300 ; CHECK-APPLE: movb 8(%r12) 301 ; CHECK-APPLE: movq %r12, %rdi 302 ; CHECK_APPLE: callq {{.*}}free 303 304 ; The second swifterror value: 305 ; CHECK-APPLE: xorl %r12d, %r12d 306 ; CHECK-APPLE: callq {{.*}}foo 307 ; CHECK-APPLE: testq %r12, %r12 308 ; CHECK-APPLE: jne 309 ; Access part of the error object and save it to error_ref 310 ; CHECK-APPLE: movb 8(%r12) 311 ; CHECK-APPLE: movq %r12, %rdi 312 ; CHECK_APPLE: callq {{.*}}free 313 314 ; CHECK-O0-LABEL: caller_with_multiple_swifterror_values: 315 316 ; The first swifterror value: 317 ; CHECK-O0: xorl 318 ; CHECK-O0: movl %{{.*}}, %r12d 319 ; CHECK-O0: callq {{.*}}foo 320 ; CHECK-O0: jne 321 322 ; The second swifterror value: 323 ; CHECK-O0: xorl 324 ; CHECK-O0: movl %{{.*}}, %r12d 325 ; CHECK-O0: callq {{.*}}foo 326 ; CHECK-O0: jne 327 entry: 328 %error_ptr_ref = alloca swifterror %swift_error* 329 store %swift_error* null, %swift_error** %error_ptr_ref 330 %call = call float @foo(%swift_error** swifterror %error_ptr_ref) 331 %error_from_foo = load %swift_error*, %swift_error** %error_ptr_ref 332 %had_error_from_foo = icmp ne %swift_error* %error_from_foo, null 333 %tmp = bitcast %swift_error* %error_from_foo to i8* 334 br i1 %had_error_from_foo, label %handler, label %cont 335 cont: 336 %v1 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo, i64 0, i32 1 337 %t = load i8, i8* %v1 338 store i8 %t, i8* %error_ref 339 br label %handler 340 handler: 341 call void @free(i8* %tmp) 342 343 %error_ptr_ref2 = alloca swifterror %swift_error* 344 store %swift_error* null, %swift_error** %error_ptr_ref2 345 %call2 = call float @foo(%swift_error** swifterror %error_ptr_ref2) 346 %error_from_foo2 = load %swift_error*, %swift_error** %error_ptr_ref2 347 %had_error_from_foo2 = icmp ne %swift_error* %error_from_foo2, null 348 %bitcast2 = bitcast %swift_error* %error_from_foo2 to i8* 349 br i1 %had_error_from_foo2, label %handler2, label %cont2 350 cont2: 351 %v2 = getelementptr inbounds %swift_error, %swift_error* %error_from_foo2, i64 0, i32 1 352 %t2 = load i8, i8* %v2 353 store i8 %t2, i8* %error_ref2 354 br label %handler2 355 handler2: 356 call void @free(i8* %bitcast2) 357 358 ret float 1.0 359 } 360