Skip to content

Loop termination handling #726

@LebedevRI

Description

@LebedevRI

Nowadays, LLVM, at least nominally, does not assume that loops must progress,
but requires mustprogress annotation for that.
But it seems like alive2 doesn't deal with that.

For example,

; ModuleID = '/tmp/test.ll'
source_filename = "/tmp/test.ll"
target triple = "x86_64"

declare void @escape_inner(i8, i8, i8, i1, i8) #0

declare void @escape_outer(i8, i8, i8, i1, i8) #0

define i8 @src(i8 %val, i8 %start, i8 %extraoffset) {
entry:
  br label %loop

loop:
  %iv = phi i8 [ %start, %entry ], [ %iv.next, %loop ]
  %nbits = add nsw i8 %iv, %extraoffset
  %val.shifted = ashr i8 %val, %nbits
  %val.shifted.iszero = icmp eq i8 %val.shifted, 0
  %iv.next = add i8 %iv, 1

  call void @escape_inner(i8 %iv, i8 %nbits, i8 %val.shifted, i1 %val.shifted.iszero, i8 %iv.next)

  br i1 %val.shifted.iszero, label %end, label %loop

end:
  %iv.res = phi i8 [ %iv, %loop ]
  %nbits.res = phi i8 [ %nbits, %loop ]
  %val.shifted.res = phi i8 [ %val.shifted, %loop ]
  %val.shifted.iszero.res = phi i1 [ %val.shifted.iszero, %loop ]
  %iv.next.res = phi i8 [ %iv.next, %loop ]

  call void @escape_outer(i8 %iv.res, i8 %nbits.res, i8 %val.shifted.res, i1 %val.shifted.iszero.res, i8 %iv.next.res)

  ret i8 %iv.res
}

define i8 @tgt(i8 %val, i8 %start, i8 %extraoffset) #0 {
entry:
  %val.numleadingzeros = call i8 @llvm.ctlz.i8(i8 %val, i1 false)
  %val.numactivebits = sub nuw nsw i8 8, %val.numleadingzeros
  %0 = sub i8 0, %extraoffset
  %val.numactivebits.offset = add nsw i8 %val.numactivebits, %0
  %iv.final = call i8 @llvm.smax.i8(i8 %val.numactivebits.offset, i8 %start)
  %loop.backedgetakencount = sub nsw i8 %iv.final, %start
  %loop.tripcount = add nuw nsw i8 %loop.backedgetakencount, 1
  br label %loop

loop:                                             ; preds = %loop, %entry
  %loop.iv = phi i8 [ 0, %entry ], [ %loop.iv.next, %loop ]
  %loop.iv.next = add nuw nsw i8 %loop.iv, 1
  %loop.ivcheck = icmp eq i8 %loop.iv.next, %loop.tripcount
  %iv = add nsw i8 %loop.iv, %start
  %nbits = add nsw i8 %iv, %extraoffset
  %val.shifted = ashr i8 %val, %nbits
  %iv.next = add i8 %iv, 1
  call void @escape_inner(i8 %iv, i8 %nbits, i8 %val.shifted, i1 %loop.ivcheck, i8 %iv.next)
  br i1 %loop.ivcheck, label %end, label %loop

end:                                              ; preds = %loop
  %iv.res = phi i8 [ %iv.final, %loop ]
  %nbits.res = phi i8 [ %nbits, %loop ]
  %val.shifted.res = phi i8 [ %val.shifted, %loop ]
  %val.shifted.iszero.res = phi i1 [ %loop.ivcheck, %loop ]
  %iv.next.res = phi i8 [ %iv.next, %loop ]
  call void @escape_outer(i8 %iv.res, i8 %nbits.res, i8 %val.shifted.res, i1 %val.shifted.iszero.res, i8 %iv.next.res)
  ret i8 %iv.res
}

; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
declare i8 @llvm.ctlz.i8(i8, i1 immarg) #1

; Function Attrs: nofree nosync nounwind readnone speculatable willreturn
declare i8 @llvm.smax.i8(i8, i8) #1

attributes #0 = { "target-cpu"="core-avx2" }
attributes #1 = { nofree nosync nounwind readnone speculatable willreturn }

presumably shouldn't be a valid refinement - the original loop is endless for negative %start,
while the new one is not.

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions