1; RUN: llc -mtriple=thumbv6m-eabi %s -o - | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-T1 2; RUN: llc -mtriple=thumbv7m-eabi %s -o - | FileCheck %s -check-prefix=CHECK -check-prefix=CHECK-T2 3 4 5; Register offset 6 7; CHECK-LABEL: ldrsb_rr 8; CHECK: ldrsb r0, [r0, r1] 9define i32 @ldrsb_rr(i8* %p, i32 %n) { 10entry: 11 %arrayidx = getelementptr inbounds i8, i8* %p, i32 %n 12 %0 = load i8, i8* %arrayidx, align 1 13 %conv = sext i8 %0 to i32 14 ret i32 %conv 15} 16 17; CHECK-LABEL: ldrsh_rr 18; CHECK-T1: lsls r1, r1, #1 19; CHECK-T1: ldrsh r0, [r0, r1] 20; CHECK-T2: ldrsh.w r0, [r0, r1, lsl #1] 21define i32 @ldrsh_rr(i16* %p, i32 %n) { 22entry: 23 %arrayidx = getelementptr inbounds i16, i16* %p, i32 %n 24 %0 = load i16, i16* %arrayidx, align 2 25 %conv = sext i16 %0 to i32 26 ret i32 %conv 27} 28 29; CHECK-LABEL: ldrb_rr 30; CHECK: ldrb r0, [r0, r1] 31define i32 @ldrb_rr(i8* %p, i32 %n) { 32entry: 33 %arrayidx = getelementptr inbounds i8, i8* %p, i32 %n 34 %0 = load i8, i8* %arrayidx, align 1 35 %conv = zext i8 %0 to i32 36 ret i32 %conv 37} 38 39; CHECK-LABEL: ldrh_rr 40; CHECK-T1: lsls r1, r1, #1 41; CHECK-T1: ldrh r0, [r0, r1] 42; CHECK-T2: ldrh.w r0, [r0, r1, lsl #1] 43define i32 @ldrh_rr(i16* %p, i32 %n) { 44entry: 45 %arrayidx = getelementptr inbounds i16, i16* %p, i32 %n 46 %0 = load i16, i16* %arrayidx, align 2 47 %conv = zext i16 %0 to i32 48 ret i32 %conv 49} 50 51; CHECK-LABEL: ldr_rr 52; CHECK-T1: lsls r1, r1, #2 53; CHECK-T1: ldr r0, [r0, r1] 54; CHECK-T2: ldr.w r0, [r0, r1, lsl #2] 55define i32 @ldr_rr(i32* %p, i32 %n) { 56entry: 57 %arrayidx = getelementptr inbounds i32, i32* %p, i32 %n 58 %0 = load i32, i32* %arrayidx, align 4 59 ret i32 %0 60} 61 62; CHECK-LABEL: strb_rr 63; CHECK: strb r2, [r0, r1] 64define void @strb_rr(i8* %p, i32 %n, i32 %x) { 65entry: 66 %conv = trunc i32 %x to i8 67 %arrayidx = getelementptr inbounds i8, i8* %p, i32 %n 68 store i8 %conv, i8* %arrayidx, align 1 69 ret void 70} 71 72; CHECK-LABEL: strh_rr 73; CHECK-T1: lsls r1, r1, #1 74; CHECK-T1: strh r2, [r0, r1] 75; CHECK-T2: strh.w r2, [r0, r1, lsl #1] 76define void @strh_rr(i16* %p, i32 %n, i32 %x) { 77entry: 78 %conv = trunc i32 %x to i16 79 %arrayidx = getelementptr inbounds i16, i16* %p, i32 %n 80 store i16 %conv, i16* %arrayidx, align 2 81 ret void 82} 83 84; CHECK-LABEL: str_rr 85; CHECK-T1: lsls r1, r1, #2 86; CHECK-T1: str r2, [r0, r1] 87; CHECK-T2: str.w r2, [r0, r1, lsl #2] 88define void @str_rr(i32* %p, i32 %n, i32 %x) { 89entry: 90 %arrayidx = getelementptr inbounds i32, i32* %p, i32 %n 91 store i32 %x, i32* %arrayidx, align 4 92 ret void 93} 94 95 96; Immediate offset of zero 97 98; CHECK-LABEL: ldrsb_ri_zero 99; CHECK-T1: ldrb r0, [r0] 100; CHECK-T1: sxtb r0, r0 101; CHECK-T2: ldrsb.w r0, [r0] 102define i32 @ldrsb_ri_zero(i8* %p) { 103entry: 104 %0 = load i8, i8* %p, align 1 105 %conv = sext i8 %0 to i32 106 ret i32 %conv 107} 108 109; CHECK-LABEL: ldrsh_ri_zero 110; CHECK-T1: ldrh r0, [r0] 111; CHECK-T1: sxth r0, r0 112; CHECK-T2: ldrsh.w r0, [r0] 113define i32 @ldrsh_ri_zero(i16* %p) { 114entry: 115 %0 = load i16, i16* %p, align 2 116 %conv = sext i16 %0 to i32 117 ret i32 %conv 118} 119 120; CHECK-LABEL: ldrb_ri_zero 121; CHECK: ldrb r0, [r0] 122define i32 @ldrb_ri_zero(i8* %p) { 123entry: 124 %0 = load i8, i8* %p, align 1 125 %conv = zext i8 %0 to i32 126 ret i32 %conv 127} 128 129; CHECK-LABEL: ldrh_ri_zero 130; CHECK: ldrh r0, [r0] 131define i32 @ldrh_ri_zero(i16* %p) { 132entry: 133 %0 = load i16, i16* %p, align 2 134 %conv = zext i16 %0 to i32 135 ret i32 %conv 136} 137 138; CHECK-LABEL: ldr_ri_zero 139; CHECK: ldr r0, [r0] 140define i32 @ldr_ri_zero(i32* %p) { 141entry: 142 %0 = load i32, i32* %p, align 4 143 ret i32 %0 144} 145 146; CHECK-LABEL: strb_ri_zero 147; CHECK: strb r1, [r0] 148define void @strb_ri_zero(i8* %p, i32 %x) { 149entry: 150 %conv = trunc i32 %x to i8 151 store i8 %conv, i8* %p, align 1 152 ret void 153} 154 155; CHECK-LABEL: strh_ri_zero 156; CHECK: strh r1, [r0] 157define void @strh_ri_zero(i16* %p, i32 %x) { 158entry: 159 %conv = trunc i32 %x to i16 160 store i16 %conv, i16* %p, align 2 161 ret void 162} 163 164; CHECK-LABEL: str_ri_zero 165; CHECK: str r1, [r0] 166define void @str_ri_zero(i32* %p, i32 %x) { 167entry: 168 store i32 %x, i32* %p, align 4 169 ret void 170} 171 172 173; Maximum Thumb-1 immediate offset 174 175; CHECK-LABEL: ldrsb_ri_t1_max 176; CHECK-T1: movs r1, #31 177; CHECK-T1: ldrsb r0, [r0, r1] 178; CHECK-T2: ldrsb.w r0, [r0, #31] 179define i32 @ldrsb_ri_t1_max(i8* %p) { 180entry: 181 %arrayidx = getelementptr inbounds i8, i8* %p, i32 31 182 %0 = load i8, i8* %arrayidx, align 1 183 %conv = sext i8 %0 to i32 184 ret i32 %conv 185} 186 187; CHECK-LABEL: ldrsh_ri_t1_max 188; CHECK-T1: movs r1, #62 189; CHECK-T1: ldrsh r0, [r0, r1] 190; CHECK-T2: ldrsh.w r0, [r0, #62] 191define i32 @ldrsh_ri_t1_max(i16* %p) { 192entry: 193 %arrayidx = getelementptr inbounds i16, i16* %p, i32 31 194 %0 = load i16, i16* %arrayidx, align 2 195 %conv = sext i16 %0 to i32 196 ret i32 %conv 197} 198 199; CHECK-LABEL: ldrb_ri_t1_max 200; CHECK: ldrb r0, [r0, #31] 201define i32 @ldrb_ri_t1_max(i8* %p) { 202entry: 203 %arrayidx = getelementptr inbounds i8, i8* %p, i32 31 204 %0 = load i8, i8* %arrayidx, align 1 205 %conv = zext i8 %0 to i32 206 ret i32 %conv 207} 208 209; CHECK-LABEL: ldrh_ri_t1_max 210; CHECK: ldrh r0, [r0, #62] 211define i32 @ldrh_ri_t1_max(i16* %p) { 212entry: 213 %arrayidx = getelementptr inbounds i16, i16* %p, i32 31 214 %0 = load i16, i16* %arrayidx, align 2 215 %conv = zext i16 %0 to i32 216 ret i32 %conv 217} 218 219; CHECK-LABEL: ldr_ri_t1_max 220; CHECK: ldr r0, [r0, #124] 221define i32 @ldr_ri_t1_max(i32* %p) { 222entry: 223 %arrayidx = getelementptr inbounds i32, i32* %p, i32 31 224 %0 = load i32, i32* %arrayidx, align 4 225 ret i32 %0 226} 227 228; CHECK-LABEL: strb_ri_t1_max 229; CHECK: strb r1, [r0, #31] 230define void @strb_ri_t1_max(i8* %p, i32 %x) { 231entry: 232 %conv = trunc i32 %x to i8 233 %arrayidx = getelementptr inbounds i8, i8* %p, i32 31 234 store i8 %conv, i8* %arrayidx, align 1 235 ret void 236} 237 238; CHECK-LABEL: strh_ri_t1_max 239; CHECK: strh r1, [r0, #62] 240define void @strh_ri_t1_max(i16* %p, i32 %x) { 241entry: 242 %conv = trunc i32 %x to i16 243 %arrayidx = getelementptr inbounds i16, i16* %p, i32 31 244 store i16 %conv, i16* %arrayidx, align 2 245 ret void 246} 247 248; CHECK-LABEL: str_ri_t1_max 249; CHECK: str r1, [r0, #124] 250define void @str_ri_t1_max(i32* %p, i32 %x) { 251entry: 252 %arrayidx = getelementptr inbounds i32, i32* %p, i32 31 253 store i32 %x, i32* %arrayidx, align 4 254 ret void 255} 256 257 258; One past maximum Thumb-1 immediate offset 259 260; CHECK-LABEL: ldrsb_ri_t1_too_big 261; CHECK-T1: movs r1, #32 262; CHECK-T1: ldrsb r0, [r0, r1] 263; CHECK-T2: ldrsb.w r0, [r0, #32] 264define i32 @ldrsb_ri_t1_too_big(i8* %p) { 265entry: 266 %arrayidx = getelementptr inbounds i8, i8* %p, i32 32 267 %0 = load i8, i8* %arrayidx, align 1 268 %conv = sext i8 %0 to i32 269 ret i32 %conv 270} 271 272; CHECK-LABEL: ldrsh_ri_t1_too_big 273; CHECK-T1: movs r1, #64 274; CHECK-T1: ldrsh r0, [r0, r1] 275; CHECK-T2: ldrsh.w r0, [r0, #64] 276define i32 @ldrsh_ri_t1_too_big(i16* %p) { 277entry: 278 %arrayidx = getelementptr inbounds i16, i16* %p, i32 32 279 %0 = load i16, i16* %arrayidx, align 2 280 %conv = sext i16 %0 to i32 281 ret i32 %conv 282} 283 284; CHECK-LABEL: ldrb_ri_t1_too_big 285; CHECK-T1: movs r1, #32 286; CHECK-T1: ldrb r0, [r0, r1] 287; CHECK-T2: ldrb.w r0, [r0, #32] 288define i32 @ldrb_ri_t1_too_big(i8* %p) { 289entry: 290 %arrayidx = getelementptr inbounds i8, i8* %p, i32 32 291 %0 = load i8, i8* %arrayidx, align 1 292 %conv = zext i8 %0 to i32 293 ret i32 %conv 294} 295 296; CHECK-LABEL: ldrh_ri_t1_too_big 297; CHECK-T1: movs r1, #64 298; CHECK-T1: ldrh r0, [r0, r1] 299; CHECK-T2: ldrh.w r0, [r0, #64] 300define i32 @ldrh_ri_t1_too_big(i16* %p) { 301entry: 302 %arrayidx = getelementptr inbounds i16, i16* %p, i32 32 303 %0 = load i16, i16* %arrayidx, align 2 304 %conv = zext i16 %0 to i32 305 ret i32 %conv 306} 307 308; CHECK-LABEL: ldr_ri_t1_too_big 309; CHECK-T1: movs r1, #128 310; CHECK-T1: ldr r0, [r0, r1] 311; CHECK-T2: ldr.w r0, [r0, #128] 312define i32 @ldr_ri_t1_too_big(i32* %p) { 313entry: 314 %arrayidx = getelementptr inbounds i32, i32* %p, i32 32 315 %0 = load i32, i32* %arrayidx, align 4 316 ret i32 %0 317} 318 319; CHECK-LABEL: strb_ri_t1_too_big 320; CHECK-T1: movs r2, #32 321; CHECK-T1: strb r1, [r0, r2] 322; CHECK-T2: strb.w r1, [r0, #32] 323define void @strb_ri_t1_too_big(i8* %p, i32 %x) { 324entry: 325 %conv = trunc i32 %x to i8 326 %arrayidx = getelementptr inbounds i8, i8* %p, i32 32 327 store i8 %conv, i8* %arrayidx, align 1 328 ret void 329} 330 331; CHECK-LABEL: strh_ri_t1_too_big 332; CHECK-T1: movs r2, #64 333; CHECK-T1: strh r1, [r0, r2] 334; CHECK-T2: strh.w r1, [r0, #64] 335define void @strh_ri_t1_too_big(i16* %p, i32 %x) { 336entry: 337 %conv = trunc i32 %x to i16 338 %arrayidx = getelementptr inbounds i16, i16* %p, i32 32 339 store i16 %conv, i16* %arrayidx, align 2 340 ret void 341} 342 343; CHECK-LABEL: str_ri_t1_too_big 344; CHECK-T1: movs r2, #128 345; CHECK-T1: str r1, [r0, r2] 346; CHECK-T2: str.w r1, [r0, #128] 347define void @str_ri_t1_too_big(i32* %p, i32 %x) { 348entry: 349 %arrayidx = getelementptr inbounds i32, i32* %p, i32 32 350 store i32 %x, i32* %arrayidx, align 4 351 ret void 352} 353 354 355; Maximum Thumb-2 immediate offset 356 357; CHECK-LABEL: ldrsb_ri_t2_max 358; CHECK-T1: ldr r1, .LCP 359; CHECK-T1: ldrsb r0, [r0, r1] 360; CHECK-T2: ldrsb.w r0, [r0, #4095] 361define i32 @ldrsb_ri_t2_max(i8* %p) { 362entry: 363 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095 364 %0 = load i8, i8* %add.ptr, align 1 365 %conv = sext i8 %0 to i32 366 ret i32 %conv 367} 368 369; CHECK-LABEL: ldrsh_ri_t2_max 370; CHECK-T1: ldr r1, .LCP 371; CHECK-T1: ldrsh r0, [r0, r1] 372; CHECK-T2: ldrsh.w r0, [r0, #4095] 373define i32 @ldrsh_ri_t2_max(i8* %p) { 374entry: 375 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095 376 %0 = bitcast i8* %add.ptr to i16* 377 %1 = load i16, i16* %0, align 2 378 %conv = sext i16 %1 to i32 379 ret i32 %conv 380} 381 382; CHECK-LABEL: ldrb_ri_t2_max 383; CHECK-T1: ldr r1, .LCP 384; CHECK-T1: ldrb r0, [r0, r1] 385; CHECK-T2: ldrb.w r0, [r0, #4095] 386define i32 @ldrb_ri_t2_max(i8* %p) { 387entry: 388 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095 389 %0 = load i8, i8* %add.ptr, align 1 390 %conv = zext i8 %0 to i32 391 ret i32 %conv 392} 393 394; CHECK-LABEL: ldrh_ri_t2_max 395; CHECK-T1: ldr r1, .LCP 396; CHECK-T1: ldrh r0, [r0, r1] 397; CHECK-T2: ldrh.w r0, [r0, #4095] 398define i32 @ldrh_ri_t2_max(i8* %p) { 399entry: 400 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095 401 %0 = bitcast i8* %add.ptr to i16* 402 %1 = load i16, i16* %0, align 2 403 %conv = zext i16 %1 to i32 404 ret i32 %conv 405} 406 407; CHECK-LABEL: ldr_ri_t2_max 408; CHECK-T1: ldr r1, .LCP 409; CHECK-T1: ldr r0, [r0, r1] 410; CHECK-T2: ldr.w r0, [r0, #4095] 411define i32 @ldr_ri_t2_max(i8* %p) { 412entry: 413 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095 414 %0 = bitcast i8* %add.ptr to i32* 415 %1 = load i32, i32* %0, align 4 416 ret i32 %1 417} 418 419; CHECK-LABEL: strb_ri_t2_max 420; CHECK-T1: ldr r2, .LCP 421; CHECK-T1: strb r1, [r0, r2] 422; CHECK-T2: strb.w r1, [r0, #4095] 423define void @strb_ri_t2_max(i8* %p, i32 %x) { 424entry: 425 %conv = trunc i32 %x to i8 426 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095 427 store i8 %conv, i8* %add.ptr, align 1 428 ret void 429} 430 431; CHECK-LABEL: strh_ri_t2_max 432; CHECK-T1: ldr r2, .LCP 433; CHECK-T1: strh r1, [r0, r2] 434; CHECK-T2: strh.w r1, [r0, #4095] 435define void @strh_ri_t2_max(i8* %p, i32 %x) { 436entry: 437 %conv = trunc i32 %x to i16 438 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095 439 %0 = bitcast i8* %add.ptr to i16* 440 store i16 %conv, i16* %0, align 2 441 ret void 442} 443 444; CHECK-LABEL: str_ri_t2_max 445; CHECK-T1: ldr r2, .LCP 446; CHECK-T1: str r1, [r0, r2] 447; CHECK-T2: str.w r1, [r0, #4095] 448define void @str_ri_t2_max(i8* %p, i32 %x) { 449entry: 450 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4095 451 %0 = bitcast i8* %add.ptr to i32* 452 store i32 %x, i32* %0, align 4 453 ret void 454} 455 456 457; One past maximum Thumb-2 immediate offset 458 459; CHECK-LABEL: ldrsb_ri_t2_too_big 460; CHECK-T1: movs r1, #1 461; CHECK-T1: lsls r1, r1, #12 462; CHECK-T2: mov.w r1, #4096 463; CHECK: ldrsb r0, [r0, r1] 464define i32 @ldrsb_ri_t2_too_big(i8* %p) { 465entry: 466 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096 467 %0 = load i8, i8* %add.ptr, align 1 468 %conv = sext i8 %0 to i32 469 ret i32 %conv 470} 471 472; CHECK-LABEL: ldrsh_ri_t2_too_big 473; CHECK-T1: movs r1, #1 474; CHECK-T1: lsls r1, r1, #12 475; CHECK-T2: mov.w r1, #4096 476; CHECK: ldrsh r0, [r0, r1] 477define i32 @ldrsh_ri_t2_too_big(i8* %p) { 478entry: 479 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096 480 %0 = bitcast i8* %add.ptr to i16* 481 %1 = load i16, i16* %0, align 2 482 %conv = sext i16 %1 to i32 483 ret i32 %conv 484} 485 486; CHECK-LABEL: ldrb_ri_t2_too_big 487; CHECK-T1: movs r1, #1 488; CHECK-T1: lsls r1, r1, #12 489; CHECK-T2: mov.w r1, #4096 490; CHECK: ldrb r0, [r0, r1] 491define i32 @ldrb_ri_t2_too_big(i8* %p) { 492entry: 493 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096 494 %0 = load i8, i8* %add.ptr, align 1 495 %conv = zext i8 %0 to i32 496 ret i32 %conv 497} 498 499; CHECK-LABEL: ldrh_ri_t2_too_big 500; CHECK-T1: movs r1, #1 501; CHECK-T1: lsls r1, r1, #12 502; CHECK-T2: mov.w r1, #4096 503; CHECK: ldrh r0, [r0, r1] 504define i32 @ldrh_ri_t2_too_big(i8* %p) { 505entry: 506 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096 507 %0 = bitcast i8* %add.ptr to i16* 508 %1 = load i16, i16* %0, align 2 509 %conv = zext i16 %1 to i32 510 ret i32 %conv 511} 512 513; CHECK-LABEL: ldr_ri_t2_too_big 514; CHECK-T1: movs r1, #1 515; CHECK-T1: lsls r1, r1, #12 516; CHECK-T2: mov.w r1, #4096 517; CHECK: ldr r0, [r0, r1] 518define i32 @ldr_ri_t2_too_big(i8* %p) { 519entry: 520 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096 521 %0 = bitcast i8* %add.ptr to i32* 522 %1 = load i32, i32* %0, align 4 523 ret i32 %1 524} 525 526; CHECK-LABEL: strb_ri_t2_too_big 527; CHECK-T1: movs r2, #1 528; CHECK-T1: lsls r2, r2, #12 529; CHECK-T2: mov.w r2, #4096 530; CHECK: strb r1, [r0, r2] 531define void @strb_ri_t2_too_big(i8* %p, i32 %x) { 532entry: 533 %conv = trunc i32 %x to i8 534 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096 535 store i8 %conv, i8* %add.ptr, align 1 536 ret void 537} 538 539; CHECK-LABEL: strh_ri_t2_too_big 540; CHECK-T1: movs r2, #1 541; CHECK-T1: lsls r2, r2, #12 542; CHECK-T2: mov.w r2, #4096 543; CHECK: strh r1, [r0, r2] 544define void @strh_ri_t2_too_big(i8* %p, i32 %x) { 545entry: 546 %conv = trunc i32 %x to i16 547 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096 548 %0 = bitcast i8* %add.ptr to i16* 549 store i16 %conv, i16* %0, align 2 550 ret void 551} 552 553; CHECK-LABEL: str_ri_t2_too_big 554; CHECK-T1: movs r2, #1 555; CHECK-T1: lsls r2, r2, #12 556; CHECK-T2: mov.w r2, #4096 557; CHECK: str r1, [r0, r2] 558define void @str_ri_t2_too_big(i8* %p, i32 %x) { 559entry: 560 %add.ptr = getelementptr inbounds i8, i8* %p, i32 4096 561 %0 = bitcast i8* %add.ptr to i32* 562 store i32 %x, i32* %0, align 4 563 ret void 564} 565