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