The current code structure results in cases where if a) we can't clone the IV user (because it's not in our whitelist) or b) can't prove the SCEV expressions are identical, we'd sometimes leave both the original unwiddened IV and the partially widdened IV in code. Instead, just truncate thw wide IV to the use - same as what we'd do if we couldn't find an addrec to start with. Noticed this while playing with changing how we produce addrecs. The current structure results in a very tight interlock between SCEVs internal capabilities and indvars code.
102 lines
3.2 KiB
LLVM
102 lines
3.2 KiB
LLVM
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
|
|
; RUN: opt -S -passes=indvars < %s | FileCheck %s
|
|
|
|
; This tests the case where a terminator can be modeled by SCEV,
|
|
; because it has a returned attribute.
|
|
|
|
target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128"
|
|
|
|
declare i32 @foo(i32)
|
|
|
|
define void @test(ptr %p) personality ptr undef {
|
|
; CHECK-LABEL: @test(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ], [ 0, [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: [[TMP0:%.*]] = trunc i64 [[INDVARS_IV]] to i32
|
|
; CHECK-NEXT: [[RES:%.*]] = invoke i32 @foo(i32 returned [[TMP0]])
|
|
; CHECK-NEXT: to label [[LOOP_LATCH]] unwind label [[EXIT:%.*]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add i64 [[INDVARS_IV]], 1
|
|
; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[INDVARS_IV]] to i32
|
|
; CHECK-NEXT: [[TMP2:%.*]] = call i32 @foo(i32 [[TMP1]])
|
|
; CHECK-NEXT: br label [[LOOP]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: [[LP:%.*]] = landingpad { ptr, i32 }
|
|
; CHECK-NEXT: cleanup
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
%res = invoke i32 @foo(i32 returned %iv)
|
|
to label %loop.latch unwind label %exit
|
|
|
|
loop.latch:
|
|
%ext = zext i32 %iv to i64
|
|
%tmp5 = getelementptr inbounds i8, ptr %p, i64 %ext
|
|
%iv.next = add nuw i32 %iv, 1
|
|
call i32 @foo(i32 %res)
|
|
br label %loop
|
|
|
|
exit:
|
|
%lp = landingpad { ptr, i32 }
|
|
cleanup
|
|
ret void
|
|
}
|
|
|
|
define void @test_critedge(i1 %c, ptr %p) personality ptr undef {
|
|
; CHECK-LABEL: @test_critedge(
|
|
; CHECK-NEXT: entry:
|
|
; CHECK-NEXT: br label [[LOOP:%.*]]
|
|
; CHECK: loop:
|
|
; CHECK-NEXT: [[INDVARS_IV:%.*]] = phi i64 [ [[INDVARS_IV_NEXT:%.*]], [[LOOP_LATCH:%.*]] ], [ 0, [[ENTRY:%.*]] ]
|
|
; CHECK-NEXT: br i1 [[C:%.*]], label [[LOOP_INVOKE:%.*]], label [[LOOP_OTHER:%.*]]
|
|
; CHECK: loop.invoke:
|
|
; CHECK-NEXT: [[TMP0:%.*]] = trunc i64 [[INDVARS_IV]] to i32
|
|
; CHECK-NEXT: [[TMP1:%.*]] = trunc i64 [[INDVARS_IV]] to i32
|
|
; CHECK-NEXT: [[RES:%.*]] = invoke i32 @foo(i32 returned [[TMP0]])
|
|
; CHECK-NEXT: to label [[LOOP_LATCH]] unwind label [[EXIT:%.*]]
|
|
; CHECK: loop.other:
|
|
; CHECK-NEXT: br label [[LOOP_LATCH]]
|
|
; CHECK: loop.latch:
|
|
; CHECK-NEXT: [[PHI:%.*]] = phi i32 [ [[TMP1]], [[LOOP_INVOKE]] ], [ 0, [[LOOP_OTHER]] ]
|
|
; CHECK-NEXT: [[INDVARS_IV_NEXT]] = add i64 [[INDVARS_IV]], 1
|
|
; CHECK-NEXT: [[TMP2:%.*]] = call i32 @foo(i32 [[PHI]])
|
|
; CHECK-NEXT: br label [[LOOP]]
|
|
; CHECK: exit:
|
|
; CHECK-NEXT: [[LP:%.*]] = landingpad { ptr, i32 }
|
|
; CHECK-NEXT: cleanup
|
|
; CHECK-NEXT: ret void
|
|
;
|
|
entry:
|
|
br label %loop
|
|
|
|
loop:
|
|
%iv = phi i32 [ 0, %entry ], [ %iv.next, %loop.latch ]
|
|
br i1 %c, label %loop.invoke, label %loop.other
|
|
|
|
loop.invoke:
|
|
%res = invoke i32 @foo(i32 returned %iv)
|
|
to label %loop.latch unwind label %exit
|
|
|
|
loop.other:
|
|
br label %loop.latch
|
|
|
|
loop.latch:
|
|
%phi = phi i32 [ %res, %loop.invoke ], [ 0, %loop.other ]
|
|
%ext = zext i32 %iv to i64
|
|
%tmp5 = getelementptr inbounds i8, ptr %p, i64 %ext
|
|
%iv.next = add nuw i32 %iv, 1
|
|
call i32 @foo(i32 %phi)
|
|
br label %loop
|
|
|
|
exit:
|
|
%lp = landingpad { ptr, i32 }
|
|
cleanup
|
|
ret void
|
|
}
|