diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp index 87a6b834beff..da5ba0b8520f 100644 --- a/llvm/lib/Analysis/ValueTracking.cpp +++ b/llvm/lib/Analysis/ValueTracking.cpp @@ -1502,6 +1502,23 @@ static bool isGEPKnownNonNull(GEPOperator *GEP, const DataLayout *DL, return false; } +/// Does the 'Range' metadata (which must be a valid MD_range operand list) +/// ensure that the value it's attached to is never Value? 'RangeType' is +/// is the type of the value described by the range. +static bool rangeMetadataExcludesValue(MDNode* Ranges, + const APInt& Value) { + const unsigned NumRanges = Ranges->getNumOperands() / 2; + assert(NumRanges >= 1); + for (unsigned i = 0; i < NumRanges; ++i) { + ConstantInt *Lower = cast(Ranges->getOperand(2*i + 0)); + ConstantInt *Upper = cast(Ranges->getOperand(2*i + 1)); + ConstantRange Range(Lower->getValue(), Upper->getValue()); + if (Range.contains(Value)) + return false; + } + return true; +} + /// isKnownNonZero - Return true if the given value is known to be non-zero /// when defined. For vectors return true if every element is known to be /// non-zero when defined. Supports values with integer or pointer type and @@ -1518,6 +1535,18 @@ bool isKnownNonZero(Value *V, const DataLayout *TD, unsigned Depth, return false; } + if (Instruction* I = dyn_cast(V)) { + if (MDNode *Ranges = I->getMetadata(LLVMContext::MD_range)) { + // If the possible ranges don't contain zero, then the value is + // definitely non-zero. + if (IntegerType* Ty = dyn_cast(V->getType())) { + const APInt ZeroValue(Ty->getBitWidth(), 0); + if (rangeMetadataExcludesValue(Ranges, ZeroValue)) + return true; + } + } + } + // The remaining tests are all recursive, so bail out if we hit the limit. if (Depth++ >= MaxDepth) return false; diff --git a/llvm/test/Transforms/InstCombine/icmp-range.ll b/llvm/test/Transforms/InstCombine/icmp-range.ll new file mode 100644 index 000000000000..97d231f0ea32 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/icmp-range.ll @@ -0,0 +1,61 @@ +; RUN: opt < %s -instcombine -S | FileCheck %s +; These should be InstSimplify checks, but most of the code +; is currently only in InstCombine. TODO: move supporting code + +; Definitely out of range +define i1 @test_nonzero(i32* nocapture readonly %arg) { +; CHECK-LABEL:test_nonzero +; CHECK: ret i1 true + %val = load i32* %arg, !range !0 + %rval = icmp ne i32 %val, 0 + ret i1 %rval +} +define i1 @test_nonzero2(i32* nocapture readonly %arg) { +; CHECK-LABEL:test_nonzero2 +; CHECK: ret i1 false + %val = load i32* %arg, !range !0 + %rval = icmp eq i32 %val, 0 + ret i1 %rval +} + +; Potentially in range +define i1 @test_nonzero3(i32* nocapture readonly %arg) { +; CHECK-LABEL: test_nonzero3 +; Check that this does not trigger - it wouldn't be legal +; CHECK: icmp + %val = load i32* %arg, !range !1 + %rval = icmp ne i32 %val, 0 + ret i1 %rval +} + +; Definitely in range +define i1 @test_nonzero4(i8* nocapture readonly %arg) { +; CHECK-LABEL: test_nonzero4 +; CHECK: ret i1 false + %val = load i8* %arg, !range !2 + %rval = icmp ne i8 %val, 0 + ret i1 %rval +} + +define i1 @test_nonzero5(i8* nocapture readonly %arg) { +; CHECK-LABEL: test_nonzero5 +; CHECK: ret i1 false + %val = load i8* %arg, !range !2 + %rval = icmp ugt i8 %val, 0 + ret i1 %rval +} + +; Cheaper checks (most values in range meet requirements) +define i1 @test_nonzero6(i8* %argw) { +; CHECK-LABEL: test_nonzero6 +; CHECK: icmp ne i8 %val, 0 + %val = load i8* %argw, !range !3 + %rval = icmp sgt i8 %val, 0 + ret i1 %rval +} + + +!0 = metadata !{i32 1, i32 6} +!1 = metadata !{i32 0, i32 6} +!2 = metadata !{i8 0, i8 1} +!3 = metadata !{i8 0, i8 6}