diff --git a/debian/changelog b/debian/changelog index e23cf936..4ddcb4c0 100644 --- a/debian/changelog +++ b/debian/changelog @@ -3,6 +3,8 @@ llvm-toolchain-10 (1:10.0.0-2) UNRELEASED; urgency=medium [ Dimitri John Ledkov ] * s390x: set default abi to z196 for debian, and z13 for ubuntu. LP: #1864226 + [ Matthias Klose ] + * Apply D76596.diff, proposed backport from the trunk. LP: #1867173. -- Gianfranco Costamagna Fri, 27 Mar 2020 05:16:28 +0100 diff --git a/debian/patches/D76596.diff b/debian/patches/D76596.diff new file mode 100644 index 00000000..0f25439e --- /dev/null +++ b/debian/patches/D76596.diff @@ -0,0 +1,1303 @@ +diff --git a/llvm/include/llvm/Analysis/ValueLattice.h b/llvm/include/llvm/Analysis/ValueLattice.h +--- a/llvm/include/llvm/Analysis/ValueLattice.h ++++ b/llvm/include/llvm/Analysis/ValueLattice.h +@@ -29,7 +29,12 @@ + /// producing instruction is dead. Caution: We use this as the starting + /// state in our local meet rules. In this usage, it's taken to mean + /// "nothing known yet". +- undefined, ++ unknown, ++ ++ /// This Value is an UndefValue constant or produces undef. Undefined values ++ /// can be merged with constants (or single element constant ranges), ++ /// assuming all uses of the result will be replaced. ++ undef, + + /// This Value has a specific constant value. (For constant integers, + /// constantrange is used instead. Integer typed constantexprs can appear +@@ -60,14 +65,15 @@ + + public: + // Const and Range are initialized on-demand. +- ValueLatticeElement() : Tag(undefined) {} ++ ValueLatticeElement() : Tag(unknown) {} + + /// Custom destructor to ensure Range is properly destroyed, when the object + /// is deallocated. + ~ValueLatticeElement() { + switch (Tag) { + case overdefined: +- case undefined: ++ case unknown: ++ case undef: + case constant: + case notconstant: + break; +@@ -79,7 +85,7 @@ + + /// Custom copy constructor, to ensure Range gets initialized when + /// copying a constant range lattice element. +- ValueLatticeElement(const ValueLatticeElement &Other) : Tag(undefined) { ++ ValueLatticeElement(const ValueLatticeElement &Other) : Tag(unknown) { + *this = Other; + } + +@@ -109,7 +115,8 @@ + ConstVal = Other.ConstVal; + break; + case overdefined: +- case undefined: ++ case unknown: ++ case undef: + break; + } + Tag = Other.Tag; +@@ -118,14 +125,16 @@ + + static ValueLatticeElement get(Constant *C) { + ValueLatticeElement Res; +- if (!isa(C)) ++ if (isa(C)) ++ Res.markUndef(); ++ else + Res.markConstant(C); + return Res; + } + static ValueLatticeElement getNot(Constant *C) { + ValueLatticeElement Res; +- if (!isa(C)) +- Res.markNotConstant(C); ++ assert(!isa(C) && "!= undef is not supported"); ++ Res.markNotConstant(C); + return Res; + } + static ValueLatticeElement getRange(ConstantRange CR) { +@@ -139,7 +148,9 @@ + return Res; + } + +- bool isUndefined() const { return Tag == undefined; } ++ bool isUndef() const { return Tag == undef; } ++ bool isUnknown() const { return Tag == unknown; } ++ bool isUnknownOrUndef() const { return Tag == unknown || Tag == undef; } + bool isConstant() const { return Tag == constant; } + bool isNotConstant() const { return Tag == notconstant; } + bool isConstantRange() const { return Tag == constantrange; } +@@ -170,89 +181,123 @@ + return None; + } + +-private: +- void markOverdefined() { ++ bool markOverdefined() { + if (isOverdefined()) +- return; ++ return false; + if (isConstant() || isNotConstant()) + ConstVal = nullptr; + if (isConstantRange()) + Range.~ConstantRange(); + Tag = overdefined; ++ return true; + } + +- void markConstant(Constant *V) { +- assert(V && "Marking constant with NULL"); +- if (ConstantInt *CI = dyn_cast(V)) { +- markConstantRange(ConstantRange(CI->getValue())); +- return; +- } ++ bool markUndef() { ++ if (isUndef()) ++ return false; ++ ++ assert(isUnknown()); ++ Tag = undef; ++ return true; ++ } ++ ++ bool markConstant(Constant *V) { + if (isa(V)) +- return; ++ return markUndef(); + +- assert((!isConstant() || getConstant() == V) && +- "Marking constant with different value"); +- assert(isUndefined()); ++ if (isConstant()) { ++ assert(getConstant() == V && "Marking constant with different value"); ++ return false; ++ } ++ ++ if (ConstantInt *CI = dyn_cast(V)) ++ return markConstantRange(ConstantRange(CI->getValue())); ++ ++ assert(isUnknown() || isUndef()); + Tag = constant; + ConstVal = V; ++ return true; + } + +- void markNotConstant(Constant *V) { ++ bool markNotConstant(Constant *V) { + assert(V && "Marking constant with NULL"); +- if (ConstantInt *CI = dyn_cast(V)) { +- markConstantRange(ConstantRange(CI->getValue() + 1, CI->getValue())); +- return; +- } ++ if (ConstantInt *CI = dyn_cast(V)) ++ return markConstantRange( ++ ConstantRange(CI->getValue() + 1, CI->getValue())); ++ + if (isa(V)) +- return; ++ return false; + +- assert((!isConstant() || getConstant() != V) && +- "Marking constant !constant with same value"); +- assert((!isNotConstant() || getNotConstant() == V) && +- "Marking !constant with different value"); +- assert(isUndefined() || isConstant()); ++ if (isNotConstant()) { ++ assert(getNotConstant() == V && "Marking !constant with different value"); ++ return false; ++ } ++ ++ assert(isUnknown()); + Tag = notconstant; + ConstVal = V; ++ return true; + } + +- void markConstantRange(ConstantRange NewR) { ++ /// Mark the object as constant range with \p NewR. If the object is already a ++ /// constant range, nothing changes if the existing range is equal to \p ++ /// NewR. Otherwise \p NewR must be a superset of the existing range or the ++ /// object must be undef. ++ bool markConstantRange(ConstantRange NewR) { + if (isConstantRange()) { ++ if (getConstantRange() == NewR) ++ return false; ++ + if (NewR.isEmptySet()) +- markOverdefined(); +- else { +- Range = std::move(NewR); +- } +- return; ++ return markOverdefined(); ++ ++ assert(NewR.contains(getConstantRange()) && ++ "Existing range must be a subset of NewR"); ++ Range = std::move(NewR); ++ return true; + } + +- assert(isUndefined()); ++ assert(isUnknown() || isUndef()); + if (NewR.isEmptySet()) +- markOverdefined(); +- else { +- Tag = constantrange; +- new (&Range) ConstantRange(std::move(NewR)); +- } ++ return markOverdefined(); ++ ++ Tag = constantrange; ++ new (&Range) ConstantRange(std::move(NewR)); ++ return true; + } + +-public: + /// Updates this object to approximate both this object and RHS. Returns + /// true if this object has been changed. + bool mergeIn(const ValueLatticeElement &RHS, const DataLayout &DL) { +- if (RHS.isUndefined() || isOverdefined()) ++ if (RHS.isUnknown() || isOverdefined()) + return false; + if (RHS.isOverdefined()) { + markOverdefined(); + return true; + } + +- if (isUndefined()) { ++ if (isUndef()) { ++ assert(!RHS.isUnknown()); ++ if (RHS.isUndef()) ++ return false; ++ if (RHS.isConstant()) ++ return markConstant(RHS.getConstant()); ++ if (RHS.isConstantRange() && RHS.getConstantRange().isSingleElement()) ++ return markConstantRange(RHS.getConstantRange()); ++ return markOverdefined(); ++ } ++ ++ if (isUnknown()) { ++ assert(!RHS.isUnknown() && "Unknow RHS should be handled earlier"); + *this = RHS; +- return !RHS.isUndefined(); ++ return true; + } + + if (isConstant()) { + if (RHS.isConstant() && getConstant() == RHS.getConstant()) + return false; ++ if (RHS.isUndef()) ++ return false; + markOverdefined(); + return true; + } +@@ -265,6 +310,9 @@ + } + + assert(isConstantRange() && "New ValueLattice type?"); ++ if (RHS.isUndef() && getConstantRange().isSingleElement()) ++ return false; ++ + if (!RHS.isConstantRange()) { + // We can get here if we've encountered a constantexpr of integer type + // and merge it with a constantrange. +@@ -273,18 +321,11 @@ + } + ConstantRange NewR = getConstantRange().unionWith(RHS.getConstantRange()); + if (NewR.isFullSet()) +- markOverdefined(); ++ return markOverdefined(); + else if (NewR == getConstantRange()) + return false; + else +- markConstantRange(std::move(NewR)); +- return true; +- } +- +- ConstantInt *getConstantInt() const { +- assert(isConstant() && isa(getConstant()) && +- "No integer constant"); +- return cast(getConstant()); ++ return markConstantRange(std::move(NewR)); + } + + /// Compares this symbolic value with Other using Pred and returns either +@@ -292,7 +333,7 @@ + /// evaluated. + Constant *getCompare(CmpInst::Predicate Pred, Type *Ty, + const ValueLatticeElement &Other) const { +- if (isUndefined() || Other.isUndefined()) ++ if (isUnknownOrUndef() || Other.isUnknownOrUndef()) + return UndefValue::get(Ty); + + if (isConstant() && Other.isConstant()) +diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp +--- a/llvm/lib/Analysis/LazyValueInfo.cpp ++++ b/llvm/lib/Analysis/LazyValueInfo.cpp +@@ -96,9 +96,9 @@ + const ValueLatticeElement &B) { + // Undefined is the strongest state. It means the value is known to be along + // an unreachable path. +- if (A.isUndefined()) ++ if (A.isUnknown()) + return A; +- if (B.isUndefined()) ++ if (B.isUnknown()) + return B; + + // If we gave up for one, but got a useable fact from the other, use it. +@@ -1203,7 +1203,7 @@ + // false SETNE. + if (isTrueDest == (Predicate == ICmpInst::ICMP_EQ)) + return ValueLatticeElement::get(cast(RHS)); +- else ++ else if (!isa(RHS)) + return ValueLatticeElement::getNot(cast(RHS)); + } + } +@@ -1722,7 +1722,7 @@ + const DataLayout &DL = BB->getModule()->getDataLayout(); + ValueLatticeElement Result = + getImpl(PImpl, AC, &DL, DT).getValueInBlock(V, BB, CxtI); +- if (Result.isUndefined()) ++ if (Result.isUnknown()) + return ConstantRange::getEmpty(Width); + if (Result.isConstantRange()) + return Result.getConstantRange(); +@@ -1761,7 +1761,7 @@ + ValueLatticeElement Result = + getImpl(PImpl, AC, &DL, DT).getValueOnEdge(V, FromBB, ToBB, CxtI); + +- if (Result.isUndefined()) ++ if (Result.isUnknown()) + return ConstantRange::getEmpty(Width); + if (Result.isConstantRange()) + return Result.getConstantRange(); +@@ -1991,7 +1991,7 @@ + for (auto &Arg : F->args()) { + ValueLatticeElement Result = LVIImpl->getValueInBlock( + const_cast(&Arg), const_cast(BB)); +- if (Result.isUndefined()) ++ if (Result.isUnknown()) + continue; + OS << "; LatticeVal for: '" << Arg << "' is: " << Result << "\n"; + } +diff --git a/llvm/lib/Analysis/ValueLattice.cpp b/llvm/lib/Analysis/ValueLattice.cpp +--- a/llvm/lib/Analysis/ValueLattice.cpp ++++ b/llvm/lib/Analysis/ValueLattice.cpp +@@ -10,8 +10,10 @@ + + namespace llvm { + raw_ostream &operator<<(raw_ostream &OS, const ValueLatticeElement &Val) { +- if (Val.isUndefined()) +- return OS << "undefined"; ++ if (Val.isUnknown()) ++ return OS << "unknown"; ++ if (Val.isUndef()) ++ return OS << "undef"; + if (Val.isOverdefined()) + return OS << "overdefined"; + +diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/merge-range-and-undef.ll b/llvm/test/Transforms/CorrelatedValuePropagation/merge-range-and-undef.ll +new file mode 100644 +--- /dev/null ++++ b/llvm/test/Transforms/CorrelatedValuePropagation/merge-range-and-undef.ll +@@ -0,0 +1,299 @@ ++; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ++; RUN: opt -S -correlated-propagation %s | FileCheck %s ++ ++; Test case for PR44949. ++ ++; We can remove `%res = and i64 %p, 255`, because %r = 0 and we can eliminate ++; %p as well. ++define i64 @constant_and_undef(i1 %c1, i64 %a) { ++; CHECK-LABEL: @constant_and_undef( ++; CHECK-NEXT: entry: ++; CHECK-NEXT: br i1 [[C1:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ++; CHECK: bb1: ++; CHECK-NEXT: br label [[BB3:%.*]] ++; CHECK: bb2: ++; CHECK-NEXT: [[R:%.*]] = and i64 [[A:%.*]], 0 ++; CHECK-NEXT: br label [[BB3]] ++; CHECK: bb3: ++; CHECK-NEXT: ret i64 0 ++; ++entry: ++ br i1 %c1, label %bb1, label %bb2 ++ ++bb1: ++ br label %bb3 ++ ++bb2: ++ %r = and i64 %a, 0 ++ br label %bb3 ++ ++bb3: ++ %p = phi i64 [ undef, %bb1 ], [ %r, %bb2 ] ++ %res = and i64 %p, 255 ++ ret i64 %res ++} ++ ++; Check that we go to overdefined when merging a constant range with undef. We ++; cannot remove '%res = and i64 %p, 255'. ++; FIXME: should not remove '%res = and i64 %p, 255' ++define i64 @constant_range_and_undef(i1 %cond, i64 %a) { ++; CHECK-LABEL: @constant_range_and_undef( ++; CHECK-NEXT: entry: ++; CHECK-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ++; CHECK: bb1: ++; CHECK-NEXT: br label [[BB3:%.*]] ++; CHECK: bb2: ++; CHECK-NEXT: [[R:%.*]] = and i64 [[A:%.*]], 255 ++; CHECK-NEXT: br label [[BB3]] ++; CHECK: bb3: ++; CHECK-NEXT: [[P:%.*]] = phi i64 [ undef, [[BB1]] ], [ [[R]], [[BB2]] ] ++; CHECK-NEXT: [[RES:%.*]] = and i64 [[P]], 255 ++; CHECK-NEXT: ret i64 [[RES]] ++; ++entry: ++ br i1 %cond, label %bb1, label %bb2 ++ ++bb1: ++ br label %bb3 ++ ++bb2: ++ %r = and i64 %a, 255 ++ br label %bb3 ++ ++bb3: ++ %p = phi i64 [ undef, %bb1 ], [ %r, %bb2 ] ++ %res = and i64 %p, 255 ++ ret i64 %res ++} ++ ++define i64 @constant_range_and_undef2(i1 %c1, i1 %c2, i64 %a) { ++; CHECK-LABEL: @constant_range_and_undef2( ++; CHECK-NEXT: entry: ++; CHECK-NEXT: br i1 [[C1:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ++; CHECK: bb1: ++; CHECK-NEXT: [[V1:%.*]] = add i64 undef, undef ++; CHECK-NEXT: br label [[BB3:%.*]] ++; CHECK: bb2: ++; CHECK-NEXT: [[V2:%.*]] = and i64 [[A:%.*]], 255 ++; CHECK-NEXT: br label [[BB3]] ++; CHECK: bb3: ++; CHECK-NEXT: [[P:%.*]] = phi i64 [ [[V1]], [[BB1]] ], [ [[V2]], [[BB2]] ] ++; CHECK-NEXT: br i1 [[C2:%.*]], label [[BB4:%.*]], label [[BB5:%.*]] ++; CHECK: bb4: ++; CHECK-NEXT: br label [[BB6:%.*]] ++; CHECK: bb5: ++; CHECK-NEXT: [[V3:%.*]] = and i64 [[A]], 255 ++; CHECK-NEXT: br label [[BB6]] ++; CHECK: bb6: ++; CHECK-NEXT: [[P2:%.*]] = phi i64 [ [[P]], [[BB4]] ], [ [[V3]], [[BB5]] ] ++; CHECK-NEXT: [[RES:%.*]] = and i64 [[P2]], 255 ++; CHECK-NEXT: ret i64 [[RES]] ++; ++entry: ++ br i1 %c1, label %bb1, label %bb2 ++ ++bb1: ++ %v1 = add i64 undef, undef ++ br label %bb3 ++ ++bb2: ++ %v2 = and i64 %a, 255 ++ br label %bb3 ++ ++bb3: ++ %p = phi i64 [ %v1, %bb1 ], [ %v2, %bb2 ] ++ br i1 %c2, label %bb4, label %bb5 ++ ++bb4: ++ br label %bb6 ++ ++bb5: ++ %v3 = and i64 %a, 255 ++ br label %bb6 ++ ++bb6: ++ %p2 = phi i64 [ %p, %bb4 ], [ %v3, %bb5 ] ++ %res = and i64 %p2, 255 ++ ret i64 %res ++} ++ ++define i1 @constant_range_and_undef_3(i1 %cond, i64 %a) { ++; CHECK-LABEL: @constant_range_and_undef_3( ++; CHECK-NEXT: entry: ++; CHECK-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ++; CHECK: bb1: ++; CHECK-NEXT: br label [[BB3:%.*]] ++; CHECK: bb2: ++; CHECK-NEXT: [[R:%.*]] = and i64 [[A:%.*]], 255 ++; CHECK-NEXT: br label [[BB3]] ++; CHECK: bb3: ++; CHECK-NEXT: [[P:%.*]] = phi i64 [ undef, [[BB1]] ], [ [[R]], [[BB2]] ] ++; CHECK-NEXT: [[C:%.*]] = icmp ult i64 [[P]], 256 ++; CHECK-NEXT: ret i1 [[C]] ++; ++entry: ++ br i1 %cond, label %bb1, label %bb2 ++ ++bb1: ++ br label %bb3 ++ ++bb2: ++ %r = and i64 %a, 255 ++ br label %bb3 ++ ++bb3: ++ %p = phi i64 [ undef, %bb1 ], [ %r, %bb2 ] ++ %c = icmp ult i64 %p, 256 ++ ret i1 %c ++} ++ ++; Same as @constant_range_and_undef, but with 3 incoming ++; values: undef, a constant and a constant range. ++define i64 @constant_range_and_undef_3_incoming_v1(i1 %c1, i1 %c2, i64 %a) { ++; CHECK-LABEL: @constant_range_and_undef_3_incoming_v1( ++; CHECK-NEXT: entry: ++; CHECK-NEXT: br i1 [[C1:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ++; CHECK: bb1: ++; CHECK-NEXT: [[R:%.*]] = and i64 [[A:%.*]], 255 ++; CHECK-NEXT: br label [[BB4:%.*]] ++; CHECK: bb2: ++; CHECK-NEXT: br i1 [[C2:%.*]], label [[BB3:%.*]], label [[BB4]] ++; CHECK: bb3: ++; CHECK-NEXT: br label [[BB4]] ++; CHECK: bb4: ++; CHECK-NEXT: [[P:%.*]] = phi i64 [ [[R]], [[BB1]] ], [ 10, [[BB2]] ], [ undef, [[BB3]] ] ++; CHECK-NEXT: [[RES:%.*]] = and i64 [[P]], 255 ++; CHECK-NEXT: ret i64 [[RES]] ++; ++entry: ++ br i1 %c1, label %bb1, label %bb2 ++ ++bb1: ++ %r = and i64 %a, 255 ++ br label %bb4 ++ ++bb2: ++ br i1 %c2, label %bb3, label %bb4 ++ ++bb3: ++ br label %bb4 ++ ++bb4: ++ %p = phi i64 [ %r, %bb1 ], [ 10, %bb2], [ undef, %bb3 ] ++ %res = and i64 %p, 255 ++ ret i64 %res ++} ++ ++; Same as @constant_range_and_undef_3_incoming_v1, but with different order of ++; incoming values. ++define i64 @constant_range_and_undef_3_incoming_v2(i1 %c1, i1 %c2, i64 %a) { ++; CHECK-LABEL: @constant_range_and_undef_3_incoming_v2( ++; CHECK-NEXT: entry: ++; CHECK-NEXT: br i1 [[C1:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ++; CHECK: bb1: ++; CHECK-NEXT: br label [[BB4:%.*]] ++; CHECK: bb2: ++; CHECK-NEXT: br i1 [[C2:%.*]], label [[BB3:%.*]], label [[BB4]] ++; CHECK: bb3: ++; CHECK-NEXT: [[R:%.*]] = and i64 [[A:%.*]], 255 ++; CHECK-NEXT: br label [[BB4]] ++; CHECK: bb4: ++; CHECK-NEXT: [[P:%.*]] = phi i64 [ undef, [[BB1]] ], [ 10, [[BB2]] ], [ [[R]], [[BB3]] ] ++; CHECK-NEXT: ret i64 [[P]] ++; ++entry: ++ br i1 %c1, label %bb1, label %bb2 ++ ++bb1: ++ br label %bb4 ++ ++bb2: ++ br i1 %c2, label %bb3, label %bb4 ++ ++bb3: ++ %r = and i64 %a, 255 ++ br label %bb4 ++ ++bb4: ++ %p = phi i64 [ undef, %bb1 ], [ 10, %bb2], [ %r, %bb3 ] ++ %res = and i64 %p, 255 ++ ret i64 %res ++} ++ ++; Same as @constant_range_and_undef_3_incoming_v1, but with different order of ++; incoming values. ++define i64 @constant_range_and_undef_3_incoming_v3(i1 %c1, i1 %c2, i64 %a) { ++; CHECK-LABEL: @constant_range_and_undef_3_incoming_v3( ++; CHECK-NEXT: entry: ++; CHECK-NEXT: br i1 [[C1:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ++; CHECK: bb1: ++; CHECK-NEXT: [[R:%.*]] = and i64 [[A:%.*]], 255 ++; CHECK-NEXT: br label [[BB4:%.*]] ++; CHECK: bb2: ++; CHECK-NEXT: br i1 [[C2:%.*]], label [[BB3:%.*]], label [[BB4]] ++; CHECK: bb3: ++; CHECK-NEXT: br label [[BB4]] ++; CHECK: bb4: ++; CHECK-NEXT: [[P:%.*]] = phi i64 [ [[R]], [[BB1]] ], [ undef, [[BB2]] ], [ 10, [[BB3]] ] ++; CHECK-NEXT: [[RES:%.*]] = and i64 [[P]], 255 ++; CHECK-NEXT: ret i64 [[RES]] ++; ++entry: ++ br i1 %c1, label %bb1, label %bb2 ++ ++bb1: ++ %r = and i64 %a, 255 ++ br label %bb4 ++ ++bb2: ++ br i1 %c2, label %bb3, label %bb4 ++ ++bb3: ++ br label %bb4 ++ ++bb4: ++ %p = phi i64 [ %r, %bb1 ], [ undef, %bb2], [ 10, %bb3 ] ++ %res = and i64 %p, 255 ++ ret i64 %res ++} ++ ++ ++define i64 @constant_range_and_phi_constant_undef(i1 %c1, i1 %c2, i64 %a) { ++; CHECK-LABEL: @constant_range_and_phi_constant_undef( ++; CHECK-NEXT: entry: ++; CHECK-NEXT: br i1 [[C1:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ++; CHECK: bb1: ++; CHECK-NEXT: [[R:%.*]] = and i64 [[A:%.*]], 255 ++; CHECK-NEXT: br label [[BB5:%.*]] ++; CHECK: bb2: ++; CHECK-NEXT: br i1 [[C2:%.*]], label [[BB3:%.*]], label [[BB4:%.*]] ++; CHECK: bb3: ++; CHECK-NEXT: br label [[BB4]] ++; CHECK: bb4: ++; CHECK-NEXT: br label [[BB5]] ++; CHECK: bb5: ++; CHECK-NEXT: [[P:%.*]] = phi i64 [ [[R]], [[BB1]] ], [ 10, [[BB4]] ] ++; CHECK-NEXT: ret i64 [[P]] ++; ++entry: ++ br i1 %c1, label %bb1, label %bb2 ++ ++bb1: ++ %r = and i64 %a, 255 ++ br label %bb5 ++ ++bb2: ++ br i1 %c2, label %bb3, label %bb4 ++ ++bb3: ++ br label %bb4 ++ ++bb4: ++ %p.1 = phi i64 [ 10, %bb2 ], [ undef, %bb3] ++ br label %bb5 ++ ++bb5: ++ %p = phi i64 [ %r, %bb1 ], [ %p.1, %bb4] ++ %res = and i64 %p, 255 ++ ret i64 %res ++} +diff --git a/llvm/test/Transforms/JumpThreading/ne-undef.ll b/llvm/test/Transforms/JumpThreading/ne-undef.ll +new file mode 100644 +--- /dev/null ++++ b/llvm/test/Transforms/JumpThreading/ne-undef.ll +@@ -0,0 +1,61 @@ ++; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ++; RUN: opt -jump-threading -S %s | FileCheck %s ++ ++declare i1 @cond() ++ ++define hidden void @hoge(i1 %c1, i32 %x) { ++; CHECK-LABEL: @hoge( ++; CHECK-NEXT: bb: ++; CHECK-NEXT: br label [[BB13:%.*]] ++; CHECK: bb4: ++; CHECK-NEXT: [[TMP3:%.*]] = icmp ne i32 [[TMP7:%.*]], undef ++; CHECK-NEXT: br i1 [[TMP3]], label [[BB5:%.*]], label [[BB13]] ++; CHECK: bb5: ++; CHECK-NEXT: br label [[BB6:%.*]] ++; CHECK: bb6: ++; CHECK-NEXT: [[TMP7]] = phi i32 [ [[TMP7]], [[BB5]] ], [ [[X:%.*]], [[BB8:%.*]] ] ++; CHECK-NEXT: [[C:%.*]] = call i1 @cond() ++; CHECK-NEXT: br i1 [[C]], label [[BB4:%.*]], label [[BB8]] ++; CHECK: bb8: ++; CHECK-NEXT: br label [[BB6]] ++; CHECK: bb13: ++; CHECK-NEXT: ret void ++; ++bb: ++ br i1 false, label %bb1, label %bb13 ++ ++bb1: ; preds = %bb ++ br label %bb2 ++ ++bb2: ; preds = %bb12, %bb1 ++ %tmp = phi i32 [ 10, %bb1 ], [ %tmp7, %bb12 ] ++ %tmp3 = icmp ne i32 %tmp, undef ++ br label %bb4 ++ ++bb4: ; preds = %bb2 ++ br i1 %tmp3, label %bb5, label %bb13 ++ ++bb5: ; preds = %bb4 ++ br label %bb6 ++ ++bb6: ; preds = %bb8, %bb5 ++ %tmp7 = phi i32 [ %tmp, %bb5 ], [ %x, %bb8 ] ++ %c = call i1 @cond() ++ br i1 %c, label %bb9, label %bb8 ++ ++bb8: ; preds = %bb6 ++ br label %bb6 ++ ++bb9: ; preds = %bb6 ++ br label %bb10 ++ ++bb10: ; preds = %bb9 ++ br label %bb12 ++ ++bb12: ; preds = %bb10 ++ br label %bb2 ++ ++bb13: ; preds = %bb4 ++ ret void ++ ++} +diff --git a/llvm/test/Transforms/SCCP/float-phis.ll b/llvm/test/Transforms/SCCP/float-phis.ll +new file mode 100644 +--- /dev/null ++++ b/llvm/test/Transforms/SCCP/float-phis.ll +@@ -0,0 +1,26 @@ ++; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ++; RUN: opt < %s -sccp -S | FileCheck %s ++ ++declare void @use(i1) ++ ++define void @test(i1 %c) { ++; CHECK-LABEL: @test( ++; CHECK-NEXT: br label [[DO_BODY:%.*]] ++; CHECK: do.body: ++; CHECK-NEXT: br i1 [[C:%.*]], label [[DO_BODY]], label [[FOR_COND41:%.*]] ++; CHECK: for.cond41: ++; CHECK-NEXT: call void @use(i1 true) ++; CHECK-NEXT: br label [[FOR_COND41]] ++; ++ br label %do.body ++ ++do.body: ; preds = %do.body, %entry ++ br i1 %c, label %do.body, label %for.cond41 ++ ++for.cond41: ; preds = %for.cond41, %do.body ++ %mid.0 = phi float [ 0.000000e+00, %for.cond41 ], [ undef, %do.body ] ++ %fc = fcmp oeq float %mid.0, 0.000000e+00 ++ call void @use(i1 %fc) ++ ++ br label %for.cond41 ++} +diff --git a/llvm/test/Transforms/SCCP/int-phis.ll b/llvm/test/Transforms/SCCP/int-phis.ll +new file mode 100644 +--- /dev/null ++++ b/llvm/test/Transforms/SCCP/int-phis.ll +@@ -0,0 +1,61 @@ ++; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ++; RUN: opt < %s -sccp -S | FileCheck %s ++ ++declare void @use(i1) ++ ++define void @read_dmatrix() #0 { ++; CHECK-LABEL: @read_dmatrix( ++; CHECK-NEXT: entry: ++; CHECK-NEXT: [[HEIGHT:%.*]] = alloca i32, align 4 ++; CHECK-NEXT: br label [[FOR_COND:%.*]] ++; CHECK: for.cond: ++; CHECK-NEXT: [[TMP0:%.*]] = load i32, i32* [[HEIGHT]], align 4 ++; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 0, [[TMP0]] ++; CHECK-NEXT: br i1 [[CMP]], label [[FOR_COND6:%.*]], label [[FOR_END16:%.*]] ++; CHECK: for.cond6: ++; CHECK-NEXT: br label [[FOR_COND]] ++; CHECK: for.end16: ++; CHECK-NEXT: ret void ++; ++entry: ++ %height = alloca i32, align 4 ++ br label %for.cond ++ ++for.cond: ; preds = %for.cond6, %entry ++ %j.0 = phi i32 [ undef, %entry ], [ 0, %for.cond6 ] ++ %0 = load i32, i32* %height, align 4 ++ %cmp = icmp slt i32 0, %0 ++ br i1 %cmp, label %for.cond6, label %for.end16 ++ ++for.cond6: ; preds = %for.cond ++ br label %for.cond ++ ++for.end16: ; preds = %for.cond ++ %sub21 = sub nsw i32 %j.0, 1 ++ ret void ++} ++ ++declare i1 @cond() ++ ++define void @emptyTT() #0 { ++; CHECK-LABEL: @emptyTT( ++; CHECK-NEXT: entry: ++; CHECK-NEXT: br label [[FOR_COND:%.*]] ++; CHECK: for.cond: ++; CHECK-NEXT: [[C:%.*]] = call i1 @cond() ++; CHECK-NEXT: br i1 [[C]], label [[FOR_COND]], label [[EXIT:%.*]] ++; CHECK: exit: ++; CHECK-NEXT: ret void ++; ++entry: ++ br label %for.cond ++ ++for.cond: ; preds = %for.cond, %entry ++ %.compoundliteral.sroa.0.0 = phi i64 [ undef, %entry ], [ 0, %for.cond ] ++ %bf.clear = and i64 %.compoundliteral.sroa.0.0, -67108864 ++ %c = call i1 @cond() ++ br i1 %c, label %for.cond, label %exit ++ ++exit: ++ ret void ++} +diff --git a/llvm/test/Transforms/SCCP/range-and-ip.ll b/llvm/test/Transforms/SCCP/range-and-ip.ll +new file mode 100644 +--- /dev/null ++++ b/llvm/test/Transforms/SCCP/range-and-ip.ll +@@ -0,0 +1,47 @@ ++; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ++; RUN: opt -S -ipsccp %s | FileCheck %s ++ ++; Make sure IPSCCP does not assume %r < 256 for @f1. Undef is passed at a call ++; site, which won't be eliminated. ++ ++define i1 @constant_and_undef(i64 %a) { ++; CHECK-LABEL: @constant_and_undef( ++; CHECK-NEXT: [[C_1:%.*]] = call i1 @f1(i64 undef) ++; CHECK-NEXT: br label [[BB1:%.*]] ++; CHECK: bb1: ++; CHECK-NEXT: [[C_2:%.*]] = call i1 @f1(i64 10) ++; CHECK-NEXT: br label [[BB2:%.*]] ++; CHECK: bb2: ++; CHECK-NEXT: [[RANGE:%.*]] = and i64 [[A:%.*]], 255 ++; CHECK-NEXT: [[C_3:%.*]] = call i1 @f1(i64 [[RANGE]]) ++; CHECK-NEXT: [[R_1:%.*]] = and i1 [[C_1]], [[C_2]] ++; CHECK-NEXT: [[R_2:%.*]] = and i1 [[R_1]], [[C_3]] ++; CHECK-NEXT: ret i1 [[R_2]] ++; ++ %c.1 = call i1 @f1(i64 undef) ++ br label %bb1 ++ ++bb1: ++ %c.2 = call i1 @f1(i64 10) ++ br label %bb2 ++ ++bb2: ++ %range = and i64 %a, 255 ++ %c.3 = call i1 @f1(i64 %range) ++ %r.1 = and i1 %c.1, %c.2 ++ %r.2 = and i1 %r.1, %c.3 ++ ret i1 %r.2 ++} ++ ++declare void @sideeffect(i1, i64 %a) ++ ++define internal i1 @f1(i64 %r) { ++; CHECK-LABEL: define {{.*}} @f1( ++; CHECK-NEXT: [[C:%.*]] = icmp ult i64 [[R:%.*]], 256 ++; CHECK-NEXT: call void @sideeffect(i1 [[C]], i64 [[R]]) ++; CHECK-NEXT: ret i1 [[C]] ++; ++ %c = icmp ult i64 %r, 256 ++ call void @sideeffect(i1 %c, i64 %r) ++ ret i1 %c ++} +diff --git a/llvm/test/Transforms/SCCP/range-and.ll b/llvm/test/Transforms/SCCP/range-and.ll +new file mode 100644 +--- /dev/null ++++ b/llvm/test/Transforms/SCCP/range-and.ll +@@ -0,0 +1,395 @@ ++; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ++; RUN: opt -S -sccp %s | FileCheck %s ++ ++; Test case for PR44949. ++ ++; We can remove `%res = and i64 %p, 255`, because %r = 0 and we can eliminate ++; %p as well. ++define i64 @constant_and_undef(i1 %c1, i64 %a) { ++; CHECK-LABEL: @constant_and_undef( ++; CHECK-NEXT: entry: ++; CHECK-NEXT: br i1 [[C1:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ++; CHECK: bb1: ++; CHECK-NEXT: br label [[BB3:%.*]] ++; CHECK: bb2: ++; CHECK-NEXT: br label [[BB3]] ++; CHECK: bb3: ++; CHECK-NEXT: ret i64 0 ++; ++entry: ++ br i1 %c1, label %bb1, label %bb2 ++ ++bb1: ++ br label %bb3 ++ ++bb2: ++ %r = and i64 %a, 0 ++ br label %bb3 ++ ++bb3: ++ %p = phi i64 [ undef, %bb1 ], [ %r, %bb2 ] ++ %res = and i64 %p, 255 ++ ret i64 %res ++} ++ ++; Check that we go to overdefined when merging a constant range with undef. We ++; cannot remove '%res = and i64 %p, 255'. ++define i64 @constant_range_and_undef(i1 %cond, i64 %a) { ++; CHECK-LABEL: @constant_range_and_undef( ++; CHECK-NEXT: entry: ++; CHECK-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ++; CHECK: bb1: ++; CHECK-NEXT: br label [[BB3:%.*]] ++; CHECK: bb2: ++; CHECK-NEXT: [[R:%.*]] = and i64 [[A:%.*]], 255 ++; CHECK-NEXT: br label [[BB3]] ++; CHECK: bb3: ++; CHECK-NEXT: [[P:%.*]] = phi i64 [ undef, [[BB1]] ], [ [[R]], [[BB2]] ] ++; CHECK-NEXT: [[RES:%.*]] = and i64 [[P]], 255 ++; CHECK-NEXT: ret i64 [[RES]] ++; ++entry: ++ br i1 %cond, label %bb1, label %bb2 ++ ++bb1: ++ br label %bb3 ++ ++bb2: ++ %r = and i64 %a, 255 ++ br label %bb3 ++ ++bb3: ++ %p = phi i64 [ undef, %bb1 ], [ %r, %bb2 ] ++ %res = and i64 %p, 255 ++ ret i64 %res ++} ++ ++; Same as @constant_range_and_undef, with the undef coming from the other ++; block. ++define i64 @constant_range_and_undef_switched_incoming(i1 %cond, i64 %a) { ++; CHECK-LABEL: @constant_range_and_undef_switched_incoming( ++; CHECK-NEXT: entry: ++; CHECK-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ++; CHECK: bb1: ++; CHECK-NEXT: [[R:%.*]] = and i64 [[A:%.*]], 255 ++; CHECK-NEXT: br label [[BB3:%.*]] ++; CHECK: bb2: ++; CHECK-NEXT: br label [[BB3]] ++; CHECK: bb3: ++; CHECK-NEXT: [[P:%.*]] = phi i64 [ [[R]], [[BB1]] ], [ undef, [[BB2]] ] ++; CHECK-NEXT: [[RES:%.*]] = and i64 [[P]], 255 ++; CHECK-NEXT: ret i64 [[RES]] ++; ++entry: ++ br i1 %cond, label %bb1, label %bb2 ++ ++bb1: ++ %r = and i64 %a, 255 ++ br label %bb3 ++ ++bb2: ++ br label %bb3 ++ ++bb3: ++ %p = phi i64 [ %r, %bb1 ], [ undef, %bb2 ] ++ %res = and i64 %p, 255 ++ ret i64 %res ++} ++ ++define i1 @constant_range_and_255_100(i1 %cond, i64 %a) { ++; CHECK-LABEL: @constant_range_and_255_100( ++; CHECK-NEXT: entry: ++; CHECK-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ++; CHECK: bb1: ++; CHECK-NEXT: [[R_1:%.*]] = and i64 [[A:%.*]], 100 ++; CHECK-NEXT: br label [[BB3:%.*]] ++; CHECK: bb2: ++; CHECK-NEXT: [[R_2:%.*]] = and i64 [[A]], 255 ++; CHECK-NEXT: br label [[BB3]] ++; CHECK: bb3: ++; CHECK-NEXT: [[P:%.*]] = phi i64 [ [[R_1]], [[BB1]] ], [ [[R_2]], [[BB2]] ] ++; CHECK-NEXT: [[P_AND:%.*]] = and i64 [[P]], 512 ++; CHECK-NEXT: [[C:%.*]] = icmp ult i64 [[P_AND]], 256 ++; CHECK-NEXT: ret i1 [[C]] ++; ++entry: ++ br i1 %cond, label %bb1, label %bb2 ++ ++bb1: ++ %r.1 = and i64 %a, 100 ++ br label %bb3 ++ ++bb2: ++ %r.2 = and i64 %a, 255 ++ br label %bb3 ++ ++bb3: ++ %p = phi i64 [ %r.1, %bb1 ], [ %r.2, %bb2 ] ++ %p.and = and i64 %p, 512 ++ %c = icmp ult i64 %p.and, 256 ++ ret i1 %c ++} ++ ++ ++define i64 @constant_range_and_undef2(i1 %c1, i1 %c2, i64 %a) { ++; CHECK-LABEL: @constant_range_and_undef2( ++; CHECK-NEXT: entry: ++; CHECK-NEXT: br i1 [[C1:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ++; CHECK: bb1: ++; CHECK-NEXT: br label [[BB3:%.*]] ++; CHECK: bb2: ++; CHECK-NEXT: [[V2:%.*]] = and i64 [[A:%.*]], 255 ++; CHECK-NEXT: br label [[BB3]] ++; CHECK: bb3: ++; CHECK-NEXT: [[P:%.*]] = phi i64 [ undef, [[BB1]] ], [ [[V2]], [[BB2]] ] ++; CHECK-NEXT: br i1 [[C2:%.*]], label [[BB4:%.*]], label [[BB5:%.*]] ++; CHECK: bb4: ++; CHECK-NEXT: br label [[BB6:%.*]] ++; CHECK: bb5: ++; CHECK-NEXT: [[V3:%.*]] = and i64 [[A]], 255 ++; CHECK-NEXT: br label [[BB6]] ++; CHECK: bb6: ++; CHECK-NEXT: [[P2:%.*]] = phi i64 [ [[P]], [[BB4]] ], [ [[V3]], [[BB5]] ] ++; CHECK-NEXT: [[RES:%.*]] = and i64 [[P2]], 255 ++; CHECK-NEXT: ret i64 [[RES]] ++; ++entry: ++ br i1 %c1, label %bb1, label %bb2 ++ ++bb1: ++ %v1 = add i64 undef, undef ++ br label %bb3 ++ ++bb2: ++ %v2 = and i64 %a, 255 ++ br label %bb3 ++ ++bb3: ++ %p = phi i64 [ %v1, %bb1 ], [ %v2, %bb2 ] ++ br i1 %c2, label %bb4, label %bb5 ++ ++bb4: ++ br label %bb6 ++ ++bb5: ++ %v3 = and i64 %a, 255 ++ br label %bb6 ++ ++bb6: ++ %p2 = phi i64 [ %p, %bb4 ], [ %v3, %bb5 ] ++ %res = and i64 %p2, 255 ++ ret i64 %res ++} ++ ++define i1 @constant_range_and_undef_3(i1 %cond, i64 %a) { ++; CHECK-LABEL: @constant_range_and_undef_3( ++; CHECK-NEXT: entry: ++; CHECK-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ++; CHECK: bb1: ++; CHECK-NEXT: br label [[BB3:%.*]] ++; CHECK: bb2: ++; CHECK-NEXT: [[R:%.*]] = and i64 [[A:%.*]], 255 ++; CHECK-NEXT: br label [[BB3]] ++; CHECK: bb3: ++; CHECK-NEXT: [[P:%.*]] = phi i64 [ undef, [[BB1]] ], [ [[R]], [[BB2]] ] ++; CHECK-NEXT: [[C:%.*]] = icmp ult i64 [[P]], 256 ++; CHECK-NEXT: ret i1 [[C]] ++; ++entry: ++ br i1 %cond, label %bb1, label %bb2 ++ ++bb1: ++ br label %bb3 ++ ++bb2: ++ %r = and i64 %a, 255 ++ br label %bb3 ++ ++bb3: ++ %p = phi i64 [ undef, %bb1 ], [ %r, %bb2 ] ++ %c = icmp ult i64 %p, 256 ++ ret i1 %c ++} ++ ++define i1 @constant_range_and_undef_3_switched_incoming(i1 %cond, i64 %a) { ++; CHECK-LABEL: @constant_range_and_undef_3_switched_incoming( ++; CHECK-NEXT: entry: ++; CHECK-NEXT: br i1 [[COND:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ++; CHECK: bb1: ++; CHECK-NEXT: [[R:%.*]] = and i64 [[A:%.*]], 255 ++; CHECK-NEXT: br label [[BB3:%.*]] ++; CHECK: bb2: ++; CHECK-NEXT: br label [[BB3]] ++; CHECK: bb3: ++; CHECK-NEXT: [[P:%.*]] = phi i64 [ [[R]], [[BB1]] ], [ undef, [[BB2]] ] ++; CHECK-NEXT: [[C:%.*]] = icmp ult i64 [[P]], 256 ++; CHECK-NEXT: ret i1 [[C]] ++; ++entry: ++ br i1 %cond, label %bb1, label %bb2 ++ ++bb1: ++ %r = and i64 %a, 255 ++ br label %bb3 ++ ++bb2: ++ br label %bb3 ++ ++bb3: ++ %p = phi i64 [ %r, %bb1 ], [ undef, %bb2 ] ++ %c = icmp ult i64 %p, 256 ++ ret i1 %c ++} ++ ++; Same as @constant_range_and_undef, but with 3 incoming ++; values: undef, a constant and a constant range. ++define i64 @constant_range_and_undef_3_incoming_v1(i1 %c1, i1 %c2, i64 %a) { ++; CHECK-LABEL: @constant_range_and_undef_3_incoming_v1( ++; CHECK-NEXT: entry: ++; CHECK-NEXT: br i1 [[C1:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ++; CHECK: bb1: ++; CHECK-NEXT: [[R:%.*]] = and i64 [[A:%.*]], 255 ++; CHECK-NEXT: br label [[BB4:%.*]] ++; CHECK: bb2: ++; CHECK-NEXT: br i1 [[C2:%.*]], label [[BB3:%.*]], label [[BB4]] ++; CHECK: bb3: ++; CHECK-NEXT: br label [[BB4]] ++; CHECK: bb4: ++; CHECK-NEXT: [[P:%.*]] = phi i64 [ [[R]], [[BB1]] ], [ 10, [[BB2]] ], [ undef, [[BB3]] ] ++; CHECK-NEXT: [[RES:%.*]] = and i64 [[P]], 255 ++; CHECK-NEXT: ret i64 [[RES]] ++; ++entry: ++ br i1 %c1, label %bb1, label %bb2 ++ ++bb1: ++ %r = and i64 %a, 255 ++ br label %bb4 ++ ++bb2: ++ br i1 %c2, label %bb3, label %bb4 ++ ++bb3: ++ br label %bb4 ++ ++bb4: ++ %p = phi i64 [ %r, %bb1 ], [ 10, %bb2], [ undef, %bb3 ] ++ %res = and i64 %p, 255 ++ ret i64 %res ++} ++ ++; Same as @constant_range_and_undef_3_incoming_v1, but with different order of ++; incoming values. ++define i64 @constant_range_and_undef_3_incoming_v2(i1 %c1, i1 %c2, i64 %a) { ++; CHECK-LABEL: @constant_range_and_undef_3_incoming_v2( ++; CHECK-NEXT: entry: ++; CHECK-NEXT: br i1 [[C1:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ++; CHECK: bb1: ++; CHECK-NEXT: br label [[BB4:%.*]] ++; CHECK: bb2: ++; CHECK-NEXT: br i1 [[C2:%.*]], label [[BB3:%.*]], label [[BB4]] ++; CHECK: bb3: ++; CHECK-NEXT: [[R:%.*]] = and i64 [[A:%.*]], 255 ++; CHECK-NEXT: br label [[BB4]] ++; CHECK: bb4: ++; CHECK-NEXT: [[P:%.*]] = phi i64 [ undef, [[BB1]] ], [ 10, [[BB2]] ], [ [[R]], [[BB3]] ] ++; CHECK-NEXT: [[RES:%.*]] = and i64 [[P]], 255 ++; CHECK-NEXT: ret i64 [[RES]] ++; ++entry: ++ br i1 %c1, label %bb1, label %bb2 ++ ++bb1: ++ br label %bb4 ++ ++bb2: ++ br i1 %c2, label %bb3, label %bb4 ++ ++bb3: ++ %r = and i64 %a, 255 ++ br label %bb4 ++ ++bb4: ++ %p = phi i64 [ undef, %bb1 ], [ 10, %bb2], [ %r, %bb3 ] ++ %res = and i64 %p, 255 ++ ret i64 %res ++} ++ ++; Same as @constant_range_and_undef_3_incoming_v1, but with different order of ++; incoming values. ++define i64 @constant_range_and_undef_3_incoming_v3(i1 %c1, i1 %c2, i64 %a) { ++; CHECK-LABEL: @constant_range_and_undef_3_incoming_v3( ++; CHECK-NEXT: entry: ++; CHECK-NEXT: br i1 [[C1:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ++; CHECK: bb1: ++; CHECK-NEXT: [[R:%.*]] = and i64 [[A:%.*]], 255 ++; CHECK-NEXT: br label [[BB4:%.*]] ++; CHECK: bb2: ++; CHECK-NEXT: br i1 [[C2:%.*]], label [[BB3:%.*]], label [[BB4]] ++; CHECK: bb3: ++; CHECK-NEXT: br label [[BB4]] ++; CHECK: bb4: ++; CHECK-NEXT: [[P:%.*]] = phi i64 [ [[R]], [[BB1]] ], [ undef, [[BB2]] ], [ 10, [[BB3]] ] ++; CHECK-NEXT: [[RES:%.*]] = and i64 [[P]], 255 ++; CHECK-NEXT: ret i64 [[RES]] ++; ++entry: ++ br i1 %c1, label %bb1, label %bb2 ++ ++bb1: ++ %r = and i64 %a, 255 ++ br label %bb4 ++ ++bb2: ++ br i1 %c2, label %bb3, label %bb4 ++ ++bb3: ++ br label %bb4 ++ ++bb4: ++ %p = phi i64 [ %r, %bb1 ], [ undef, %bb2], [ 10, %bb3 ] ++ %res = and i64 %p, 255 ++ ret i64 %res ++} ++ ++ ++define i64 @constant_range_and_phi_constant_undef(i1 %c1, i1 %c2, i64 %a) { ++; CHECK-LABEL: @constant_range_and_phi_constant_undef( ++; CHECK-NEXT: entry: ++; CHECK-NEXT: br i1 [[C1:%.*]], label [[BB1:%.*]], label [[BB2:%.*]] ++; CHECK: bb1: ++; CHECK-NEXT: [[R:%.*]] = and i64 [[A:%.*]], 255 ++; CHECK-NEXT: br label [[BB5:%.*]] ++; CHECK: bb2: ++; CHECK-NEXT: br i1 [[C2:%.*]], label [[BB3:%.*]], label [[BB4:%.*]] ++; CHECK: bb3: ++; CHECK-NEXT: br label [[BB4]] ++; CHECK: bb4: ++; CHECK-NEXT: br label [[BB5]] ++; CHECK: bb5: ++; CHECK-NEXT: [[P:%.*]] = phi i64 [ [[R]], [[BB1]] ], [ 10, [[BB4]] ] ++; CHECK-NEXT: [[RES:%.*]] = and i64 [[P]], 255 ++; CHECK-NEXT: ret i64 [[RES]] ++; ++entry: ++ br i1 %c1, label %bb1, label %bb2 ++ ++bb1: ++ %r = and i64 %a, 255 ++ br label %bb5 ++ ++bb2: ++ br i1 %c2, label %bb3, label %bb4 ++ ++bb3: ++ br label %bb4 ++ ++bb4: ++ %p.1 = phi i64 [ 10, %bb2 ], [ undef, %bb3] ++ br label %bb5 ++ ++bb5: ++ %p = phi i64 [ %r, %bb1 ], [ %p.1, %bb4] ++ %res = and i64 %p, 255 ++ ret i64 %res ++} +diff --git a/llvm/unittests/Analysis/ValueLatticeTest.cpp b/llvm/unittests/Analysis/ValueLatticeTest.cpp +--- a/llvm/unittests/Analysis/ValueLatticeTest.cpp ++++ b/llvm/unittests/Analysis/ValueLatticeTest.cpp +@@ -43,6 +43,23 @@ + EXPECT_TRUE(ValueLatticeElement::getNot(C2).isNotConstant()); + } + ++TEST_F(ValueLatticeTest, MarkConstantRange) { ++ auto LV1 = ++ ValueLatticeElement::getRange({APInt(32, 10, true), APInt(32, 20, true)}); ++ ++ // Test markConstantRange() with an equal range. ++ EXPECT_FALSE( ++ LV1.markConstantRange({APInt(32, 10, true), APInt(32, 20, true)})); ++ ++ // Test markConstantRange() with supersets of existing range. ++ EXPECT_TRUE(LV1.markConstantRange({APInt(32, 5, true), APInt(32, 20, true)})); ++ EXPECT_EQ(LV1.getConstantRange().getLower().getLimitedValue(), 5U); ++ EXPECT_EQ(LV1.getConstantRange().getUpper().getLimitedValue(), 20U); ++ EXPECT_TRUE(LV1.markConstantRange({APInt(32, 5, true), APInt(32, 23, true)})); ++ EXPECT_EQ(LV1.getConstantRange().getLower().getLimitedValue(), 5U); ++ EXPECT_EQ(LV1.getConstantRange().getUpper().getLimitedValue(), 23U); ++} ++ + TEST_F(ValueLatticeTest, MergeIn) { + auto I32Ty = IntegerType::get(Context, 32); + auto *C1 = ConstantInt::get(I32Ty, 1); + diff --git a/debian/patches/series b/debian/patches/series index 169ae904..4eaaeebe 100644 --- a/debian/patches/series +++ b/debian/patches/series @@ -139,4 +139,8 @@ no-z3.patch python3-shebang.patch print-lldb-path.patch no-cgi.patch -947f9692440836dcb8d88b74b69dd379d85974ce.patch +d21664cce1db8debe2528f36b1fbd2b8af9c9401.patch + +0001-systemz-allow-configuring-default-SYSTEMZ_DEFAULT_AR.patch + +D76596.diff