Hi folks,

Our project is using ValueTracking’s computeConstantRange() to refine loop bounds, and we’re seeing some surprising behavior when llvm.assume is put in the mix.

Here’s an example (which can be copied into ValueTrackingTest.cpp and executed):

{

// Assumptions:

// * x.2 < x.1

// (x.1 is unknown [full-set])

auto M = parseModule(R"(

declare void @llvm.assume(i1)

define i32 @test(i32 %x.1, i32 %x.2) {

%lt = icmp ule i32 %x.2, %x.1

call void @llvm.assume(i1 %lt)

%stride.plus.one = add nsw nuw i32 %x.1, 1

ret i32 %stride.plus.one

})");

Function *F = M->getFunction(“test”);

AssumptionCache AC(*F);

Value *X2 = &*std::next(F->arg_begin());

Instruction *I = &findInstructionByName(F, “stride.plus.one”);

ConstantRange CR1 = computeConstantRange(X2, true, &AC, I);

EXPECT_EQ(0, CR1.getLower());

EXPECT_EQ(1, CR1.getUpper()); // ???

}

The value of %x.1 is completely unknown, so its range is [full-set].

The llvm.assume of %lt is intended to communicate that %x.2 is <=(u) %x.1, whatever the value of %x.1 may be.

If we ask computeConstantRange about %x.2, it returns [0,1) which seems too restrictive (and potentially leading to miscompilation).

The assume is interpreted as “only values that can never violate the assumption are allowed”. Which in this case, is only 0.

Is this the correct interpretation of llvm.assume?

— CJ