1 ; RUN: llc < %s -march=xcore | FileCheck %s 2 ; RUN: llc < %s -march=xcore -disable-fp-elim | FileCheck %s -check-prefix=CHECKFP 3 4 declare i8* @llvm.frameaddress(i32) nounwind readnone 5 declare i8* @llvm.returnaddress(i32) nounwind 6 declare i8* @llvm.eh.dwarf.cfa(i32) nounwind 7 declare void @llvm.eh.return.i32(i32, i8*) nounwind 8 declare void @llvm.eh.unwind.init() nounwind 9 10 define i8* @FA0() nounwind { 11 entry: 12 ; CHECK-LABEL: FA0 13 ; CHECK: ldaw r0, sp[0] 14 ; CHECK-NEXT: retsp 0 15 %0 = call i8* @llvm.frameaddress(i32 0) 16 ret i8* %0 17 } 18 19 define i8* @FA1() nounwind { 20 entry: 21 ; CHECK-LABEL: FA1 22 ; CHECK: entsp 100 23 ; CHECK-NEXT: ldaw r0, sp[0] 24 ; CHECK-NEXT: retsp 100 25 %0 = alloca [100 x i32] 26 %1 = call i8* @llvm.frameaddress(i32 0) 27 ret i8* %1 28 } 29 30 define i8* @RA0() nounwind { 31 entry: 32 ; CHECK-LABEL: RA0 33 ; CHECK: stw lr, sp[0] 34 ; CHECK-NEXT: ldw r0, sp[0] 35 ; CHECK-NEXT: ldw lr, sp[0] 36 ; CHECK-NEXT: retsp 0 37 %0 = call i8* @llvm.returnaddress(i32 0) 38 ret i8* %0 39 } 40 41 define i8* @RA1() nounwind { 42 entry: 43 ; CHECK-LABEL: RA1 44 ; CHECK: entsp 100 45 ; CHECK-NEXT: ldw r0, sp[100] 46 ; CHECK-NEXT: retsp 100 47 %0 = alloca [100 x i32] 48 %1 = call i8* @llvm.returnaddress(i32 0) 49 ret i8* %1 50 } 51 52 ; test FRAME_TO_ARGS_OFFSET lowering 53 define i8* @FTAO0() nounwind { 54 entry: 55 ; CHECK-LABEL: FTAO0 56 ; CHECK: ldc r0, 0 57 ; CHECK-NEXT: ldaw r1, sp[0] 58 ; CHECK-NEXT: add r0, r1, r0 59 ; CHECK-NEXT: retsp 0 60 %0 = call i8* @llvm.eh.dwarf.cfa(i32 0) 61 ret i8* %0 62 } 63 64 define i8* @FTAO1() nounwind { 65 entry: 66 ; CHECK-LABEL: FTAO1 67 ; CHECK: entsp 100 68 ; CHECK-NEXT: ldc r0, 400 69 ; CHECK-NEXT: ldaw r1, sp[0] 70 ; CHECK-NEXT: add r0, r1, r0 71 ; CHECK-NEXT: retsp 100 72 %0 = alloca [100 x i32] 73 %1 = call i8* @llvm.eh.dwarf.cfa(i32 0) 74 ret i8* %1 75 } 76 77 define i8* @EH0(i32 %offset, i8* %handler) { 78 entry: 79 ; CHECK-LABEL: EH0 80 ; CHECK: entsp 2 81 ; CHECK: .cfi_def_cfa_offset 8 82 ; CHECK: .cfi_offset 15, 0 83 ; CHECK: .cfi_offset 1, -8 84 ; CHECK: .cfi_offset 0, -4 85 ; CHECK: ldc r2, 8 86 ; CHECK-NEXT: ldaw r3, sp[0] 87 ; CHECK-NEXT: add r2, r3, r2 88 ; CHECK-NEXT: add r2, r2, r0 89 ; CHECK-NEXT: mov r3, r1 90 ; CHECK-NEXT: ldw r1, sp[0] 91 ; CHECK-NEXT: ldw r0, sp[1] 92 ; CHECK-NEXT: set sp, r2 93 ; CHECK-NEXT: bau r3 94 call void @llvm.eh.return.i32(i32 %offset, i8* %handler) 95 unreachable 96 } 97 98 declare void @foo(...) 99 define i8* @EH1(i32 %offset, i8* %handler) { 100 entry: 101 ; CHECK-LABEL: EH1 102 ; CHECK: entsp 5 103 ; CHECK: .cfi_def_cfa_offset 20 104 ; CHECK: .cfi_offset 15, 0 105 ; CHECK: .cfi_offset 1, -16 106 ; CHECK: .cfi_offset 0, -12 107 ; CHECK: stw r4, sp[4] 108 ; CHECK: .cfi_offset 4, -4 109 ; CHECK: stw r5, sp[3] 110 ; CHECK: .cfi_offset 5, -8 111 ; CHECK: mov r4, r1 112 ; CHECK-NEXT: mov r5, r0 113 ; CHECK-NEXT: bl foo 114 ; CHECK-NEXT: ldc r0, 20 115 ; CHECK-NEXT: ldaw r1, sp[0] 116 ; CHECK-NEXT: add r0, r1, r0 117 ; CHECK-NEXT: add r2, r0, r5 118 ; CHECK-NEXT: mov r3, r4 119 ; CHECK-NEXT: ldw r5, sp[3] 120 ; CHECK-NEXT: ldw r4, sp[4] 121 ; CHECK-NEXT: ldw r1, sp[1] 122 ; CHECK-NEXT: ldw r0, sp[2] 123 ; CHECK-NEXT: set sp, r2 124 ; CHECK-NEXT: bau r3 125 call void (...) @foo() 126 call void @llvm.eh.return.i32(i32 %offset, i8* %handler) 127 unreachable 128 } 129 130 @offset = external constant i32 131 @handler = external constant i8 132 define i8* @EH2(i32 %r0, i32 %r1, i32 %r2, i32 %r3) { 133 entry: 134 ; CHECK-LABEL: EH2 135 ; CHECK: entsp 3 136 ; CHECK: bl foo 137 ; CHECK-NEXT: ldw r0, dp[offset] 138 ; CHECK-NEXT: ldc r1, 12 139 ; CHECK-NEXT: ldaw r2, sp[0] 140 ; CHECK-NEXT: add r1, r2, r1 141 ; CHECK-NEXT: add r2, r1, r0 142 ; CHECK-NEXT: ldaw r3, dp[handler] 143 ; CHECK-NEXT: ldw r1, sp[1] 144 ; CHECK-NEXT: ldw r0, sp[2] 145 ; CHECK-NEXT: set sp, r2 146 ; CHECK-NEXT: bau r3 147 call void (...) @foo() 148 %0 = load i32, i32* @offset 149 call void @llvm.eh.return.i32(i32 %0, i8* @handler) 150 unreachable 151 } 152 153 154 ; FP: spill FP+SR+R0:1+R4:9 = entsp 2+2+6 155 ; But we dont actually spill or restore R0:1 156 ; CHECKFP-LABEL: Unwind0: 157 ; CHECKFP: entsp 10 158 ; CHECKFP: stw r10, sp[1] 159 ; CHECKFP: ldaw r10, sp[0] 160 ; CHECKFP: stw r4, r10[9] 161 ; CHECKFP: stw r5, r10[8] 162 ; CHECKFP: stw r6, r10[7] 163 ; CHECKFP: stw r7, r10[6] 164 ; CHECKFP: stw r8, r10[5] 165 ; CHECKFP: stw r9, r10[4] 166 ; CHECKFP: ldw r9, r10[4] 167 ; CHECKFP: ldw r8, r10[5] 168 ; CHECKFP: ldw r7, r10[6] 169 ; CHECKFP: ldw r6, r10[7] 170 ; CHECKFP: ldw r5, r10[8] 171 ; CHECKFP: ldw r4, r10[9] 172 ; CHECKFP: set sp, r10 173 ; CHECKFP: ldw r10, sp[1] 174 ; CHECKFP: retsp 10 175 ; 176 ; !FP: spill R0:1+R4:10 = entsp 2+7 177 ; But we dont actually spill or restore R0:1 178 ; CHECK-LABEL: Unwind0: 179 ; CHECK: entsp 9 180 ; CHECK: stw r4, sp[8] 181 ; CHECK: stw r5, sp[7] 182 ; CHECK: stw r6, sp[6] 183 ; CHECK: stw r7, sp[5] 184 ; CHECK: stw r8, sp[4] 185 ; CHECK: stw r9, sp[3] 186 ; CHECK: stw r10, sp[2] 187 ; CHECK: ldw r10, sp[2] 188 ; CHECK: ldw r9, sp[3] 189 ; CHECK: ldw r8, sp[4] 190 ; CHECK: ldw r7, sp[5] 191 ; CHECK: ldw r6, sp[6] 192 ; CHECK: ldw r5, sp[7] 193 ; CHECK: ldw r4, sp[8] 194 ; CHECK: retsp 9 195 define void @Unwind0() { 196 call void @llvm.eh.unwind.init() 197 ret void 198 } 199 200 201 ; FP: spill FP+SR+R0:1+R4:9+LR = entsp 2+2+6 + extsp 1 202 ; But we dont actually spill or restore R0:1 203 ; CHECKFP-LABEL: Unwind1: 204 ; CHECKFP: entsp 10 205 ; CHECKFP: stw r10, sp[1] 206 ; CHECKFP: ldaw r10, sp[0] 207 ; CHECKFP: stw r4, r10[9] 208 ; CHECKFP: stw r5, r10[8] 209 ; CHECKFP: stw r6, r10[7] 210 ; CHECKFP: stw r7, r10[6] 211 ; CHECKFP: stw r8, r10[5] 212 ; CHECKFP: stw r9, r10[4] 213 ; CHECKFP: extsp 1 214 ; CHECKFP: bl foo 215 ; CHECKFP: ldaw sp, sp[1] 216 ; CHECKFP: ldw r9, r10[4] 217 ; CHECKFP: ldw r8, r10[5] 218 ; CHECKFP: ldw r7, r10[6] 219 ; CHECKFP: ldw r6, r10[7] 220 ; CHECKFP: ldw r5, r10[8] 221 ; CHECKFP: ldw r4, r10[9] 222 ; CHECKFP: set sp, r10 223 ; CHECKFP: ldw r10, sp[1] 224 ; CHECKFP: retsp 10 225 ; 226 ; !FP: spill R0:1+R4:10+LR = entsp 2+7+1 227 ; But we dont actually spill or restore R0:1 228 ; CHECK-LABEL: Unwind1: 229 ; CHECK: entsp 10 230 ; CHECK: stw r4, sp[9] 231 ; CHECK: stw r5, sp[8] 232 ; CHECK: stw r6, sp[7] 233 ; CHECK: stw r7, sp[6] 234 ; CHECK: stw r8, sp[5] 235 ; CHECK: stw r9, sp[4] 236 ; CHECK: stw r10, sp[3] 237 ; CHECK: bl foo 238 ; CHECK: ldw r10, sp[3] 239 ; CHECK: ldw r9, sp[4] 240 ; CHECK: ldw r8, sp[5] 241 ; CHECK: ldw r7, sp[6] 242 ; CHECK: ldw r6, sp[7] 243 ; CHECK: ldw r5, sp[8] 244 ; CHECK: ldw r4, sp[9] 245 ; CHECK: retsp 10 246 define void @Unwind1() { 247 call void (...) @foo() 248 call void @llvm.eh.unwind.init() 249 ret void 250 } 251 252 ; FP: spill FP+SR+R0:1+R4:9 = entsp 2+2+6 253 ; We dont spill R0:1 254 ; We only restore R0:1 during eh.return 255 ; CHECKFP-LABEL: UnwindEH: 256 ; CHECKFP: entsp 10 257 ; CHECKFP: .cfi_def_cfa_offset 40 258 ; CHECKFP: .cfi_offset 15, 0 259 ; CHECKFP: stw r10, sp[1] 260 ; CHECKFP: .cfi_offset 10, -36 261 ; CHECKFP: ldaw r10, sp[0] 262 ; CHECKFP: .cfi_def_cfa_register 10 263 ; CHECKFP: .cfi_offset 1, -32 264 ; CHECKFP: .cfi_offset 0, -28 265 ; CHECKFP: stw r4, r10[9] 266 ; CHECKFP: .cfi_offset 4, -4 267 ; CHECKFP: stw r5, r10[8] 268 ; CHECKFP: .cfi_offset 5, -8 269 ; CHECKFP: stw r6, r10[7] 270 ; CHECKFP: .cfi_offset 6, -12 271 ; CHECKFP: stw r7, r10[6] 272 ; CHECKFP: .cfi_offset 7, -16 273 ; CHECKFP: stw r8, r10[5] 274 ; CHECKFP: .cfi_offset 8, -20 275 ; CHECKFP: stw r9, r10[4] 276 ; CHECKFP: .cfi_offset 9, -24 277 ; CHECKFP: bt r0, .LBB{{[0-9_]+}} 278 ; CHECKFP: ldw r9, r10[4] 279 ; CHECKFP-NEXT: ldw r8, r10[5] 280 ; CHECKFP-NEXT: ldw r7, r10[6] 281 ; CHECKFP-NEXT: ldw r6, r10[7] 282 ; CHECKFP-NEXT: ldw r5, r10[8] 283 ; CHECKFP-NEXT: ldw r4, r10[9] 284 ; CHECKFP-NEXT: set sp, r10 285 ; CHECKFP-NEXT: ldw r10, sp[1] 286 ; CHECKFP-NEXT: retsp 10 287 ; CHECKFP: .LBB{{[0-9_]+}} 288 ; CHECKFP-NEXT: ldc r2, 40 289 ; CHECKFP-NEXT: add r2, r10, r2 290 ; CHECKFP-NEXT: add r2, r2, r0 291 ; CHECKFP-NEXT: mov r3, r1 292 ; CHECKFP-NEXT: ldw r9, r10[4] 293 ; CHECKFP-NEXT: ldw r8, r10[5] 294 ; CHECKFP-NEXT: ldw r7, r10[6] 295 ; CHECKFP-NEXT: ldw r6, r10[7] 296 ; CHECKFP-NEXT: ldw r5, r10[8] 297 ; CHECKFP-NEXT: ldw r4, r10[9] 298 ; CHECKFP-NEXT: ldw r1, sp[2] 299 ; CHECKFP-NEXT: ldw r0, sp[3] 300 ; CHECKFP-NEXT: set sp, r2 301 ; CHECKFP-NEXT: bau r3 302 ; 303 ; !FP: spill R0:1+R4:10 = entsp 2+7 304 ; We dont spill R0:1 305 ; We only restore R0:1 during eh.return 306 ; CHECK-LABEL: UnwindEH: 307 ; CHECK: entsp 9 308 ; CHECK: .cfi_def_cfa_offset 36 309 ; CHECK: .cfi_offset 15, 0 310 ; CHECK: .cfi_offset 1, -36 311 ; CHECK: .cfi_offset 0, -32 312 ; CHECK: stw r4, sp[8] 313 ; CHECK: .cfi_offset 4, -4 314 ; CHECK: stw r5, sp[7] 315 ; CHECK: .cfi_offset 5, -8 316 ; CHECK: stw r6, sp[6] 317 ; CHECK: .cfi_offset 6, -12 318 ; CHECK: stw r7, sp[5] 319 ; CHECK: .cfi_offset 7, -16 320 ; CHECK: stw r8, sp[4] 321 ; CHECK: .cfi_offset 8, -20 322 ; CHECK: stw r9, sp[3] 323 ; CHECK: .cfi_offset 9, -24 324 ; CHECK: stw r10, sp[2] 325 ; CHECK: .cfi_offset 10, -28 326 ; CHECK: bt r0, .LBB{{[0-9_]+}} 327 ; CHECK: ldw r10, sp[2] 328 ; CHECK-NEXT: ldw r9, sp[3] 329 ; CHECK-NEXT: ldw r8, sp[4] 330 ; CHECK-NEXT: ldw r7, sp[5] 331 ; CHECK-NEXT: ldw r6, sp[6] 332 ; CHECK-NEXT: ldw r5, sp[7] 333 ; CHECK-NEXT: ldw r4, sp[8] 334 ; CHECK-NEXT: retsp 9 335 ; CHECK: .LBB{{[0-9_]+}} 336 ; CHECK-NEXT: ldc r2, 36 337 ; CHECK-NEXT: ldaw r3, sp[0] 338 ; CHECK-NEXT: add r2, r3, r2 339 ; CHECK-NEXT: add r2, r2, r0 340 ; CHECK-NEXT: mov r3, r1 341 ; CHECK-NEXT: ldw r10, sp[2] 342 ; CHECK-NEXT: ldw r9, sp[3] 343 ; CHECK-NEXT: ldw r8, sp[4] 344 ; CHECK-NEXT: ldw r7, sp[5] 345 ; CHECK-NEXT: ldw r6, sp[6] 346 ; CHECK-NEXT: ldw r5, sp[7] 347 ; CHECK-NEXT: ldw r4, sp[8] 348 ; CHECK-NEXT: ldw r1, sp[0] 349 ; CHECK-NEXT: ldw r0, sp[1] 350 ; CHECK-NEXT: set sp, r2 351 ; CHECK-NEXT: bau r3 352 define void @UnwindEH(i32 %offset, i8* %handler) { 353 call void @llvm.eh.unwind.init() 354 %cmp = icmp eq i32 %offset, 0 355 br i1 %cmp, label %normal, label %eh 356 eh: 357 call void @llvm.eh.return.i32(i32 %offset, i8* %handler) 358 unreachable 359 normal: 360 ret void 361 } 362