[Loads][LAA] Properly handle multiple deref assumptions (#204083)
The current code uses a `DerefRK = std::max(DerefRK, RK)` pattern, which mostly "works" by accident. The maximum here is based on RK.ArgValue, which will be 0 on initialization and then (incorrectly) set to 1 for variable dereferenceable assumptions, or N for constant ones. So if we have a single variable dereferenceable assumption, this ends up working. If we have multiple, or there are also constant assumptions, or we fix the incorrect ArgValue initialization, this breaks down. Fix this by individually inspecting the RK values. Do the checks for each one until we have both align and dereferenceable proven. For the LAA case, add all the applicable dereferenceable assumptions to the umax expression.
This commit is contained in:
parent
60ad6ed5df
commit
8f7b80b178
3 changed files with 206 additions and 47 deletions
|
|
@ -37,30 +37,29 @@ static bool isDereferenceableAndAlignedPointerViaAssumption(
|
|||
function_ref<bool(const RetainedKnowledge &RK)> CheckSize) {
|
||||
if (!SQ.CxtI)
|
||||
return false;
|
||||
/// Look through assumes to see if both dereferencability and alignment can
|
||||
/// be proven by an assume if needed.
|
||||
RetainedKnowledge AlignRK;
|
||||
RetainedKnowledge DerefRK;
|
||||
// Look through assumes to see if both dereferenceability and alignment can
|
||||
// be proven by an assume if needed.
|
||||
bool PtrCanBeFreed = Ptr->canBeFreed() && !IgnoreFree;
|
||||
bool IsAligned = Ptr->getPointerAlignment(SQ.DL) >= Alignment;
|
||||
bool IsDerefable = false;
|
||||
return getKnowledgeForValue(
|
||||
Ptr, {Attribute::Dereferenceable, Attribute::Alignment}, *SQ.AC,
|
||||
[&](RetainedKnowledge RK, Instruction *Assume, auto) {
|
||||
if (!isValidAssumeForContext(Assume, SQ.CxtI, SQ.DT))
|
||||
return false;
|
||||
if (RK.AttrKind == Attribute::Alignment)
|
||||
AlignRK = std::max(AlignRK, RK);
|
||||
|
||||
// Dereferenceable information from assumptions is only valid if the
|
||||
// value cannot be freed between the assumption and use.
|
||||
if ((!PtrCanBeFreed || willNotFreeBetween(Assume, SQ.CxtI)) &&
|
||||
RK.AttrKind == Attribute::Dereferenceable)
|
||||
DerefRK = std::max(DerefRK, RK);
|
||||
IsAligned |= AlignRK && AlignRK.ArgValue >= Alignment.value();
|
||||
if (IsAligned && DerefRK && CheckSize(DerefRK))
|
||||
return true; // We have found what we needed so we stop looking
|
||||
return false; // Other assumes may have better information. so
|
||||
// keep looking
|
||||
if (RK.AttrKind == Attribute::Alignment) {
|
||||
IsAligned |= RK.ArgValue >= Alignment.value();
|
||||
} else {
|
||||
assert(RK.AttrKind == Attribute::Dereferenceable);
|
||||
// Dereferenceable information from assumptions is only valid if the
|
||||
// value cannot be freed between the assumption and use.
|
||||
if (!IsDerefable &&
|
||||
(!PtrCanBeFreed || willNotFreeBetween(Assume, SQ.CxtI)) &&
|
||||
CheckSize(RK))
|
||||
IsDerefable = true;
|
||||
}
|
||||
// Stop looking if we have proven both necessary facts.
|
||||
return IsAligned && IsDerefable;
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -240,22 +240,20 @@ static bool evaluatePtrAddRecAtMaxBTCWillNotWrap(
|
|||
if (isa<UncondBrInst, CondBrInst>(LoopPred->getTerminator()))
|
||||
CtxI = LoopPred->getTerminator();
|
||||
}
|
||||
RetainedKnowledge DerefRK;
|
||||
getKnowledgeForValue(StartPtrV, {Attribute::Dereferenceable}, *AC,
|
||||
[&](RetainedKnowledge RK, Instruction *Assume, auto) {
|
||||
if (!isValidAssumeForContext(Assume, CtxI, DT))
|
||||
return false;
|
||||
DerefRK = std::max(DerefRK, RK);
|
||||
return true;
|
||||
});
|
||||
if (DerefRK) {
|
||||
const SCEV *DerefRKSCEV = SE.getSCEV(DerefRK.IRArgValue);
|
||||
Type *CommonTy =
|
||||
SE.getWiderType(DerefBytesSCEV->getType(), DerefRKSCEV->getType());
|
||||
DerefBytesSCEV = SE.getNoopOrZeroExtend(DerefBytesSCEV, CommonTy);
|
||||
DerefRKSCEV = SE.getNoopOrZeroExtend(DerefRKSCEV, CommonTy);
|
||||
DerefBytesSCEV = SE.getUMaxExpr(DerefBytesSCEV, DerefRKSCEV);
|
||||
}
|
||||
getKnowledgeForValue(
|
||||
StartPtrV, Attribute::Dereferenceable, *AC,
|
||||
[&](RetainedKnowledge RK, Instruction *Assume, auto) {
|
||||
if (!isValidAssumeForContext(Assume, CtxI, DT))
|
||||
return false;
|
||||
const SCEV *DerefRKSCEV = SE.getSCEV(RK.IRArgValue);
|
||||
Type *CommonTy =
|
||||
SE.getWiderType(DerefBytesSCEV->getType(), DerefRKSCEV->getType());
|
||||
DerefBytesSCEV = SE.getNoopOrZeroExtend(DerefBytesSCEV, CommonTy);
|
||||
DerefRKSCEV = SE.getNoopOrZeroExtend(DerefRKSCEV, CommonTy);
|
||||
DerefBytesSCEV = SE.getUMaxExpr(DerefBytesSCEV, DerefRKSCEV);
|
||||
// Continue with other assumptions.
|
||||
return false;
|
||||
});
|
||||
|
||||
if (DerefBytesSCEV->isZero())
|
||||
return false;
|
||||
|
|
|
|||
|
|
@ -81,6 +81,168 @@ exit:
|
|||
ret void
|
||||
}
|
||||
|
||||
; Adding an extra dereferenceable assume with constant size should not
|
||||
; interfere.
|
||||
define void @deref_assumption_in_preheader_non_constant_trip_count_access_i8_extra_constant_assume(ptr noalias noundef %a, ptr noalias %b, ptr noalias %c, i64 %n) nofree nosync {
|
||||
; CHECK-LABEL: define void @deref_assumption_in_preheader_non_constant_trip_count_access_i8_extra_constant_assume(
|
||||
; CHECK-SAME: ptr noalias noundef [[A:%.*]], ptr noalias [[B:%.*]], ptr noalias [[C:%.*]], i64 [[N:%.*]]) #[[ATTR0]] {
|
||||
; CHECK-NEXT: [[ENTRY:.*]]:
|
||||
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[A]], i64 4), "dereferenceable"(ptr [[A]], i64 100) ]
|
||||
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[A]], i64 4), "dereferenceable"(ptr [[A]], i64 [[N]]) ]
|
||||
; CHECK-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[N]], 2
|
||||
; CHECK-NEXT: br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]]
|
||||
; CHECK: [[VECTOR_PH]]:
|
||||
; CHECK-NEXT: [[N_MOD_VF:%.*]] = urem i64 [[N]], 2
|
||||
; CHECK-NEXT: [[N_VEC:%.*]] = sub i64 [[N]], [[N_MOD_VF]]
|
||||
; CHECK-NEXT: br label %[[VECTOR_BODY:.*]]
|
||||
; CHECK: [[VECTOR_BODY]]:
|
||||
; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ]
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[INDEX]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[B]], i64 [[INDEX]]
|
||||
; CHECK-NEXT: [[WIDE_LOAD:%.*]] = load <2 x i8>, ptr [[TMP1]], align 1
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = icmp sge <2 x i8> [[WIDE_LOAD]], zeroinitializer
|
||||
; CHECK-NEXT: [[WIDE_LOAD1:%.*]] = load <2 x i8>, ptr [[TMP0]], align 1
|
||||
; CHECK-NEXT: [[PREDPHI:%.*]] = select <2 x i1> [[TMP2]], <2 x i8> [[WIDE_LOAD]], <2 x i8> [[WIDE_LOAD1]]
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 [[INDEX]]
|
||||
; CHECK-NEXT: store <2 x i8> [[PREDPHI]], ptr [[TMP3]], align 1
|
||||
; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 2
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
|
||||
; CHECK-NEXT: br i1 [[TMP4]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP4:![0-9]+]]
|
||||
; CHECK: [[MIDDLE_BLOCK]]:
|
||||
; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[N]], [[N_VEC]]
|
||||
; CHECK-NEXT: br i1 [[CMP_N]], label %[[EXIT:.*]], label %[[SCALAR_PH]]
|
||||
; CHECK: [[SCALAR_PH]]:
|
||||
; CHECK-NEXT: [[BC_RESUME_VAL:%.*]] = phi i64 [ [[N_VEC]], %[[MIDDLE_BLOCK]] ], [ 0, %[[ENTRY]] ]
|
||||
; CHECK-NEXT: br label %[[LOOP_HEADER:.*]]
|
||||
; CHECK: [[LOOP_HEADER]]:
|
||||
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[BC_RESUME_VAL]], %[[SCALAR_PH]] ], [ [[IV_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
|
||||
; CHECK-NEXT: [[GEP_A:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[IV]]
|
||||
; CHECK-NEXT: [[GEP_B:%.*]] = getelementptr inbounds i8, ptr [[B]], i64 [[IV]]
|
||||
; CHECK-NEXT: [[L_B:%.*]] = load i8, ptr [[GEP_B]], align 1
|
||||
; CHECK-NEXT: [[C_1:%.*]] = icmp sge i8 [[L_B]], 0
|
||||
; CHECK-NEXT: br i1 [[C_1]], label %[[LOOP_LATCH]], label %[[LOOP_THEN:.*]]
|
||||
; CHECK: [[LOOP_THEN]]:
|
||||
; CHECK-NEXT: [[L_A:%.*]] = load i8, ptr [[GEP_A]], align 1
|
||||
; CHECK-NEXT: br label %[[LOOP_LATCH]]
|
||||
; CHECK: [[LOOP_LATCH]]:
|
||||
; CHECK-NEXT: [[MERGE:%.*]] = phi i8 [ [[L_A]], %[[LOOP_THEN]] ], [ [[L_B]], %[[LOOP_HEADER]] ]
|
||||
; CHECK-NEXT: [[GEP_C:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 [[IV]]
|
||||
; CHECK-NEXT: store i8 [[MERGE]], ptr [[GEP_C]], align 1
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
|
||||
; CHECK-NEXT: [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]]
|
||||
; CHECK-NEXT: br i1 [[EC]], label %[[EXIT]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP5:![0-9]+]]
|
||||
; CHECK: [[EXIT]]:
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
entry:
|
||||
call void @llvm.assume(i1 true) [ "align"(ptr %a, i64 4), "dereferenceable"(ptr %a, i64 100) ]
|
||||
call void @llvm.assume(i1 true) [ "align"(ptr %a, i64 4), "dereferenceable"(ptr %a, i64 %n) ]
|
||||
br label %loop.header
|
||||
|
||||
loop.header:
|
||||
%iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
||||
%gep.a = getelementptr inbounds i8, ptr %a, i64 %iv
|
||||
%gep.b = getelementptr inbounds i8, ptr %b, i64 %iv
|
||||
%l.b = load i8, ptr %gep.b, align 1
|
||||
%c.1 = icmp sge i8 %l.b, 0
|
||||
br i1 %c.1, label %loop.latch, label %loop.then
|
||||
|
||||
loop.then:
|
||||
%l.a = load i8, ptr %gep.a, align 1
|
||||
br label %loop.latch
|
||||
|
||||
loop.latch:
|
||||
%merge = phi i8 [ %l.a, %loop.then ], [ %l.b, %loop.header ]
|
||||
%gep.c = getelementptr inbounds i8, ptr %c, i64 %iv
|
||||
store i8 %merge, ptr %gep.c, align 1
|
||||
%iv.next = add nuw nsw i64 %iv, 1
|
||||
%ec = icmp eq i64 %iv.next, %n
|
||||
br i1 %ec, label %exit, label %loop.header
|
||||
|
||||
exit:
|
||||
ret void
|
||||
}
|
||||
|
||||
define void @deref_assumption_in_preheader_non_constant_trip_count_access_i8_extra_variable_assume(ptr noalias noundef %a, ptr noalias %b, ptr noalias %c, i64 %n, i64 %m) nofree nosync {
|
||||
; CHECK-LABEL: define void @deref_assumption_in_preheader_non_constant_trip_count_access_i8_extra_variable_assume(
|
||||
; CHECK-SAME: ptr noalias noundef [[A:%.*]], ptr noalias [[B:%.*]], ptr noalias [[C:%.*]], i64 [[N:%.*]], i64 [[M:%.*]]) #[[ATTR0]] {
|
||||
; CHECK-NEXT: [[ENTRY:.*]]:
|
||||
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[A]], i64 4), "dereferenceable"(ptr [[A]], i64 [[M]]) ]
|
||||
; CHECK-NEXT: call void @llvm.assume(i1 true) [ "align"(ptr [[A]], i64 4), "dereferenceable"(ptr [[A]], i64 [[N]]) ]
|
||||
; CHECK-NEXT: [[MIN_ITERS_CHECK:%.*]] = icmp ult i64 [[N]], 2
|
||||
; CHECK-NEXT: br i1 [[MIN_ITERS_CHECK]], label %[[SCALAR_PH:.*]], label %[[VECTOR_PH:.*]]
|
||||
; CHECK: [[VECTOR_PH]]:
|
||||
; CHECK-NEXT: [[N_MOD_VF:%.*]] = urem i64 [[N]], 2
|
||||
; CHECK-NEXT: [[N_VEC:%.*]] = sub i64 [[N]], [[N_MOD_VF]]
|
||||
; CHECK-NEXT: br label %[[VECTOR_BODY:.*]]
|
||||
; CHECK: [[VECTOR_BODY]]:
|
||||
; CHECK-NEXT: [[INDEX:%.*]] = phi i64 [ 0, %[[VECTOR_PH]] ], [ [[INDEX_NEXT:%.*]], %[[VECTOR_BODY]] ]
|
||||
; CHECK-NEXT: [[TMP0:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[INDEX]]
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = getelementptr inbounds i8, ptr [[B]], i64 [[INDEX]]
|
||||
; CHECK-NEXT: [[WIDE_LOAD:%.*]] = load <2 x i8>, ptr [[TMP1]], align 1
|
||||
; CHECK-NEXT: [[TMP2:%.*]] = icmp sge <2 x i8> [[WIDE_LOAD]], zeroinitializer
|
||||
; CHECK-NEXT: [[WIDE_LOAD1:%.*]] = load <2 x i8>, ptr [[TMP0]], align 1
|
||||
; CHECK-NEXT: [[PREDPHI:%.*]] = select <2 x i1> [[TMP2]], <2 x i8> [[WIDE_LOAD]], <2 x i8> [[WIDE_LOAD1]]
|
||||
; CHECK-NEXT: [[TMP3:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 [[INDEX]]
|
||||
; CHECK-NEXT: store <2 x i8> [[PREDPHI]], ptr [[TMP3]], align 1
|
||||
; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 2
|
||||
; CHECK-NEXT: [[TMP4:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
|
||||
; CHECK-NEXT: br i1 [[TMP4]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP6:![0-9]+]]
|
||||
; CHECK: [[MIDDLE_BLOCK]]:
|
||||
; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[N]], [[N_VEC]]
|
||||
; CHECK-NEXT: br i1 [[CMP_N]], label %[[EXIT:.*]], label %[[SCALAR_PH]]
|
||||
; CHECK: [[SCALAR_PH]]:
|
||||
; CHECK-NEXT: [[BC_RESUME_VAL:%.*]] = phi i64 [ [[N_VEC]], %[[MIDDLE_BLOCK]] ], [ 0, %[[ENTRY]] ]
|
||||
; CHECK-NEXT: br label %[[LOOP_HEADER:.*]]
|
||||
; CHECK: [[LOOP_HEADER]]:
|
||||
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ [[BC_RESUME_VAL]], %[[SCALAR_PH]] ], [ [[IV_NEXT:%.*]], %[[LOOP_LATCH:.*]] ]
|
||||
; CHECK-NEXT: [[GEP_A:%.*]] = getelementptr inbounds i8, ptr [[A]], i64 [[IV]]
|
||||
; CHECK-NEXT: [[GEP_B:%.*]] = getelementptr inbounds i8, ptr [[B]], i64 [[IV]]
|
||||
; CHECK-NEXT: [[L_B:%.*]] = load i8, ptr [[GEP_B]], align 1
|
||||
; CHECK-NEXT: [[C_1:%.*]] = icmp sge i8 [[L_B]], 0
|
||||
; CHECK-NEXT: br i1 [[C_1]], label %[[LOOP_LATCH]], label %[[LOOP_THEN:.*]]
|
||||
; CHECK: [[LOOP_THEN]]:
|
||||
; CHECK-NEXT: [[L_A:%.*]] = load i8, ptr [[GEP_A]], align 1
|
||||
; CHECK-NEXT: br label %[[LOOP_LATCH]]
|
||||
; CHECK: [[LOOP_LATCH]]:
|
||||
; CHECK-NEXT: [[MERGE:%.*]] = phi i8 [ [[L_A]], %[[LOOP_THEN]] ], [ [[L_B]], %[[LOOP_HEADER]] ]
|
||||
; CHECK-NEXT: [[GEP_C:%.*]] = getelementptr inbounds i8, ptr [[C]], i64 [[IV]]
|
||||
; CHECK-NEXT: store i8 [[MERGE]], ptr [[GEP_C]], align 1
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
|
||||
; CHECK-NEXT: [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]]
|
||||
; CHECK-NEXT: br i1 [[EC]], label %[[EXIT]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP7:![0-9]+]]
|
||||
; CHECK: [[EXIT]]:
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
entry:
|
||||
call void @llvm.assume(i1 true) [ "align"(ptr %a, i64 4), "dereferenceable"(ptr %a, i64 %m) ]
|
||||
call void @llvm.assume(i1 true) [ "align"(ptr %a, i64 4), "dereferenceable"(ptr %a, i64 %n) ]
|
||||
br label %loop.header
|
||||
|
||||
loop.header:
|
||||
%iv = phi i64 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
||||
%gep.a = getelementptr inbounds i8, ptr %a, i64 %iv
|
||||
%gep.b = getelementptr inbounds i8, ptr %b, i64 %iv
|
||||
%l.b = load i8, ptr %gep.b, align 1
|
||||
%c.1 = icmp sge i8 %l.b, 0
|
||||
br i1 %c.1, label %loop.latch, label %loop.then
|
||||
|
||||
loop.then:
|
||||
%l.a = load i8, ptr %gep.a, align 1
|
||||
br label %loop.latch
|
||||
|
||||
loop.latch:
|
||||
%merge = phi i8 [ %l.a, %loop.then ], [ %l.b, %loop.header ]
|
||||
%gep.c = getelementptr inbounds i8, ptr %c, i64 %iv
|
||||
store i8 %merge, ptr %gep.c, align 1
|
||||
%iv.next = add nuw nsw i64 %iv, 1
|
||||
%ec = icmp eq i64 %iv.next, %n
|
||||
br i1 %ec, label %exit, label %loop.header
|
||||
|
||||
exit:
|
||||
ret void
|
||||
}
|
||||
|
||||
; %a is known dereferenceable via assume for the whole loop.
|
||||
define void @deref_assumption_in_preheader_non_constant_trip_count_access_i32(ptr noalias noundef %a, ptr noalias %b, ptr noalias %c, i64 %n) nofree nosync {
|
||||
; CHECK-LABEL: define void @deref_assumption_in_preheader_non_constant_trip_count_access_i32(
|
||||
|
|
@ -106,7 +268,7 @@ define void @deref_assumption_in_preheader_non_constant_trip_count_access_i32(pt
|
|||
; CHECK-NEXT: store <2 x i32> [[PREDPHI]], ptr [[TMP6]], align 1
|
||||
; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[TMP0]], 2
|
||||
; CHECK-NEXT: [[TMP8:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
|
||||
; CHECK-NEXT: br i1 [[TMP8]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP4:![0-9]+]]
|
||||
; CHECK-NEXT: br i1 [[TMP8]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP8:![0-9]+]]
|
||||
; CHECK: [[MIDDLE_BLOCK]]:
|
||||
; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[N]], [[N_VEC]]
|
||||
; CHECK-NEXT: br i1 [[CMP_N]], label %[[EXIT:.*]], label %[[SCALAR_PH]]
|
||||
|
|
@ -129,7 +291,7 @@ define void @deref_assumption_in_preheader_non_constant_trip_count_access_i32(pt
|
|||
; CHECK-NEXT: store i32 [[MERGE]], ptr [[GEP_C]], align 1
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
|
||||
; CHECK-NEXT: [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]]
|
||||
; CHECK-NEXT: br i1 [[EC]], label %[[EXIT]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP5:![0-9]+]]
|
||||
; CHECK-NEXT: br i1 [[EC]], label %[[EXIT]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP9:![0-9]+]]
|
||||
; CHECK: [[EXIT]]:
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
|
|
@ -204,7 +366,7 @@ define void @deref_assumption_in_preheader_too_small_non_constant_trip_count_acc
|
|||
; CHECK-NEXT: store <2 x i32> [[PREDPHI]], ptr [[TMP6]], align 1
|
||||
; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[TMP0]], 2
|
||||
; CHECK-NEXT: [[TMP8:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
|
||||
; CHECK-NEXT: br i1 [[TMP8]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP6:![0-9]+]]
|
||||
; CHECK-NEXT: br i1 [[TMP8]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP10:![0-9]+]]
|
||||
; CHECK: [[MIDDLE_BLOCK]]:
|
||||
; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[N]], [[N_VEC]]
|
||||
; CHECK-NEXT: br i1 [[CMP_N]], label %[[EXIT:.*]], label %[[SCALAR_PH]]
|
||||
|
|
@ -227,7 +389,7 @@ define void @deref_assumption_in_preheader_too_small_non_constant_trip_count_acc
|
|||
; CHECK-NEXT: store i32 [[MERGE]], ptr [[GEP_C]], align 1
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
|
||||
; CHECK-NEXT: [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]]
|
||||
; CHECK-NEXT: br i1 [[EC]], label %[[EXIT]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP7:![0-9]+]]
|
||||
; CHECK-NEXT: br i1 [[EC]], label %[[EXIT]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP11:![0-9]+]]
|
||||
; CHECK: [[EXIT]]:
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
|
|
@ -300,7 +462,7 @@ define void @deref_assumption_in_preheader_too_small2_non_constant_trip_count_ac
|
|||
; CHECK-NEXT: store <2 x i32> [[PREDPHI]], ptr [[TMP6]], align 1
|
||||
; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[TMP0]], 2
|
||||
; CHECK-NEXT: [[TMP8:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
|
||||
; CHECK-NEXT: br i1 [[TMP8]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP8:![0-9]+]]
|
||||
; CHECK-NEXT: br i1 [[TMP8]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP12:![0-9]+]]
|
||||
; CHECK: [[MIDDLE_BLOCK]]:
|
||||
; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[N]], [[N_VEC]]
|
||||
; CHECK-NEXT: br i1 [[CMP_N]], label %[[EXIT:.*]], label %[[SCALAR_PH]]
|
||||
|
|
@ -323,7 +485,7 @@ define void @deref_assumption_in_preheader_too_small2_non_constant_trip_count_ac
|
|||
; CHECK-NEXT: store i32 [[MERGE]], ptr [[GEP_C]], align 1
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
|
||||
; CHECK-NEXT: [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]]
|
||||
; CHECK-NEXT: br i1 [[EC]], label %[[EXIT]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP9:![0-9]+]]
|
||||
; CHECK-NEXT: br i1 [[EC]], label %[[EXIT]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP13:![0-9]+]]
|
||||
; CHECK: [[EXIT]]:
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
|
|
@ -380,7 +542,7 @@ define void @deref_assumption_in_preheader_non_constant_trip_count_access_i32_al
|
|||
; CHECK-NEXT: store <2 x i32> [[PREDPHI]], ptr [[TMP5]], align 1
|
||||
; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 2
|
||||
; CHECK-NEXT: [[TMP7:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
|
||||
; CHECK-NEXT: br i1 [[TMP7]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP10:![0-9]+]]
|
||||
; CHECK-NEXT: br i1 [[TMP7]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP14:![0-9]+]]
|
||||
; CHECK: [[MIDDLE_BLOCK]]:
|
||||
; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[N]], [[N_VEC]]
|
||||
; CHECK-NEXT: br i1 [[CMP_N]], label %[[EXIT:.*]], label %[[SCALAR_PH]]
|
||||
|
|
@ -403,7 +565,7 @@ define void @deref_assumption_in_preheader_non_constant_trip_count_access_i32_al
|
|||
; CHECK-NEXT: store i32 [[MERGE]], ptr [[GEP_C]], align 1
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
|
||||
; CHECK-NEXT: [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]]
|
||||
; CHECK-NEXT: br i1 [[EC]], label %[[EXIT]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP11:![0-9]+]]
|
||||
; CHECK-NEXT: br i1 [[EC]], label %[[EXIT]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP15:![0-9]+]]
|
||||
; CHECK: [[EXIT]]:
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
|
|
@ -478,7 +640,7 @@ define void @deref_assumption_in_preheader_non_constant_trip_count_access_i32_al
|
|||
; CHECK-NEXT: store <2 x i32> [[PREDPHI]], ptr [[TMP16]], align 1
|
||||
; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 2
|
||||
; CHECK-NEXT: [[TMP18:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
|
||||
; CHECK-NEXT: br i1 [[TMP18]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP12:![0-9]+]]
|
||||
; CHECK-NEXT: br i1 [[TMP18]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP16:![0-9]+]]
|
||||
; CHECK: [[MIDDLE_BLOCK]]:
|
||||
; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[N]], [[N_VEC]]
|
||||
; CHECK-NEXT: br i1 [[CMP_N]], label %[[EXIT:.*]], label %[[SCALAR_PH]]
|
||||
|
|
@ -501,7 +663,7 @@ define void @deref_assumption_in_preheader_non_constant_trip_count_access_i32_al
|
|||
; CHECK-NEXT: store i32 [[MERGE]], ptr [[GEP_C]], align 1
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
|
||||
; CHECK-NEXT: [[EC:%.*]] = icmp eq i64 [[IV_NEXT]], [[N]]
|
||||
; CHECK-NEXT: br i1 [[EC]], label %[[EXIT]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP13:![0-9]+]]
|
||||
; CHECK-NEXT: br i1 [[EC]], label %[[EXIT]], label %[[LOOP_HEADER]], !llvm.loop [[LOOP17:![0-9]+]]
|
||||
; CHECK: [[EXIT]]:
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
|
|
@ -584,7 +746,7 @@ define void @deref_assumption_loop_access_start_variable(i8 %v, ptr noundef %P,
|
|||
; CHECK-NEXT: store <2 x i32> [[PREDPHI]], ptr [[TMP17]], align 1
|
||||
; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 2
|
||||
; CHECK-NEXT: [[TMP18:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
|
||||
; CHECK-NEXT: br i1 [[TMP18]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP14:![0-9]+]]
|
||||
; CHECK-NEXT: br i1 [[TMP18]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP18:![0-9]+]]
|
||||
; CHECK: [[MIDDLE_BLOCK]]:
|
||||
; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[TMP3]], [[N_VEC]]
|
||||
; CHECK-NEXT: br i1 [[CMP_N]], label %[[EXIT:.*]], label %[[SCALAR_PH]]
|
||||
|
|
@ -607,7 +769,7 @@ define void @deref_assumption_loop_access_start_variable(i8 %v, ptr noundef %P,
|
|||
; CHECK-NEXT: store i32 [[MERGE]], ptr [[GEP_C]], align 1
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
|
||||
; CHECK-NEXT: [[TERM_COND:%.*]] = icmp slt i64 [[IV_NEXT]], [[N]]
|
||||
; CHECK-NEXT: br i1 [[TERM_COND]], label %[[LOOP]], label %[[EXIT]], !llvm.loop [[LOOP15:![0-9]+]]
|
||||
; CHECK-NEXT: br i1 [[TERM_COND]], label %[[LOOP]], label %[[EXIT]], !llvm.loop [[LOOP19:![0-9]+]]
|
||||
; CHECK: [[EXIT]]:
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
|
|
@ -694,7 +856,7 @@ define void @deref_assumption_loop_access_start_variable_unknown_range(i8 %v, pt
|
|||
; CHECK-NEXT: store <2 x i32> [[PREDPHI]], ptr [[TMP17]], align 1
|
||||
; CHECK-NEXT: [[INDEX_NEXT]] = add nuw i64 [[INDEX]], 2
|
||||
; CHECK-NEXT: [[TMP18:%.*]] = icmp eq i64 [[INDEX_NEXT]], [[N_VEC]]
|
||||
; CHECK-NEXT: br i1 [[TMP18]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP16:![0-9]+]]
|
||||
; CHECK-NEXT: br i1 [[TMP18]], label %[[MIDDLE_BLOCK:.*]], label %[[VECTOR_BODY]], !llvm.loop [[LOOP20:![0-9]+]]
|
||||
; CHECK: [[MIDDLE_BLOCK]]:
|
||||
; CHECK-NEXT: [[CMP_N:%.*]] = icmp eq i64 [[TMP0]], [[N_VEC]]
|
||||
; CHECK-NEXT: br i1 [[CMP_N]], label %[[EXIT:.*]], label %[[SCALAR_PH]]
|
||||
|
|
@ -717,7 +879,7 @@ define void @deref_assumption_loop_access_start_variable_unknown_range(i8 %v, pt
|
|||
; CHECK-NEXT: store i32 [[MERGE]], ptr [[GEP_C]], align 1
|
||||
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1
|
||||
; CHECK-NEXT: [[TERM_COND:%.*]] = icmp slt i64 [[IV_NEXT]], [[N]]
|
||||
; CHECK-NEXT: br i1 [[TERM_COND]], label %[[LOOP]], label %[[EXIT]], !llvm.loop [[LOOP17:![0-9]+]]
|
||||
; CHECK-NEXT: br i1 [[TERM_COND]], label %[[LOOP]], label %[[EXIT]], !llvm.loop [[LOOP21:![0-9]+]]
|
||||
; CHECK: [[EXIT]]:
|
||||
; CHECK-NEXT: ret void
|
||||
;
|
||||
|
|
|
|||
Loading…
Reference in a new issue