diff --git a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp index 4884c23f16e12..2f5ea8a2e4681 100644 --- a/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp +++ b/llvm/lib/Transforms/Scalar/ConstraintElimination.cpp @@ -522,6 +522,13 @@ static Decomposition decompose(Value *V, if (match(V, m_NSWAdd(m_Value(Op0), m_Value(Op1)))) return MergeResults(Op0, Op1, IsSigned); + if (match(V, m_NSWSub(m_Value(Op0), m_Value(Op1)))) { + auto ResA = decompose(Op0, Preconditions, IsSigned, DL); + auto ResB = decompose(Op1, Preconditions, IsSigned, DL); + ResA.sub(ResB); + return ResA; + } + ConstantInt *CI; if (match(V, m_NSWMul(m_Value(Op0), m_ConstantInt(CI))) && canUseSExt(CI)) { auto Result = decompose(Op0, Preconditions, IsSigned, DL); diff --git a/llvm/test/Transforms/ConstraintElimination/sub-nsw.ll b/llvm/test/Transforms/ConstraintElimination/sub-nsw.ll new file mode 100644 index 0000000000000..3ea60d267043d --- /dev/null +++ b/llvm/test/Transforms/ConstraintElimination/sub-nsw.ll @@ -0,0 +1,129 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -passes=constraint-elimination -S %s | FileCheck %s + +define i1 @test_decompose_sub_nsw_sgt_nonneg(i32 %x, i32 %y) { +; CHECK-LABEL: define i1 @test_decompose_sub_nsw_sgt_nonneg( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[Y]], [[X]] +; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[SUB]], 10 +; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]] +; CHECK: [[IF_THEN]]: +; CHECK-NEXT: ret i1 true +; CHECK: [[IF_ELSE]]: +; CHECK-NEXT: ret i1 true +; +entry: + %sub = sub nsw i32 %y, %x + %cond = icmp sgt i32 %sub, 10 + br i1 %cond, label %if.then, label %if.else + +if.then: + %ret = icmp slt i32 %x, %y + ret i1 %ret + +if.else: + ret i1 true +} + +define i1 @test_decompose_sub_nsw_sgt_zero(i32 %x, i32 %y) { +; CHECK-LABEL: define i1 @test_decompose_sub_nsw_sgt_zero( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[Y]], [[X]] +; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[SUB]], 0 +; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]] +; CHECK: [[IF_THEN]]: +; CHECK-NEXT: ret i1 true +; CHECK: [[IF_ELSE]]: +; CHECK-NEXT: ret i1 true +; +entry: + %sub = sub nsw i32 %y, %x + %cond = icmp sgt i32 %sub, 0 + br i1 %cond, label %if.then, label %if.else + +if.then: + %ret = icmp slt i32 %x, %y + ret i1 %ret + +if.else: + ret i1 true +} + +define i1 @test_decompose_sub_nsw_sgt_zero_inv(i32 %x, i32 %y) { +; CHECK-LABEL: define i1 @test_decompose_sub_nsw_sgt_zero_inv( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[Y]], [[X]] +; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[SUB]], 10 +; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]] +; CHECK: [[IF_THEN]]: +; CHECK-NEXT: ret i1 false +; CHECK: [[IF_ELSE]]: +; CHECK-NEXT: ret i1 true +; +entry: + %sub = sub nsw i32 %y, %x + %cond = icmp sgt i32 %sub, 10 + br i1 %cond, label %if.then, label %if.else + +if.then: + %ret = icmp sge i32 %x, %y + ret i1 %ret + +if.else: + ret i1 true +} + +define i1 @test_decompose_sub_nonsw_sgt_zero(i32 %x, i32 %y) { +; CHECK-LABEL: define i1 @test_decompose_sub_nonsw_sgt_zero( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[SUB:%.*]] = sub i32 [[Y]], [[X]] +; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[SUB]], 10 +; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]] +; CHECK: [[IF_THEN]]: +; CHECK-NEXT: [[RET:%.*]] = icmp slt i32 [[X]], [[Y]] +; CHECK-NEXT: ret i1 [[RET]] +; CHECK: [[IF_ELSE]]: +; CHECK-NEXT: ret i1 true +; +entry: + %sub = sub i32 %y, %x + %cond = icmp sgt i32 %sub, 10 + br i1 %cond, label %if.then, label %if.else + +if.then: + %ret = icmp slt i32 %x, %y + ret i1 %ret + +if.else: + ret i1 true +} + +define i1 @test_decompose_sub_nsw_sgt_neg(i32 %x, i32 %y) { +; CHECK-LABEL: define i1 @test_decompose_sub_nsw_sgt_neg( +; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) { +; CHECK-NEXT: [[ENTRY:.*:]] +; CHECK-NEXT: [[SUB:%.*]] = sub nsw i32 [[Y]], [[X]] +; CHECK-NEXT: [[COND:%.*]] = icmp sgt i32 [[SUB]], -10 +; CHECK-NEXT: br i1 [[COND]], label %[[IF_THEN:.*]], label %[[IF_ELSE:.*]] +; CHECK: [[IF_THEN]]: +; CHECK-NEXT: [[RET:%.*]] = icmp slt i32 [[X]], [[Y]] +; CHECK-NEXT: ret i1 [[RET]] +; CHECK: [[IF_ELSE]]: +; CHECK-NEXT: ret i1 true +; +entry: + %sub = sub nsw i32 %y, %x + %cond = icmp sgt i32 %sub, -10 + br i1 %cond, label %if.then, label %if.else + +if.then: + %ret = icmp slt i32 %x, %y + ret i1 %ret + +if.else: + ret i1 true +}