1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py 2; RUN: llc -mtriple=riscv64 -verify-machineinstrs < %s \ 3; RUN: | FileCheck -check-prefix=RV64I %s 4 5; Check indexed and unindexed, sext, zext and anyext loads 6 7define dso_local i64 @lb(ptr %a) nounwind { 8; RV64I-LABEL: lb: 9; RV64I: # %bb.0: 10; RV64I-NEXT: lb a1, 1(a0) 11; RV64I-NEXT: lbu zero, 0(a0) 12; RV64I-NEXT: mv a0, a1 13; RV64I-NEXT: ret 14 %1 = getelementptr i8, ptr %a, i32 1 15 %2 = load i8, ptr %1 16 %3 = sext i8 %2 to i64 17 ; the unused load will produce an anyext for selection 18 %4 = load volatile i8, ptr %a 19 ret i64 %3 20} 21 22define dso_local i64 @lh(ptr %a) nounwind { 23; RV64I-LABEL: lh: 24; RV64I: # %bb.0: 25; RV64I-NEXT: lh a1, 4(a0) 26; RV64I-NEXT: lh zero, 0(a0) 27; RV64I-NEXT: mv a0, a1 28; RV64I-NEXT: ret 29 %1 = getelementptr i16, ptr %a, i32 2 30 %2 = load i16, ptr %1 31 %3 = sext i16 %2 to i64 32 ; the unused load will produce an anyext for selection 33 %4 = load volatile i16, ptr %a 34 ret i64 %3 35} 36 37define dso_local i64 @lw(ptr %a) nounwind { 38; RV64I-LABEL: lw: 39; RV64I: # %bb.0: 40; RV64I-NEXT: lw a1, 12(a0) 41; RV64I-NEXT: lw zero, 0(a0) 42; RV64I-NEXT: mv a0, a1 43; RV64I-NEXT: ret 44 %1 = getelementptr i32, ptr %a, i32 3 45 %2 = load i32, ptr %1 46 %3 = sext i32 %2 to i64 47 ; the unused load will produce an anyext for selection 48 %4 = load volatile i32, ptr %a 49 ret i64 %3 50} 51 52define dso_local i64 @lbu(ptr %a) nounwind { 53; RV64I-LABEL: lbu: 54; RV64I: # %bb.0: 55; RV64I-NEXT: lbu a1, 4(a0) 56; RV64I-NEXT: lbu a0, 0(a0) 57; RV64I-NEXT: add a0, a1, a0 58; RV64I-NEXT: ret 59 %1 = getelementptr i8, ptr %a, i32 4 60 %2 = load i8, ptr %1 61 %3 = zext i8 %2 to i64 62 %4 = load volatile i8, ptr %a 63 %5 = zext i8 %4 to i64 64 %6 = add i64 %3, %5 65 ret i64 %6 66} 67 68define dso_local i64 @lhu(ptr %a) nounwind { 69; RV64I-LABEL: lhu: 70; RV64I: # %bb.0: 71; RV64I-NEXT: lhu a1, 10(a0) 72; RV64I-NEXT: lhu a0, 0(a0) 73; RV64I-NEXT: add a0, a1, a0 74; RV64I-NEXT: ret 75 %1 = getelementptr i16, ptr %a, i32 5 76 %2 = load i16, ptr %1 77 %3 = zext i16 %2 to i64 78 %4 = load volatile i16, ptr %a 79 %5 = zext i16 %4 to i64 80 %6 = add i64 %3, %5 81 ret i64 %6 82} 83 84define dso_local i64 @lwu(ptr %a) nounwind { 85; RV64I-LABEL: lwu: 86; RV64I: # %bb.0: 87; RV64I-NEXT: lwu a1, 24(a0) 88; RV64I-NEXT: lwu a0, 0(a0) 89; RV64I-NEXT: add a0, a1, a0 90; RV64I-NEXT: ret 91 %1 = getelementptr i32, ptr %a, i32 6 92 %2 = load i32, ptr %1 93 %3 = zext i32 %2 to i64 94 %4 = load volatile i32, ptr %a 95 %5 = zext i32 %4 to i64 96 %6 = add i64 %3, %5 97 ret i64 %6 98} 99 100; Check indexed and unindexed stores 101 102define dso_local void @sb(ptr %a, i8 %b) nounwind { 103; RV64I-LABEL: sb: 104; RV64I: # %bb.0: 105; RV64I-NEXT: sb a1, 0(a0) 106; RV64I-NEXT: sb a1, 7(a0) 107; RV64I-NEXT: ret 108 store i8 %b, ptr %a 109 %1 = getelementptr i8, ptr %a, i32 7 110 store i8 %b, ptr %1 111 ret void 112} 113 114define dso_local void @sh(ptr %a, i16 %b) nounwind { 115; RV64I-LABEL: sh: 116; RV64I: # %bb.0: 117; RV64I-NEXT: sh a1, 0(a0) 118; RV64I-NEXT: sh a1, 16(a0) 119; RV64I-NEXT: ret 120 store i16 %b, ptr %a 121 %1 = getelementptr i16, ptr %a, i32 8 122 store i16 %b, ptr %1 123 ret void 124} 125 126define dso_local void @sw(ptr %a, i32 %b) nounwind { 127; RV64I-LABEL: sw: 128; RV64I: # %bb.0: 129; RV64I-NEXT: sw a1, 0(a0) 130; RV64I-NEXT: sw a1, 36(a0) 131; RV64I-NEXT: ret 132 store i32 %b, ptr %a 133 %1 = getelementptr i32, ptr %a, i32 9 134 store i32 %b, ptr %1 135 ret void 136} 137 138; 64-bit loads and stores 139 140define dso_local i64 @ld(ptr %a) nounwind { 141; RV64I-LABEL: ld: 142; RV64I: # %bb.0: 143; RV64I-NEXT: ld a1, 80(a0) 144; RV64I-NEXT: ld zero, 0(a0) 145; RV64I-NEXT: mv a0, a1 146; RV64I-NEXT: ret 147 %1 = getelementptr i64, ptr %a, i32 10 148 %2 = load i64, ptr %1 149 %3 = load volatile i64, ptr %a 150 ret i64 %2 151} 152 153define dso_local void @sd(ptr %a, i64 %b) nounwind { 154; RV64I-LABEL: sd: 155; RV64I: # %bb.0: 156; RV64I-NEXT: sd a1, 0(a0) 157; RV64I-NEXT: sd a1, 88(a0) 158; RV64I-NEXT: ret 159 store i64 %b, ptr %a 160 %1 = getelementptr i64, ptr %a, i32 11 161 store i64 %b, ptr %1 162 ret void 163} 164 165; Check load and store to an i1 location 166define dso_local i64 @load_sext_zext_anyext_i1(ptr %a) nounwind { 167; RV64I-LABEL: load_sext_zext_anyext_i1: 168; RV64I: # %bb.0: 169; RV64I-NEXT: lbu a1, 1(a0) 170; RV64I-NEXT: lbu a2, 2(a0) 171; RV64I-NEXT: lbu zero, 0(a0) 172; RV64I-NEXT: sub a0, a2, a1 173; RV64I-NEXT: ret 174 ; sextload i1 175 %1 = getelementptr i1, ptr %a, i32 1 176 %2 = load i1, ptr %1 177 %3 = sext i1 %2 to i64 178 ; zextload i1 179 %4 = getelementptr i1, ptr %a, i32 2 180 %5 = load i1, ptr %4 181 %6 = zext i1 %5 to i64 182 %7 = add i64 %3, %6 183 ; extload i1 (anyext). Produced as the load is unused. 184 %8 = load volatile i1, ptr %a 185 ret i64 %7 186} 187 188define dso_local i16 @load_sext_zext_anyext_i1_i16(ptr %a) nounwind { 189; RV64I-LABEL: load_sext_zext_anyext_i1_i16: 190; RV64I: # %bb.0: 191; RV64I-NEXT: lbu a1, 1(a0) 192; RV64I-NEXT: lbu a2, 2(a0) 193; RV64I-NEXT: lbu zero, 0(a0) 194; RV64I-NEXT: sub a0, a2, a1 195; RV64I-NEXT: ret 196 ; sextload i1 197 %1 = getelementptr i1, ptr %a, i32 1 198 %2 = load i1, ptr %1 199 %3 = sext i1 %2 to i16 200 ; zextload i1 201 %4 = getelementptr i1, ptr %a, i32 2 202 %5 = load i1, ptr %4 203 %6 = zext i1 %5 to i16 204 %7 = add i16 %3, %6 205 ; extload i1 (anyext). Produced as the load is unused. 206 %8 = load volatile i1, ptr %a 207 ret i16 %7 208} 209 210; Check load and store to a global 211@G = dso_local global i64 0 212 213define dso_local i64 @ld_sd_global(i64 %a) nounwind { 214; RV64I-LABEL: ld_sd_global: 215; RV64I: # %bb.0: 216; RV64I-NEXT: lui a2, %hi(G) 217; RV64I-NEXT: ld a1, %lo(G)(a2) 218; RV64I-NEXT: addi a3, a2, %lo(G) 219; RV64I-NEXT: sd a0, %lo(G)(a2) 220; RV64I-NEXT: ld zero, 72(a3) 221; RV64I-NEXT: sd a0, 72(a3) 222; RV64I-NEXT: mv a0, a1 223; RV64I-NEXT: ret 224 %1 = load volatile i64, ptr @G 225 store i64 %a, ptr @G 226 %2 = getelementptr i64, ptr @G, i64 9 227 %3 = load volatile i64, ptr %2 228 store i64 %a, ptr %2 229 ret i64 %1 230} 231 232define i64 @lw_near_local(ptr %a) { 233; RV64I-LABEL: lw_near_local: 234; RV64I: # %bb.0: 235; RV64I-NEXT: addi a0, a0, 2047 236; RV64I-NEXT: ld a0, 9(a0) 237; RV64I-NEXT: ret 238 %1 = getelementptr inbounds i64, ptr %a, i64 257 239 %2 = load volatile i64, ptr %1 240 ret i64 %2 241} 242 243define void @st_near_local(ptr %a, i64 %b) { 244; RV64I-LABEL: st_near_local: 245; RV64I: # %bb.0: 246; RV64I-NEXT: addi a0, a0, 2047 247; RV64I-NEXT: sd a1, 9(a0) 248; RV64I-NEXT: ret 249 %1 = getelementptr inbounds i64, ptr %a, i64 257 250 store i64 %b, ptr %1 251 ret void 252} 253 254define i64 @lw_sw_near_local(ptr %a, i64 %b) { 255; RV64I-LABEL: lw_sw_near_local: 256; RV64I: # %bb.0: 257; RV64I-NEXT: addi a2, a0, 2047 258; RV64I-NEXT: ld a0, 9(a2) 259; RV64I-NEXT: sd a1, 9(a2) 260; RV64I-NEXT: ret 261 %1 = getelementptr inbounds i64, ptr %a, i64 257 262 %2 = load volatile i64, ptr %1 263 store i64 %b, ptr %1 264 ret i64 %2 265} 266 267define i64 @lw_far_local(ptr %a) { 268; RV64I-LABEL: lw_far_local: 269; RV64I: # %bb.0: 270; RV64I-NEXT: lui a1, 8 271; RV64I-NEXT: add a0, a0, a1 272; RV64I-NEXT: ld a0, -8(a0) 273; RV64I-NEXT: ret 274 %1 = getelementptr inbounds i64, ptr %a, i64 4095 275 %2 = load volatile i64, ptr %1 276 ret i64 %2 277} 278 279define void @st_far_local(ptr %a, i64 %b) { 280; RV64I-LABEL: st_far_local: 281; RV64I: # %bb.0: 282; RV64I-NEXT: lui a2, 8 283; RV64I-NEXT: add a0, a0, a2 284; RV64I-NEXT: sd a1, -8(a0) 285; RV64I-NEXT: ret 286 %1 = getelementptr inbounds i64, ptr %a, i64 4095 287 store i64 %b, ptr %1 288 ret void 289} 290 291define i64 @lw_sw_far_local(ptr %a, i64 %b) { 292; RV64I-LABEL: lw_sw_far_local: 293; RV64I: # %bb.0: 294; RV64I-NEXT: lui a2, 8 295; RV64I-NEXT: add a2, a0, a2 296; RV64I-NEXT: ld a0, -8(a2) 297; RV64I-NEXT: sd a1, -8(a2) 298; RV64I-NEXT: ret 299 %1 = getelementptr inbounds i64, ptr %a, i64 4095 300 %2 = load volatile i64, ptr %1 301 store i64 %b, ptr %1 302 ret i64 %2 303} 304 305; Make sure we don't fold the addiw into the load offset. The sign extend of the 306; addiw is required. 307define i64 @lw_really_far_local(ptr %a) { 308; RV64I-LABEL: lw_really_far_local: 309; RV64I: # %bb.0: 310; RV64I-NEXT: lui a1, 524288 311; RV64I-NEXT: addiw a1, a1, -2048 312; RV64I-NEXT: add a0, a0, a1 313; RV64I-NEXT: ld a0, 0(a0) 314; RV64I-NEXT: ret 315 %1 = getelementptr inbounds i64, ptr %a, i64 268435200 316 %2 = load volatile i64, ptr %1 317 ret i64 %2 318} 319 320; Make sure we don't fold the addiw into the store offset. The sign extend of 321; the addiw is required. 322define void @st_really_far_local(ptr %a, i64 %b) { 323; RV64I-LABEL: st_really_far_local: 324; RV64I: # %bb.0: 325; RV64I-NEXT: lui a2, 524288 326; RV64I-NEXT: addiw a2, a2, -2048 327; RV64I-NEXT: add a0, a0, a2 328; RV64I-NEXT: sd a1, 0(a0) 329; RV64I-NEXT: ret 330 %1 = getelementptr inbounds i64, ptr %a, i64 268435200 331 store i64 %b, ptr %1 332 ret void 333} 334 335; Make sure we don't fold the addiw into the load/store offset. The sign extend 336; of the addiw is required. 337define i64 @lw_sw_really_far_local(ptr %a, i64 %b) { 338; RV64I-LABEL: lw_sw_really_far_local: 339; RV64I: # %bb.0: 340; RV64I-NEXT: lui a2, 524288 341; RV64I-NEXT: addiw a2, a2, -2048 342; RV64I-NEXT: add a2, a0, a2 343; RV64I-NEXT: ld a0, 0(a2) 344; RV64I-NEXT: sd a1, 0(a2) 345; RV64I-NEXT: ret 346 %1 = getelementptr inbounds i64, ptr %a, i64 268435200 347 %2 = load volatile i64, ptr %1 348 store i64 %b, ptr %1 349 ret i64 %2 350} 351 352%struct.quux = type { i32, [0 x i8] } 353 354; Make sure we don't remove the addi and fold the C from 355; (add (addi FrameIndex, C), X) into the store address. 356; FrameIndex cannot be the operand of an ADD. We must keep the ADDI. 357define void @addi_fold_crash(i64 %arg) nounwind { 358; RV64I-LABEL: addi_fold_crash: 359; RV64I: # %bb.0: # %bb 360; RV64I-NEXT: addi sp, sp, -16 361; RV64I-NEXT: sd ra, 8(sp) # 8-byte Folded Spill 362; RV64I-NEXT: addi a1, sp, 4 363; RV64I-NEXT: add a0, a1, a0 364; RV64I-NEXT: sb zero, 0(a0) 365; RV64I-NEXT: mv a0, a1 366; RV64I-NEXT: call snork 367; RV64I-NEXT: ld ra, 8(sp) # 8-byte Folded Reload 368; RV64I-NEXT: addi sp, sp, 16 369; RV64I-NEXT: ret 370bb: 371 %tmp = alloca %struct.quux, align 8 372 %tmp1 = getelementptr inbounds %struct.quux, ptr %tmp, i64 0, i32 1 373 %tmp2 = getelementptr inbounds %struct.quux, ptr %tmp, i64 0, i32 1, i64 %arg 374 store i8 0, ptr %tmp2, align 1 375 call void @snork(ptr %tmp1) 376 ret void 377} 378 379declare void @snork(ptr) 380