Author: Florian Hahn Date: 2021-02-20T16:25:18Z New Revision: a0d1941ff08d2e460c653ea948fbd88d7ad2620b
URL: https://github.com/llvm/llvm-project/commit/a0d1941ff08d2e460c653ea948fbd88d7ad2620b DIFF: https://github.com/llvm/llvm-project/commit/a0d1941ff08d2e460c653ea948fbd88d7ad2620b.diff LOG: [IndVars] Add test cases inspired by PR48965. Added: llvm/test/Transforms/IndVarSimplify/simplify-pointer-arithmetic.ll Modified: Removed: ################################################################################ diff --git a/llvm/test/Transforms/IndVarSimplify/simplify-pointer-arithmetic.ll b/llvm/test/Transforms/IndVarSimplify/simplify-pointer-arithmetic.ll new file mode 100644 index 000000000000..6ca5f43bb7d7 --- /dev/null +++ b/llvm/test/Transforms/IndVarSimplify/simplify-pointer-arithmetic.ll @@ -0,0 +1,377 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --check-attributes +; RUN: opt -indvars -S %s | FileCheck %s + +; Test cases inspired by PR48965. + +; %len is zero-extended before being used to compute %p.end, which guarantees +; the offset is positive. %i.ult.ext can be simplified. +define i1 @can_simplify_ult_i32_ptr_len_zext(i32* %p.base, i32 %len) { +; CHECK-LABEL: @can_simplify_ult_i32_ptr_len_zext( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[EXT:%.*]] = zext i32 [[LEN:%.*]] to i64 +; CHECK-NEXT: [[P_END:%.*]] = getelementptr inbounds i32, i32* [[P_BASE:%.*]], i64 [[EXT]] +; CHECK-NEXT: [[LEN_NONZERO:%.*]] = icmp ne i32 [[LEN]], 0 +; CHECK-NEXT: br i1 [[LEN_NONZERO]], label [[HEADER_PREHEADER:%.*]], label [[TRAP:%.*]] +; CHECK: header.preheader: +; CHECK-NEXT: br label [[HEADER:%.*]] +; CHECK: trap.loopexit: +; CHECK-NEXT: br label [[TRAP]] +; CHECK: trap: +; CHECK-NEXT: ret i1 false +; CHECK: header: +; CHECK-NEXT: [[P:%.*]] = phi i32* [ [[P_INC:%.*]], [[LATCH:%.*]] ], [ [[P_BASE]], [[HEADER_PREHEADER]] ] +; CHECK-NEXT: [[I:%.*]] = phi i64 [ [[I_INC:%.*]], [[LATCH]] ], [ 0, [[HEADER_PREHEADER]] ] +; CHECK-NEXT: [[I_INC]] = add nuw nsw i64 [[I]], 1 +; CHECK-NEXT: [[I_ULT_EXT:%.*]] = icmp ult i64 [[I]], [[EXT]] +; CHECK-NEXT: br i1 [[I_ULT_EXT]], label [[LATCH]], label [[TRAP_LOOPEXIT:%.*]] +; CHECK: latch: +; CHECK-NEXT: [[P_INC]] = getelementptr inbounds i32, i32* [[P]], i64 1 +; CHECK-NEXT: [[C:%.*]] = icmp ne i32* [[P_INC]], [[P_END]] +; CHECK-NEXT: store i32 0, i32* [[P]], align 4 +; CHECK-NEXT: br i1 [[C]], label [[HEADER]], label [[EXIT:%.*]] +; CHECK: exit: +; CHECK-NEXT: ret i1 true +; +entry: + %ext = zext i32 %len to i64 + %p.end = getelementptr inbounds i32, i32* %p.base, i64 %ext + %len.nonzero = icmp ne i32 %len, 0 + br i1 %len.nonzero, label %header, label %trap + +trap: + ret i1 false + +header: + %p = phi i32* [ %p.base, %entry ], [ %p.inc, %latch ] + %i = phi i64 [ 0, %entry ], [ %i.inc, %latch] + %i.inc = add nsw nuw i64 %i, 1 + %i.ult.ext = icmp ult i64 %i, %ext + br i1 %i.ult.ext, label %latch, label %trap + +latch: + %p.inc = getelementptr inbounds i32, i32* %p, i64 1 + %c = icmp ne i32* %p.inc, %p.end + store i32 0, i32* %p + br i1 %c, label %header, label %exit + +exit: + ret i1 true +} + +; %len may be (signed) negative, %i.ult.ext cannot be simplified. +define i1 @cannot_simplify_ult_i32_ptr_len_ult(i32* %p.base, i64 %len) { +; CHECK-LABEL: @cannot_simplify_ult_i32_ptr_len_ult( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[P_END:%.*]] = getelementptr inbounds i32, i32* [[P_BASE:%.*]], i64 [[LEN:%.*]] +; CHECK-NEXT: [[LEN_NONZERO:%.*]] = icmp ne i64 [[LEN]], 0 +; CHECK-NEXT: br i1 [[LEN_NONZERO]], label [[HEADER_PREHEADER:%.*]], label [[TRAP:%.*]] +; CHECK: header.preheader: +; CHECK-NEXT: br label [[HEADER:%.*]] +; CHECK: trap.loopexit: +; CHECK-NEXT: br label [[TRAP]] +; CHECK: trap: +; CHECK-NEXT: ret i1 false +; CHECK: header: +; CHECK-NEXT: [[P:%.*]] = phi i32* [ [[P_INC:%.*]], [[LATCH:%.*]] ], [ [[P_BASE]], [[HEADER_PREHEADER]] ] +; CHECK-NEXT: [[I:%.*]] = phi i64 [ [[I_INC:%.*]], [[LATCH]] ], [ 0, [[HEADER_PREHEADER]] ] +; CHECK-NEXT: [[I_INC]] = add nuw nsw i64 [[I]], 1 +; CHECK-NEXT: [[I_ULT_EXT:%.*]] = icmp ult i64 [[I]], [[LEN]] +; CHECK-NEXT: br i1 [[I_ULT_EXT]], label [[LATCH]], label [[TRAP_LOOPEXIT:%.*]] +; CHECK: latch: +; CHECK-NEXT: [[P_INC]] = getelementptr inbounds i32, i32* [[P]], i64 1 +; CHECK-NEXT: [[C:%.*]] = icmp ne i32* [[P_INC]], [[P_END]] +; CHECK-NEXT: store i32 0, i32* [[P]], align 4 +; CHECK-NEXT: br i1 [[C]], label [[HEADER]], label [[EXIT:%.*]] +; CHECK: exit: +; CHECK-NEXT: ret i1 true +; +entry: + %p.end = getelementptr inbounds i32, i32* %p.base, i64 %len + %len.nonzero = icmp ne i64 %len, 0 + br i1 %len.nonzero, label %header, label %trap + +trap: + ret i1 false + +header: + %p = phi i32* [ %p.base, %entry ], [ %p.inc, %latch ] + %i = phi i64 [ 0, %entry ], [ %i.inc, %latch] + %i.inc = add nsw nuw i64 %i, 1 + %i.ult.ext = icmp ult i64 %i, %len + br i1 %i.ult.ext, label %latch, label %trap + +latch: + %p.inc = getelementptr inbounds i32, i32* %p, i64 1 + %c = icmp ne i32* %p.inc, %p.end + store i32 0, i32* %p + br i1 %c, label %header, label %exit + +exit: + ret i1 true +} + +; Similar to can_simplify_ult_i32_ptr_len_zext, but %i has 1 as start value. %i.ult.ext cannot be simplified. +define i1 @cannot_simplify_ult_i32_ptr_len_zext(i32* %p.base, i32 %len) { +; CHECK-LABEL: @cannot_simplify_ult_i32_ptr_len_zext( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[EXT:%.*]] = zext i32 [[LEN:%.*]] to i64 +; CHECK-NEXT: [[P_END:%.*]] = getelementptr inbounds i32, i32* [[P_BASE:%.*]], i64 [[EXT]] +; CHECK-NEXT: [[LEN_NONZERO:%.*]] = icmp ne i32 [[LEN]], 0 +; CHECK-NEXT: br i1 [[LEN_NONZERO]], label [[HEADER_PREHEADER:%.*]], label [[TRAP:%.*]] +; CHECK: header.preheader: +; CHECK-NEXT: br label [[HEADER:%.*]] +; CHECK: trap.loopexit: +; CHECK-NEXT: br label [[TRAP]] +; CHECK: trap: +; CHECK-NEXT: ret i1 false +; CHECK: header: +; CHECK-NEXT: [[P:%.*]] = phi i32* [ [[P_INC:%.*]], [[LATCH:%.*]] ], [ [[P_BASE]], [[HEADER_PREHEADER]] ] +; CHECK-NEXT: [[I:%.*]] = phi i64 [ [[I_INC:%.*]], [[LATCH]] ], [ 1, [[HEADER_PREHEADER]] ] +; CHECK-NEXT: [[I_INC]] = add nuw nsw i64 [[I]], 1 +; CHECK-NEXT: [[I_ULT_EXT:%.*]] = icmp ult i64 [[I]], [[EXT]] +; CHECK-NEXT: br i1 [[I_ULT_EXT]], label [[LATCH]], label [[TRAP_LOOPEXIT:%.*]] +; CHECK: latch: +; CHECK-NEXT: [[P_INC]] = getelementptr inbounds i32, i32* [[P]], i64 1 +; CHECK-NEXT: [[C:%.*]] = icmp ne i32* [[P_INC]], [[P_END]] +; CHECK-NEXT: store i32 0, i32* [[P]], align 4 +; CHECK-NEXT: br i1 [[C]], label [[HEADER]], label [[EXIT:%.*]] +; CHECK: exit: +; CHECK-NEXT: ret i1 true +; +entry: + %ext = zext i32 %len to i64 + %p.end = getelementptr inbounds i32, i32* %p.base, i64 %ext + %len.nonzero = icmp ne i32 %len, 0 + br i1 %len.nonzero, label %header, label %trap + +trap: + ret i1 false + +header: + %p = phi i32* [ %p.base, %entry ], [ %p.inc, %latch ] + %i = phi i64 [ 1, %entry ], [ %i.inc, %latch] + %i.inc = add nsw nuw i64 %i, 1 + %i.ult.ext = icmp ult i64 %i, %ext + br i1 %i.ult.ext, label %latch, label %trap + +latch: + %p.inc = getelementptr inbounds i32, i32* %p, i64 1 + %c = icmp ne i32* %p.inc, %p.end + store i32 0, i32* %p + br i1 %c, label %header, label %exit + +exit: + ret i1 true +} + +define i1 @can_simplify_ule_i32_ptr_len_zext(i32* %p.base, i32 %len) { +; CHECK-LABEL: @can_simplify_ule_i32_ptr_len_zext( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[EXT:%.*]] = zext i32 [[LEN:%.*]] to i64 +; CHECK-NEXT: [[P_END:%.*]] = getelementptr inbounds i32, i32* [[P_BASE:%.*]], i64 [[EXT]] +; CHECK-NEXT: [[LEN_NONZERO:%.*]] = icmp ne i32 [[LEN]], 0 +; CHECK-NEXT: br i1 [[LEN_NONZERO]], label [[HEADER_PREHEADER:%.*]], label [[TRAP:%.*]] +; CHECK: header.preheader: +; CHECK-NEXT: br label [[HEADER:%.*]] +; CHECK: trap.loopexit: +; CHECK-NEXT: br label [[TRAP]] +; CHECK: trap: +; CHECK-NEXT: ret i1 false +; CHECK: header: +; CHECK-NEXT: [[P:%.*]] = phi i32* [ [[P_INC:%.*]], [[LATCH:%.*]] ], [ [[P_BASE]], [[HEADER_PREHEADER]] ] +; CHECK-NEXT: [[I:%.*]] = phi i64 [ [[I_INC:%.*]], [[LATCH]] ], [ 1, [[HEADER_PREHEADER]] ] +; CHECK-NEXT: [[I_INC]] = add nuw nsw i64 [[I]], 1 +; CHECK-NEXT: [[I_ULT_EXT:%.*]] = icmp ule i64 [[I]], [[EXT]] +; CHECK-NEXT: br i1 [[I_ULT_EXT]], label [[LATCH]], label [[TRAP_LOOPEXIT:%.*]] +; CHECK: latch: +; CHECK-NEXT: [[P_INC]] = getelementptr inbounds i32, i32* [[P]], i64 1 +; CHECK-NEXT: [[C:%.*]] = icmp ne i32* [[P_INC]], [[P_END]] +; CHECK-NEXT: store i32 0, i32* [[P]], align 4 +; CHECK-NEXT: br i1 [[C]], label [[HEADER]], label [[EXIT:%.*]] +; CHECK: exit: +; CHECK-NEXT: ret i1 true +; +entry: + %ext = zext i32 %len to i64 + %p.end = getelementptr inbounds i32, i32* %p.base, i64 %ext + %len.nonzero = icmp ne i32 %len, 0 + br i1 %len.nonzero, label %header, label %trap + +trap: + ret i1 false + +header: + %p = phi i32* [ %p.base, %entry ], [ %p.inc, %latch ] + %i = phi i64 [ 1, %entry ], [ %i.inc, %latch] + %i.inc = add nsw nuw i64 %i, 1 + %i.ult.ext = icmp ule i64 %i, %ext + br i1 %i.ult.ext, label %latch, label %trap + +latch: + %p.inc = getelementptr inbounds i32, i32* %p, i64 1 + %c = icmp ne i32* %p.inc, %p.end + store i32 0, i32* %p + br i1 %c, label %header, label %exit + +exit: + ret i1 true +} + +; %len is zero-extended before being used to compute %p.end, which guarantees +; the offset is positive. %i.uge.ext can be simplified. +define i1 @can_simplify_uge_i32_ptr_len_zext(i32* %p.base, i32 %len) { +; CHECK-LABEL: @can_simplify_uge_i32_ptr_len_zext( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[EXT:%.*]] = zext i32 [[LEN:%.*]] to i64 +; CHECK-NEXT: [[P_END:%.*]] = getelementptr inbounds i32, i32* [[P_BASE:%.*]], i64 [[EXT]] +; CHECK-NEXT: [[LEN_NONZERO:%.*]] = icmp ne i32 [[LEN]], 0 +; CHECK-NEXT: br i1 [[LEN_NONZERO]], label [[HEADER_PREHEADER:%.*]], label [[TRAP:%.*]] +; CHECK: header.preheader: +; CHECK-NEXT: br label [[HEADER:%.*]] +; CHECK: trap.loopexit: +; CHECK-NEXT: br label [[TRAP]] +; CHECK: trap: +; CHECK-NEXT: ret i1 false +; CHECK: header: +; CHECK-NEXT: [[P:%.*]] = phi i32* [ [[P_INC:%.*]], [[LATCH:%.*]] ], [ [[P_BASE]], [[HEADER_PREHEADER]] ] +; CHECK-NEXT: [[I:%.*]] = phi i64 [ [[I_INC:%.*]], [[LATCH]] ], [ 0, [[HEADER_PREHEADER]] ] +; CHECK-NEXT: [[I_INC]] = add nuw nsw i64 [[I]], 1 +; CHECK-NEXT: [[I_UGE_EXT:%.*]] = icmp uge i64 [[I]], [[EXT]] +; CHECK-NEXT: br i1 [[I_UGE_EXT]], label [[TRAP_LOOPEXIT:%.*]], label [[LATCH]] +; CHECK: latch: +; CHECK-NEXT: [[P_INC]] = getelementptr inbounds i32, i32* [[P]], i64 1 +; CHECK-NEXT: [[C:%.*]] = icmp ne i32* [[P_INC]], [[P_END]] +; CHECK-NEXT: store i32 0, i32* [[P]], align 4 +; CHECK-NEXT: br i1 [[C]], label [[HEADER]], label [[EXIT:%.*]] +; CHECK: exit: +; CHECK-NEXT: ret i1 true +; +entry: + %ext = zext i32 %len to i64 + %p.end = getelementptr inbounds i32, i32* %p.base, i64 %ext + %len.nonzero = icmp ne i32 %len, 0 + br i1 %len.nonzero, label %header, label %trap + +trap: + ret i1 false + +header: + %p = phi i32* [ %p.base, %entry ], [ %p.inc, %latch ] + %i = phi i64 [ 0, %entry ], [ %i.inc, %latch] + %i.inc = add nsw nuw i64 %i, 1 + %i.uge.ext = icmp uge i64 %i, %ext + br i1 %i.uge.ext, label %trap, label %latch + +latch: + %p.inc = getelementptr inbounds i32, i32* %p, i64 1 + %c = icmp ne i32* %p.inc, %p.end + store i32 0, i32* %p + br i1 %c, label %header, label %exit + +exit: + ret i1 true +} + +define i1 @cannot_simplify_uge_i32_ptr_len(i32* %p.base, i64 %len) { +; CHECK-LABEL: @cannot_simplify_uge_i32_ptr_len( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[P_END:%.*]] = getelementptr inbounds i32, i32* [[P_BASE:%.*]], i64 [[LEN:%.*]] +; CHECK-NEXT: [[LEN_NONZERO:%.*]] = icmp ne i64 [[LEN]], 0 +; CHECK-NEXT: br i1 [[LEN_NONZERO]], label [[HEADER_PREHEADER:%.*]], label [[TRAP:%.*]] +; CHECK: header.preheader: +; CHECK-NEXT: br label [[HEADER:%.*]] +; CHECK: trap.loopexit: +; CHECK-NEXT: br label [[TRAP]] +; CHECK: trap: +; CHECK-NEXT: ret i1 false +; CHECK: header: +; CHECK-NEXT: [[P:%.*]] = phi i32* [ [[P_INC:%.*]], [[LATCH:%.*]] ], [ [[P_BASE]], [[HEADER_PREHEADER]] ] +; CHECK-NEXT: [[I:%.*]] = phi i64 [ [[I_INC:%.*]], [[LATCH]] ], [ 0, [[HEADER_PREHEADER]] ] +; CHECK-NEXT: [[I_INC]] = add nuw nsw i64 [[I]], 1 +; CHECK-NEXT: [[I_UGE_EXT:%.*]] = icmp uge i64 [[I]], [[LEN]] +; CHECK-NEXT: br i1 [[I_UGE_EXT]], label [[TRAP_LOOPEXIT:%.*]], label [[LATCH]] +; CHECK: latch: +; CHECK-NEXT: [[P_INC]] = getelementptr inbounds i32, i32* [[P]], i64 1 +; CHECK-NEXT: [[C:%.*]] = icmp ne i32* [[P_INC]], [[P_END]] +; CHECK-NEXT: store i32 0, i32* [[P]], align 4 +; CHECK-NEXT: br i1 [[C]], label [[HEADER]], label [[EXIT:%.*]] +; CHECK: exit: +; CHECK-NEXT: ret i1 true +; +entry: + %p.end = getelementptr inbounds i32, i32* %p.base, i64 %len + %len.nonzero = icmp ne i64 %len, 0 + br i1 %len.nonzero, label %header, label %trap + +trap: + ret i1 false + +header: + %p = phi i32* [ %p.base, %entry ], [ %p.inc, %latch ] + %i = phi i64 [ 0, %entry ], [ %i.inc, %latch] + %i.inc = add nsw nuw i64 %i, 1 + %i.uge.ext = icmp uge i64 %i, %len + br i1 %i.uge.ext, label %trap, label %latch + +latch: + %p.inc = getelementptr inbounds i32, i32* %p, i64 1 + %c = icmp ne i32* %p.inc, %p.end + store i32 0, i32* %p + br i1 %c, label %header, label %exit + +exit: + ret i1 true +} + +define i1 @cannot_simplify_uge_i32_ptr_len_zext_step_2(i32* %p.base, i32 %len) { +; CHECK-LABEL: @cannot_simplify_uge_i32_ptr_len_zext_step_2( +; CHECK-NEXT: entry: +; CHECK-NEXT: [[EXT:%.*]] = zext i32 [[LEN:%.*]] to i64 +; CHECK-NEXT: [[P_END:%.*]] = getelementptr inbounds i32, i32* [[P_BASE:%.*]], i64 [[EXT]] +; CHECK-NEXT: [[LEN_NONZERO:%.*]] = icmp ne i32 [[LEN]], 0 +; CHECK-NEXT: br i1 [[LEN_NONZERO]], label [[HEADER_PREHEADER:%.*]], label [[TRAP:%.*]] +; CHECK: header.preheader: +; CHECK-NEXT: br label [[HEADER:%.*]] +; CHECK: trap.loopexit: +; CHECK-NEXT: br label [[TRAP]] +; CHECK: trap: +; CHECK-NEXT: ret i1 false +; CHECK: header: +; CHECK-NEXT: [[P:%.*]] = phi i32* [ [[P_INC:%.*]], [[LATCH:%.*]] ], [ [[P_BASE]], [[HEADER_PREHEADER]] ] +; CHECK-NEXT: [[I:%.*]] = phi i64 [ [[I_INC:%.*]], [[LATCH]] ], [ 0, [[HEADER_PREHEADER]] ] +; CHECK-NEXT: [[I_INC]] = add nuw nsw i64 [[I]], 2 +; CHECK-NEXT: [[I_UGE_EXT:%.*]] = icmp uge i64 [[I]], [[EXT]] +; CHECK-NEXT: br i1 [[I_UGE_EXT]], label [[TRAP_LOOPEXIT:%.*]], label [[LATCH]] +; CHECK: latch: +; CHECK-NEXT: [[P_INC]] = getelementptr inbounds i32, i32* [[P]], i64 1 +; CHECK-NEXT: [[C:%.*]] = icmp ne i32* [[P_INC]], [[P_END]] +; CHECK-NEXT: store i32 0, i32* [[P]], align 4 +; CHECK-NEXT: br i1 [[C]], label [[HEADER]], label [[EXIT:%.*]] +; CHECK: exit: +; CHECK-NEXT: ret i1 true +; +entry: + %ext = zext i32 %len to i64 + %p.end = getelementptr inbounds i32, i32* %p.base, i64 %ext + %len.nonzero = icmp ne i32 %len, 0 + br i1 %len.nonzero, label %header, label %trap + +trap: + ret i1 false + +header: + %p = phi i32* [ %p.base, %entry ], [ %p.inc, %latch ] + %i = phi i64 [ 0, %entry ], [ %i.inc, %latch] + %i.inc = add nsw nuw i64 %i, 2 + %i.uge.ext = icmp uge i64 %i, %ext + br i1 %i.uge.ext, label %trap, label %latch + +latch: + %p.inc = getelementptr inbounds i32, i32* %p, i64 1 + %c = icmp ne i32* %p.inc, %p.end + store i32 0, i32* %p + br i1 %c, label %header, label %exit + +exit: + ret i1 true +} _______________________________________________ llvm-branch-commits mailing list llvm-branch-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits