[Polly] Assumptions used to derive domain must not be pruned by that domain (#190436)

The code that emits the conditions for whether a statement is executed
by checking whether we are in the statement's domain may apply
assumptions (such as an integer truncation being reversible). Later code
then assumes that these assumptions are only relevent for then the
statement is executed, but actually it is used for determining whether
it is executed.

Break this circular reasoning by introducing an `IsInsideDomain` flag
that can be set when the domain has not been verified yet.

Fixes #190128

Thanks to @thapgua for the bug report
This commit is contained in:
Michael Kruse 2026-04-04 13:42:04 +02:00 committed by GitHub
parent 4066590d8e
commit 948a64720b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
10 changed files with 244 additions and 89 deletions

View File

@ -110,10 +110,14 @@ class ScopBuilder final {
/// This will fill @p ConditionSets with the conditions under which control
/// will be moved from @p TI to its successors. Hence, @p ConditionSets will
/// have as many elements as @p TI has successors.
///
/// Set @p IsInsideDomain to false when building the conditions that check
/// whether @p BB is to be executed, since we are not in its domain yet.
bool buildConditionSets(BasicBlock *BB, Instruction *TI, Loop *L,
__isl_keep isl_set *Domain,
DenseMap<BasicBlock *, isl::set> &InvalidDomainMap,
SmallVectorImpl<__isl_give isl_set *> &ConditionSets);
SmallVectorImpl<__isl_give isl_set *> &ConditionSets,
bool IsInsideDomain = true);
/// Build the conditions sets for the branch condition @p Condition in
/// the @p Domain.
@ -123,20 +127,28 @@ class ScopBuilder final {
/// have as many elements as @p TI has successors. If @p TI is nullptr the
/// context under which @p Condition is true/false will be returned as the
/// new elements of @p ConditionSets.
///
/// Set @p IsInsideDomain to false when building the conditions that check
/// whether @p BB is to be executed, since we are not in its domain yet.
bool buildConditionSets(BasicBlock *BB, Value *Condition, Instruction *TI,
Loop *L, __isl_keep isl_set *Domain,
DenseMap<BasicBlock *, isl::set> &InvalidDomainMap,
SmallVectorImpl<__isl_give isl_set *> &ConditionSets);
SmallVectorImpl<__isl_give isl_set *> &ConditionSets,
bool IsInsideDomain = true);
/// Build the conditions sets for the switch @p SI in the @p Domain.
///
/// This will fill @p ConditionSets with the conditions under which control
/// will be moved from @p SI to its successors. Hence, @p ConditionSets will
/// have as many elements as @p SI has successors.
///
/// Set @p IsInsideDomain to false when building the conditions that check
/// whether @p BB is to be executed, since we are not in its domain yet.
bool buildConditionSets(BasicBlock *BB, SwitchInst *SI, Loop *L,
__isl_keep isl_set *Domain,
DenseMap<BasicBlock *, isl::set> &InvalidDomainMap,
SmallVectorImpl<__isl_give isl_set *> &ConditionSets);
SmallVectorImpl<__isl_give isl_set *> &ConditionSets,
bool IsInsideDomain = true);
/// Build condition sets for unsigned ICmpInst(s).
/// Special handling is required for unsigned operands to ensure that if
@ -145,12 +157,15 @@ class ScopBuilder final {
///
/// @param IsStrictUpperBound holds information on the predicate relation
/// between TestVal and UpperBound, i.e,
///
/// Set @p IsInsideDomain to false when building the conditions that check
/// whether @p BB is to be executed, since we are not in its domain yet.
/// TestVal < UpperBound OR TestVal <= UpperBound
__isl_give isl_set *buildUnsignedConditionSets(
BasicBlock *BB, Value *Condition, __isl_keep isl_set *Domain,
const SCEV *SCEV_TestVal, const SCEV *SCEV_UpperBound,
DenseMap<BasicBlock *, isl::set> &InvalidDomainMap,
bool IsStrictUpperBound);
bool IsStrictUpperBound, bool IsInsideDomain = true);
/// Propagate the domain constraints through the region @p R.
///
@ -235,13 +250,19 @@ class ScopBuilder final {
/// @param InvalidDomainMap A map of BB to their invalid domains.
/// @param E The SCEV that should be translated.
/// @param NonNegative Flag to indicate the @p E has to be
/// non-negative.
/// non-negative.
/// @param IsInsideDomain If true, assumptions only need to apply during the
/// execution of @p BB. That is, when we know that we
/// are in its domain. Must be false if the SCEV is
/// evaluated outside a ScopStmt, or for code that
/// computes the domain (since while doing that, we
/// don't know whether we are in the domain yet).
///
/// Note that this function will also adjust the invalid context
/// accordingly.
__isl_give isl_pw_aff *
getPwAff(BasicBlock *BB, DenseMap<BasicBlock *, isl::set> &InvalidDomainMap,
const SCEV *E, bool NonNegative = false);
const SCEV *E, bool NonNegative = false, bool IsInsideDomain = true);
/// Create equivalence classes for required invariant accesses.
///

View File

@ -2483,6 +2483,12 @@ public:
/// SCEVs known to not reference any loops in the SCoP can be
/// passed without a @p BB.
/// @param NonNegative Flag to indicate the @p E has to be non-negative.
/// @param IsInsideDomain If true, assumptions only need to apply during the
/// execution of @p BB. That is, when we know that we
/// are in its domain. Must be false if the SCEV is
/// evaluated outside a ScopStmt, or for code that
/// computes the domain (since while doing that, we
/// don't know whether we are in the domain yet).
///
/// Note that this function will always return a valid isl_pw_aff. However, if
/// the translation of @p E was deemed to complex the SCoP is invalidated and
@ -2490,7 +2496,8 @@ public:
/// for complex cases without "error handling code" needed on the users side.
PWACtx getPwAff(const SCEV *E, BasicBlock *BB = nullptr,
bool NonNegative = false,
RecordedAssumptionsTy *RecordedAssumptions = nullptr);
RecordedAssumptionsTy *RecordedAssumptions = nullptr,
bool IsInsideDomain = true);
/// Compute the isl representation for the SCEV @p E
///

View File

@ -33,12 +33,21 @@ public:
/// Translate a SCEV to an isl::pw_aff.
///
/// @param E he expression that is translated.
/// @param E The expression that is translated.
/// @param BB The block in which @p E is executed.
/// @param RecordedAssumptions If set, assumptions that make the translation
/// valid are added here.
/// @param IsInsideDomain If true, assumptions only need to apply during the
/// execution of @p BB. That is, when we know that we
/// are in its domain. Must be false if the SCEV is
/// evaluated outside a ScopStmt, or for code that
/// computes the domain (since while doing that, we
/// don't know whether we are in the domain yet).
///
/// @returns The isl representation of the SCEV @p E in @p Domain.
PWACtx getPwAff(const llvm::SCEV *E, llvm::BasicBlock *BB = nullptr,
RecordedAssumptionsTy *RecordedAssumptions = nullptr);
RecordedAssumptionsTy *RecordedAssumptions = nullptr,
bool IsInsideDomain = true);
/// Take the assumption that @p PWAC is non-negative.
void takeNonNegativeAssumption(
@ -66,6 +75,12 @@ private:
llvm::ScalarEvolution &SE;
llvm::LoopInfo &LI;
llvm::BasicBlock *BB;
/// Whether the evaluation takes place only when @p BB's domain has already
/// been checked.
/// @see getPwAff
bool IsInsideDomain = true;
RecordedAssumptionsTy *RecordedAssumptions = nullptr;
/// Target data for element size computing.

View File

@ -333,21 +333,12 @@ isl::set ScopBuilder::adjustDomainDimensions(isl::set Dom, Loop *OldL,
return Dom;
}
/// Compute the isl representation for the SCEV @p E in this BB.
///
/// @param BB The BB for which isl representation is to be
/// computed.
/// @param InvalidDomainMap A map of BB to their invalid domains.
/// @param E The SCEV that should be translated.
/// @param NonNegative Flag to indicate the @p E has to be non-negative.
///
/// Note that this function will also adjust the invalid context accordingly.
__isl_give isl_pw_aff *
ScopBuilder::getPwAff(BasicBlock *BB,
DenseMap<BasicBlock *, isl::set> &InvalidDomainMap,
const SCEV *E, bool NonNegative) {
PWACtx PWAC = scop->getPwAff(E, BB, NonNegative, &RecordedAssumptions);
const SCEV *E, bool NonNegative, bool IsInsideDomain) {
PWACtx PWAC =
scop->getPwAff(E, BB, NonNegative, &RecordedAssumptions, IsInsideDomain);
InvalidDomainMap[BB] = InvalidDomainMap[BB].unite(PWAC.second);
return PWAC.first.release();
}
@ -363,14 +354,15 @@ ScopBuilder::getPwAff(BasicBlock *BB,
__isl_give isl_set *ScopBuilder::buildUnsignedConditionSets(
BasicBlock *BB, Value *Condition, __isl_keep isl_set *Domain,
const SCEV *SCEV_TestVal, const SCEV *SCEV_UpperBound,
DenseMap<BasicBlock *, isl::set> &InvalidDomainMap,
bool IsStrictUpperBound) {
DenseMap<BasicBlock *, isl::set> &InvalidDomainMap, bool IsStrictUpperBound,
bool IsInsideDomain) {
// Do not take NonNeg assumption on TestVal
// as it might have MSB (Sign bit) set.
isl_pw_aff *TestVal = getPwAff(BB, InvalidDomainMap, SCEV_TestVal, false);
isl_pw_aff *TestVal = getPwAff(BB, InvalidDomainMap, SCEV_TestVal,
/*NonNegative=*/false, IsInsideDomain);
// Take NonNeg assumption on UpperBound.
isl_pw_aff *UpperBound =
getPwAff(BB, InvalidDomainMap, SCEV_UpperBound, true);
isl_pw_aff *UpperBound = getPwAff(BB, InvalidDomainMap, SCEV_UpperBound,
/*NonNegative=*/true, IsInsideDomain);
// 0 <= TestVal
isl_set *First =
@ -393,11 +385,12 @@ __isl_give isl_set *ScopBuilder::buildUnsignedConditionSets(
bool ScopBuilder::buildConditionSets(
BasicBlock *BB, SwitchInst *SI, Loop *L, __isl_keep isl_set *Domain,
DenseMap<BasicBlock *, isl::set> &InvalidDomainMap,
SmallVectorImpl<__isl_give isl_set *> &ConditionSets) {
SmallVectorImpl<__isl_give isl_set *> &ConditionSets, bool IsInsideDomain) {
Value *Condition = SI->getCondition();
isl_pw_aff *LHS, *RHS;
LHS = getPwAff(BB, InvalidDomainMap, SE.getSCEVAtScope(Condition, L));
LHS = getPwAff(BB, InvalidDomainMap, SE.getSCEVAtScope(Condition, L),
/*NonNegative=*/false, IsInsideDomain);
unsigned NumSuccessors = SI->getNumSuccessors();
ConditionSets.resize(NumSuccessors);
@ -405,7 +398,8 @@ bool ScopBuilder::buildConditionSets(
unsigned Idx = Case.getSuccessorIndex();
ConstantInt *CaseValue = Case.getCaseValue();
RHS = getPwAff(BB, InvalidDomainMap, SE.getSCEV(CaseValue));
RHS = getPwAff(BB, InvalidDomainMap, SE.getSCEV(CaseValue),
/*NonNegative=*/false, IsInsideDomain);
isl_set *CaseConditionSet =
buildConditionSet(ICmpInst::ICMP_EQ, isl::manage_copy(LHS),
isl::manage(RHS))
@ -430,15 +424,17 @@ bool ScopBuilder::buildConditionSets(
BasicBlock *BB, Value *Condition, Instruction *TI, Loop *L,
__isl_keep isl_set *Domain,
DenseMap<BasicBlock *, isl::set> &InvalidDomainMap,
SmallVectorImpl<__isl_give isl_set *> &ConditionSets) {
SmallVectorImpl<__isl_give isl_set *> &ConditionSets, bool IsInsideDomain) {
isl_set *ConsequenceCondSet = nullptr;
if (auto Load = dyn_cast<LoadInst>(Condition)) {
const SCEV *LHSSCEV = SE.getSCEVAtScope(Load, L);
const SCEV *RHSSCEV = SE.getZero(LHSSCEV->getType());
bool NonNeg = false;
isl_pw_aff *LHS = getPwAff(BB, InvalidDomainMap, LHSSCEV, NonNeg);
isl_pw_aff *RHS = getPwAff(BB, InvalidDomainMap, RHSSCEV, NonNeg);
isl_pw_aff *LHS =
getPwAff(BB, InvalidDomainMap, LHSSCEV, NonNeg, IsInsideDomain);
isl_pw_aff *RHS =
getPwAff(BB, InvalidDomainMap, RHSSCEV, NonNeg, IsInsideDomain);
ConsequenceCondSet = buildConditionSet(ICmpInst::ICMP_SLE, isl::manage(LHS),
isl::manage(RHS))
.release();
@ -462,10 +458,11 @@ bool ScopBuilder::buildConditionSets(
auto Opcode = BinOp->getOpcode();
assert(Opcode == Instruction::And || Opcode == Instruction::Or);
bool Valid = buildConditionSets(BB, BinOp->getOperand(0), TI, L, Domain,
InvalidDomainMap, ConditionSets) &&
buildConditionSets(BB, BinOp->getOperand(1), TI, L, Domain,
InvalidDomainMap, ConditionSets);
bool Valid =
buildConditionSets(BB, BinOp->getOperand(0), TI, L, Domain,
InvalidDomainMap, ConditionSets, IsInsideDomain) &&
buildConditionSets(BB, BinOp->getOperand(1), TI, L, Domain,
InvalidDomainMap, ConditionSets, IsInsideDomain);
if (!Valid) {
while (!ConditionSets.empty())
isl_set_free(ConditionSets.pop_back_val());
@ -501,28 +498,29 @@ bool ScopBuilder::buildConditionSets(
switch (ICond->getPredicate()) {
case ICmpInst::ICMP_ULT:
ConsequenceCondSet =
buildUnsignedConditionSets(BB, Condition, Domain, LeftOperand,
RightOperand, InvalidDomainMap, true);
ConsequenceCondSet = buildUnsignedConditionSets(
BB, Condition, Domain, LeftOperand, RightOperand, InvalidDomainMap,
/*IsStrictUpperBound=*/true, IsInsideDomain);
break;
case ICmpInst::ICMP_ULE:
ConsequenceCondSet =
buildUnsignedConditionSets(BB, Condition, Domain, LeftOperand,
RightOperand, InvalidDomainMap, false);
ConsequenceCondSet = buildUnsignedConditionSets(
BB, Condition, Domain, LeftOperand, RightOperand, InvalidDomainMap,
/*IsStrictUpperBound=*/false, IsInsideDomain);
break;
case ICmpInst::ICMP_UGT:
ConsequenceCondSet =
buildUnsignedConditionSets(BB, Condition, Domain, RightOperand,
LeftOperand, InvalidDomainMap, true);
ConsequenceCondSet = buildUnsignedConditionSets(
BB, Condition, Domain, RightOperand, LeftOperand, InvalidDomainMap,
/*IsStrictUpperBound=*/true, IsInsideDomain);
break;
case ICmpInst::ICMP_UGE:
ConsequenceCondSet =
buildUnsignedConditionSets(BB, Condition, Domain, RightOperand,
LeftOperand, InvalidDomainMap, false);
ConsequenceCondSet = buildUnsignedConditionSets(
BB, Condition, Domain, RightOperand, LeftOperand, InvalidDomainMap,
/*IsStrictUpperBound=*/false, IsInsideDomain);
break;
default:
LHS = getPwAff(BB, InvalidDomainMap, LeftOperand, NonNeg);
RHS = getPwAff(BB, InvalidDomainMap, RightOperand, NonNeg);
LHS = getPwAff(BB, InvalidDomainMap, LeftOperand, NonNeg, IsInsideDomain);
RHS =
getPwAff(BB, InvalidDomainMap, RightOperand, NonNeg, IsInsideDomain);
ConsequenceCondSet = buildConditionSet(ICond->getPredicate(),
isl::manage(LHS), isl::manage(RHS))
.release();
@ -566,10 +564,10 @@ bool ScopBuilder::buildConditionSets(
bool ScopBuilder::buildConditionSets(
BasicBlock *BB, Instruction *TI, Loop *L, __isl_keep isl_set *Domain,
DenseMap<BasicBlock *, isl::set> &InvalidDomainMap,
SmallVectorImpl<__isl_give isl_set *> &ConditionSets) {
SmallVectorImpl<__isl_give isl_set *> &ConditionSets, bool IsInsideDomain) {
if (SwitchInst *SI = dyn_cast<SwitchInst>(TI))
return buildConditionSets(BB, SI, L, Domain, InvalidDomainMap,
ConditionSets);
ConditionSets, IsInsideDomain);
if (isa<UncondBrInst>(TI)) {
ConditionSets.push_back(isl_set_copy(Domain));
@ -578,7 +576,7 @@ bool ScopBuilder::buildConditionSets(
Value *Condition = cast<CondBrInst>(TI)->getCondition();
return buildConditionSets(BB, Condition, TI, L, Domain, InvalidDomainMap,
ConditionSets);
ConditionSets, IsInsideDomain);
}
bool ScopBuilder::propagateDomainConstraints(
@ -756,7 +754,8 @@ bool ScopBuilder::addLoopBoundsToHeaderDomain(
SmallVector<isl_set *, 8> ConditionSets;
int idx = BI->getSuccessor(0) != HeaderBB;
if (!buildConditionSets(LatchBB, TI, L, LatchBBDom.get(),
InvalidDomainMap, ConditionSets))
InvalidDomainMap, ConditionSets,
/*IsInsideDomain=*/false))
return false;
// Free the non back edge condition set as we do not need it.
@ -930,7 +929,7 @@ bool ScopBuilder::buildDomainsWithBranchConstraints(
if (RN->isSubRegion())
ConditionSets.push_back(Domain.copy());
else if (!buildConditionSets(BB, TI, BBLoop, Domain.get(), InvalidDomainMap,
ConditionSets))
ConditionSets, /*IsInsideDomain=*/false))
return false;
// Now iterate over the successors and set their initial domain based on
@ -1324,34 +1323,67 @@ void ScopBuilder::buildEscapingDependences(Instruction *Inst) {
void ScopBuilder::addRecordedAssumptions() {
for (auto &AS : llvm::reverse(RecordedAssumptions)) {
isl::set S = AS.Set;
AssumptionSign Sign = AS.Sign;
if (!AS.BB) {
scop->addAssumption(AS.Kind, AS.Set, AS.Loc, AS.Sign,
nullptr /* BasicBlock */, AS.RequiresRTC);
continue;
// Assumptions/restructions apply only when the code containing it is
// actually executed
if (AS.BB && !AS.Set.is_params()) {
// If the domain was deleted the assumptions are void.
isl::set Dom = scop->getDomainConditions(AS.BB);
if (Dom.is_null())
continue;
// If a basic block was given use its domain to simplify the assumption.
// In case of restrictions we know they only have to hold on the domain,
// thus we can intersect them with the domain of the block. However, for
// assumptions the domain has to imply them, thus:
// _ _____
// Dom => S <==> A v B <==> A - B
//
// To avoid the complement we will register A - B as a restriction not an
// assumption.
if (Sign == AS_RESTRICTION) {
S = std::move(S).intersect(std::move(Dom));
} else {
S = std::move(Dom).subtract(std::move(S));
Sign = AS_RESTRICTION;
}
}
// If the domain was deleted the assumptions are void.
isl_set *Dom = scop->getDomainConditions(AS.BB).release();
if (!Dom)
continue;
// If a basic block was given use its domain to simplify the assumption.
// In case of restrictions we know they only have to hold on the domain,
// thus we can intersect them with the domain of the block. However, for
// assumptions the domain has to imply them, thus:
// _ _____
// Dom => S <==> A v B <==> A - B
isl::set PSet = S.params();
#ifndef NDEBUG
// .params() is an overapproximation; if an AS_ASSUMPTION says
//
// To avoid the complement we will register A - B as a restriction not an
// assumption.
isl_set *S = AS.Set.copy();
if (AS.Sign == AS_RESTRICTION)
S = isl_set_params(isl_set_intersect(S, Dom));
else /* (AS.Sign == AS_ASSUMPTION) */
S = isl_set_params(isl_set_subtract(Dom, S));
// [p] -> { [i] : p == 1 and i == 1 }
//
// the params space will be
//
// [p] -> { [] : }
//
// (because there is at least one element with p == 1 in the set);
// if RequiresRTC is true, we will not include a check for p at all. The
// code above adds the domain constraints which don't need (and should not)
// to checked, but the actual assumption/restructions should have access to
// the parameters only.
if (AS.RequiresRTC && Sign == AS_RESTRICTION) {
// Overapproximation is OK in this case: failing more RTC checks than
// strictly necessary (Underapproximation of RTC-checked AS_ASSUMPTIONs
// would be as well)
} else if (!AS.RequiresRTC && Sign == AS_ASSUMPTION) {
// Overapproximation of defined behavior is OK: Only too optimistic
// assumptions could lead to invalid transformations; the universe set
// would be equivalent to "no assumptions" (Underapproximation of
// undefined behaviour would be as well)
} else {
isl::set ReconstructedSet =
S.get_space().universe_set().intersect_params(PSet);
assert(ReconstructedSet.is_subset(S) &&
"Must not overapproximate assumptions/restructions");
}
#endif
scop->addAssumption(AS.Kind, isl::manage(S), AS.Loc, AS_RESTRICTION, AS.BB,
scop->addAssumption(AS.Kind, std::move(PSet), AS.Loc, Sign, AS.BB,
AS.RequiresRTC);
}
}

View File

@ -2169,13 +2169,14 @@ isl::ctx Scop::getIslCtx() const { return IslCtx.get(); }
__isl_give PWACtx Scop::getPwAff(const SCEV *E, BasicBlock *BB,
bool NonNegative,
RecordedAssumptionsTy *RecordedAssumptions) {
RecordedAssumptionsTy *RecordedAssumptions,
bool IsInsideDomain) {
// First try to use the SCEVAffinator to generate a piecewise defined
// affine function from @p E in the context of @p BB. If that tasks becomes to
// complex the affinator might return a nullptr. In such a case we invalidate
// the SCoP and return a dummy value. This way we do not need to add error
// handling code to all users of this function.
auto PWAC = Affinator.getPwAff(E, BB, RecordedAssumptions);
PWACtx PWAC = Affinator.getPwAff(E, BB, RecordedAssumptions, IsInsideDomain);
if (!PWAC.first.is_null()) {
// TODO: We could use a heuristic and either use:
// SCEVAffinator::takeNonNegativeAssumption

View File

@ -115,8 +115,10 @@ PWACtx SCEVAffinator::getPWACtxFromPWA(isl::pw_aff PWA) {
}
PWACtx SCEVAffinator::getPwAff(const SCEV *Expr, BasicBlock *BB,
RecordedAssumptionsTy *RecordedAssumptions) {
RecordedAssumptionsTy *RecordedAssumptions,
bool IsInsideDomain) {
this->BB = BB;
this->IsInsideDomain = IsInsideDomain;
this->RecordedAssumptions = RecordedAssumptions;
if (BB) {
@ -309,7 +311,7 @@ PWACtx SCEVAffinator::visitTruncateExpr(const SCEVTruncateExpr *Expr) {
}
recordAssumption(RecordedAssumptions, UNSIGNED, isl::manage(OutOfBoundsDom),
DebugLoc(), AS_RESTRICTION, BB);
DebugLoc(), AS_RESTRICTION, IsInsideDomain ? BB : nullptr);
return OpPWAC;
}

View File

@ -210,8 +210,6 @@ void polly::recordAssumption(polly::RecordedAssumptionsTy *RecordedAssumptions,
polly::AssumptionKind Kind, isl::set Set,
DebugLoc Loc, polly::AssumptionSign Sign,
BasicBlock *BB, bool RTC) {
assert((Set.is_params() || BB) &&
"Assumptions without a basic block must be parameter sets");
if (RecordedAssumptions)
RecordedAssumptions->push_back({Kind, Sign, Set, Loc, BB, RTC});
}

View File

@ -0,0 +1,71 @@
; RUN: opt %loadNPMPolly '-passes=polly-custom<scops>' -polly-print-scops -disable-output < %s 2>&1 | FileCheck %s
;
; https://github.com/llvm/llvm-project/issues/190128
;
; void func(int arg, unsigned char arr_4[11]) {
; int shl1 = 2147483592LL << arg; // 2147483592
; int trunc1 = (short)(shl1); // -56
; int start = trunc1 + 56; // = 0
; for (short i_0 = start; i_0 < 1; i_0 += 1) {
; arr_4[i_0] = i_0;
; for (int i_2 = 1; i_2 < 3; i_2 += 1)
; ; // somehow this matters -- different CFG
; }
; }
;
; The constraint -58 <= shl < 32768 (ignorable trunc range) must be checked in an RTC (here: InvalidConstant).
; Alternatively, %conv6 could be used as a parameter, instead of %shl.
; CHECK: Context:
; CHECK-NEXT: [shl] -> { : -9223372036854775808 <= shl <= 9223372036854775800 }
; CHECK: Assumed Context:
; CHECK-NEXT: [shl] -> { : }
; CHECK: Invalid Context:
; CHECK-NEXT: [shl] -> { : shl <= -57 or shl >= 32768 }
; CHECK: Defined Behavior Context:
; CHECK-NEXT: [shl] -> { : -56 <= shl <= 32710 }
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
; Function Attrs: nofree noinline norecurse nosync nounwind memory(argmem: write) uwtable
define dso_local void @func(i32 noundef %arg, ptr noundef writeonly captures(none) %arr_4) local_unnamed_addr #0 {
entry:
%sh_prom = zext nneg i32 %arg to i64
%shl = shl i64 2147483592, %sh_prom
%conv1 = trunc i64 %shl to i16
%add = add i16 %conv1, 56
%cmp22 = icmp slt i16 %add, 1
br i1 %cmp22, label %for.body, label %for.cond.cleanup
for.cond.cleanup: ; preds = %for.body, %entry
ret void
for.body: ; preds = %for.body, %entry
%i_0.023 = phi i16 [ %add15, %for.body ], [ %add, %entry ]
%conv6 = trunc i16 %i_0.023 to i8
%idxprom = sext i16 %i_0.023 to i64
%arrayidx = getelementptr inbounds i8, ptr %arr_4, i64 %idxprom
store i8 %conv6, ptr %arrayidx, align 1, !tbaa !8
%add15 = add nsw i16 %i_0.023, 1
%cmp = icmp ugt i16 %i_0.023, 32766
br i1 %cmp, label %for.body, label %for.cond.cleanup, !llvm.loop !9
}
attributes #0 = { nofree noinline norecurse nosync nounwind memory(argmem: write) uwtable "min-legal-vector-width"="0" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="x86-64" "target-features"="+cmov,+cx8,+fxsr,+mmx,+sse,+sse2,+x87" "tune-cpu"="generic" }
!llvm.module.flags = !{!0, !1, !2}
!llvm.ident = !{!3}
!llvm.errno.tbaa = !{!4}
!0 = !{i32 8, !"PIC Level", i32 2}
!1 = !{i32 7, !"PIE Level", i32 2}
!2 = !{i32 7, !"uwtable", i32 2}
!3 = !{!"clang version 23.0.0git (/home/meinersbur/src/llvm/polly/_src/clang a2d3783b451c0c19a5eb09b1ab9a1c66d81ab6ca)"}
!4 = !{!5, !5, i64 0}
!5 = !{!"int", !6, i64 0}
!6 = !{!"omnipotent char", !7, i64 0}
!7 = !{!"Simple C/C++ TBAA"}
!8 = !{!6, !6, i64 0}
!9 = distinct !{!9, !10, !11}
!10 = !{!"llvm.loop.mustprogress"}
!11 = !{!"llvm.loop.unroll.disable"}

View File

@ -9,10 +9,14 @@
; }
;
; FIXME: The truncated value should be a parameter.
; CHECK: {{^ *}}Context:
; CHECK-NEXT: [N, tmp, M] -> { : -2147483648 <= N <= 2147483647 and -2147483648 <= tmp <= 2147483647 and -2147483648 <= M <= 2147483647 }
; CHECK: Assumed Context:
; CHECK-NEXT: [N, tmp, M] -> { : }
; CHECK-NEXT: Invalid Context:
; CHECK-NEXT: [N, tmp, M] -> { : N < 0 or (N > 0 and tmp >= 128) or (N > 0 and tmp < 0) or (N > 0 and M < 0) }
; CHECK: Invalid Context:
; CHECK-NEXT: [N, tmp, M] -> { : tmp <= -129 or tmp >= 128 or N < 0 or (N > 0 and tmp < 0) or (N > 0 and M < 0) }
; CHECK: Defined Behavior Context:
; CHECK-NEXT: [N, tmp, M] -> { : -128 <= tmp <= 127 and -2147483648 <= M <= 2147483647 and ((0 < N <= 2147483647 and tmp >= 0 and M >= 0) or N = 0) }
;
; CHECK: Domain :=
; CHECK-NEXT: [N, tmp, M] -> { Stmt_if_then[i0] : tmp >= 0 and M > tmp and 0 <= i0 < N };

View File

@ -8,10 +8,14 @@
; }
; }
;
; CHECK: {{^ *}}Context:
; CHECK-NEXT: [N, tmp] -> { : -2147483648 <= N <= 2147483647 and -9223372036854775808 <= tmp <= 9223372036854775807 }
; CHECK: Assumed Context:
; CHECK-NEXT: [N, tmp] -> { : }
; CHECK-NEXT: Invalid Context:
; CHECK-NEXT: [N, tmp] -> { : N > 0 and (tmp < 0 or tmp >= 2147483648) }
; CHECK-NEXT: [N, tmp] -> { : }
; CHECK: Invalid Context:
; CHECK-NEXT: [N, tmp] -> { : tmp <= -2147483649 or tmp >= 2147483648 or (N > 0 and tmp < 0) }
; CHECK: Defined Behavior Context:
; CHECK-NEXT: [N, tmp] -> { : -2147483648 <= tmp <= 2147483647 and ((0 < N <= 2147483647 and tmp >= 0) or N = 0) }
;
; CHECK: Domain :=
; CHECK-NEXT: [N, tmp] -> { Stmt_if_then[i0] : tmp >= 0 and tmp < i0 < N };