cmp instruction form

Hi all:

I write C code like this:

for (int i =0; i< 128; i++) {
printf("hello");
}

I use this command to compile the above code.
``

clang -Xclang -disable-O0-optnone -O0 -emit-llvm -S main.c
opt -O2 --print-after-all main.ll -S -o main.mid.ll

``
And I find the LLVM IR have this changed after instCombine optimization.


*** IR Dump After Dead Argument Elimination ***
; Function Attrs: noinline nounwind uwtable
define dso_local i32 @main(i32 %argc, i8** %argv) local_unnamed_addr #0 {
entry:
br label %for.cond

for.cond: ; preds = %for.body, %entry
%i.0 = phi i32 [ 0, %entry ], [ %inc, %for.body ]
%cmp = **icmp sle i32 %i.0, 128**
br i1 %cmp, label %for.body, label %for.end

for.body: ; preds = %for.cond
%call = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([6 x i8], [6 x i8]* @.str, i64 0, i64 0))
%inc = add nsw i32 %i.0, 1
br label %for.cond

for.end: ; preds = %for.cond
ret i32 0
}

*** IR Dump After Combine redundant instructions ***
; Function Attrs: noinline nounwind uwtable
define dso_local i32 @main(i32 %argc, i8** %argv) local_unnamed_addr #0 {
entry:
br label %for.cond

for.cond: ; preds = %for.body, %entry
%i.0 = phi i32 [ 0, %entry ], [ %inc, %for.body ]
%cmp = **icmp ult i32 %i.0, 129**
br i1 %cmp, label %for.body, label %for.end

for.body: ; preds = %for.cond
%call = call i32 (i8*, ...) @printf(i8* nonnull dereferenceable(1) getelementptr inbounds ([6 x i8], [6 x i8]* @.str, i64 0, i64 0))
%inc = add nuw nsw i32 %i.0, 1
br label %for.cond

for.end: ; preds = %for.cond
ret i32 0
}

···
I find the value 128 chaned to 129. So I want to know what's the purpose to changed the form?Can you give some example?

Thanks
Rock

(icmp reference: <https://llvm.org/docs/LangRef.html#id303f>)

Before, it uses "icmp sle" which is "signed <=", so effectively "<= 128".

After, it uses "icmp ult" which is "unsigned <", so effectively "< 129".

These are equivalent.

-Dimitry

I understand it’s equivalent.But I don’t know the benefit. And I don’t understand why this statement changed to
not eq in the last either.
···
%exitcond = icmp ne i32 %inc, 129

···

Thanks
Rock

There are a couple things going on.

InstCombine prefers to canonicalize ule/uge/sle/sge compares with constants to ult/ugt/slt/sgt by adjusting the constant. This allows transforms in InstCombine and other passes to not need to check for two forms of equivalent operations. The backends sometimes have to reverse this to get better code.

There’s a second transform that’s turning the signed compare into an unsigned compare because the loop counter starts at zero and counts up to a positive number so the value will never be negative. Unsigned compares are easier for some optimizations to reason about so the compiler tries to make unsigned compares when it can.

Thanks for explaining. I think I have get the meaning of this optimzation.And I also find this pattern changed to the “not eq” by “induction variable canonicalize”.
Thank all again.

~Rock