1; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 2 2; RUN: llc < %s -mtriple=s390x-linux-gnu | FileCheck %s 3; 4; Test PC-relative memory accesses of globals with packed struct types. 5; PC-relative memory accesses cannot be used when the address is not 6; aligned. This can happen with programs like the following (which are not 7; strictly correct): 8; 9; #pragma pack(1) 10; struct { 11; short a; 12; int b; 13; } c; 14; 15; void main() { 16; int *e = &c.b; 17; *e = 0; 18; } 19; 20 21%packed.i16i32 = type <{ i16, i32 }> 22%packed.i16i32i16i32 = type <{ i16, i32, i16, i32 }> 23%packed.i16i64 = type <{ i16, i64 }> 24%packed.i8i16 = type <{ i8, i16 }> 25 26@A_align2 = dso_local global %packed.i16i32 zeroinitializer, align 2 27@B_align2 = dso_local global %packed.i16i32i16i32 zeroinitializer, align 2 28@C_align2 = dso_local global %packed.i16i64 zeroinitializer, align 2 29@D_align4 = dso_local global %packed.i16i32 zeroinitializer, align 4 30@E_align4 = dso_local global %packed.i16i32i16i32 zeroinitializer, align 4 31@F_align2 = dso_local global %packed.i8i16 zeroinitializer, align 2 32 33;;; Stores 34 35; unaligned packed struct + 2 -> unaligned address 36define dso_local void @f1() { 37; CHECK-LABEL: f1: 38; CHECK: # %bb.0: 39; CHECK-NEXT: larl %r1, A_align2 40; CHECK-NEXT: mvhi 2(%r1), 0 41; CHECK-NEXT: br %r14 42 store i32 0, ptr getelementptr inbounds (%packed.i16i32, ptr @A_align2, i64 0, i32 1), align 4 43 ret void 44} 45 46; unaligned packed struct + 8 -> unaligned address 47define dso_local void @f2() { 48; CHECK-LABEL: f2: 49; CHECK: # %bb.0: 50; CHECK-NEXT: larl %r1, B_align2 51; CHECK-NEXT: mvhi 8(%r1), 0 52; CHECK-NEXT: br %r14 53 store i32 0, ptr getelementptr inbounds (%packed.i16i32i16i32, ptr @B_align2, i64 0, i32 3), align 4 54 ret void 55} 56 57; aligned packed struct + 2 -> unaligned address 58define dso_local void @f3() { 59; CHECK-LABEL: f3: 60; CHECK: # %bb.0: 61; CHECK-NEXT: larl %r1, D_align4 62; CHECK-NEXT: mvhi 2(%r1), 0 63; CHECK-NEXT: br %r14 64 store i32 0, ptr getelementptr inbounds (%packed.i16i32, ptr @D_align4, i64 0, i32 1), align 4 65 ret void 66} 67 68; aligned packed struct + 8 -> aligned address 69define dso_local void @f4() { 70; CHECK-LABEL: f4: 71; CHECK: # %bb.0: 72; CHECK-NEXT: lhi %r0, 0 73; CHECK-NEXT: strl %r0, E_align4+8 74; CHECK-NEXT: br %r14 75 store i32 0, ptr getelementptr inbounds (%packed.i16i32i16i32, ptr @E_align4, i64 0, i32 3), align 4 76 ret void 77} 78 79define dso_local void @f5() { 80; CHECK-LABEL: f5: 81; CHECK: # %bb.0: 82; CHECK-NEXT: larl %r1, C_align2 83; CHECK-NEXT: mvghi 2(%r1), 0 84; CHECK-NEXT: br %r14 85 store i64 0, ptr getelementptr inbounds (%packed.i16i64, ptr @C_align2, i64 0, i32 1), align 8 86 ret void 87} 88 89define dso_local void @f6() { 90; CHECK-LABEL: f6: 91; CHECK: # %bb.0: 92; CHECK-NEXT: larl %r1, F_align2 93; CHECK-NEXT: mvhhi 1(%r1), 0 94; CHECK-NEXT: br %r14 95 store i16 0, ptr getelementptr inbounds (%packed.i8i16, ptr @F_align2, i64 0, i32 1), align 2 96 ret void 97} 98 99define dso_local void @f7(ptr %Src) { 100; CHECK-LABEL: f7: 101; CHECK: # %bb.0: 102; CHECK-NEXT: lg %r0, 0(%r2) 103; CHECK-NEXT: larl %r1, D_align4 104; CHECK-NEXT: st %r0, 2(%r1) 105; CHECK-NEXT: br %r14 106 %L = load i64, ptr %Src 107 %T = trunc i64 %L to i32 108 store i32 %T, ptr getelementptr inbounds (%packed.i16i32, ptr @D_align4, i64 0, i32 1), align 4 109 ret void 110} 111 112define dso_local void @f8(ptr %Src) { 113; CHECK-LABEL: f8: 114; CHECK: # %bb.0: 115; CHECK-NEXT: lg %r0, 0(%r2) 116; CHECK-NEXT: larl %r1, F_align2 117; CHECK-NEXT: sth %r0, 1(%r1) 118; CHECK-NEXT: br %r14 119 %L = load i64, ptr %Src 120 %T = trunc i64 %L to i16 121 store i16 %T, ptr getelementptr inbounds (%packed.i8i16, ptr @F_align2, i64 0, i32 1), align 2 122 ret void 123} 124 125;;; Loads 126 127; unaligned packed struct + 2 -> unaligned address 128define dso_local i32 @f9() { 129; CHECK-LABEL: f9: 130; CHECK: # %bb.0: 131; CHECK-NEXT: larl %r1, A_align2 132; CHECK-NEXT: l %r2, 2(%r1) 133; CHECK-NEXT: br %r14 134 %L = load i32, ptr getelementptr inbounds (%packed.i16i32, ptr @A_align2, i64 0, i32 1), align 4 135 ret i32 %L 136} 137 138; unaligned packed struct + 8 -> unaligned address 139define dso_local i32 @f10() { 140; CHECK-LABEL: f10: 141; CHECK: # %bb.0: 142; CHECK-NEXT: larl %r1, B_align2 143; CHECK-NEXT: l %r2, 8(%r1) 144; CHECK-NEXT: br %r14 145 %L = load i32, ptr getelementptr inbounds (%packed.i16i32i16i32, ptr @B_align2, i64 0, i32 3), align 4 146 ret i32 %L 147} 148 149; aligned packed struct + 2 -> unaligned address 150define dso_local i32 @f11() { 151; CHECK-LABEL: f11: 152; CHECK: # %bb.0: 153; CHECK-NEXT: larl %r1, D_align4 154; CHECK-NEXT: l %r2, 2(%r1) 155; CHECK-NEXT: br %r14 156 %L = load i32, ptr getelementptr inbounds (%packed.i16i32, ptr @D_align4, i64 0, i32 1), align 4 157 ret i32 %L 158} 159 160; aligned packed struct + 8 -> aligned address 161define dso_local i32 @f12() { 162; CHECK-LABEL: f12: 163; CHECK: # %bb.0: 164; CHECK-NEXT: lrl %r2, E_align4+8 165; CHECK-NEXT: br %r14 166 %L = load i32, ptr getelementptr inbounds (%packed.i16i32i16i32, ptr @E_align4, i64 0, i32 3), align 4 167 ret i32 %L 168} 169 170define dso_local i64 @f13() { 171; CHECK-LABEL: f13: 172; CHECK: # %bb.0: 173; CHECK-NEXT: larl %r1, C_align2 174; CHECK-NEXT: lg %r2, 2(%r1) 175; CHECK-NEXT: br %r14 176 %L = load i64, ptr getelementptr inbounds (%packed.i16i64, ptr @C_align2, i64 0, i32 1), align 8 177 ret i64 %L 178} 179 180define dso_local i32 @f14() { 181; CHECK-LABEL: f14: 182; CHECK: # %bb.0: 183; CHECK-NEXT: larl %r1, F_align2 184; CHECK-NEXT: lh %r2, 1(%r1) 185; CHECK-NEXT: br %r14 186 %L = load i16, ptr getelementptr inbounds (%packed.i8i16, ptr @F_align2, i64 0, i32 1), align 2 187 %ext = sext i16 %L to i32 188 ret i32 %ext 189} 190 191define dso_local i64 @f15() { 192; CHECK-LABEL: f15: 193; CHECK: # %bb.0: 194; CHECK-NEXT: larl %r1, F_align2 195; CHECK-NEXT: llgh %r2, 1(%r1) 196; CHECK-NEXT: br %r14 197 %L = load i16, ptr getelementptr inbounds (%packed.i8i16, ptr @F_align2, i64 0, i32 1), align 2 198 %ext = zext i16 %L to i64 199 ret i64 %ext 200} 201 202;;; Loads folded into compare instructions 203 204define dso_local i32 @f16(i32 %src1) { 205; CHECK-LABEL: f16: 206; CHECK: # %bb.0: # %entry 207; CHECK-NEXT: larl %r1, A_align2 208; CHECK-NEXT: c %r2, 2(%r1) 209; CHECK-NEXT: blr %r14 210; CHECK-NEXT: .LBB15_1: # %mulb 211; CHECK-NEXT: msr %r2, %r2 212; CHECK-NEXT: br %r14 213entry: 214 %src2 = load i32, ptr getelementptr inbounds (%packed.i16i32, ptr @A_align2, i64 0, i32 1), align 4 215 %cond = icmp slt i32 %src1, %src2 216 br i1 %cond, label %exit, label %mulb 217mulb: 218 %mul = mul i32 %src1, %src1 219 br label %exit 220exit: 221 %res = phi i32 [ %src1, %entry ], [ %mul, %mulb ] 222 ret i32 %res 223} 224 225define dso_local i64 @f17(i64 %src1) { 226; CHECK-LABEL: f17: 227; CHECK: # %bb.0: # %entry 228; CHECK-NEXT: larl %r1, C_align2 229; CHECK-NEXT: clg %r2, 2(%r1) 230; CHECK-NEXT: blr %r14 231; CHECK-NEXT: .LBB16_1: # %mulb 232; CHECK-NEXT: msgr %r2, %r2 233; CHECK-NEXT: br %r14 234entry: 235 %src2 = load i64, ptr getelementptr inbounds (%packed.i16i64, ptr @C_align2, i64 0, i32 1), align 8 236 %cond = icmp ult i64 %src1, %src2 237 br i1 %cond, label %exit, label %mulb 238mulb: 239 %mul = mul i64 %src1, %src1 240 br label %exit 241exit: 242 %res = phi i64 [ %src1, %entry ], [ %mul, %mulb ] 243 ret i64 %res 244} 245