brintos

brintos / llvm-project-archived public Read only

0
0
Text · 22.1 KiB · 89576f1 Raw
420 lines · plain
1; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-globals none --version 52; RUN: opt < %s -S -passes='function(loop-versioning-licm,loop-mssa(licm))' | FileCheck %s3 4target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128-Fn32"5 6; In these tests we have a loop where we can calculate the bounds of some memory7; accesses but not others.8 9; Load from a gep whose bounds can't be calculated as the offset is loaded from memory10define void @gep_loaded_offset(ptr %p, ptr %q, ptr %r, i32 %n) {11; CHECK-LABEL: define void @gep_loaded_offset(12; CHECK-SAME: ptr [[P:%.*]], ptr [[Q:%.*]], ptr [[R:%.*]], i32 [[N:%.*]]) {13; CHECK-NEXT:  [[WHILE_BODY_LVER_CHECK:.*:]]14; CHECK-NEXT:    [[TMP0:%.*]] = add nsw i32 [[N]], -115; CHECK-NEXT:    [[TMP1:%.*]] = zext i32 [[TMP0]] to i6416; CHECK-NEXT:    [[TMP2:%.*]] = shl nuw nsw i64 [[TMP1]], 217; CHECK-NEXT:    [[TMP3:%.*]] = add nuw nsw i64 [[TMP2]], 418; CHECK-NEXT:    [[SCEVGEP:%.*]] = getelementptr i8, ptr [[P]], i64 [[TMP3]]19; CHECK-NEXT:    [[SCEVGEP1:%.*]] = getelementptr i8, ptr [[R]], i64 820; CHECK-NEXT:    [[BOUND0:%.*]] = icmp ult ptr [[P]], [[SCEVGEP1]]21; CHECK-NEXT:    [[BOUND1:%.*]] = icmp ult ptr [[R]], [[SCEVGEP]]22; CHECK-NEXT:    [[FOUND_CONFLICT:%.*]] = and i1 [[BOUND0]], [[BOUND1]]23; CHECK-NEXT:    br i1 [[FOUND_CONFLICT]], label %[[WHILE_BODY_PH_LVER_ORIG:.*]], label %[[WHILE_BODY_PH:.*]]24; CHECK:       [[WHILE_BODY_PH_LVER_ORIG]]:25; CHECK-NEXT:    br label %[[WHILE_BODY_LVER_ORIG:.*]]26; CHECK:       [[WHILE_BODY_LVER_ORIG]]:27; CHECK-NEXT:    [[N_ADDR:%.*]] = phi i32 [ [[DEC:%.*]], %[[WHILE_BODY_LVER_ORIG]] ], [ [[N]], %[[WHILE_BODY_PH_LVER_ORIG]] ]28; CHECK-NEXT:    [[P_ADDR:%.*]] = phi ptr [ [[INCDEC_PTR:%.*]], %[[WHILE_BODY_LVER_ORIG]] ], [ [[P]], %[[WHILE_BODY_PH_LVER_ORIG]] ]29; CHECK-NEXT:    [[DEC]] = add nsw i32 [[N_ADDR]], -130; CHECK-NEXT:    [[RVAL:%.*]] = load i64, ptr [[R]], align 431; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[Q]], i64 [[RVAL]]32; CHECK-NEXT:    [[VAL:%.*]] = load i32, ptr [[ARRAYIDX]], align 433; CHECK-NEXT:    [[INCDEC_PTR]] = getelementptr inbounds nuw i8, ptr [[P_ADDR]], i64 434; CHECK-NEXT:    store i32 [[VAL]], ptr [[P_ADDR]], align 435; CHECK-NEXT:    [[TOBOOL_NOT:%.*]] = icmp eq i32 [[DEC]], 036; CHECK-NEXT:    br i1 [[TOBOOL_NOT]], label %[[WHILE_END_LOOPEXIT:.*]], label %[[WHILE_BODY_LVER_ORIG]], !llvm.loop [[LOOP0:![0-9]+]]37; CHECK:       [[WHILE_BODY_PH]]:38; CHECK-NEXT:    [[RVAL1:%.*]] = load i64, ptr [[R]], align 4, !alias.scope [[META2:![0-9]+]]39; CHECK-NEXT:    [[ARRAYIDX1:%.*]] = getelementptr inbounds i32, ptr [[Q]], i64 [[RVAL1]]40; CHECK-NEXT:    br label %[[WHILE_BODY:.*]]41; CHECK:       [[WHILE_BODY]]:42; CHECK-NEXT:    [[N_ADDR1:%.*]] = phi i32 [ [[DEC1:%.*]], %[[WHILE_BODY]] ], [ [[N]], %[[WHILE_BODY_PH]] ]43; CHECK-NEXT:    [[P_ADDR1:%.*]] = phi ptr [ [[INCDEC_PTR1:%.*]], %[[WHILE_BODY]] ], [ [[P]], %[[WHILE_BODY_PH]] ]44; CHECK-NEXT:    [[DEC1]] = add nsw i32 [[N_ADDR1]], -145; CHECK-NEXT:    [[VAL1:%.*]] = load i32, ptr [[ARRAYIDX1]], align 446; CHECK-NEXT:    [[INCDEC_PTR1]] = getelementptr inbounds nuw i8, ptr [[P_ADDR1]], i64 447; CHECK-NEXT:    store i32 [[VAL1]], ptr [[P_ADDR1]], align 4, !alias.scope [[META5:![0-9]+]], !noalias [[META2]]48; CHECK-NEXT:    [[TOBOOL_NOT1:%.*]] = icmp eq i32 [[DEC1]], 049; CHECK-NEXT:    br i1 [[TOBOOL_NOT1]], label %[[WHILE_END_LOOPEXIT2:.*]], label %[[WHILE_BODY]], !llvm.loop [[LOOP7:![0-9]+]]50; CHECK:       [[WHILE_END_LOOPEXIT]]:51; CHECK-NEXT:    br label %[[WHILE_END:.*]]52; CHECK:       [[WHILE_END_LOOPEXIT2]]:53; CHECK-NEXT:    br label %[[WHILE_END]]54; CHECK:       [[WHILE_END]]:55; CHECK-NEXT:    ret void56;57entry:58  br label %while.body59 60while.body:61  %n.addr = phi i32 [ %dec, %while.body ], [ %n, %entry ]62  %p.addr = phi ptr [ %incdec.ptr, %while.body ], [ %p, %entry ]63  %dec = add nsw i32 %n.addr, -164  %rval = load i64, ptr %r, align 465  %arrayidx = getelementptr inbounds i32, ptr %q, i64 %rval66  %val = load i32, ptr %arrayidx, align 467  %incdec.ptr = getelementptr inbounds nuw i8, ptr %p.addr, i64 468  store i32 %val, ptr %p.addr, align 469  %tobool.not = icmp eq i32 %dec, 070  br i1 %tobool.not, label %while.end, label %while.body71 72while.end:73  ret void74}75 76; As above but with a store to the loaded address. This should prevent the loop77; from being versioned, as we wouldn't be able to do any code motion.78define void @gep_loaded_offset_with_store(ptr %p, ptr %q, ptr %r, i32 %n) {79; CHECK-LABEL: define void @gep_loaded_offset_with_store(80; CHECK-SAME: ptr [[P:%.*]], ptr [[Q:%.*]], ptr [[R:%.*]], i32 [[N:%.*]]) {81; CHECK-NEXT:  [[ENTRY:.*]]:82; CHECK-NEXT:    br label %[[WHILE_BODY:.*]]83; CHECK:       [[WHILE_BODY]]:84; CHECK-NEXT:    [[N_ADDR:%.*]] = phi i32 [ [[DEC:%.*]], %[[WHILE_BODY]] ], [ [[N]], %[[ENTRY]] ]85; CHECK-NEXT:    [[P_ADDR:%.*]] = phi ptr [ [[INCDEC_PTR:%.*]], %[[WHILE_BODY]] ], [ [[P]], %[[ENTRY]] ]86; CHECK-NEXT:    [[DEC]] = add nsw i32 [[N_ADDR]], -187; CHECK-NEXT:    [[RVAL:%.*]] = load i64, ptr [[R]], align 488; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[Q]], i64 [[RVAL]]89; CHECK-NEXT:    [[VAL:%.*]] = load i32, ptr [[ARRAYIDX]], align 490; CHECK-NEXT:    store i32 0, ptr [[ARRAYIDX]], align 491; CHECK-NEXT:    [[INCDEC_PTR]] = getelementptr inbounds nuw i8, ptr [[P_ADDR]], i64 492; CHECK-NEXT:    store i32 [[VAL]], ptr [[P_ADDR]], align 493; CHECK-NEXT:    [[TOBOOL_NOT:%.*]] = icmp eq i32 [[DEC]], 094; CHECK-NEXT:    br i1 [[TOBOOL_NOT]], label %[[WHILE_END:.*]], label %[[WHILE_BODY]]95; CHECK:       [[WHILE_END]]:96; CHECK-NEXT:    ret void97;98entry:99  br label %while.body100 101while.body:102  %n.addr = phi i32 [ %dec, %while.body ], [ %n, %entry ]103  %p.addr = phi ptr [ %incdec.ptr, %while.body ], [ %p, %entry ]104  %dec = add nsw i32 %n.addr, -1105  %rval = load i64, ptr %r, align 4106  %arrayidx = getelementptr inbounds i32, ptr %q, i64 %rval107  %val = load i32, ptr %arrayidx, align 4108  store i32 0, ptr %arrayidx, align 4109  %incdec.ptr = getelementptr inbounds nuw i8, ptr %p.addr, i64 4110  store i32 %val, ptr %p.addr, align 4111  %tobool.not = icmp eq i32 %dec, 0112  br i1 %tobool.not, label %while.end, label %while.body113 114while.end:115  ret void116}117 118; Load from a gep whose bounds can't be calculated as the pointer is loaded from memory119define void @gep_loaded_base(ptr %p, ptr %q, ptr %r, i32 %n) {120; CHECK-LABEL: define void @gep_loaded_base(121; CHECK-SAME: ptr [[P:%.*]], ptr [[Q:%.*]], ptr [[R:%.*]], i32 [[N:%.*]]) {122; CHECK-NEXT:  [[WHILE_BODY_LVER_CHECK:.*:]]123; CHECK-NEXT:    [[TMP0:%.*]] = add nsw i32 [[N]], -1124; CHECK-NEXT:    [[TMP1:%.*]] = zext i32 [[TMP0]] to i64125; CHECK-NEXT:    [[TMP2:%.*]] = shl nuw nsw i64 [[TMP1]], 2126; CHECK-NEXT:    [[TMP3:%.*]] = add nuw nsw i64 [[TMP2]], 4127; CHECK-NEXT:    [[SCEVGEP:%.*]] = getelementptr i8, ptr [[P]], i64 [[TMP3]]128; CHECK-NEXT:    [[SCEVGEP1:%.*]] = getelementptr i8, ptr [[R]], i64 8129; CHECK-NEXT:    [[BOUND0:%.*]] = icmp ult ptr [[P]], [[SCEVGEP1]]130; CHECK-NEXT:    [[BOUND1:%.*]] = icmp ult ptr [[R]], [[SCEVGEP]]131; CHECK-NEXT:    [[FOUND_CONFLICT:%.*]] = and i1 [[BOUND0]], [[BOUND1]]132; CHECK-NEXT:    br i1 [[FOUND_CONFLICT]], label %[[WHILE_BODY_PH_LVER_ORIG:.*]], label %[[WHILE_BODY_PH:.*]]133; CHECK:       [[WHILE_BODY_PH_LVER_ORIG]]:134; CHECK-NEXT:    br label %[[WHILE_BODY_LVER_ORIG:.*]]135; CHECK:       [[WHILE_BODY_LVER_ORIG]]:136; CHECK-NEXT:    [[N_ADDR:%.*]] = phi i32 [ [[DEC:%.*]], %[[WHILE_BODY_LVER_ORIG]] ], [ [[N]], %[[WHILE_BODY_PH_LVER_ORIG]] ]137; CHECK-NEXT:    [[P_ADDR:%.*]] = phi ptr [ [[INCDEC_PTR:%.*]], %[[WHILE_BODY_LVER_ORIG]] ], [ [[P]], %[[WHILE_BODY_PH_LVER_ORIG]] ]138; CHECK-NEXT:    [[DEC]] = add nsw i32 [[N_ADDR]], -1139; CHECK-NEXT:    [[RVAL:%.*]] = load ptr, ptr [[R]], align 4140; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[RVAL]], i64 0141; CHECK-NEXT:    [[VAL:%.*]] = load i32, ptr [[ARRAYIDX]], align 4142; CHECK-NEXT:    [[INCDEC_PTR]] = getelementptr inbounds nuw i8, ptr [[P_ADDR]], i64 4143; CHECK-NEXT:    store i32 [[VAL]], ptr [[P_ADDR]], align 4144; CHECK-NEXT:    [[TOBOOL_NOT:%.*]] = icmp eq i32 [[DEC]], 0145; CHECK-NEXT:    br i1 [[TOBOOL_NOT]], label %[[WHILE_END_LOOPEXIT:.*]], label %[[WHILE_BODY_LVER_ORIG]], !llvm.loop [[LOOP9:![0-9]+]]146; CHECK:       [[WHILE_BODY_PH]]:147; CHECK-NEXT:    [[RVAL1:%.*]] = load ptr, ptr [[R]], align 4, !alias.scope [[META10:![0-9]+]]148; CHECK-NEXT:    [[ARRAYIDX1:%.*]] = getelementptr inbounds i32, ptr [[RVAL1]], i64 0149; CHECK-NEXT:    br label %[[WHILE_BODY:.*]]150; CHECK:       [[WHILE_BODY]]:151; CHECK-NEXT:    [[N_ADDR1:%.*]] = phi i32 [ [[DEC1:%.*]], %[[WHILE_BODY]] ], [ [[N]], %[[WHILE_BODY_PH]] ]152; CHECK-NEXT:    [[P_ADDR1:%.*]] = phi ptr [ [[INCDEC_PTR1:%.*]], %[[WHILE_BODY]] ], [ [[P]], %[[WHILE_BODY_PH]] ]153; CHECK-NEXT:    [[DEC1]] = add nsw i32 [[N_ADDR1]], -1154; CHECK-NEXT:    [[VAL1:%.*]] = load i32, ptr [[ARRAYIDX1]], align 4155; CHECK-NEXT:    [[INCDEC_PTR1]] = getelementptr inbounds nuw i8, ptr [[P_ADDR1]], i64 4156; CHECK-NEXT:    store i32 [[VAL1]], ptr [[P_ADDR1]], align 4, !alias.scope [[META13:![0-9]+]], !noalias [[META10]]157; CHECK-NEXT:    [[TOBOOL_NOT1:%.*]] = icmp eq i32 [[DEC1]], 0158; CHECK-NEXT:    br i1 [[TOBOOL_NOT1]], label %[[WHILE_END_LOOPEXIT2:.*]], label %[[WHILE_BODY]], !llvm.loop [[LOOP15:![0-9]+]]159; CHECK:       [[WHILE_END_LOOPEXIT]]:160; CHECK-NEXT:    br label %[[WHILE_END:.*]]161; CHECK:       [[WHILE_END_LOOPEXIT2]]:162; CHECK-NEXT:    br label %[[WHILE_END]]163; CHECK:       [[WHILE_END]]:164; CHECK-NEXT:    ret void165;166entry:167  br label %while.body168 169while.body:170  %n.addr = phi i32 [ %dec, %while.body ], [ %n, %entry ]171  %p.addr = phi ptr [ %incdec.ptr, %while.body ], [ %p, %entry ]172  %dec = add nsw i32 %n.addr, -1173  %rval = load ptr, ptr %r, align 4174  %arrayidx = getelementptr inbounds i32, ptr %rval, i64 0175  %val = load i32, ptr %arrayidx, align 4176  %incdec.ptr = getelementptr inbounds nuw i8, ptr %p.addr, i64 4177  store i32 %val, ptr %p.addr, align 4178  %tobool.not = icmp eq i32 %dec, 0179  br i1 %tobool.not, label %while.end, label %while.body180 181while.end:182  ret void183}184 185; Load from a gep with an offset that scalar evolution can't describe186define void @gep_strange_offset(ptr %p, ptr %q, ptr %r, i32 %n) {187; CHECK-LABEL: define void @gep_strange_offset(188; CHECK-SAME: ptr [[P:%.*]], ptr [[Q:%.*]], ptr [[R:%.*]], i32 [[N:%.*]]) {189; CHECK-NEXT:  [[WHILE_BODY_LVER_CHECK:.*:]]190; CHECK-NEXT:    [[TMP0:%.*]] = add nsw i32 [[N]], -1191; CHECK-NEXT:    [[TMP1:%.*]] = zext i32 [[TMP0]] to i64192; CHECK-NEXT:    [[TMP2:%.*]] = shl nuw nsw i64 [[TMP1]], 2193; CHECK-NEXT:    [[TMP3:%.*]] = add nuw nsw i64 [[TMP2]], 4194; CHECK-NEXT:    [[SCEVGEP:%.*]] = getelementptr i8, ptr [[P]], i64 [[TMP3]]195; CHECK-NEXT:    [[SCEVGEP1:%.*]] = getelementptr i8, ptr [[Q]], i64 4196; CHECK-NEXT:    [[BOUND0:%.*]] = icmp ult ptr [[P]], [[SCEVGEP1]]197; CHECK-NEXT:    [[BOUND1:%.*]] = icmp ult ptr [[Q]], [[SCEVGEP]]198; CHECK-NEXT:    [[FOUND_CONFLICT:%.*]] = and i1 [[BOUND0]], [[BOUND1]]199; CHECK-NEXT:    br i1 [[FOUND_CONFLICT]], label %[[WHILE_BODY_PH_LVER_ORIG:.*]], label %[[WHILE_BODY_PH:.*]]200; CHECK:       [[WHILE_BODY_PH_LVER_ORIG]]:201; CHECK-NEXT:    br label %[[WHILE_BODY_LVER_ORIG:.*]]202; CHECK:       [[WHILE_BODY_LVER_ORIG]]:203; CHECK-NEXT:    [[N_ADDR:%.*]] = phi i32 [ [[DEC:%.*]], %[[WHILE_BODY_LVER_ORIG]] ], [ [[N]], %[[WHILE_BODY_PH_LVER_ORIG]] ]204; CHECK-NEXT:    [[P_ADDR:%.*]] = phi ptr [ [[INCDEC_PTR:%.*]], %[[WHILE_BODY_LVER_ORIG]] ], [ [[P]], %[[WHILE_BODY_PH_LVER_ORIG]] ]205; CHECK-NEXT:    [[DEC]] = add nsw i32 [[N_ADDR]], -1206; CHECK-NEXT:    [[QVAL:%.*]] = load i32, ptr [[Q]], align 4207; CHECK-NEXT:    [[REM:%.*]] = srem i32 [[DEC]], 2208; CHECK-NEXT:    [[IDXPROM:%.*]] = sext i32 [[REM]] to i64209; CHECK-NEXT:    [[ARRAYIDX:%.*]] = getelementptr inbounds i32, ptr [[R]], i64 [[IDXPROM]]210; CHECK-NEXT:    [[VAL:%.*]] = load i32, ptr [[ARRAYIDX]], align 4211; CHECK-NEXT:    [[ADD:%.*]] = add nsw i32 [[VAL]], [[QVAL]]212; CHECK-NEXT:    [[INCDEC_PTR]] = getelementptr inbounds nuw i8, ptr [[P_ADDR]], i64 4213; CHECK-NEXT:    store i32 [[ADD]], ptr [[P_ADDR]], align 4214; CHECK-NEXT:    [[TOBOOL_NOT:%.*]] = icmp eq i32 [[DEC]], 0215; CHECK-NEXT:    br i1 [[TOBOOL_NOT]], label %[[WHILE_END_LOOPEXIT:.*]], label %[[WHILE_BODY_LVER_ORIG]], !llvm.loop [[LOOP16:![0-9]+]]216; CHECK:       [[WHILE_BODY_PH]]:217; CHECK-NEXT:    [[QVAL1:%.*]] = load i32, ptr [[Q]], align 4, !alias.scope [[META17:![0-9]+]]218; CHECK-NEXT:    br label %[[WHILE_BODY:.*]]219; CHECK:       [[WHILE_BODY]]:220; CHECK-NEXT:    [[N_ADDR1:%.*]] = phi i32 [ [[DEC1:%.*]], %[[WHILE_BODY]] ], [ [[N]], %[[WHILE_BODY_PH]] ]221; CHECK-NEXT:    [[P_ADDR1:%.*]] = phi ptr [ [[INCDEC_PTR1:%.*]], %[[WHILE_BODY]] ], [ [[P]], %[[WHILE_BODY_PH]] ]222; CHECK-NEXT:    [[DEC1]] = add nsw i32 [[N_ADDR1]], -1223; CHECK-NEXT:    [[REM1:%.*]] = srem i32 [[DEC1]], 2224; CHECK-NEXT:    [[IDXPROM1:%.*]] = sext i32 [[REM1]] to i64225; CHECK-NEXT:    [[ARRAYIDX1:%.*]] = getelementptr inbounds i32, ptr [[R]], i64 [[IDXPROM1]]226; CHECK-NEXT:    [[VAL1:%.*]] = load i32, ptr [[ARRAYIDX1]], align 4227; CHECK-NEXT:    [[ADD1:%.*]] = add nsw i32 [[VAL1]], [[QVAL1]]228; CHECK-NEXT:    [[INCDEC_PTR1]] = getelementptr inbounds nuw i8, ptr [[P_ADDR1]], i64 4229; CHECK-NEXT:    store i32 [[ADD1]], ptr [[P_ADDR1]], align 4, !alias.scope [[META20:![0-9]+]], !noalias [[META17]]230; CHECK-NEXT:    [[TOBOOL_NOT1:%.*]] = icmp eq i32 [[DEC1]], 0231; CHECK-NEXT:    br i1 [[TOBOOL_NOT1]], label %[[WHILE_END_LOOPEXIT2:.*]], label %[[WHILE_BODY]], !llvm.loop [[LOOP22:![0-9]+]]232; CHECK:       [[WHILE_END_LOOPEXIT]]:233; CHECK-NEXT:    br label %[[WHILE_END:.*]]234; CHECK:       [[WHILE_END_LOOPEXIT2]]:235; CHECK-NEXT:    br label %[[WHILE_END]]236; CHECK:       [[WHILE_END]]:237; CHECK-NEXT:    ret void238;239entry:240  br label %while.body241 242while.body:243  %n.addr = phi i32 [ %dec, %while.body ], [ %n, %entry ]244  %p.addr = phi ptr [ %incdec.ptr, %while.body ], [ %p, %entry ]245  %dec = add nsw i32 %n.addr, -1246  %qval = load i32, ptr %q, align 4247  %rem = srem i32 %dec, 2248  %idxprom = sext i32 %rem to i64249  %arrayidx = getelementptr inbounds i32, ptr %r, i64 %idxprom250  %val = load i32, ptr %arrayidx, align 4251  %add = add nsw i32 %val, %qval252  %incdec.ptr = getelementptr inbounds nuw i8, ptr %p.addr, i64 4253  store i32 %add, ptr %p.addr, align 4254  %tobool.not = icmp eq i32 %dec, 0255  br i1 %tobool.not, label %while.end, label %while.body256 257while.end:258  ret void259}260 261; A memcpy-like loop where the source address is loaded from a pointer262define void @memcpy_load_src(ptr %dst, ptr %src, i32 %n) {263; CHECK-LABEL: define void @memcpy_load_src(264; CHECK-SAME: ptr [[DST:%.*]], ptr [[SRC:%.*]], i32 [[N:%.*]]) {265; CHECK-NEXT:  [[WHILE_BODY_LVER_CHECK:.*:]]266; CHECK-NEXT:    [[SCEVGEP:%.*]] = getelementptr i8, ptr [[SRC]], i64 8267; CHECK-NEXT:    [[TMP0:%.*]] = add nsw i32 [[N]], -1268; CHECK-NEXT:    [[TMP1:%.*]] = zext i32 [[TMP0]] to i64269; CHECK-NEXT:    [[TMP2:%.*]] = add nuw nsw i64 [[TMP1]], 1270; CHECK-NEXT:    [[SCEVGEP1:%.*]] = getelementptr i8, ptr [[DST]], i64 [[TMP2]]271; CHECK-NEXT:    [[BOUND0:%.*]] = icmp ult ptr [[SRC]], [[SCEVGEP1]]272; CHECK-NEXT:    [[BOUND1:%.*]] = icmp ult ptr [[DST]], [[SCEVGEP]]273; CHECK-NEXT:    [[FOUND_CONFLICT:%.*]] = and i1 [[BOUND0]], [[BOUND1]]274; CHECK-NEXT:    br i1 [[FOUND_CONFLICT]], label %[[WHILE_BODY_PH_LVER_ORIG:.*]], label %[[WHILE_BODY_PH:.*]]275; CHECK:       [[WHILE_BODY_PH_LVER_ORIG]]:276; CHECK-NEXT:    br label %[[WHILE_BODY_LVER_ORIG:.*]]277; CHECK:       [[WHILE_BODY_LVER_ORIG]]:278; CHECK-NEXT:    [[N_VAL:%.*]] = phi i32 [ [[DEC:%.*]], %[[WHILE_BODY_LVER_ORIG]] ], [ [[N]], %[[WHILE_BODY_PH_LVER_ORIG]] ]279; CHECK-NEXT:    [[DST_VAL:%.*]] = phi ptr [ [[DST_VAL_NEXT:%.*]], %[[WHILE_BODY_LVER_ORIG]] ], [ [[DST]], %[[WHILE_BODY_PH_LVER_ORIG]] ]280; CHECK-NEXT:    [[DEC]] = add nsw i32 [[N_VAL]], -1281; CHECK-NEXT:    [[SRC_VAL:%.*]] = load ptr, ptr [[SRC]], align 8282; CHECK-NEXT:    [[SRC_VAL_NEXT:%.*]] = getelementptr inbounds nuw i8, ptr [[SRC_VAL]], i64 1283; CHECK-NEXT:    [[DST_VAL_NEXT]] = getelementptr inbounds nuw i8, ptr [[DST_VAL]], i64 1284; CHECK-NEXT:    store ptr [[SRC_VAL_NEXT]], ptr [[SRC]], align 8285; CHECK-NEXT:    [[VAL:%.*]] = load i8, ptr [[SRC_VAL]], align 1286; CHECK-NEXT:    store i8 [[VAL]], ptr [[DST_VAL]], align 1287; CHECK-NEXT:    [[TOBOOL_NOT:%.*]] = icmp eq i32 [[DEC]], 0288; CHECK-NEXT:    br i1 [[TOBOOL_NOT]], label %[[WHILE_END_LOOPEXIT:.*]], label %[[WHILE_BODY_LVER_ORIG]], !llvm.loop [[LOOP23:![0-9]+]]289; CHECK:       [[WHILE_BODY_PH]]:290; CHECK-NEXT:    [[SRC_PROMOTED:%.*]] = load ptr, ptr [[SRC]], align 8, !alias.scope [[META24:![0-9]+]], !noalias [[META27:![0-9]+]]291; CHECK-NEXT:    br label %[[WHILE_BODY:.*]]292; CHECK:       [[WHILE_BODY]]:293; CHECK-NEXT:    [[SRC_VAL_NEXT3:%.*]] = phi ptr [ [[SRC_VAL_NEXT1:%.*]], %[[WHILE_BODY]] ], [ [[SRC_PROMOTED]], %[[WHILE_BODY_PH]] ]294; CHECK-NEXT:    [[N_VAL1:%.*]] = phi i32 [ [[DEC1:%.*]], %[[WHILE_BODY]] ], [ [[N]], %[[WHILE_BODY_PH]] ]295; CHECK-NEXT:    [[DST_VAL1:%.*]] = phi ptr [ [[DST_VAL_NEXT1:%.*]], %[[WHILE_BODY]] ], [ [[DST]], %[[WHILE_BODY_PH]] ]296; CHECK-NEXT:    [[DEC1]] = add nsw i32 [[N_VAL1]], -1297; CHECK-NEXT:    [[SRC_VAL_NEXT1]] = getelementptr inbounds nuw i8, ptr [[SRC_VAL_NEXT3]], i64 1298; CHECK-NEXT:    [[DST_VAL_NEXT1]] = getelementptr inbounds nuw i8, ptr [[DST_VAL1]], i64 1299; CHECK-NEXT:    store ptr [[SRC_VAL_NEXT1]], ptr [[SRC]], align 8, !alias.scope [[META24]], !noalias [[META27]]300; CHECK-NEXT:    [[VAL1:%.*]] = load i8, ptr [[SRC_VAL_NEXT3]], align 1301; CHECK-NEXT:    store i8 [[VAL1]], ptr [[DST_VAL1]], align 1, !alias.scope [[META27]]302; CHECK-NEXT:    [[TOBOOL_NOT1:%.*]] = icmp eq i32 [[DEC1]], 0303; CHECK-NEXT:    br i1 [[TOBOOL_NOT1]], label %[[WHILE_END_LOOPEXIT2:.*]], label %[[WHILE_BODY]], !llvm.loop [[LOOP29:![0-9]+]]304; CHECK:       [[WHILE_END_LOOPEXIT]]:305; CHECK-NEXT:    br label %[[WHILE_END:.*]]306; CHECK:       [[WHILE_END_LOOPEXIT2]]:307; CHECK-NEXT:    br label %[[WHILE_END]]308; CHECK:       [[WHILE_END]]:309; CHECK-NEXT:    ret void310;311entry:312  br label %while.body313 314while.body:315  %n_val = phi i32 [ %dec, %while.body ], [ %n, %entry ]316  %dst_val = phi ptr [ %dst_val.next, %while.body ], [ %dst, %entry ]317  %dec = add nsw i32 %n_val, -1318  %src_val = load ptr, ptr %src, align 8319  %src_val.next = getelementptr inbounds nuw i8, ptr %src_val, i64 1320  %dst_val.next = getelementptr inbounds nuw i8, ptr %dst_val, i64 1321  store ptr %src_val.next, ptr %src, align 8322  %val = load i8, ptr %src_val, align 1323  store i8 %val, ptr %dst_val, align 1324  %tobool.not = icmp eq i32 %dec, 0325  br i1 %tobool.not, label %while.end, label %while.body326 327while.end:328  ret void329}330 331; A memcpy-like loop where the destination address is loaded from a pointer332; FIXME: We could hoist the load of the destination address, but doing the333; bounds check of the store through that pointer itself requires using the334; hoisted load.335define void @memcpy_load_dst(ptr %dst, ptr %src, i32 %n) {336; CHECK-LABEL: define void @memcpy_load_dst(337; CHECK-SAME: ptr [[DST:%.*]], ptr [[SRC:%.*]], i32 [[N:%.*]]) {338; CHECK-NEXT:  [[ENTRY:.*]]:339; CHECK-NEXT:    br label %[[WHILE_BODY:.*]]340; CHECK:       [[WHILE_BODY]]:341; CHECK-NEXT:    [[N_VAL:%.*]] = phi i32 [ [[DEC:%.*]], %[[WHILE_BODY]] ], [ [[N]], %[[ENTRY]] ]342; CHECK-NEXT:    [[SRC_VAL:%.*]] = phi ptr [ [[SRC_VAL_NEXT:%.*]], %[[WHILE_BODY]] ], [ [[SRC]], %[[ENTRY]] ]343; CHECK-NEXT:    [[DEC]] = add nsw i32 [[N_VAL]], -1344; CHECK-NEXT:    [[DST_VAL:%.*]] = load ptr, ptr [[DST]], align 8345; CHECK-NEXT:    [[SRC_VAL_NEXT]] = getelementptr inbounds nuw i8, ptr [[SRC_VAL]], i64 1346; CHECK-NEXT:    [[DST_VAL_NEXT:%.*]] = getelementptr inbounds nuw i8, ptr [[DST_VAL]], i64 1347; CHECK-NEXT:    store ptr [[DST_VAL_NEXT]], ptr [[DST]], align 8348; CHECK-NEXT:    [[VAL:%.*]] = load i8, ptr [[SRC_VAL]], align 1349; CHECK-NEXT:    store i8 [[VAL]], ptr [[DST_VAL]], align 1350; CHECK-NEXT:    [[TOBOOL_NOT:%.*]] = icmp eq i32 [[DEC]], 0351; CHECK-NEXT:    br i1 [[TOBOOL_NOT]], label %[[WHILE_END:.*]], label %[[WHILE_BODY]]352; CHECK:       [[WHILE_END]]:353; CHECK-NEXT:    ret void354;355entry:356  br label %while.body357 358while.body:359  %n_val = phi i32 [ %dec, %while.body ], [ %n, %entry ]360  %src_val = phi ptr [ %src_val.next, %while.body ], [ %src, %entry ]361  %dec = add nsw i32 %n_val, -1362  %dst_val = load ptr, ptr %dst, align 8363  %src_val.next = getelementptr inbounds nuw i8, ptr %src_val, i64 1364  %dst_val.next = getelementptr inbounds nuw i8, ptr %dst_val, i64 1365  store ptr %dst_val.next, ptr %dst, align 8366  %val = load i8, ptr %src_val, align 1367  store i8 %val, ptr %dst_val, align 1368  %tobool.not = icmp eq i32 %dec, 0369  br i1 %tobool.not, label %while.end, label %while.body370 371while.end:372  ret void373}374 375; A memcpy-like loop where both the source and destination pointers are loaded from pointers376; FIXME: We could hoist the loads of both addresses, but doing the bounds check377; of the store through the destination address itself requires using the hoisted378; load.379define void @memcpy_load_src_dst(ptr %dst, ptr %src, i32 %n) {380; CHECK-LABEL: define void @memcpy_load_src_dst(381; CHECK-SAME: ptr [[DST:%.*]], ptr [[SRC:%.*]], i32 [[N:%.*]]) {382; CHECK-NEXT:  [[ENTRY:.*]]:383; CHECK-NEXT:    br label %[[WHILE_BODY:.*]]384; CHECK:       [[WHILE_BODY]]:385; CHECK-NEXT:    [[N_VAL:%.*]] = phi i32 [ [[DEC:%.*]], %[[WHILE_BODY]] ], [ [[N]], %[[ENTRY]] ]386; CHECK-NEXT:    [[DEC]] = add nsw i32 [[N_VAL]], -1387; CHECK-NEXT:    [[SRC_VAL:%.*]] = load ptr, ptr [[SRC]], align 8388; CHECK-NEXT:    [[DST_VAL:%.*]] = load ptr, ptr [[DST]], align 8389; CHECK-NEXT:    [[SRC_VAL_NEXT:%.*]] = getelementptr inbounds nuw i8, ptr [[SRC_VAL]], i64 1390; CHECK-NEXT:    [[DST_VAL_NEXT:%.*]] = getelementptr inbounds nuw i8, ptr [[DST_VAL]], i64 1391; CHECK-NEXT:    store ptr [[SRC_VAL_NEXT]], ptr [[SRC]], align 8392; CHECK-NEXT:    store ptr [[DST_VAL_NEXT]], ptr [[DST]], align 8393; CHECK-NEXT:    [[VAL:%.*]] = load i8, ptr [[SRC_VAL]], align 1394; CHECK-NEXT:    store i8 [[VAL]], ptr [[DST_VAL]], align 1395; CHECK-NEXT:    [[TOBOOL_NOT:%.*]] = icmp eq i32 [[DEC]], 0396; CHECK-NEXT:    br i1 [[TOBOOL_NOT]], label %[[WHILE_END:.*]], label %[[WHILE_BODY]]397; CHECK:       [[WHILE_END]]:398; CHECK-NEXT:    ret void399;400entry:401  br label %while.body402 403while.body:404  %n_val = phi i32 [ %dec, %while.body ], [ %n, %entry ]405  %dec = add nsw i32 %n_val, -1406  %src_val = load ptr, ptr %src, align 8407  %dst_val = load ptr, ptr %dst, align 8408  %src_val.next = getelementptr inbounds nuw i8, ptr %src_val, i64 1409  %dst_val.next = getelementptr inbounds nuw i8, ptr %dst_val, i64 1410  store ptr %src_val.next, ptr %src, align 8411  store ptr %dst_val.next, ptr %dst, align 8412  %val = load i8, ptr %src_val, align 1413  store i8 %val, ptr %dst_val, align 1414  %tobool.not = icmp eq i32 %dec, 0415  br i1 %tobool.not, label %while.end, label %while.body416 417while.end:418  ret void419}420