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

[NFC][IRCE] Add unit test to show room for improvement #71506

Merged
merged 1 commit into from
Nov 7, 2023

Conversation

aleks-tmb
Copy link
Contributor

Add tests for compound loop bounds where IRCE is possible

if (K > 0 && M > 0)
for (i = 0; i < min(K, M); i++) {...}

if (K > 0 && M > 0)
for (i = min(K, M); i >= 0; i--) {...}

@llvmbot
Copy link
Collaborator

llvmbot commented Nov 7, 2023

@llvm/pr-subscribers-llvm-transforms

Author: Aleksandr Popov (aleks-tmb)

Changes

Add tests for compound loop bounds where IRCE is possible

if (K > 0 && M > 0)
for (i = 0; i < min(K, M); i++) {...}

if (K > 0 && M > 0)
for (i = min(K, M); i >= 0; i--) {...}


Full diff: https://github.com/llvm/llvm-project/pull/71506.diff

1 Files Affected:

  • (added) llvm/test/Transforms/IRCE/compound-loop-bound.ll (+132)
diff --git a/llvm/test/Transforms/IRCE/compound-loop-bound.ll b/llvm/test/Transforms/IRCE/compound-loop-bound.ll
new file mode 100644
index 000000000000000..0930d19e22154fc
--- /dev/null
+++ b/llvm/test/Transforms/IRCE/compound-loop-bound.ll
@@ -0,0 +1,132 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 3
+; RUN: opt -passes=irce < %s -S | FileCheck %s
+
+; if (K > 0 && M > 0)
+;   for (i = 0; i < min(K, M); i++) {...}
+;
+; TODO: Loop bounds are safe according to loop guards. IRCE is allowed.
+define void @incrementing_loop(ptr %arr, ptr %len_ptr, i32 %K, i32 %M) {
+; CHECK-LABEL: define void @incrementing_loop(
+; CHECK-SAME: ptr [[ARR:%.*]], ptr [[LEN_PTR:%.*]], i32 [[K:%.*]], i32 [[M:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr [[LEN_PTR]], align 4, !range [[RNG0:![0-9]+]]
+; CHECK-NEXT:    [[CHECK0:%.*]] = icmp sgt i32 [[K]], 0
+; CHECK-NEXT:    [[CHECK1:%.*]] = icmp sgt i32 [[M]], 0
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CHECK0]], [[CHECK1]]
+; CHECK-NEXT:    br i1 [[AND]], label [[PREHEADER:%.*]], label [[EXIT:%.*]]
+; CHECK:       preheader:
+; CHECK-NEXT:    [[SMIN:%.*]] = call i32 @llvm.smin.i32(i32 [[K]], i32 [[M]])
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[IDX:%.*]] = phi i32 [ 0, [[PREHEADER]] ], [ [[IDX_NEXT:%.*]], [[IN_BOUNDS:%.*]] ]
+; CHECK-NEXT:    [[IDX_NEXT]] = add i32 [[IDX]], 1
+; CHECK-NEXT:    [[GUARD:%.*]] = icmp slt i32 [[IDX]], [[LEN]]
+; CHECK-NEXT:    br i1 [[GUARD]], label [[IN_BOUNDS]], label [[OUT_OF_BOUNDS:%.*]]
+; CHECK:       in.bounds:
+; CHECK-NEXT:    [[ADDR:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[IDX]]
+; CHECK-NEXT:    store i32 0, ptr [[ADDR]], align 4
+; CHECK-NEXT:    [[NEXT:%.*]] = icmp slt i32 [[IDX_NEXT]], [[SMIN]]
+; CHECK-NEXT:    br i1 [[NEXT]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
+; CHECK:       out.of.bounds:
+; CHECK-NEXT:    ret void
+; CHECK:       exit.loopexit:
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+entry:
+  %len = load i32, ptr %len_ptr, !range !0
+  %check0 = icmp sgt i32 %K, 0
+  %check1 = icmp sgt i32 %M, 0
+  %and = and i1 %check0, %check1
+  br i1 %and, label %preheader, label %exit
+
+preheader:
+  %smin = call i32 @llvm.smin.i32(i32 %K, i32 %M)
+  br label %loop
+
+loop:
+  %idx = phi i32 [ 0, %preheader ], [ %idx.next, %in.bounds ]
+  %idx.next = add i32 %idx, 1
+  %guard = icmp slt i32 %idx, %len
+  br i1 %guard, label %in.bounds, label %out.of.bounds
+
+in.bounds:
+  %addr = getelementptr i32, ptr %arr, i32 %idx
+  store i32 0, ptr %addr
+  %next = icmp slt i32 %idx.next, %smin
+  br i1 %next, label %loop, label %exit
+
+out.of.bounds:
+  ret void
+
+exit:
+  ret void
+}
+
+; if (K > 0 && M > 0)
+;   for (i = min(K, M); i >= 0; i--) {...}
+;
+; TODO: Loop bounds are safe according to loop guards. IRCE is allowed.
+define void @decrementing_loop(ptr %arr, ptr %len_ptr, i32 %K, i32 %M) {
+; CHECK-LABEL: define void @decrementing_loop(
+; CHECK-SAME: ptr [[ARR:%.*]], ptr [[LEN_PTR:%.*]], i32 [[K:%.*]], i32 [[M:%.*]]) {
+; CHECK-NEXT:  entry:
+; CHECK-NEXT:    [[LEN:%.*]] = load i32, ptr [[LEN_PTR]], align 4, !range [[RNG0]]
+; CHECK-NEXT:    [[CHECK0:%.*]] = icmp sgt i32 [[K]], 0
+; CHECK-NEXT:    [[CHECK1:%.*]] = icmp sgt i32 [[M]], 0
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[CHECK0]], [[CHECK1]]
+; CHECK-NEXT:    br i1 [[AND]], label [[PREHEADER:%.*]], label [[EXIT:%.*]]
+; CHECK:       preheader:
+; CHECK-NEXT:    [[SMIN:%.*]] = call i32 @llvm.smin.i32(i32 [[K]], i32 [[M]])
+; CHECK-NEXT:    br label [[LOOP:%.*]]
+; CHECK:       loop:
+; CHECK-NEXT:    [[IDX:%.*]] = phi i32 [ [[SMIN]], [[PREHEADER]] ], [ [[IDX_DEC:%.*]], [[IN_BOUNDS:%.*]] ]
+; CHECK-NEXT:    [[IDX_DEC]] = sub i32 [[IDX]], 1
+; CHECK-NEXT:    [[GUARD:%.*]] = icmp slt i32 [[IDX]], [[LEN]]
+; CHECK-NEXT:    br i1 [[GUARD]], label [[IN_BOUNDS]], label [[OUT_OF_BOUNDS:%.*]]
+; CHECK:       in.bounds:
+; CHECK-NEXT:    [[ADDR:%.*]] = getelementptr i32, ptr [[ARR]], i32 [[IDX]]
+; CHECK-NEXT:    store i32 0, ptr [[ADDR]], align 4
+; CHECK-NEXT:    [[NEXT:%.*]] = icmp sgt i32 [[IDX_DEC]], -1
+; CHECK-NEXT:    br i1 [[NEXT]], label [[LOOP]], label [[EXIT_LOOPEXIT:%.*]]
+; CHECK:       out.of.bounds:
+; CHECK-NEXT:    ret void
+; CHECK:       exit.loopexit:
+; CHECK-NEXT:    br label [[EXIT]]
+; CHECK:       exit:
+; CHECK-NEXT:    ret void
+;
+  entry:
+  %len = load i32, ptr %len_ptr, !range !0
+  %check0 = icmp sgt i32 %K, 0
+  %check1 = icmp sgt i32 %M, 0
+  %and = and i1 %check0, %check1
+  br i1 %and, label %preheader, label %exit
+
+  preheader:
+  %smin = call i32 @llvm.smin.i32(i32 %K, i32 %M)
+  br label %loop
+
+  loop:
+  %idx = phi i32 [ %smin, %preheader ] , [ %idx.dec, %in.bounds ]
+  %idx.dec = sub i32 %idx, 1
+  %guard = icmp slt i32 %idx, %len
+  br i1 %guard, label %in.bounds, label %out.of.bounds
+
+  in.bounds:
+  %addr = getelementptr i32, ptr %arr, i32 %idx
+  store i32 0, ptr %addr
+  %next = icmp sgt i32 %idx.dec, -1
+  br i1 %next, label %loop, label %exit
+
+  out.of.bounds:
+  ret void
+
+  exit:
+  ret void
+}
+
+declare i32 @llvm.smin.i32(i32, i32)
+
+!0 = !{i32 0, i32 2147483647}

Add tests for compound loop bounds where IRCE is possible

if (K > 0 && M > 0)
  for (i = 0; i < min(K, M); i++) {...}

if (K > 0 && M > 0)
  for (i = min(K, M); i >= 0; i--) {...}
@aleks-tmb aleks-tmb merged commit 011f25a into llvm:main Nov 7, 2023
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants