(original) (raw)

Hi all,

Let's see an example (from Alexandre Isoard) first:
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
; RUN: opt -ipsccp -deadargelim -licm -O2 -S < %s

@g = internal global i32 0

; Function Attrs: argmemonly
define internal void @foo(i32\* nonnull dereferenceable(4) %arg, i32 %val) #0 {
entry:
store i32 %val, i32\* %arg
ret void
}

define i32 @bar(i32 %n) {
entry:
store i32 1, i32\* @g
br label %loop

loop: ; preds = %bb1, %bb
%i = phi i32 \[ %i.inc, %loop \], \[ 0, %entry \]
%g.val = load i32, i32\* @g
%g.inc = add nuw i32 %g.val, 1
tail call void @foo(i32\* @g, i32 %g.inc)
%i.inc = add nuw i32 %i, 1
%cond = icmp eq i32 %i.inc, %n
br i1 %cond, label %exit, label %loop

exit: ; preds = %bb1
ret i32 %g.val
}

declare void @llvm.assume(i1)

attributes #0 = { argmemonly }
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
With opt cmd '-ipsccp -deadargelim -licm -O2', function @bar will return constant value 1, instead of correct value %n. This is crazy, right?
Let's see what happens here.
Due to pass 'ipsccp' replaced the argument of function '@foo' with global variable '@g', but keeps attr 'argmemonly' there, so pass 'licm' will hoist the load of '@g' before the loop (as the value of @g isn't changed, but it is changed), and will cause function return wrong constant value '1', instead of '%n' (the correct value) , like following:
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
; Function Attrs: nofree norecurse nounwind writeonly
define i32 @bar(i32 %n) local\_unnamed\_addr #0 {
entry:
ret i32 1
}

attributes #0 = { nofree norecurse nounwind writeonly }
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*

And if remove the 'argmemonly' attribute, function @bar will return the correct value:
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*
; Function Attrs: nofree norecurse nounwind
define i32 @bar(i32 %n) local\_unnamed\_addr #0 {
entry:
ret i32 %n
}
\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*\*

So if function attribute 'argmemonly' on function @foo is correct, then there's a bug in pass 'ipsccp'. When it replaces the function local value with global variable, then it shoud remember to remove this function attribute.

Thanks,
Fangqing