Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

LoopUnroll: runtime check introduces branch on poison if fn call doesn't return #51012

Closed
nunoplopes opened this issue Aug 30, 2021 · 2 comments
Labels
bugzilla Issues migrated from bugzilla loopoptim miscompilation

Comments

@nunoplopes
Copy link
Member

nunoplopes commented Aug 30, 2021

Bugzilla Link 51670
Version trunk
OS All
CC @atrick,@meheff,@nikic

Extended Description

Test: Transforms/LoopUnroll/loop-remarks.ll

In the test below, @​baz may not return. In that case, the source function will not branch on the possibly poison %exitcond (poison if %n poison).
The target function always branches on %n regardless of whether @​baz returns or not.
The fix is to freeze %n if the code doesn't provably reach the branch.

define i32 @runtime(i32 %n) {
%entry:
  br label %for.body

%for.body:
  %s.06 = phi i32 [ 0, %entry ], [ %add1, %for.body ]
  %i.05 = phi i32 [ 0, %entry ], [ %inc, %for.body ]
  %add = add nsw i32 %i.05, 4
  %call = call i32 @baz(i32 %add)
  %add1 = add nsw i32 %call, %s.06
  %inc = add nsw i32 %i.05, 1
  %exitcond = icmp eq i32 %inc, %n
  br i1 %exitcond, label %for.end, label %for.body

%for.end:
  ret i32 %add1
}
=>
define i32 @​runtime(i32 %n) {
%entry:
  %0 = add i32 %n, 4294967295
  %xtraiter = and i32 %n, 3
  %1 = icmp ult i32 %0, 3
  br i1 %1, label %for.end.unr-lcssa, label %entry.new

%entry.new:
  %unroll_iter = sub i32 %n, %xtraiter
  br label %for.body

%for.body:
  %s.06 = phi i32 [ 0, %entry.new ], [ %add1.3, %for.body ]
  %i.05 = phi i32 [ 0, %entry.new ], [ %inc.3, %for.body ]
  %niter = phi i32 [ %unroll_iter, %entry.new ], [ %niter.nsub.3, %for.body ]
  %add = add nsw i32 %i.05, 4
  %call = call i32 @​baz(i32 %add)
  %add1 = add nsw i32 %call, %s.06
  %inc = add nsw nuw i32 %i.05, 1
  %niter.nsub = sub i32 %niter, 1
  %add.1 = add nsw i32 %inc, 4
  %call.1 = call i32 @​baz(i32 %add.1)
  %add1.1 = add nsw i32 %call.1, %add1
  %inc.1 = add nsw nuw i32 %inc, 1
  %niter.nsub.1 = sub i32 %niter.nsub, 1
  %add.2 = add nsw i32 %inc.1, 4
  %call.2 = call i32 @​baz(i32 %add.2)
  %add1.2 = add nsw i32 %call.2, %add1.1
  %inc.2 = add nsw nuw i32 %inc.1, 1
  %niter.nsub.2 = sub i32 %niter.nsub.1, 1
  %add.3 = add nsw i32 %inc.2, 4
  %call.3 = call i32 @​baz(i32 %add.3)
  %add1.3 = add nsw i32 %call.3, %add1.2
  %inc.3 = add nsw i32 %inc.2, 1
  %niter.nsub.3 = sub i32 %niter.nsub.2, 1
  %niter.ncmp.3 = icmp eq i32 %niter.nsub.3, 0
  br i1 %niter.ncmp.3, label %for.end.unr-lcssa.loopexit, label %for.body

%for.end.unr-lcssa.loopexit:
  %add1.lcssa.ph.ph = phi i32 [ %add1.3, %for.body ]
  %s.06.unr.ph = phi i32 [ %add1.3, %for.body ]
  %i.05.unr.ph = phi i32 [ %inc.3, %for.body ]
  br label %for.end.unr-lcssa

%for.end.unr-lcssa:
  %add1.lcssa.ph = phi i32 [ undef, %entry ], [ %add1.lcssa.ph.ph, %for.end.unr-lcssa.loopexit ]
  %s.06.unr = phi i32 [ 0, %entry ], [ %s.06.unr.ph, %for.end.unr-lcssa.loopexit ]
  %i.05.unr = phi i32 [ 0, %entry ], [ %i.05.unr.ph, %for.end.unr-lcssa.loopexit ]
  %lcmp.mod = icmp ne i32 %xtraiter, 0
  br i1 %lcmp.mod, label %for.body.epil.preheader, label %for.end

%for.body.epil.preheader:
  br label %for.body.epil

%for.body.epil:
  %add.epil = add nsw i32 %i.05.unr, 4
  %call.epil = call i32 @​baz(i32 %add.epil)
  %add1.epil = add nsw i32 %call.epil, %s.06.unr
  %inc.epil = add nsw i32 %i.05.unr, 1
  %epil.iter.sub = sub i32 %xtraiter, 1
  %epil.iter.cmp = icmp ne i32 %epil.iter.sub, 0
  br i1 %epil.iter.cmp, label %for.body.epil.1, label %for.end.epilog-lcssa

%for.body.epil.1:
  %add.epil.1 = add nsw i32 %inc.epil, 4
  %call.epil.1 = call i32 @​baz(i32 %add.epil.1)
  %add1.epil.1 = add nsw i32 %call.epil.1, %add1.epil
  %inc.epil.1 = add nsw i32 %inc.epil, 1
  %epil.iter.sub.1 = sub i32 %epil.iter.sub, 1
  %epil.iter.cmp.1 = icmp ne i32 %epil.iter.sub.1, 0
  br i1 %epil.iter.cmp.1, label %for.body.epil.2, label %for.end.epilog-lcssa

%for.body.epil.2:
  %add.epil.2 = add nsw i32 %inc.epil.1, 4
  %call.epil.2 = call i32 @​baz(i32 %add.epil.2)
  %add1.epil.2 = add nsw i32 %call.epil.2, %add1.epil.1
  br label %for.end.epilog-lcssa

%for.end.epilog-lcssa:
  %add1.lcssa.ph1 = phi i32 [ %add1.epil, %for.body.epil ], [ %add1.epil.1, %for.body.epil.1 ], [ %add1.epil.2, %for.body.epil.2 ]
  br label %for.end

%for.end:
  %add1.lcssa = phi i32 [ %add1.lcssa.ph, %for.end.unr-lcssa ], [ %add1.lcssa.ph1, %for.end.epilog-lcssa ]
  ret i32 %add1.lcssa
}
Transformation doesn't verify!
ERROR: Source is more defined than target

Example:
i32 %n = poison

Source:
i32 %s.06 = #x00000000 (0)
i32 %i.05 = #x00000000 (0)
i32 %add = #x00000004 (4)
i32 %call = poison
i32 %add1 = poison
i32 %inc = #x00000001 (1)
i1 %exitcond = poison

Target:
i32 %0 = poison
i32 %xtraiter = poison
i1 %1 = poison
@llvmbot llvmbot transferred this issue from llvm/llvm-bugzilla-archive Dec 11, 2021
@fhahn
Copy link
Contributor

fhahn commented May 10, 2022

Subtask of #45489

@nikic
Copy link
Contributor

nikic commented May 18, 2022

This should be fixed by 323514d.

@nikic nikic closed this as completed May 18, 2022
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bugzilla Issues migrated from bugzilla loopoptim miscompilation
Projects
None yet
Development

No branches or pull requests

3 participants