Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[PhaseOrdering] Add test for missed vectorization with vector::at calls.
This test illustrates missed vectorization of loops with multiple std::vector::at calls, like int sum(std::vector<int> *A, std::vector<int> *B, int N) { int cost = 0; for (int i = 0; i < N; ++i) cost += A->at(i) + B->at(i); return cost; } https://clang.godbolt.org/z/KbYoaPhvq
- Loading branch information
Showing
1 changed file
with
196 additions
and
0 deletions.
There are no files selected for viewing
196 changes: 196 additions & 0 deletions
196
...est/Transforms/PhaseOrdering/AArch64/peel-multiple-unreachable-exits-for-vectorization.ll
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,196 @@ | ||
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py | ||
; RUN: opt -O2 -mtriple=arm64-apple-ios -S %s | FileCheck %s | ||
|
||
%vec = type { i64*, i64* } | ||
|
||
; Test to ensure a loop with multiple loads guarded by runtime-checks (like | ||
; from multiple calls to C++'s std::vector::at) can be vectorized after | ||
; hoisting the runtime checks out of the loop. | ||
|
||
define i64 @sum_2_at_with_int_conversion(%vec* %A, %vec* %B, i64 %N) { | ||
; CHECK-LABEL: @sum_2_at_with_int_conversion( | ||
; CHECK-NEXT: entry: | ||
; CHECK-NEXT: [[GEP_START_I:%.*]] = getelementptr [[VEC:%.*]], %vec* [[A:%.*]], i64 0, i32 0 | ||
; CHECK-NEXT: [[START_I:%.*]] = load i64*, i64** [[GEP_START_I]], align 8 | ||
; CHECK-NEXT: [[GEP_END_I:%.*]] = getelementptr [[VEC]], %vec* [[A]], i64 0, i32 1 | ||
; CHECK-NEXT: [[END_I:%.*]] = load i64*, i64** [[GEP_END_I]], align 8 | ||
; CHECK-NEXT: [[START_INT_I:%.*]] = ptrtoint i64* [[START_I]] to i64 | ||
; CHECK-NEXT: [[END_INT_I:%.*]] = ptrtoint i64* [[END_I]] to i64 | ||
; CHECK-NEXT: [[SUB_I:%.*]] = sub i64 [[END_INT_I]], [[START_INT_I]] | ||
; CHECK-NEXT: [[GEP_START_I1:%.*]] = getelementptr [[VEC]], %vec* [[B:%.*]], i64 0, i32 0 | ||
; CHECK-NEXT: [[GEP_END_I3:%.*]] = getelementptr [[VEC]], %vec* [[B]], i64 0, i32 1 | ||
; CHECK-NEXT: br label [[LOOP:%.*]] | ||
; CHECK: loop: | ||
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[AT_WITH_INT_CONVERSION_EXIT12:%.*]] ] | ||
; CHECK-NEXT: [[SUM:%.*]] = phi i64 [ 0, [[ENTRY]] ], [ [[SUM_NEXT:%.*]], [[AT_WITH_INT_CONVERSION_EXIT12]] ] | ||
; CHECK-NEXT: [[INRANGE_I:%.*]] = icmp ult i64 [[SUB_I]], [[IV]] | ||
; CHECK-NEXT: br i1 [[INRANGE_I]], label [[ERROR_I:%.*]], label [[AT_WITH_INT_CONVERSION_EXIT:%.*]] | ||
; CHECK: error.i: | ||
; CHECK-NEXT: tail call void @error() | ||
; CHECK-NEXT: unreachable | ||
; CHECK: at_with_int_conversion.exit: | ||
; CHECK-NEXT: [[START_I2:%.*]] = load i64*, i64** [[GEP_START_I1]], align 8 | ||
; CHECK-NEXT: [[END_I4:%.*]] = load i64*, i64** [[GEP_END_I3]], align 8 | ||
; CHECK-NEXT: [[START_INT_I5:%.*]] = ptrtoint i64* [[START_I2]] to i64 | ||
; CHECK-NEXT: [[END_INT_I6:%.*]] = ptrtoint i64* [[END_I4]] to i64 | ||
; CHECK-NEXT: [[SUB_I7:%.*]] = sub i64 [[END_INT_I6]], [[START_INT_I5]] | ||
; CHECK-NEXT: [[INRANGE_I8:%.*]] = icmp ult i64 [[SUB_I7]], [[IV]] | ||
; CHECK-NEXT: br i1 [[INRANGE_I8]], label [[ERROR_I11:%.*]], label [[AT_WITH_INT_CONVERSION_EXIT12]] | ||
; CHECK: error.i11: | ||
; CHECK-NEXT: tail call void @error() | ||
; CHECK-NEXT: unreachable | ||
; CHECK: at_with_int_conversion.exit12: | ||
; CHECK-NEXT: [[GEP_IDX_I:%.*]] = getelementptr i64, i64* [[START_I]], i64 [[IV]] | ||
; CHECK-NEXT: [[LV_I:%.*]] = load i64, i64* [[GEP_IDX_I]], align 4 | ||
; CHECK-NEXT: [[GEP_IDX_I9:%.*]] = getelementptr i64, i64* [[START_I2]], i64 [[IV]] | ||
; CHECK-NEXT: [[LV_I10:%.*]] = load i64, i64* [[GEP_IDX_I9]], align 4 | ||
; CHECK-NEXT: [[ADD:%.*]] = add i64 [[LV_I]], [[SUM]] | ||
; CHECK-NEXT: [[SUM_NEXT]] = add i64 [[ADD]], [[LV_I10]] | ||
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 | ||
; CHECK-NEXT: [[C:%.*]] = icmp slt i64 [[IV]], [[N:%.*]] | ||
; CHECK-NEXT: br i1 [[C]], label [[LOOP]], label [[EXIT:%.*]] | ||
; CHECK: exit: | ||
; CHECK-NEXT: ret i64 [[SUM_NEXT]] | ||
; | ||
entry: | ||
br label %loop | ||
|
||
loop: | ||
%iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] | ||
%sum = phi i64 [ 0, %entry ], [ %sum.next, %loop ] | ||
%a = call i64 @at_with_int_conversion(%vec* %A, i64 %iv) | ||
%b = call i64 @at_with_int_conversion(%vec* %B, i64 %iv) | ||
%add = add i64 %a, %b | ||
%sum.next = add i64 %sum, %add | ||
%iv.next = add nuw nsw i64 %iv, 1 | ||
%c = icmp slt i64 %iv, %N | ||
br i1 %c, label %loop, label %exit | ||
|
||
exit: | ||
ret i64 %sum.next | ||
} | ||
|
||
define i64 @sum_3_at_with_int_conversion(%vec* %A, %vec* %B, %vec* %C, i64 %N) { | ||
; CHECK-LABEL: @sum_3_at_with_int_conversion( | ||
; CHECK-NEXT: entry: | ||
; CHECK-NEXT: [[GEP_START_I:%.*]] = getelementptr [[VEC:%.*]], %vec* [[A:%.*]], i64 0, i32 0 | ||
; CHECK-NEXT: [[START_I:%.*]] = load i64*, i64** [[GEP_START_I]], align 8 | ||
; CHECK-NEXT: [[GEP_END_I:%.*]] = getelementptr [[VEC]], %vec* [[A]], i64 0, i32 1 | ||
; CHECK-NEXT: [[END_I:%.*]] = load i64*, i64** [[GEP_END_I]], align 8 | ||
; CHECK-NEXT: [[START_INT_I:%.*]] = ptrtoint i64* [[START_I]] to i64 | ||
; CHECK-NEXT: [[END_INT_I:%.*]] = ptrtoint i64* [[END_I]] to i64 | ||
; CHECK-NEXT: [[SUB_I:%.*]] = sub i64 [[END_INT_I]], [[START_INT_I]] | ||
; CHECK-NEXT: [[GEP_START_I1:%.*]] = getelementptr [[VEC]], %vec* [[B:%.*]], i64 0, i32 0 | ||
; CHECK-NEXT: [[GEP_END_I3:%.*]] = getelementptr [[VEC]], %vec* [[B]], i64 0, i32 1 | ||
; CHECK-NEXT: [[GEP_START_I13:%.*]] = getelementptr [[VEC]], %vec* [[C:%.*]], i64 0, i32 0 | ||
; CHECK-NEXT: [[GEP_END_I15:%.*]] = getelementptr [[VEC]], %vec* [[C]], i64 0, i32 1 | ||
; CHECK-NEXT: br label [[LOOP:%.*]] | ||
; CHECK: loop: | ||
; CHECK-NEXT: [[IV:%.*]] = phi i64 [ 0, [[ENTRY:%.*]] ], [ [[IV_NEXT:%.*]], [[AT_WITH_INT_CONVERSION_EXIT24:%.*]] ] | ||
; CHECK-NEXT: [[SUM:%.*]] = phi i64 [ 0, [[ENTRY]] ], [ [[SUM_NEXT:%.*]], [[AT_WITH_INT_CONVERSION_EXIT24]] ] | ||
; CHECK-NEXT: [[INRANGE_I:%.*]] = icmp ult i64 [[SUB_I]], [[IV]] | ||
; CHECK-NEXT: br i1 [[INRANGE_I]], label [[ERROR_I:%.*]], label [[AT_WITH_INT_CONVERSION_EXIT:%.*]] | ||
; CHECK: error.i: | ||
; CHECK-NEXT: tail call void @error() | ||
; CHECK-NEXT: unreachable | ||
; CHECK: at_with_int_conversion.exit: | ||
; CHECK-NEXT: [[GEP_IDX_I:%.*]] = getelementptr i64, i64* [[START_I]], i64 [[IV]] | ||
; CHECK-NEXT: [[LV_I:%.*]] = load i64, i64* [[GEP_IDX_I]], align 4 | ||
; CHECK-NEXT: [[START_I2:%.*]] = load i64*, i64** [[GEP_START_I1]], align 8 | ||
; CHECK-NEXT: [[END_I4:%.*]] = load i64*, i64** [[GEP_END_I3]], align 8 | ||
; CHECK-NEXT: [[START_INT_I5:%.*]] = ptrtoint i64* [[START_I2]] to i64 | ||
; CHECK-NEXT: [[END_INT_I6:%.*]] = ptrtoint i64* [[END_I4]] to i64 | ||
; CHECK-NEXT: [[SUB_I7:%.*]] = sub i64 [[END_INT_I6]], [[START_INT_I5]] | ||
; CHECK-NEXT: [[INRANGE_I8:%.*]] = icmp ult i64 [[SUB_I7]], [[IV]] | ||
; CHECK-NEXT: br i1 [[INRANGE_I8]], label [[ERROR_I11:%.*]], label [[AT_WITH_INT_CONVERSION_EXIT12:%.*]] | ||
; CHECK: error.i11: | ||
; CHECK-NEXT: tail call void @error() | ||
; CHECK-NEXT: unreachable | ||
; CHECK: at_with_int_conversion.exit12: | ||
; CHECK-NEXT: [[START_I14:%.*]] = load i64*, i64** [[GEP_START_I13]], align 8 | ||
; CHECK-NEXT: [[END_I16:%.*]] = load i64*, i64** [[GEP_END_I15]], align 8 | ||
; CHECK-NEXT: [[START_INT_I17:%.*]] = ptrtoint i64* [[START_I14]] to i64 | ||
; CHECK-NEXT: [[END_INT_I18:%.*]] = ptrtoint i64* [[END_I16]] to i64 | ||
; CHECK-NEXT: [[SUB_I19:%.*]] = sub i64 [[END_INT_I18]], [[START_INT_I17]] | ||
; CHECK-NEXT: [[INRANGE_I20:%.*]] = icmp ult i64 [[SUB_I19]], [[IV]] | ||
; CHECK-NEXT: br i1 [[INRANGE_I20]], label [[ERROR_I23:%.*]], label [[AT_WITH_INT_CONVERSION_EXIT24]] | ||
; CHECK: error.i23: | ||
; CHECK-NEXT: tail call void @error() | ||
; CHECK-NEXT: unreachable | ||
; CHECK: at_with_int_conversion.exit24: | ||
; CHECK-NEXT: [[GEP_IDX_I9:%.*]] = getelementptr i64, i64* [[START_I2]], i64 [[IV]] | ||
; CHECK-NEXT: [[LV_I10:%.*]] = load i64, i64* [[GEP_IDX_I9]], align 4 | ||
; CHECK-NEXT: [[GEP_IDX_I21:%.*]] = getelementptr i64, i64* [[START_I14]], i64 [[IV]] | ||
; CHECK-NEXT: [[LV_I22:%.*]] = load i64, i64* [[GEP_IDX_I21]], align 4 | ||
; CHECK-NEXT: [[ADD_1:%.*]] = add i64 [[LV_I]], [[SUM]] | ||
; CHECK-NEXT: [[ADD_2:%.*]] = add i64 [[ADD_1]], [[LV_I10]] | ||
; CHECK-NEXT: [[SUM_NEXT]] = add i64 [[ADD_2]], [[LV_I22]] | ||
; CHECK-NEXT: [[IV_NEXT]] = add nuw nsw i64 [[IV]], 1 | ||
; CHECK-NEXT: [[COND:%.*]] = icmp slt i64 [[IV]], [[N:%.*]] | ||
; CHECK-NEXT: br i1 [[COND]], label [[LOOP]], label [[EXIT:%.*]] | ||
; CHECK: exit: | ||
; CHECK-NEXT: ret i64 [[SUM_NEXT]] | ||
; | ||
entry: | ||
br label %loop | ||
|
||
loop: | ||
%iv = phi i64 [ 0, %entry ], [ %iv.next, %loop ] | ||
%sum = phi i64 [ 0, %entry ], [ %sum.next, %loop ] | ||
%a = call i64 @at_with_int_conversion(%vec* %A, i64 %iv) | ||
%b = call i64 @at_with_int_conversion(%vec* %B, i64 %iv) | ||
%c = call i64 @at_with_int_conversion(%vec* %C, i64 %iv) | ||
%add.1 = add i64 %a, %b | ||
%add.2 = add i64 %add.1, %c | ||
%sum.next = add i64 %sum, %add.2 | ||
%iv.next = add nuw nsw i64 %iv, 1 | ||
%cond = icmp slt i64 %iv, %N | ||
br i1 %cond, label %loop, label %exit | ||
|
||
exit: | ||
ret i64 %sum.next | ||
} | ||
|
||
|
||
define i64 @at_with_int_conversion(%vec* %ptr, i64 %idx) { | ||
; CHECK-LABEL: @at_with_int_conversion( | ||
; CHECK-NEXT: [[GEP_START:%.*]] = getelementptr [[VEC:%.*]], %vec* [[PTR:%.*]], i64 0, i32 0 | ||
; CHECK-NEXT: [[START:%.*]] = load i64*, i64** [[GEP_START]], align 8 | ||
; CHECK-NEXT: [[GEP_END:%.*]] = getelementptr [[VEC]], %vec* [[PTR]], i64 0, i32 1 | ||
; CHECK-NEXT: [[END:%.*]] = load i64*, i64** [[GEP_END]], align 8 | ||
; CHECK-NEXT: [[START_INT:%.*]] = ptrtoint i64* [[START]] to i64 | ||
; CHECK-NEXT: [[END_INT:%.*]] = ptrtoint i64* [[END]] to i64 | ||
; CHECK-NEXT: [[SUB:%.*]] = sub i64 [[END_INT]], [[START_INT]] | ||
; CHECK-NEXT: [[INRANGE:%.*]] = icmp ult i64 [[SUB]], [[IDX:%.*]] | ||
; CHECK-NEXT: br i1 [[INRANGE]], label [[ERROR:%.*]], label [[EXIT:%.*]] | ||
; CHECK: exit: | ||
; CHECK-NEXT: [[GEP_IDX:%.*]] = getelementptr i64, i64* [[START]], i64 [[IDX]] | ||
; CHECK-NEXT: [[LV:%.*]] = load i64, i64* [[GEP_IDX]], align 4 | ||
; CHECK-NEXT: ret i64 [[LV]] | ||
; CHECK: error: | ||
; CHECK-NEXT: tail call void @error() | ||
; CHECK-NEXT: unreachable | ||
; | ||
%gep.start = getelementptr %vec, %vec* %ptr, i64 0, i32 0 | ||
%start = load i64*, i64** %gep.start | ||
%gep.end = getelementptr %vec, %vec* %ptr, i64 0, i32 1 | ||
%end = load i64*, i64** %gep.end | ||
%start.int = ptrtoint i64* %start to i64 | ||
%end.int = ptrtoint i64* %end to i64 | ||
%sub = sub i64 %end.int, %start.int | ||
%inrange = icmp ugt i64 %idx, %sub | ||
br i1 %inrange, label %error, label %exit | ||
|
||
exit: | ||
%gep.idx = getelementptr i64, i64* %start, i64 %idx | ||
%lv = load i64, i64* %gep.idx | ||
ret i64 %lv | ||
|
||
error: | ||
call void @error() | ||
unreachable | ||
} | ||
|
||
declare void @error() | ||
|
||
|