1; RUN: llc -relocation-model=static -verify-machineinstrs -mcpu=pwr7 -O1 -code-model=medium <%s | FileCheck %s 2; RUN: llc -relocation-model=static -verify-machineinstrs -mcpu=pwr8 -O1 -code-model=medium <%s | FileCheck %s 3 4; Test peephole optimization for medium code model (32-bit TOC offsets) 5; for loading and storing small offsets within aligned values. 6 7target datalayout = "E-p:64:64:64-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f128:128:128-v128:128:128-n32:64" 8target triple = "powerpc64-unknown-linux-gnu" 9 10%struct.b4 = type<{ i8, i8, i8, i8 }> 11%struct.h2 = type<{ i16, i16 }> 12 13%struct.b8 = type<{ i8, i8, i8, i8, i8, i8, i8, i8 }> 14%struct.h4 = type<{ i16, i16, i16, i16 }> 15%struct.w2 = type<{ i32, i32 }> 16 17%struct.d2 = type<{ i64, i64 }> 18%struct.misalign = type<{ i8, i64 }> 19 20@b4v = dso_local global %struct.b4 <{ i8 1, i8 2, i8 3, i8 4 }>, align 4 21@h2v = dso_local global %struct.h2 <{ i16 1, i16 2 }>, align 4 22 23@b8v = dso_local global %struct.b8 <{ i8 1, i8 2, i8 3, i8 4, i8 5, i8 6, i8 7, i8 8 }>, align 8 24@h4v = dso_local global %struct.h4 <{ i16 1, i16 2, i16 3, i16 4 }>, align 8 25@w2v = dso_local global %struct.w2 <{ i32 1, i32 2 }>, align 8 26 27@d2v = dso_local global %struct.d2 <{ i64 1, i64 2 }>, align 16 28@misalign_v = dso_local global %struct.misalign <{ i8 1, i64 2 }>, align 16 29 30; CHECK-LABEL: test_b4: 31; CHECK: addis [[REGSTRUCT:[0-9]+]], 2, b4v@toc@ha 32; CHECK-DAG: lbz [[REG0_0:[0-9]+]], b4v@toc@l([[REGSTRUCT]]) 33; CHECK-DAG: lbz [[REG1_0:[0-9]+]], b4v@toc@l+1([[REGSTRUCT]]) 34; CHECK-DAG: lbz [[REG2_0:[0-9]+]], b4v@toc@l+2([[REGSTRUCT]]) 35; CHECK-DAG: lbz [[REG3_0:[0-9]+]], b4v@toc@l+3([[REGSTRUCT]]) 36; CHECK-DAG: addi [[REG0_1:[0-9]+]], [[REG0_0]], 1 37; CHECK-DAG: addi [[REG1_1:[0-9]+]], [[REG1_0]], 2 38; CHECK-DAG: addi [[REG2_1:[0-9]+]], [[REG2_0]], 3 39; CHECK-DAG: addi [[REG3_1:[0-9]+]], [[REG3_0]], 4 40; CHECK-DAG: stb [[REG0_1]], b4v@toc@l([[REGSTRUCT]]) 41; CHECK-DAG: stb [[REG1_1]], b4v@toc@l+1([[REGSTRUCT]]) 42; CHECK-DAG: stb [[REG2_1]], b4v@toc@l+2([[REGSTRUCT]]) 43; CHECK-DAG: stb [[REG3_1]], b4v@toc@l+3([[REGSTRUCT]]) 44 45define dso_local void @test_b4() nounwind { 46entry: 47 %0 = load i8, ptr @b4v, align 1 48 %inc0 = add nsw i8 %0, 1 49 store i8 %inc0, ptr @b4v, align 1 50 %1 = load i8, ptr getelementptr inbounds (%struct.b4, ptr @b4v, i32 0, i32 1), align 1 51 %inc1 = add nsw i8 %1, 2 52 store i8 %inc1, ptr getelementptr inbounds (%struct.b4, ptr @b4v, i32 0, i32 1), align 1 53 %2 = load i8, ptr getelementptr inbounds (%struct.b4, ptr @b4v, i32 0, i32 2), align 1 54 %inc2 = add nsw i8 %2, 3 55 store i8 %inc2, ptr getelementptr inbounds (%struct.b4, ptr @b4v, i32 0, i32 2), align 1 56 %3 = load i8, ptr getelementptr inbounds (%struct.b4, ptr @b4v, i32 0, i32 3), align 1 57 %inc3 = add nsw i8 %3, 4 58 store i8 %inc3, ptr getelementptr inbounds (%struct.b4, ptr @b4v, i32 0, i32 3), align 1 59 ret void 60} 61 62; CHECK-LABEL: test_h2: 63; CHECK: addis [[REGSTRUCT:[0-9]+]], 2, h2v@toc@ha 64; CHECK-DAG: lhz [[REG0_0:[0-9]+]], h2v@toc@l([[REGSTRUCT]]) 65; CHECK-DAG: lhz [[REG1_0:[0-9]+]], h2v@toc@l+2([[REGSTRUCT]]) 66; CHECK-DAG: addi [[REG0_1:[0-9]+]], [[REG0_0]], 1 67; CHECK-DAG: addi [[REG1_1:[0-9]+]], [[REG1_0]], 2 68; CHECK-DAG: sth [[REG0_1]], h2v@toc@l([[REGSTRUCT]]) 69; CHECK-DAG: sth [[REG1_1]], h2v@toc@l+2([[REGSTRUCT]]) 70 71define dso_local void @test_h2() nounwind { 72entry: 73 %0 = load i16, ptr @h2v, align 2 74 %inc0 = add nsw i16 %0, 1 75 store i16 %inc0, ptr @h2v, align 2 76 %1 = load i16, ptr getelementptr inbounds (%struct.h2, ptr @h2v, i32 0, i32 1), align 2 77 %inc1 = add nsw i16 %1, 2 78 store i16 %inc1, ptr getelementptr inbounds (%struct.h2, ptr @h2v, i32 0, i32 1), align 2 79 ret void 80} 81 82; CHECK-LABEL: test_h2_optsize: 83; CHECK: addis [[REGSTRUCT:[0-9]+]], 2, h2v@toc@ha 84; CHECK-DAG: lhz [[REG0_0:[0-9]+]], h2v@toc@l([[REGSTRUCT]]) 85; CHECK-DAG: lhz [[REG1_0:[0-9]+]], h2v@toc@l+2([[REGSTRUCT]]) 86; CHECK-DAG: addi [[REG0_1:[0-9]+]], [[REG0_0]], 1 87; CHECK-DAG: addi [[REG1_1:[0-9]+]], [[REG1_0]], 2 88; CHECK-DAG: sth [[REG0_1]], h2v@toc@l([[REGSTRUCT]]) 89; CHECK-DAG: sth [[REG1_1]], h2v@toc@l+2([[REGSTRUCT]]) 90define dso_local void @test_h2_optsize() optsize nounwind { 91entry: 92 %0 = load i16, ptr @h2v, align 2 93 %inc0 = add nsw i16 %0, 1 94 store i16 %inc0, ptr @h2v, align 2 95 %1 = load i16, ptr getelementptr inbounds (%struct.h2, ptr @h2v, i32 0, i32 1), align 2 96 %inc1 = add nsw i16 %1, 2 97 store i16 %inc1, ptr getelementptr inbounds (%struct.h2, ptr @h2v, i32 0, i32 1), align 2 98 ret void 99} 100 101; CHECK-LABEL: test_b8: 102; CHECK: addis [[REGSTRUCT:[0-9]+]], 2, b8v@toc@ha 103; CHECK-DAG: lbz [[REG0_0:[0-9]+]], b8v@toc@l([[REGSTRUCT]]) 104; CHECK-DAG: lbz [[REG1_0:[0-9]+]], b8v@toc@l+1([[REGSTRUCT]]) 105; CHECK-DAG: lbz [[REG2_0:[0-9]+]], b8v@toc@l+2([[REGSTRUCT]]) 106; CHECK-DAG: lbz [[REG3_0:[0-9]+]], b8v@toc@l+3([[REGSTRUCT]]) 107; CHECK-DAG: lbz [[REG4_0:[0-9]+]], b8v@toc@l+4([[REGSTRUCT]]) 108; CHECK-DAG: lbz [[REG5_0:[0-9]+]], b8v@toc@l+5([[REGSTRUCT]]) 109; CHECK-DAG: lbz [[REG6_0:[0-9]+]], b8v@toc@l+6([[REGSTRUCT]]) 110; CHECK-DAG: lbz [[REG7_0:[0-9]+]], b8v@toc@l+7([[REGSTRUCT]]) 111; CHECK-DAG: addi [[REG0_1:[0-9]+]], [[REG0_0]], 1 112; CHECK-DAG: addi [[REG1_1:[0-9]+]], [[REG1_0]], 2 113; CHECK-DAG: addi [[REG2_1:[0-9]+]], [[REG2_0]], 3 114; CHECK-DAG: addi [[REG3_1:[0-9]+]], [[REG3_0]], 4 115; CHECK-DAG: addi [[REG4_1:[0-9]+]], [[REG4_0]], 5 116; CHECK-DAG: addi [[REG5_1:[0-9]+]], [[REG5_0]], 6 117; CHECK-DAG: addi [[REG6_1:[0-9]+]], [[REG6_0]], 7 118; CHECK-DAG: addi [[REG7_1:[0-9]+]], [[REG7_0]], 8 119; CHECK-DAG: stb [[REG0_1]], b8v@toc@l([[REGSTRUCT]]) 120; CHECK-DAG: stb [[REG1_1]], b8v@toc@l+1([[REGSTRUCT]]) 121; CHECK-DAG: stb [[REG2_1]], b8v@toc@l+2([[REGSTRUCT]]) 122; CHECK-DAG: stb [[REG3_1]], b8v@toc@l+3([[REGSTRUCT]]) 123; CHECK-DAG: stb [[REG4_1]], b8v@toc@l+4([[REGSTRUCT]]) 124; CHECK-DAG: stb [[REG5_1]], b8v@toc@l+5([[REGSTRUCT]]) 125; CHECK-DAG: stb [[REG6_1]], b8v@toc@l+6([[REGSTRUCT]]) 126; CHECK-DAG: stb [[REG7_1]], b8v@toc@l+7([[REGSTRUCT]]) 127 128define dso_local void @test_b8() nounwind { 129entry: 130 %0 = load i8, ptr @b8v, align 1 131 %inc0 = add nsw i8 %0, 1 132 store i8 %inc0, ptr @b8v, align 1 133 %1 = load i8, ptr getelementptr inbounds (%struct.b8, ptr @b8v, i32 0, i32 1), align 1 134 %inc1 = add nsw i8 %1, 2 135 store i8 %inc1, ptr getelementptr inbounds (%struct.b8, ptr @b8v, i32 0, i32 1), align 1 136 %2 = load i8, ptr getelementptr inbounds (%struct.b8, ptr @b8v, i32 0, i32 2), align 1 137 %inc2 = add nsw i8 %2, 3 138 store i8 %inc2, ptr getelementptr inbounds (%struct.b8, ptr @b8v, i32 0, i32 2), align 1 139 %3 = load i8, ptr getelementptr inbounds (%struct.b8, ptr @b8v, i32 0, i32 3), align 1 140 %inc3 = add nsw i8 %3, 4 141 store i8 %inc3, ptr getelementptr inbounds (%struct.b8, ptr @b8v, i32 0, i32 3), align 1 142 %4 = load i8, ptr getelementptr inbounds (%struct.b8, ptr @b8v, i32 0, i32 4), align 1 143 %inc4 = add nsw i8 %4, 5 144 store i8 %inc4, ptr getelementptr inbounds (%struct.b8, ptr @b8v, i32 0, i32 4), align 1 145 %5 = load i8, ptr getelementptr inbounds (%struct.b8, ptr @b8v, i32 0, i32 5), align 1 146 %inc5 = add nsw i8 %5, 6 147 store i8 %inc5, ptr getelementptr inbounds (%struct.b8, ptr @b8v, i32 0, i32 5), align 1 148 %6 = load i8, ptr getelementptr inbounds (%struct.b8, ptr @b8v, i32 0, i32 6), align 1 149 %inc6 = add nsw i8 %6, 7 150 store i8 %inc6, ptr getelementptr inbounds (%struct.b8, ptr @b8v, i32 0, i32 6), align 1 151 %7 = load i8, ptr getelementptr inbounds (%struct.b8, ptr @b8v, i32 0, i32 7), align 1 152 %inc7 = add nsw i8 %7, 8 153 store i8 %inc7, ptr getelementptr inbounds (%struct.b8, ptr @b8v, i32 0, i32 7), align 1 154 ret void 155} 156 157; CHECK-LABEL: test_h4: 158; CHECK: addis [[REGSTRUCT:[0-9]+]], 2, h4v@toc@ha 159; CHECK-DAG: lhz [[REG0_0:[0-9]+]], h4v@toc@l([[REGSTRUCT]]) 160; CHECK-DAG: lhz [[REG1_0:[0-9]+]], h4v@toc@l+2([[REGSTRUCT]]) 161; CHECK-DAG: lhz [[REG2_0:[0-9]+]], h4v@toc@l+4([[REGSTRUCT]]) 162; CHECK-DAG: lhz [[REG3_0:[0-9]+]], h4v@toc@l+6([[REGSTRUCT]]) 163; CHECK-DAG: addi [[REG0_1:[0-9]+]], [[REG0_0]], 1 164; CHECK-DAG: addi [[REG1_1:[0-9]+]], [[REG1_0]], 2 165; CHECK-DAG: addi [[REG2_1:[0-9]+]], [[REG2_0]], 3 166; CHECK-DAG: addi [[REG3_1:[0-9]+]], [[REG3_0]], 4 167; CHECK-DAG: sth [[REG0_1]], h4v@toc@l([[REGSTRUCT]]) 168; CHECK-DAG: sth [[REG1_1]], h4v@toc@l+2([[REGSTRUCT]]) 169; CHECK-DAG: sth [[REG2_1]], h4v@toc@l+4([[REGSTRUCT]]) 170; CHECK-DAG: sth [[REG3_1]], h4v@toc@l+6([[REGSTRUCT]]) 171 172define dso_local void @test_h4() nounwind { 173entry: 174 %0 = load i16, ptr @h4v, align 2 175 %inc0 = add nsw i16 %0, 1 176 store i16 %inc0, ptr @h4v, align 2 177 %1 = load i16, ptr getelementptr inbounds (%struct.h4, ptr @h4v, i32 0, i32 1), align 2 178 %inc1 = add nsw i16 %1, 2 179 store i16 %inc1, ptr getelementptr inbounds (%struct.h4, ptr @h4v, i32 0, i32 1), align 2 180 %2 = load i16, ptr getelementptr inbounds (%struct.h4, ptr @h4v, i32 0, i32 2), align 2 181 %inc2 = add nsw i16 %2, 3 182 store i16 %inc2, ptr getelementptr inbounds (%struct.h4, ptr @h4v, i32 0, i32 2), align 2 183 %3 = load i16, ptr getelementptr inbounds (%struct.h4, ptr @h4v, i32 0, i32 3), align 2 184 %inc3 = add nsw i16 %3, 4 185 store i16 %inc3, ptr getelementptr inbounds (%struct.h4, ptr @h4v, i32 0, i32 3), align 2 186 ret void 187} 188 189; CHECK-LABEL: test_w2: 190; CHECK: addis [[REGSTRUCT:[0-9]+]], 2, w2v@toc@ha 191; CHECK-DAG: lwz [[REG0_0:[0-9]+]], w2v@toc@l([[REGSTRUCT]]) 192; CHECK-DAG: lwz [[REG1_0:[0-9]+]], w2v@toc@l+4([[REGSTRUCT]]) 193; CHECK-DAG: addi [[REG0_1:[0-9]+]], [[REG0_0]], 1 194; CHECK-DAG: addi [[REG1_1:[0-9]+]], [[REG1_0]], 2 195; CHECK-DAG: stw [[REG0_1]], w2v@toc@l([[REGSTRUCT]]) 196; CHECK-DAG: stw [[REG1_1]], w2v@toc@l+4([[REGSTRUCT]]) 197 198define dso_local void @test_w2() nounwind { 199entry: 200 %0 = load i32, ptr @w2v, align 4 201 %inc0 = add nsw i32 %0, 1 202 store i32 %inc0, ptr @w2v, align 4 203 %1 = load i32, ptr getelementptr inbounds (%struct.w2, ptr @w2v, i32 0, i32 1), align 4 204 %inc1 = add nsw i32 %1, 2 205 store i32 %inc1, ptr getelementptr inbounds (%struct.w2, ptr @w2v, i32 0, i32 1), align 4 206 ret void 207} 208 209; CHECK-LABEL: test_d2: 210; CHECK: addis [[REGSTRUCT:[0-9]+]], 2, d2v@toc@ha 211; CHECK: ld [[REG0_0:[0-9]+]], d2v@toc@l([[REGSTRUCT]]) 212; CHECK: addi [[BASEV:[0-9]+]], [[REGSTRUCT]], d2v@toc@l 213; CHECK-DAG: addi [[REG0_1:[0-9]+]], [[REG0_0]], 1 214; CHECK-DAG: ld [[REG1_0:[0-9]+]], 8([[BASEV]]) 215; CHECK-DAG: addi [[REG1_1:[0-9]+]], [[REG1_0]], 2 216; CHECK-DAG: std [[REG0_1]], d2v@toc@l([[REGSTRUCT]]) 217; CHECK-DAG: std [[REG1_1]], 8([[BASEV]]) 218 219define dso_local void @test_d2() nounwind { 220entry: 221 %0 = load i64, ptr @d2v, align 8 222 %inc0 = add nsw i64 %0, 1 223 store i64 %inc0, ptr @d2v, align 8 224 %1 = load i64, ptr getelementptr inbounds (%struct.d2, ptr @d2v, i32 0, i32 1), align 8 225 %inc1 = add nsw i64 %1, 2 226 store i64 %inc1, ptr getelementptr inbounds (%struct.d2, ptr @d2v, i32 0, i32 1), align 8 227 ret void 228} 229 230; CHECK-LABEL: test_singleuse: 231; CHECK: addis [[REG:[0-9]+]], 2, d2v@toc@ha+8 232; CHECK: ld 3, d2v@toc@l+8([[REG]]) 233define i64 @test_singleuse() nounwind { 234entry: 235 %0 = load i64, ptr getelementptr inbounds (%struct.d2, ptr @d2v, i32 0, i32 1), align 8 236 ret i64 %0 237} 238 239; Make sure the optimization fails to fire if the symbol is aligned, but the offset is not. 240; CHECK-LABEL: test_misalign 241; CHECK: addis [[REGSTRUCT_0:[0-9]+]], 2, misalign_v@toc@ha 242; CHECK-DAG: addi [[REGSTRUCT:[0-9]+]], [[REGSTRUCT_0]], misalign_v@toc@l 243; CHECK-DAG: li [[OFFSET_REG:[0-9]+]], 1 244; CHECK: ldx [[REG0_0:[0-9]+]], [[REGSTRUCT]], [[OFFSET_REG]] 245; CHECK: addi [[REG0_1:[0-9]+]], [[REG0_0]], 1 246; CHECK: stdx [[REG0_1]], [[REGSTRUCT]], [[OFFSET_REG]] 247define dso_local void @test_misalign() nounwind { 248entry: 249 %0 = load i64, ptr getelementptr inbounds (%struct.misalign, ptr @misalign_v, i32 0, i32 1), align 1 250 %inc0 = add nsw i64 %0, 1 251 store i64 %inc0, ptr getelementptr inbounds (%struct.misalign, ptr @misalign_v, i32 0, i32 1), align 1 252 ret void 253} 254