diff options
| -rw-r--r-- | llvm/test/Transforms/InstSimplify/icmp-abs-nabs.ll | 401 |
1 files changed, 401 insertions, 0 deletions
diff --git a/llvm/test/Transforms/InstSimplify/icmp-abs-nabs.ll b/llvm/test/Transforms/InstSimplify/icmp-abs-nabs.ll new file mode 100644 index 00000000000..1cb312bf0da --- /dev/null +++ b/llvm/test/Transforms/InstSimplify/icmp-abs-nabs.ll @@ -0,0 +1,401 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py +; RUN: opt < %s -instsimplify -S | FileCheck %s + +; This is canonical form for this IR. + +define i1 @abs_nsw_is_positive(i32 %x) { +; CHECK-LABEL: @abs_nsw_is_positive( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 0 +; CHECK-NEXT: [[NEGX:%.*]] = sub nsw i32 0, [[X]] +; CHECK-NEXT: [[ABS:%.*]] = select i1 [[CMP]], i32 [[NEGX]], i32 [[X]] +; CHECK-NEXT: [[R:%.*]] = icmp sgt i32 [[ABS]], -1 +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp slt i32 %x, 0 + %negx = sub nsw i32 0, %x + %abs = select i1 %cmp, i32 %negx, i32 %x + %r = icmp sgt i32 %abs, -1 + ret i1 %r +} + +; Test non-canonical predicate and non-canonical form of abs(). + +define i1 @abs_nsw_is_positive_sge(i32 %x) { +; CHECK-LABEL: @abs_nsw_is_positive_sge( +; CHECK-NEXT: ret i1 true +; + %cmp = icmp slt i32 %x, 1 + %negx = sub nsw i32 0, %x + %abs = select i1 %cmp, i32 %negx, i32 %x + %r = icmp sge i32 %abs, 0 + ret i1 %r +} + +; This is a range-based analysis. Any negative constant works. + +define i1 @abs_nsw_is_positive_reduced_range(i32 %x) { +; CHECK-LABEL: @abs_nsw_is_positive_reduced_range( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 0 +; CHECK-NEXT: [[NEGX:%.*]] = sub nsw i32 0, [[X]] +; CHECK-NEXT: [[ABS:%.*]] = select i1 [[CMP]], i32 [[NEGX]], i32 [[X]] +; CHECK-NEXT: [[R:%.*]] = icmp sgt i32 [[ABS]], -42 +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp slt i32 %x, 0 + %negx = sub nsw i32 0, %x + %abs = select i1 %cmp, i32 %negx, i32 %x + %r = icmp sgt i32 %abs, -42 + ret i1 %r +} + +; Negative test - we need 'nsw' in the abs(). + +define i1 @abs_is_positive_reduced_range(i32 %x) { +; CHECK-LABEL: @abs_is_positive_reduced_range( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 0 +; CHECK-NEXT: [[NEGX:%.*]] = sub i32 0, [[X]] +; CHECK-NEXT: [[ABS:%.*]] = select i1 [[CMP]], i32 [[NEGX]], i32 [[X]] +; CHECK-NEXT: [[R:%.*]] = icmp sgt i32 [[ABS]], 42 +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp slt i32 %x, 0 + %negx = sub i32 0, %x + %abs = select i1 %cmp, i32 %negx, i32 %x + %r = icmp sgt i32 %abs, 42 + ret i1 %r +} + +; Negative test - range intersection is not subset. + +define i1 @abs_nsw_is_positive_wrong_range(i32 %x) { +; CHECK-LABEL: @abs_nsw_is_positive_wrong_range( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 0 +; CHECK-NEXT: [[NEGX:%.*]] = sub nsw i32 0, [[X]] +; CHECK-NEXT: [[ABS:%.*]] = select i1 [[CMP]], i32 [[NEGX]], i32 [[X]] +; CHECK-NEXT: [[R:%.*]] = icmp sgt i32 [[ABS]], 0 +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp slt i32 %x, 0 + %negx = sub nsw i32 0, %x + %abs = select i1 %cmp, i32 %negx, i32 %x + %r = icmp sgt i32 %abs, 0 + ret i1 %r +} + +; This is canonical form for this IR. + +define i1 @abs_nsw_is_not_negative(i32 %x) { +; CHECK-LABEL: @abs_nsw_is_not_negative( +; CHECK-NEXT: ret i1 false +; + %cmp = icmp slt i32 %x, 0 + %negx = sub nsw i32 0, %x + %abs = select i1 %cmp, i32 %negx, i32 %x + %r = icmp slt i32 %abs, 0 + ret i1 %r +} + +; Test non-canonical predicate and non-canonical form of abs(). + +define i1 @abs_nsw_is_not_negative_sle(i32 %x) { +; CHECK-LABEL: @abs_nsw_is_not_negative_sle( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 1 +; CHECK-NEXT: [[NEGX:%.*]] = sub nsw i32 0, [[X]] +; CHECK-NEXT: [[ABS:%.*]] = select i1 [[CMP]], i32 [[NEGX]], i32 [[X]] +; CHECK-NEXT: [[R:%.*]] = icmp sle i32 [[ABS]], -1 +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp slt i32 %x, 1 + %negx = sub nsw i32 0, %x + %abs = select i1 %cmp, i32 %negx, i32 %x + %r = icmp sle i32 %abs, -1 + ret i1 %r +} + +; This is a range-based analysis. Any negative constant works. + +define i1 @abs_nsw_is_not_negative_reduced_range(i32 %x) { +; CHECK-LABEL: @abs_nsw_is_not_negative_reduced_range( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 0 +; CHECK-NEXT: [[NEGX:%.*]] = sub nsw i32 0, [[X]] +; CHECK-NEXT: [[ABS:%.*]] = select i1 [[CMP]], i32 [[NEGX]], i32 [[X]] +; CHECK-NEXT: [[R:%.*]] = icmp slt i32 [[ABS]], -24 +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp slt i32 %x, 0 + %negx = sub nsw i32 0, %x + %abs = select i1 %cmp, i32 %negx, i32 %x + %r = icmp slt i32 %abs, -24 + ret i1 %r +} + +; Negative test - we need 'nsw' in the abs(). + +define i1 @abs_is_not_negative_reduced_range(i32 %x) { +; CHECK-LABEL: @abs_is_not_negative_reduced_range( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 0 +; CHECK-NEXT: [[NEGX:%.*]] = sub i32 0, [[X]] +; CHECK-NEXT: [[ABS:%.*]] = select i1 [[CMP]], i32 [[NEGX]], i32 [[X]] +; CHECK-NEXT: [[R:%.*]] = icmp slt i32 [[ABS]], 42 +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp slt i32 %x, 0 + %negx = sub i32 0, %x + %abs = select i1 %cmp, i32 %negx, i32 %x + %r = icmp slt i32 %abs, 42 + ret i1 %r +} + +; Negative test - range intersection is not empty. + +define i1 @abs_nsw_is_not_negative_wrong_range(i32 %x) { +; CHECK-LABEL: @abs_nsw_is_not_negative_wrong_range( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 0 +; CHECK-NEXT: [[NEGX:%.*]] = sub nsw i32 0, [[X]] +; CHECK-NEXT: [[ABS:%.*]] = select i1 [[CMP]], i32 [[NEGX]], i32 [[X]] +; CHECK-NEXT: [[R:%.*]] = icmp sle i32 [[ABS]], 0 +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp slt i32 %x, 0 + %negx = sub nsw i32 0, %x + %abs = select i1 %cmp, i32 %negx, i32 %x + %r = icmp sle i32 %abs, 0 + ret i1 %r +} + +; This is canonical form for this IR. For nabs(), we don't require 'nsw' + +define i1 @nabs_is_negative_or_0(i32 %x) { +; CHECK-LABEL: @nabs_is_negative_or_0( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 0 +; CHECK-NEXT: [[NEGX:%.*]] = sub i32 0, [[X]] +; CHECK-NEXT: [[NABS:%.*]] = select i1 [[CMP]], i32 [[X]], i32 [[NEGX]] +; CHECK-NEXT: [[R:%.*]] = icmp slt i32 [[NABS]], 1 +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp slt i32 %x, 0 + %negx = sub i32 0, %x + %nabs = select i1 %cmp, i32 %x, i32 %negx + %r = icmp slt i32 %nabs, 1 + ret i1 %r +} + +; Test non-canonical predicate and non-canonical form of nabs(). + +define i1 @nabs_is_negative_or_0_sle(i32 %x) { +; CHECK-LABEL: @nabs_is_negative_or_0_sle( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 1 +; CHECK-NEXT: [[NEGX:%.*]] = sub i32 0, [[X]] +; CHECK-NEXT: [[NABS:%.*]] = select i1 [[CMP]], i32 [[X]], i32 [[NEGX]] +; CHECK-NEXT: [[R:%.*]] = icmp sle i32 [[NABS]], 0 +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp slt i32 %x, 1 + %negx = sub i32 0, %x + %nabs = select i1 %cmp, i32 %x, i32 %negx + %r = icmp sle i32 %nabs, 0 + ret i1 %r +} + +; This is a range-based analysis. Any positive constant works. + +define i1 @nabs_is_negative_or_0_reduced_range(i32 %x) { +; CHECK-LABEL: @nabs_is_negative_or_0_reduced_range( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 1 +; CHECK-NEXT: [[NEGX:%.*]] = sub i32 0, [[X]] +; CHECK-NEXT: [[NABS:%.*]] = select i1 [[CMP]], i32 [[X]], i32 [[NEGX]] +; CHECK-NEXT: [[R:%.*]] = icmp slt i32 [[NABS]], 421 +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp slt i32 %x, 1 + %negx = sub i32 0, %x + %nabs = select i1 %cmp, i32 %x, i32 %negx + %r = icmp slt i32 %nabs, 421 + ret i1 %r +} + +; Negative test - range intersection is not subset. + +define i1 @nabs_is_negative_or_0_wrong_range(i32 %x) { +; CHECK-LABEL: @nabs_is_negative_or_0_wrong_range( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 1 +; CHECK-NEXT: [[NEGX:%.*]] = sub i32 0, [[X]] +; CHECK-NEXT: [[NABS:%.*]] = select i1 [[CMP]], i32 [[X]], i32 [[NEGX]] +; CHECK-NEXT: [[R:%.*]] = icmp slt i32 [[NABS]], 0 +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp slt i32 %x, 1 + %negx = sub i32 0, %x + %nabs = select i1 %cmp, i32 %x, i32 %negx + %r = icmp slt i32 %nabs, 0 + ret i1 %r +} + +; This is canonical form for this IR. For nabs(), we don't require 'nsw' + +define i1 @nabs_is_not_over_0(i32 %x) { +; CHECK-LABEL: @nabs_is_not_over_0( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 0 +; CHECK-NEXT: [[NEGX:%.*]] = sub i32 0, [[X]] +; CHECK-NEXT: [[NABS:%.*]] = select i1 [[CMP]], i32 [[X]], i32 [[NEGX]] +; CHECK-NEXT: [[R:%.*]] = icmp sgt i32 [[NABS]], 0 +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp slt i32 %x, 0 + %negx = sub i32 0, %x + %nabs = select i1 %cmp, i32 %x, i32 %negx + %r = icmp sgt i32 %nabs, 0 + ret i1 %r +} + +; Test non-canonical predicate and non-canonical form of nabs(). + +define i1 @nabs_is_not_over_0_sle(i32 %x) { +; CHECK-LABEL: @nabs_is_not_over_0_sle( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 1 +; CHECK-NEXT: [[NEGX:%.*]] = sub i32 0, [[X]] +; CHECK-NEXT: [[NABS:%.*]] = select i1 [[CMP]], i32 [[X]], i32 [[NEGX]] +; CHECK-NEXT: [[R:%.*]] = icmp sge i32 [[NABS]], 1 +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp slt i32 %x, 1 + %negx = sub i32 0, %x + %nabs = select i1 %cmp, i32 %x, i32 %negx + %r = icmp sge i32 %nabs, 1 + ret i1 %r +} + +; This is a range-based analysis. Any positive constant works. + +define i1 @nabs_is_not_over_0_reduced_range(i32 %x) { +; CHECK-LABEL: @nabs_is_not_over_0_reduced_range( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 1 +; CHECK-NEXT: [[NEGX:%.*]] = sub i32 0, [[X]] +; CHECK-NEXT: [[NABS:%.*]] = select i1 [[CMP]], i32 [[X]], i32 [[NEGX]] +; CHECK-NEXT: [[R:%.*]] = icmp sgt i32 [[NABS]], 4223 +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp slt i32 %x, 1 + %negx = sub i32 0, %x + %nabs = select i1 %cmp, i32 %x, i32 %negx + %r = icmp sgt i32 %nabs, 4223 + ret i1 %r +} + +; Negative test - range intersection is not subset. + +define i1 @nabs_is_not_over_0_wrong_range(i32 %x) { +; CHECK-LABEL: @nabs_is_not_over_0_wrong_range( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[X:%.*]], 1 +; CHECK-NEXT: [[NEGX:%.*]] = sub i32 0, [[X]] +; CHECK-NEXT: [[NABS:%.*]] = select i1 [[CMP]], i32 [[X]], i32 [[NEGX]] +; CHECK-NEXT: [[R:%.*]] = icmp sgt i32 [[NABS]], -1 +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp slt i32 %x, 1 + %negx = sub i32 0, %x + %nabs = select i1 %cmp, i32 %x, i32 %negx + %r = icmp sgt i32 %nabs, -1 + ret i1 %r +} + +; More miscellaneous tests for predicates/types. + +; Equality predicates are ok. + +define i1 @abs_nsw_is_positive_eq(i32 %x) { +; CHECK-LABEL: @abs_nsw_is_positive_eq( +; CHECK-NEXT: ret i1 false +; + %cmp = icmp slt i32 %x, 1 + %negx = sub nsw i32 0, %x + %abs = select i1 %cmp, i32 %negx, i32 %x + %r = icmp eq i32 %abs, -8 + ret i1 %r +} + +; An unsigned compare may work. + +define i1 @abs_nsw_is_positive_ult(i8 %x) { +; CHECK-LABEL: @abs_nsw_is_positive_ult( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 0 +; CHECK-NEXT: [[NEGX:%.*]] = sub nsw i8 0, [[X]] +; CHECK-NEXT: [[ABS:%.*]] = select i1 [[CMP]], i8 [[NEGX]], i8 [[X]] +; CHECK-NEXT: [[R:%.*]] = icmp ult i8 [[ABS]], -117 +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp slt i8 %x, 0 + %negx = sub nsw i8 0, %x + %abs = select i1 %cmp, i8 %negx, i8 %x + %r = icmp ult i8 %abs, 139 + ret i1 %r +} + +; An unsigned compare may work. + +define i1 @abs_nsw_is_not_negative_ugt(i8 %x) { +; CHECK-LABEL: @abs_nsw_is_not_negative_ugt( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 0 +; CHECK-NEXT: [[NEGX:%.*]] = sub nsw i8 0, [[X]] +; CHECK-NEXT: [[ABS:%.*]] = select i1 [[CMP]], i8 [[NEGX]], i8 [[X]] +; CHECK-NEXT: [[R:%.*]] = icmp ugt i8 [[ABS]], 127 +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp slt i8 %x, 0 + %negx = sub nsw i8 0, %x + %abs = select i1 %cmp, i8 %negx, i8 %x + %r = icmp ugt i8 %abs, 127 + ret i1 %r +} + +; Vector types are ok. + +define <2 x i1> @abs_nsw_is_not_negative_vec_splat(<2 x i32> %x) { +; CHECK-LABEL: @abs_nsw_is_not_negative_vec_splat( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt <2 x i32> [[X:%.*]], zeroinitializer +; CHECK-NEXT: [[NEGX:%.*]] = sub nsw <2 x i32> zeroinitializer, [[X]] +; CHECK-NEXT: [[ABS:%.*]] = select <2 x i1> [[CMP]], <2 x i32> [[NEGX]], <2 x i32> [[X]] +; CHECK-NEXT: [[R:%.*]] = icmp slt <2 x i32> [[ABS]], <i32 -8, i32 -8> +; CHECK-NEXT: ret <2 x i1> [[R]] +; + %cmp = icmp slt <2 x i32> %x, zeroinitializer + %negx = sub nsw <2 x i32> zeroinitializer, %x + %abs = select <2 x i1> %cmp, <2 x i32> %negx, <2 x i32> %x + %r = icmp slt <2 x i32> %abs, <i32 -8, i32 -8> + ret <2 x i1> %r +} + +; Equality predicates are ok. + +define i1 @nabs_is_negative_or_0_ne(i8 %x) { +; CHECK-LABEL: @nabs_is_negative_or_0_ne( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt i8 [[X:%.*]], 0 +; CHECK-NEXT: [[NEGX:%.*]] = sub i8 0, [[X]] +; CHECK-NEXT: [[NABS:%.*]] = select i1 [[CMP]], i8 [[X]], i8 [[NEGX]] +; CHECK-NEXT: [[R:%.*]] = icmp ne i8 [[NABS]], 12 +; CHECK-NEXT: ret i1 [[R]] +; + %cmp = icmp slt i8 %x, 0 + %negx = sub i8 0, %x + %nabs = select i1 %cmp, i8 %x, i8 %negx + %r = icmp ne i8 %nabs, 12 + ret i1 %r +} + +; Vector types are ok. + +define <3 x i1> @nabs_is_not_over_0_sle_vec_splat(<3 x i33> %x) { +; CHECK-LABEL: @nabs_is_not_over_0_sle_vec_splat( +; CHECK-NEXT: [[CMP:%.*]] = icmp slt <3 x i33> [[X:%.*]], <i33 1, i33 1, i33 1> +; CHECK-NEXT: [[NEGX:%.*]] = sub <3 x i33> zeroinitializer, [[X]] +; CHECK-NEXT: [[NABS:%.*]] = select <3 x i1> [[CMP]], <3 x i33> [[X]], <3 x i33> [[NEGX]] +; CHECK-NEXT: [[R:%.*]] = icmp sge <3 x i33> [[NABS]], <i33 1, i33 1, i33 1> +; CHECK-NEXT: ret <3 x i1> [[R]] +; + %cmp = icmp slt <3 x i33> %x, <i33 1, i33 1, i33 1> + %negx = sub <3 x i33> zeroinitializer, %x + %nabs = select <3 x i1> %cmp, <3 x i33> %x, <3 x i33> %negx + %r = icmp sge <3 x i33> %nabs, <i33 1, i33 1, i33 1> + ret <3 x i1> %r +} + |

