| ; NOTE: Assertions have been autogenerated by utils/update_analyze_test_checks.py | |
| ; RUN: opt -passes='print<scalar-evolution>' -disable-output %s 2>&1 | FileCheck %s | |
| target datalayout = "e-p:64:64:64-p1:128:128:128:64-pu2:64:64:64:64-pe3:64:64:64:64" | |
| ; Address space 1: integral fat pointer, 128-bit representation, 64-bit address. | |
| ; Address space 2: unstable representation (must stay SCEVUnknown). | |
| ; Address space 3: external state but stable representation. | |
| ; The difference of two ptrtoints of a 128-bit fat pointer to i64 (the address | |
| ; width) equals the difference of the addresses, so it can be modeled via | |
| ; ptrtoaddr. | |
| define i64 @sub_ptrtoint_fat_to_addrwidth(ptr addrspace(1) %p, ptr addrspace(1) %q) { | |
| ; CHECK-LABEL: 'sub_ptrtoint_fat_to_addrwidth' | |
| ; CHECK-NEXT: Classifying expressions for: @sub_ptrtoint_fat_to_addrwidth | |
| ; CHECK-NEXT: %p.int = ptrtoint ptr addrspace(1) %p to i64 | |
| ; CHECK-NEXT: --> %p.int U: full-set S: full-set | |
| ; CHECK-NEXT: %q.int = ptrtoint ptr addrspace(1) %q to i64 | |
| ; CHECK-NEXT: --> %q.int U: full-set S: full-set | |
| ; CHECK-NEXT: %sub = sub i64 %p.int, %q.int | |
| ; CHECK-NEXT: --> ((-1 * (ptrtoaddr ptr addrspace(1) %q to i64)) + (ptrtoaddr ptr addrspace(1) %p to i64)) U: full-set S: full-set | |
| ; CHECK-NEXT: Determining loop execution counts for: @sub_ptrtoint_fat_to_addrwidth | |
| ; | |
| %p.int = ptrtoint ptr addrspace(1) %p to i64 | |
| %q.int = ptrtoint ptr addrspace(1) %q to i64 | |
| %sub = sub i64 %p.int, %q.int | |
| ret i64 %sub | |
| } | |
| ; ptrtoint to i128 (wider than the 64-bit address) cannot be modeled via | |
| ; ptrtoaddr without losing the high bits, so it must stay opaque. | |
| define i128 @sub_ptrtoint_fat_wider_than_addr(ptr addrspace(1) %p, ptr addrspace(1) %q) { | |
| ; CHECK-LABEL: 'sub_ptrtoint_fat_wider_than_addr' | |
| ; CHECK-NEXT: Classifying expressions for: @sub_ptrtoint_fat_wider_than_addr | |
| ; CHECK-NEXT: %p.int = ptrtoint ptr addrspace(1) %p to i128 | |
| ; CHECK-NEXT: --> %p.int U: full-set S: full-set | |
| ; CHECK-NEXT: %q.int = ptrtoint ptr addrspace(1) %q to i128 | |
| ; CHECK-NEXT: --> %q.int U: full-set S: full-set | |
| ; CHECK-NEXT: %sub = sub i128 %p.int, %q.int | |
| ; CHECK-NEXT: --> ((-1 * %q.int) + %p.int) U: full-set S: full-set | |
| ; CHECK-NEXT: Determining loop execution counts for: @sub_ptrtoint_fat_wider_than_addr | |
| ; | |
| %p.int = ptrtoint ptr addrspace(1) %p to i128 | |
| %q.int = ptrtoint ptr addrspace(1) %q to i128 | |
| %sub = sub i128 %p.int, %q.int | |
| ret i128 %sub | |
| } | |
| ; Unstable representation: ptrtoaddr is not valid, so the difference must stay | |
| ; opaque (SCEVUnknown for each ptrtoint). | |
| define i64 @sub_ptrtoint_unstable(ptr addrspace(2) %p, ptr addrspace(2) %q) { | |
| ; CHECK-LABEL: 'sub_ptrtoint_unstable' | |
| ; CHECK-NEXT: Classifying expressions for: @sub_ptrtoint_unstable | |
| ; CHECK-NEXT: %p.int = ptrtoint ptr addrspace(2) %p to i64 | |
| ; CHECK-NEXT: --> %p.int U: full-set S: full-set | |
| ; CHECK-NEXT: %q.int = ptrtoint ptr addrspace(2) %q to i64 | |
| ; CHECK-NEXT: --> %q.int U: full-set S: full-set | |
| ; CHECK-NEXT: %sub = sub i64 %p.int, %q.int | |
| ; CHECK-NEXT: --> ((-1 * %q.int) + %p.int) U: full-set S: full-set | |
| ; CHECK-NEXT: Determining loop execution counts for: @sub_ptrtoint_unstable | |
| ; | |
| %p.int = ptrtoint ptr addrspace(2) %p to i64 | |
| %q.int = ptrtoint ptr addrspace(2) %q to i64 | |
| %sub = sub i64 %p.int, %q.int | |
| ret i64 %sub | |
| } | |
| ; External state but stable representation: the address bits can be extracted | |
| ; via ptrtoaddr, so the difference can be modeled. | |
| define i64 @sub_ptrtoint_external_state(ptr addrspace(3) %p, ptr addrspace(3) %q) { | |
| ; CHECK-LABEL: 'sub_ptrtoint_external_state' | |
| ; CHECK-NEXT: Classifying expressions for: @sub_ptrtoint_external_state | |
| ; CHECK-NEXT: %p.int = ptrtoint ptr addrspace(3) %p to i64 | |
| ; CHECK-NEXT: --> %p.int U: full-set S: full-set | |
| ; CHECK-NEXT: %q.int = ptrtoint ptr addrspace(3) %q to i64 | |
| ; CHECK-NEXT: --> %q.int U: full-set S: full-set | |
| ; CHECK-NEXT: %sub = sub i64 %p.int, %q.int | |
| ; CHECK-NEXT: --> ((-1 * (ptrtoaddr ptr addrspace(3) %q to i64)) + (ptrtoaddr ptr addrspace(3) %p to i64)) U: full-set S: full-set | |
| ; CHECK-NEXT: Determining loop execution counts for: @sub_ptrtoint_external_state | |
| ; | |
| %p.int = ptrtoint ptr addrspace(3) %p to i64 | |
| %q.int = ptrtoint ptr addrspace(3) %q to i64 | |
| %sub = sub i64 %p.int, %q.int | |
| ret i64 %sub | |
| } | |
| ; ptrtoint of a pointer add-rec to the address width is modeled via ptrtoaddr. | |
| define void @ptrtoint_addrec_fat_to_addrwidth(ptr addrspace(1) %in) { | |
| ; CHECK-LABEL: 'ptrtoint_addrec_fat_to_addrwidth' | |
| ; CHECK-NEXT: Classifying expressions for: @ptrtoint_addrec_fat_to_addrwidth | |
| ; CHECK-NEXT: %iv = phi ptr addrspace(1) [ %in, %entry ], [ %iv.next, %loop ] | |
| ; CHECK-NEXT: --> {%in,+,4}<nuw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable } | |
| ; CHECK-NEXT: %iv.int = ptrtoint ptr addrspace(1) %iv to i64 | |
| ; CHECK-NEXT: --> %iv.int U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant } | |
| ; CHECK-NEXT: %iv.next = getelementptr inbounds i32, ptr addrspace(1) %iv, i64 1 | |
| ; CHECK-NEXT: --> {(4 + %in),+,4}<nw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable } | |
| ; CHECK-NEXT: %c = call i1 @cond() | |
| ; CHECK-NEXT: --> %c U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant } | |
| ; CHECK-NEXT: Determining loop execution counts for: @ptrtoint_addrec_fat_to_addrwidth | |
| ; CHECK-NEXT: Loop %loop: Unpredictable backedge-taken count. | |
| ; CHECK-NEXT: Loop %loop: Unpredictable constant max backedge-taken count. | |
| ; CHECK-NEXT: Loop %loop: Unpredictable symbolic max backedge-taken count. | |
| ; | |
| entry: | |
| br label %loop | |
| loop: | |
| %iv = phi ptr addrspace(1) [ %in, %entry ], [ %iv.next, %loop ] | |
| %iv.int = ptrtoint ptr addrspace(1) %iv to i64 | |
| %iv.next = getelementptr inbounds i32, ptr addrspace(1) %iv, i64 1 | |
| %c = call i1 @cond() | |
| br i1 %c, label %loop, label %exit | |
| exit: | |
| ret void | |
| } | |
| ; ptrtoint of a pointer add-rec on an unstable pointer must stay opaque. | |
| define void @ptrtoint_addrec_unstable(ptr addrspace(2) %in) { | |
| ; CHECK-LABEL: 'ptrtoint_addrec_unstable' | |
| ; CHECK-NEXT: Classifying expressions for: @ptrtoint_addrec_unstable | |
| ; CHECK-NEXT: %iv = phi ptr addrspace(2) [ %in, %entry ], [ %iv.next, %loop ] | |
| ; CHECK-NEXT: --> {%in,+,4}<nuw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable } | |
| ; CHECK-NEXT: %iv.int = ptrtoint ptr addrspace(2) %iv to i64 | |
| ; CHECK-NEXT: --> %iv.int U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant } | |
| ; CHECK-NEXT: %iv.next = getelementptr inbounds i32, ptr addrspace(2) %iv, i64 1 | |
| ; CHECK-NEXT: --> {(4 + %in),+,4}<nw><%loop> U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Computable } | |
| ; CHECK-NEXT: %c = call i1 @cond() | |
| ; CHECK-NEXT: --> %c U: full-set S: full-set Exits: <<Unknown>> LoopDispositions: { %loop: Variant } | |
| ; CHECK-NEXT: Determining loop execution counts for: @ptrtoint_addrec_unstable | |
| ; CHECK-NEXT: Loop %loop: Unpredictable backedge-taken count. | |
| ; CHECK-NEXT: Loop %loop: Unpredictable constant max backedge-taken count. | |
| ; CHECK-NEXT: Loop %loop: Unpredictable symbolic max backedge-taken count. | |
| ; | |
| entry: | |
| br label %loop | |
| loop: | |
| %iv = phi ptr addrspace(2) [ %in, %entry ], [ %iv.next, %loop ] | |
| %iv.int = ptrtoint ptr addrspace(2) %iv to i64 | |
| %iv.next = getelementptr inbounds i32, ptr addrspace(2) %iv, i64 1 | |
| %c = call i1 @cond() | |
| br i1 %c, label %loop, label %exit | |
| exit: | |
| ret void | |
| } | |
| ; ptrtoint to i32 (narrower than the 64-bit address). | |
| define i32 @sub_ptrtoint_narrower_than_addr(ptr addrspace(1) %p, ptr addrspace(1) %q) { | |
| ; CHECK-LABEL: 'sub_ptrtoint_narrower_than_addr' | |
| ; CHECK-NEXT: Classifying expressions for: @sub_ptrtoint_narrower_than_addr | |
| ; CHECK-NEXT: %p.int = ptrtoint ptr addrspace(1) %p to i32 | |
| ; CHECK-NEXT: --> %p.int U: full-set S: full-set | |
| ; CHECK-NEXT: %q.int = ptrtoint ptr addrspace(1) %q to i32 | |
| ; CHECK-NEXT: --> %q.int U: full-set S: full-set | |
| ; CHECK-NEXT: %sub = sub i32 %p.int, %q.int | |
| ; CHECK-NEXT: --> ((trunc i64 (ptrtoaddr ptr addrspace(1) %p to i64) to i32) + (-1 * (trunc i64 (ptrtoaddr ptr addrspace(1) %q to i64) to i32))) U: full-set S: full-set | |
| ; CHECK-NEXT: Determining loop execution counts for: @sub_ptrtoint_narrower_than_addr | |
| ; | |
| %p.int = ptrtoint ptr addrspace(1) %p to i32 | |
| %q.int = ptrtoint ptr addrspace(1) %q to i32 | |
| %sub = sub i32 %p.int, %q.int | |
| ret i32 %sub | |
| } | |
| ; The backedge-taken count of a loop iterating over a 128 bit fat pointer. | |
| define void @fat_ptr_ult_backedge_count(ptr addrspace(1) %start, ptr addrspace(1) %end) { | |
| ; CHECK-LABEL: 'fat_ptr_ult_backedge_count' | |
| ; CHECK-NEXT: Classifying expressions for: @fat_ptr_ult_backedge_count | |
| ; CHECK-NEXT: %iv = phi ptr addrspace(1) [ %start, %entry ], [ %iv.next, %loop ] | |
| ; CHECK-NEXT: --> {%start,+,4}<nuw><%loop> U: full-set S: full-set Exits: ((4 * ((-1 + (-1 * (ptrtoaddr ptr addrspace(1) %start to i64)) + ((4 + (ptrtoaddr ptr addrspace(1) %start to i64))<nuw> umax (ptrtoaddr ptr addrspace(1) %end to i64))) /u 4))<nuw> + %start)<u nuw> LoopDispositions: { %loop: Computable } | |
| ; CHECK-NEXT: %iv.next = getelementptr inbounds i32, ptr addrspace(1) %iv, i64 1 | |
| ; CHECK-NEXT: --> {(4 + %start)<nuw>,+,4}<nuw><%loop> U: [4,0) S: [4,0) Exits: (4 + (4 * ((-1 + (-1 * (ptrtoaddr ptr addrspace(1) %start to i64)) + ((4 + (ptrtoaddr ptr addrspace(1) %start to i64))<nuw> umax (ptrtoaddr ptr addrspace(1) %end to i64))) /u 4))<nuw> + %start) LoopDispositions: { %loop: Computable } | |
| ; CHECK-NEXT: Determining loop execution counts for: @fat_ptr_ult_backedge_count | |
| ; CHECK-NEXT: Loop %loop: backedge-taken count is ((-1 + (-1 * (ptrtoaddr ptr addrspace(1) %start to i64)) + ((4 + (ptrtoaddr ptr addrspace(1) %start to i64))<nuw> umax (ptrtoaddr ptr addrspace(1) %end to i64))) /u 4) | |
| ; CHECK-NEXT: Loop %loop: constant max backedge-taken count is i64 4611686018427387902 | |
| ; CHECK-NEXT: Loop %loop: symbolic max backedge-taken count is ((-1 + (-1 * (ptrtoaddr ptr addrspace(1) %start to i64)) + ((4 + (ptrtoaddr ptr addrspace(1) %start to i64))<nuw> umax (ptrtoaddr ptr addrspace(1) %end to i64))) /u 4) | |
| ; CHECK-NEXT: Loop %loop: Trip multiple is 1 | |
| ; | |
| entry: | |
| br label %loop | |
| loop: | |
| %iv = phi ptr addrspace(1) [ %start, %entry ], [ %iv.next, %loop ] | |
| %iv.next = getelementptr inbounds i32, ptr addrspace(1) %iv, i64 1 | |
| %c = icmp ult ptr addrspace(1) %iv.next, %end | |
| br i1 %c, label %loop, label %exit | |
| exit: | |
| ret void | |
| } | |
| declare i1 @cond() |