1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4 2; RUN: opt -passes="default<O3>" -S %s | FileCheck %s 3 4target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" 5target triple = "arm64-apple-macosx11.0.0" 6 7define i32 @read_only_loop_with_runtime_check(ptr noundef %array, i32 noundef %count, i32 noundef %n) { 8; CHECK-LABEL: define i32 @read_only_loop_with_runtime_check( 9; CHECK-SAME: ptr noundef readonly captures(none) [[ARRAY:%.*]], i32 noundef [[COUNT:%.*]], i32 noundef [[N:%.*]]) local_unnamed_addr #[[ATTR0:[0-9]+]] { 10; CHECK-NEXT: entry: 11; CHECK-NEXT: [[CMP6_NOT:%.*]] = icmp eq i32 [[N]], 0 12; CHECK-NEXT: br i1 [[CMP6_NOT]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY_PREHEADER:%.*]] 13; CHECK: for.body.preheader: 14; CHECK-NEXT: [[TMP0:%.*]] = zext i32 [[N]] to i64 15; CHECK-NEXT: [[TMP1:%.*]] = add i32 [[N]], -1 16; CHECK-NEXT: [[DOTNOT_NOT:%.*]] = icmp ugt i32 [[COUNT]], [[TMP1]] 17; CHECK-NEXT: br i1 [[DOTNOT_NOT]], label [[FOR_BODY_PREHEADER10:%.*]], label [[IF_THEN:%.*]] 18; CHECK: for.body.preheader10: 19; CHECK-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i32 [[N]], 8 20; CHECK-NEXT: br i1 [[MIN_ITERS_CHECK]], label [[FOR_BODY_PREHEADER13:%.*]], label [[VECTOR_PH:%.*]] 21; CHECK: vector.ph: 22; CHECK-NEXT: [[N_VEC:%.*]] = and i64 [[TMP0]], 4294967288 23; CHECK-NEXT: br label [[VECTOR_BODY:%.*]] 24; CHECK: vector.body: 25; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, [[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], [[VECTOR_BODY]] ] 26; CHECK-NEXT: [[VEC_PHI:%.*]] = phi <4 x i32> [ zeroinitializer, [[VECTOR_PH]] ], [ [[TMP4:%.*]], [[VECTOR_BODY]] ] 27; CHECK-NEXT: [[VEC_PHI11:%.*]] = phi <4 x i32> [ zeroinitializer, [[VECTOR_PH]] ], [ [[TMP5:%.*]], [[VECTOR_BODY]] ] 28; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw i32, ptr [[ARRAY]], i64 [[INDEX]] 29; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP2]], i64 16 30; CHECK-NEXT: [[WIDE_LOAD:%.*]] = load <4 x i32>, ptr [[TMP2]], align 4 31; CHECK-NEXT: [[WIDE_LOAD12:%.*]] = load <4 x i32>, ptr [[TMP3]], align 4 32; CHECK-NEXT: [[TMP4]] = add <4 x i32> [[WIDE_LOAD]], [[VEC_PHI]] 33; CHECK-NEXT: [[TMP5]] = add <4 x i32> [[WIDE_LOAD12]], [[VEC_PHI11]] 34; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 8 35; CHECK-NEXT: [[TMP6:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]] 36; CHECK-NEXT: br i1 [[TMP6]], label [[MIDDLE_BLOCK:%.*]], label [[VECTOR_BODY]], !llvm.loop [[LOOP0:![0-9]+]] 37; CHECK: middle.block: 38; CHECK-NEXT: [[BIN_RDX:%.*]] = add <4 x i32> [[TMP5]], [[TMP4]] 39; CHECK-NEXT: [[TMP7:%.*]] = tail call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> [[BIN_RDX]]) 40; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[N_VEC]], [[TMP0]] 41; CHECK-NEXT: br i1 [[CMP_N]], label [[FOR_COND_CLEANUP]], label [[FOR_BODY_PREHEADER13]] 42; CHECK: for.body.preheader13: 43; CHECK-NEXT: [[INDVARS_IV_PH:%.*]] = phi i64 [ 0, [[FOR_BODY_PREHEADER10]] ], [ [[N_VEC]], [[MIDDLE_BLOCK]] ] 44; CHECK-NEXT: [[SUM_07_PH:%.*]] = phi i32 [ 0, [[FOR_BODY_PREHEADER10]] ], [ [[TMP7]], [[MIDDLE_BLOCK]] ] 45; CHECK-NEXT: br label [[FOR_BODY:%.*]] 46; CHECK: for.cond.cleanup: 47; CHECK-NEXT: [[SUM_0_LCSSA:%.*]] = phi i32 [ 0, [[ENTRY:%.*]] ], [ [[TMP7]], [[MIDDLE_BLOCK]] ], [ [[ADD:%.*]], [[FOR_BODY]] ] 48; CHECK-NEXT: ret i32 [[SUM_0_LCSSA]] 49; CHECK: for.body: 50; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], [[FOR_BODY]] ], [ [[INDVARS_IV_PH]], [[FOR_BODY_PREHEADER13]] ] 51; CHECK-NEXT: [[SUM_07:%.*]] = phi i32 [ [[ADD]], [[FOR_BODY]] ], [ [[SUM_07_PH]], [[FOR_BODY_PREHEADER13]] ] 52; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds nuw i32, ptr [[ARRAY]], i64 [[INDVARS_IV]] 53; CHECK-NEXT: [[TMP8:%.*]] = load i32, ptr [[ARRAYIDX]], align 4 54; CHECK-NEXT: [[ADD]] = add nsw i32 [[TMP8]], [[SUM_07]] 55; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add nuw nsw i64 [[INDVARS_IV]], 1 56; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i64 [[INDVARS_IV_NEXT]], [[TMP0]] 57; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label [[FOR_COND_CLEANUP]], label [[FOR_BODY]], !llvm.loop [[LOOP3:![0-9]+]] 58; CHECK: if.then: 59; CHECK-NEXT: tail call void @llvm.trap() 60; CHECK-NEXT: unreachable 61; 62entry: 63 %array.addr = alloca ptr, align 8 64 %count.addr = alloca i32, align 4 65 %n.addr = alloca i32, align 4 66 %sum = alloca i32, align 4 67 %i = alloca i32, align 4 68 store ptr %array, ptr %array.addr, align 8 69 store i32 %count, ptr %count.addr, align 4 70 store i32 %n, ptr %n.addr, align 4 71 call void @llvm.lifetime.start.p0(i64 4, ptr %sum) #3 72 store i32 0, ptr %sum, align 4 73 call void @llvm.lifetime.start.p0(i64 4, ptr %i) #3 74 store i32 0, ptr %i, align 4 75 br label %for.cond 76 77for.cond: ; preds = %for.inc, %entry 78 %0 = load i32, ptr %i, align 4 79 %1 = load i32, ptr %n.addr, align 4 80 %cmp = icmp ult i32 %0, %1 81 br i1 %cmp, label %for.body, label %for.cond.cleanup 82 83for.cond.cleanup: ; preds = %for.cond 84 call void @llvm.lifetime.end.p0(i64 4, ptr %i) #3 85 br label %for.end 86 87for.body: ; preds = %for.cond 88 %2 = load i32, ptr %i, align 4 89 %3 = load i32, ptr %count.addr, align 4 90 %cmp1 = icmp uge i32 %2, %3 91 br i1 %cmp1, label %if.then, label %if.end 92 93if.then: ; preds = %for.body 94 call void @llvm.trap() 95 br label %if.end 96 97if.end: ; preds = %if.then, %for.body 98 %4 = load ptr, ptr %array.addr, align 8 99 %5 = load i32, ptr %i, align 4 100 %idxprom = zext i32 %5 to i64 101 %arrayidx = getelementptr inbounds i32, ptr %4, i64 %idxprom 102 %6 = load i32, ptr %arrayidx, align 4 103 %7 = load i32, ptr %sum, align 4 104 %add = add nsw i32 %7, %6 105 store i32 %add, ptr %sum, align 4 106 br label %for.inc 107 108for.inc: ; preds = %if.end 109 %8 = load i32, ptr %i, align 4 110 %inc = add i32 %8, 1 111 store i32 %inc, ptr %i, align 4 112 br label %for.cond 113 114for.end: ; preds = %for.cond.cleanup 115 %9 = load i32, ptr %sum, align 4 116 call void @llvm.lifetime.end.p0(i64 4, ptr %sum) 117 ret i32 %9 118} 119 120%"class.std::__1::span" = type { ptr, i64 } 121%"class.std::__1::__wrap_iter" = type { ptr } 122 123define dso_local noundef i32 @sum_prefix_with_sum(ptr %s.coerce0, i64 %s.coerce1, i64 noundef %n) { 124; CHECK-LABEL: define dso_local noundef i32 @sum_prefix_with_sum( 125; CHECK-SAME: ptr readonly captures(none) [[S_COERCE0:%.*]], i64 [[S_COERCE1:%.*]], i64 noundef [[N:%.*]]) local_unnamed_addr #[[ATTR0]] { 126; CHECK-NEXT: entry: 127; CHECK-NEXT: [[CMP5_NOT:%.*]] = icmp eq i64 [[N]], 0 128; CHECK-NEXT: br i1 [[CMP5_NOT]], label [[FOR_COND_CLEANUP:%.*]], label [[FOR_BODY_PREHEADER:%.*]] 129; CHECK: for.body.preheader: 130; CHECK-NEXT: [[TMP0:%.*]] = add i64 [[N]], -1 131; CHECK-NEXT: [[DOTNOT_NOT:%.*]] = icmp ugt i64 [[S_COERCE1]], [[TMP0]] 132; CHECK-NEXT: br i1 [[DOTNOT_NOT]], label [[FOR_BODY_PREHEADER8:%.*]], label [[COND_FALSE_I:%.*]], !prof [[PROF4:![0-9]+]] 133; CHECK: for.body.preheader8: 134; CHECK-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[N]], 8 135; CHECK-NEXT: br i1 [[MIN_ITERS_CHECK]], label [[FOR_BODY_PREHEADER11:%.*]], label [[VECTOR_PH:%.*]] 136; CHECK: vector.ph: 137; CHECK-NEXT: [[N_VEC:%.*]] = and i64 [[N]], -8 138; CHECK-NEXT: br label [[FOR_BODY:%.*]] 139; CHECK: vector.body: 140; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, [[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], [[FOR_BODY]] ] 141; CHECK-NEXT: [[VEC_PHI:%.*]] = phi <4 x i32> [ zeroinitializer, [[VECTOR_PH]] ], [ [[TMP3:%.*]], [[FOR_BODY]] ] 142; CHECK-NEXT: [[VEC_PHI9:%.*]] = phi <4 x i32> [ zeroinitializer, [[VECTOR_PH]] ], [ [[TMP4:%.*]], [[FOR_BODY]] ] 143; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i32, ptr [[S_COERCE0]], i64 [[INDEX]] 144; CHECK-NEXT: [[TMP2:%.*]] = getelementptr inbounds nuw i8, ptr [[TMP1]], i64 16 145; CHECK-NEXT: [[WIDE_LOAD:%.*]] = load <4 x i32>, ptr [[TMP1]], align 4 146; CHECK-NEXT: [[WIDE_LOAD10:%.*]] = load <4 x i32>, ptr [[TMP2]], align 4 147; CHECK-NEXT: [[TMP3]] = add <4 x i32> [[WIDE_LOAD]], [[VEC_PHI]] 148; CHECK-NEXT: [[TMP4]] = add <4 x i32> [[WIDE_LOAD10]], [[VEC_PHI9]] 149; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 8 150; CHECK-NEXT: [[TMP5:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]] 151; CHECK-NEXT: br i1 [[TMP5]], label [[SPAN_CHECKED_ACCESS_EXIT:%.*]], label [[FOR_BODY]], !llvm.loop [[LOOP5:![0-9]+]] 152; CHECK: middle.block: 153; CHECK-NEXT: [[BIN_RDX:%.*]] = add <4 x i32> [[TMP4]], [[TMP3]] 154; CHECK-NEXT: [[ADD:%.*]] = tail call i32 @llvm.vector.reduce.add.v4i32(<4 x i32> [[BIN_RDX]]) 155; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[N]], [[N_VEC]] 156; CHECK-NEXT: br i1 [[CMP_N]], label [[FOR_COND_CLEANUP]], label [[FOR_BODY_PREHEADER11]] 157; CHECK: for.body.preheader11: 158; CHECK-NEXT: [[I_07_PH:%.*]] = phi i64 [ 0, [[FOR_BODY_PREHEADER8]] ], [ [[N_VEC]], [[SPAN_CHECKED_ACCESS_EXIT]] ] 159; CHECK-NEXT: [[RET_0_LCSSA:%.*]] = phi i32 [ 0, [[FOR_BODY_PREHEADER8]] ], [ [[ADD]], [[SPAN_CHECKED_ACCESS_EXIT]] ] 160; CHECK-NEXT: br label [[FOR_BODY1:%.*]] 161; CHECK: for.cond.cleanup: 162; CHECK-NEXT: [[RET_0_LCSSA1:%.*]] = phi i32 [ 0, [[ENTRY1:%.*]] ], [ [[ADD]], [[SPAN_CHECKED_ACCESS_EXIT]] ], [ [[ADD1:%.*]], [[FOR_BODY1]] ] 163; CHECK-NEXT: ret i32 [[RET_0_LCSSA1]] 164; CHECK: for.body: 165; CHECK-NEXT: [[I_07:%.*]] = phi i64 [ [[INC:%.*]], [[FOR_BODY1]] ], [ [[I_07_PH]], [[FOR_BODY_PREHEADER11]] ] 166; CHECK-NEXT: [[RET_06:%.*]] = phi i32 [ [[ADD1]], [[FOR_BODY1]] ], [ [[RET_0_LCSSA]], [[FOR_BODY_PREHEADER11]] ] 167; CHECK-NEXT: [[ARRAYIDX_I:%.*]] = getelementptr inbounds i32, ptr [[S_COERCE0]], i64 [[I_07]] 168; CHECK-NEXT: [[TMP7:%.*]] = load i32, ptr [[ARRAYIDX_I]], align 4 169; CHECK-NEXT: [[ADD1]] = add nsw i32 [[TMP7]], [[RET_06]] 170; CHECK-NEXT: [[INC]] = add nuw i64 [[I_07]], 1 171; CHECK-NEXT: [[EXITCOND_NOT:%.*]] = icmp eq i64 [[INC]], [[N]] 172; CHECK-NEXT: br i1 [[EXITCOND_NOT]], label [[FOR_COND_CLEANUP]], label [[FOR_BODY1]], !llvm.loop [[LOOP6:![0-9]+]] 173; CHECK: cond.false.i: 174; CHECK-NEXT: tail call void @llvm.trap() 175; CHECK-NEXT: unreachable 176; 177entry: 178 %s = alloca %"class.std::__1::span", align 8 179 %n.addr = alloca i64, align 8 180 %ret = alloca i32, align 4 181 %i = alloca i64, align 8 182 %0 = getelementptr inbounds { ptr, i64 }, ptr %s, i32 0, i32 0 183 store ptr %s.coerce0, ptr %0, align 8 184 %1 = getelementptr inbounds { ptr, i64 }, ptr %s, i32 0, i32 1 185 store i64 %s.coerce1, ptr %1, align 8 186 store i64 %n, ptr %n.addr, align 8 187 call void @llvm.lifetime.start.p0(i64 4, ptr %ret) #7 188 store i32 0, ptr %ret, align 4 189 call void @llvm.lifetime.start.p0(i64 8, ptr %i) #7 190 store i64 0, ptr %i, align 8 191 br label %for.cond 192 193for.cond: ; preds = %for.inc, %entry 194 %2 = load i64, ptr %i, align 8 195 %3 = load i64, ptr %n.addr, align 8 196 %cmp = icmp ult i64 %2, %3 197 br i1 %cmp, label %for.body, label %for.cond.cleanup 198 199for.cond.cleanup: ; preds = %for.cond 200 call void @llvm.lifetime.end.p0(i64 8, ptr %i) #7 201 br label %for.end 202 203for.body: ; preds = %for.cond 204 %4 = load i64, ptr %i, align 8 205 %call = call noundef nonnull align 4 dereferenceable(4) ptr @span_checked_access(ptr noundef nonnull align 8 dereferenceable(16) %s, i64 noundef %4) #7 206 %5 = load i32, ptr %call, align 4 207 %6 = load i32, ptr %ret, align 4 208 %add = add nsw i32 %6, %5 209 store i32 %add, ptr %ret, align 4 210 br label %for.inc 211 212for.inc: ; preds = %for.body 213 %7 = load i64, ptr %i, align 8 214 %inc = add i64 %7, 1 215 store i64 %inc, ptr %i, align 8 216 br label %for.cond 217 218for.end: ; preds = %for.cond.cleanup 219 %8 = load i32, ptr %ret, align 4 220 call void @llvm.lifetime.end.p0(i64 4, ptr %ret) 221 ret i32 %8 222} 223 224define hidden noundef nonnull align 4 dereferenceable(4) ptr @span_checked_access(ptr noundef nonnull align 8 dereferenceable(16) %this, i64 noundef %__idx) { 225; CHECK-LABEL: define hidden noundef nonnull align 4 dereferenceable(4) ptr @span_checked_access( 226; CHECK-SAME: ptr noundef nonnull readonly align 8 captures(none) dereferenceable(16) [[THIS:%.*]], i64 noundef [[__IDX:%.*]]) local_unnamed_addr #[[ATTR0]] { 227; CHECK-NEXT: entry: 228; CHECK-NEXT: [[__SIZE__I:%.*]] = getelementptr inbounds nuw i8, ptr [[THIS]], i64 8 229; CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr [[__SIZE__I]], align 8 230; CHECK-NEXT: [[CMP:%.*]] = icmp ult i64 [[__IDX]], [[TMP0]] 231; CHECK-NEXT: br i1 [[CMP]], label [[COND_END:%.*]], label [[COND_FALSE:%.*]], !prof [[PROF4]] 232; CHECK: cond.false: 233; CHECK-NEXT: tail call void @llvm.trap() 234; CHECK-NEXT: unreachable 235; CHECK: cond.end: 236; CHECK-NEXT: [[TMP1:%.*]] = load ptr, ptr [[THIS]], align 8 237; CHECK-NEXT: [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[TMP1]], i64 [[__IDX]] 238; CHECK-NEXT: ret ptr [[ARRAYIDX]] 239; 240entry: 241 %this.addr = alloca ptr, align 8 242 %__idx.addr = alloca i64, align 8 243 store ptr %this, ptr %this.addr, align 8 244 store i64 %__idx, ptr %__idx.addr, align 8 245 %this1 = load ptr, ptr %this.addr, align 8 246 %0 = load i64, ptr %__idx.addr, align 8 247 %call = call noundef i64 @span_access(ptr noundef nonnull align 8 dereferenceable(16) %this1) 248 %cmp = icmp ult i64 %0, %call 249 %conv = zext i1 %cmp to i64 250 %expval = call i64 @llvm.expect.i64(i64 %conv, i64 1) 251 %tobool = icmp ne i64 %expval, 0 252 br i1 %tobool, label %cond.true, label %cond.false 253 254cond.true: ; preds = %entry 255 br label %cond.end 256 257cond.false: ; preds = %entry 258 call void @llvm.trap() 259 br label %cond.end 260 261cond.end: ; preds = %cond.false, %cond.true 262 %__data_ = getelementptr inbounds %"class.std::__1::span", ptr %this1, i32 0, i32 0 263 %1 = load ptr, ptr %__data_, align 8 264 %2 = load i64, ptr %__idx.addr, align 8 265 %arrayidx = getelementptr inbounds i32, ptr %1, i64 %2 266 ret ptr %arrayidx 267} 268 269define hidden noundef i64 @span_access(ptr noundef nonnull align 8 dereferenceable(16) %this) { 270; CHECK-LABEL: define hidden noundef i64 @span_access( 271; CHECK-SAME: ptr noundef nonnull readonly align 8 captures(none) dereferenceable(16) [[THIS:%.*]]) local_unnamed_addr #[[ATTR1:[0-9]+]] { 272; CHECK-NEXT: entry: 273; CHECK-NEXT: [[__SIZE_:%.*]] = getelementptr inbounds nuw i8, ptr [[THIS]], i64 8 274; CHECK-NEXT: [[TMP0:%.*]] = load i64, ptr [[__SIZE_]], align 8 275; CHECK-NEXT: ret i64 [[TMP0]] 276; 277entry: 278 %this.addr = alloca ptr, align 8 279 store ptr %this, ptr %this.addr, align 8 280 %this1 = load ptr, ptr %this.addr, align 8 281 %__size_ = getelementptr inbounds %"class.std::__1::span", ptr %this1, i32 0, i32 1 282 %0 = load i64, ptr %__size_, align 8 283 ret i64 %0 284} 285 286declare void @llvm.lifetime.start.p0(i64 immarg, ptr nocapture) 287 288declare void @llvm.trap() 289 290declare void @llvm.lifetime.end.p0(i64 immarg, ptr nocapture) 291;. 292; CHECK: [[LOOP0]] = distinct !{[[LOOP0]], [[META1:![0-9]+]], [[META2:![0-9]+]]} 293; CHECK: [[META1]] = !{!"llvm.loop.isvectorized", i32 1} 294; CHECK: [[META2]] = !{!"llvm.loop.unroll.runtime.disable"} 295; CHECK: [[LOOP3]] = distinct !{[[LOOP3]], [[META2]], [[META1]]} 296; CHECK: [[PROF4]] = !{!"branch_weights", !"expected", i32 2000, i32 1} 297; CHECK: [[LOOP5]] = distinct !{[[LOOP5]], [[META1]], [[META2]]} 298; CHECK: [[LOOP6]] = distinct !{[[LOOP6]], [[META2]], [[META1]]} 299;. 300