diff --git a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp index 39f526c95fb68..46e4f6b7edd33 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -3185,6 +3185,20 @@ Instruction *InstCombinerImpl::foldICmpInstWithConstant(ICmpInst &Cmp) { if (auto *II = dyn_cast(Cmp.getOperand(0))) if (Instruction *I = foldICmpIntrinsicWithConstant(Cmp, II, *C)) return I; + + // (extractval ([s/u]subo X, Y), 0) == 0 --> X == Y + // (extractval ([s/u]subo X, Y), 0) != 0 --> X != Y + // TODO: This checks one-use, but that is not strictly necessary. + Value *Cmp0 = Cmp.getOperand(0); + Value *X, *Y; + if (C->isZero() && Cmp.isEquality() && Cmp0->hasOneUse() && + (match(Cmp0, + m_ExtractValue<0>(m_Intrinsic( + m_Value(X), m_Value(Y)))) || + match(Cmp0, + m_ExtractValue<0>(m_Intrinsic( + m_Value(X), m_Value(Y)))))) + return new ICmpInst(Cmp.getPredicate(), X, Y); } if (match(Cmp.getOperand(1), m_APIntAllowUndef(C))) diff --git a/llvm/test/Transforms/InstCombine/ssubo.ll b/llvm/test/Transforms/InstCombine/ssubo.ll index d8f965d396e22..30749afdfc570 100644 --- a/llvm/test/Transforms/InstCombine/ssubo.ll +++ b/llvm/test/Transforms/InstCombine/ssubo.ll @@ -102,8 +102,7 @@ define i1 @sub_eq0(i8 %x, i8 %y, i1 %b) { ; CHECK-NEXT: [[SS:%.*]] = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[SS]], 1 ; CHECK-NEXT: call void @use(i1 [[OV]]) -; CHECK-NEXT: [[SUB:%.*]] = extractvalue { i8, i1 } [[SS]], 0 -; CHECK-NEXT: [[EQ0:%.*]] = icmp eq i8 [[SUB]], 0 +; CHECK-NEXT: [[EQ0:%.*]] = icmp eq i8 [[X]], [[Y]] ; CHECK-NEXT: ret i1 [[EQ0]] ; %ss = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %x, i8 %y) @@ -119,8 +118,7 @@ define i1 @sub_ne0(i8 %x, i8 %y, i1 %b) { ; CHECK-NEXT: [[SS:%.*]] = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) ; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[SS]], 1 ; CHECK-NEXT: call void @use(i1 [[OV]]) -; CHECK-NEXT: [[SUB:%.*]] = extractvalue { i8, i1 } [[SS]], 0 -; CHECK-NEXT: [[NE0:%.*]] = icmp ne i8 [[SUB]], 0 +; CHECK-NEXT: [[NE0:%.*]] = icmp ne i8 [[X]], [[Y]] ; CHECK-NEXT: ret i1 [[NE0]] ; %ss = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %x, i8 %y) @@ -130,3 +128,41 @@ define i1 @sub_ne0(i8 %x, i8 %y, i1 %b) { %ne0 = icmp ne i8 %sub, 0 ret i1 %ne0 } + +; negative test - need zero + +define i1 @sub_eq1(i8 %x, i8 %y, i1 %b) { +; CHECK-LABEL: @sub_eq1( +; CHECK-NEXT: [[SS:%.*]] = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) +; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[SS]], 1 +; CHECK-NEXT: call void @use(i1 [[OV]]) +; CHECK-NEXT: [[SUB:%.*]] = extractvalue { i8, i1 } [[SS]], 0 +; CHECK-NEXT: [[EQ1:%.*]] = icmp eq i8 [[SUB]], 1 +; CHECK-NEXT: ret i1 [[EQ1]] +; + %ss = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %x, i8 %y) + %ov = extractvalue { i8, i1 } %ss, 1 + call void @use(i1 %ov) + %sub = extractvalue { i8, i1 } %ss, 0 + %eq1 = icmp eq i8 %sub, 1 + ret i1 %eq1 +} + +; negative test - need equality pred + +define i1 @sub_sgt0(i8 %x, i8 %y, i1 %b) { +; CHECK-LABEL: @sub_sgt0( +; CHECK-NEXT: [[SS:%.*]] = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) +; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[SS]], 1 +; CHECK-NEXT: call void @use(i1 [[OV]]) +; CHECK-NEXT: [[SUB:%.*]] = extractvalue { i8, i1 } [[SS]], 0 +; CHECK-NEXT: [[SGT0:%.*]] = icmp sgt i8 [[SUB]], 0 +; CHECK-NEXT: ret i1 [[SGT0]] +; + %ss = call { i8, i1 } @llvm.ssub.with.overflow.i8(i8 %x, i8 %y) + %ov = extractvalue { i8, i1 } %ss, 1 + call void @use(i1 %ov) + %sub = extractvalue { i8, i1 } %ss, 0 + %sgt0 = icmp sgt i8 %sub, 0 + ret i1 %sgt0 +} diff --git a/llvm/test/Transforms/InstCombine/usubo.ll b/llvm/test/Transforms/InstCombine/usubo.ll index 7ecbef2f329e5..2074190a2cd45 100644 --- a/llvm/test/Transforms/InstCombine/usubo.ll +++ b/llvm/test/Transforms/InstCombine/usubo.ll @@ -98,11 +98,9 @@ define i1 @test_constant255(i8 %a) { define i1 @sub_eq0(i8 %x, i8 %y, i1 %b) { ; CHECK-LABEL: @sub_eq0( -; CHECK-NEXT: [[US:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) -; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[US]], 1 +; CHECK-NEXT: [[OV:%.*]] = icmp ult i8 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: call void @use(i1 [[OV]]) -; CHECK-NEXT: [[SUB:%.*]] = extractvalue { i8, i1 } [[US]], 0 -; CHECK-NEXT: [[EQ0:%.*]] = icmp eq i8 [[SUB]], 0 +; CHECK-NEXT: [[EQ0:%.*]] = icmp eq i8 [[X]], [[Y]] ; CHECK-NEXT: ret i1 [[EQ0]] ; %us = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %x, i8 %y) @@ -115,11 +113,9 @@ define i1 @sub_eq0(i8 %x, i8 %y, i1 %b) { define i1 @sub_ne0(i8 %x, i8 %y, i1 %b) { ; CHECK-LABEL: @sub_ne0( -; CHECK-NEXT: [[US:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) -; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[US]], 1 +; CHECK-NEXT: [[OV:%.*]] = icmp ult i8 [[X:%.*]], [[Y:%.*]] ; CHECK-NEXT: call void @use(i1 [[OV]]) -; CHECK-NEXT: [[SUB:%.*]] = extractvalue { i8, i1 } [[US]], 0 -; CHECK-NEXT: [[NE0:%.*]] = icmp ne i8 [[SUB]], 0 +; CHECK-NEXT: [[NE0:%.*]] = icmp ne i8 [[X]], [[Y]] ; CHECK-NEXT: ret i1 [[NE0]] ; %us = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %x, i8 %y) @@ -129,3 +125,41 @@ define i1 @sub_ne0(i8 %x, i8 %y, i1 %b) { %ne0 = icmp ne i8 %sub, 0 ret i1 %ne0 } + +; negative test - need zero + +define i1 @sub_eq1(i8 %x, i8 %y, i1 %b) { +; CHECK-LABEL: @sub_eq1( +; CHECK-NEXT: [[SS:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) +; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[SS]], 1 +; CHECK-NEXT: call void @use(i1 [[OV]]) +; CHECK-NEXT: [[SUB:%.*]] = extractvalue { i8, i1 } [[SS]], 0 +; CHECK-NEXT: [[EQ1:%.*]] = icmp eq i8 [[SUB]], 1 +; CHECK-NEXT: ret i1 [[EQ1]] +; + %ss = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %x, i8 %y) + %ov = extractvalue { i8, i1 } %ss, 1 + call void @use(i1 %ov) + %sub = extractvalue { i8, i1 } %ss, 0 + %eq1 = icmp eq i8 %sub, 1 + ret i1 %eq1 +} + +; negative test - need equality pred + +define i1 @sub_sgt0(i8 %x, i8 %y, i1 %b) { +; CHECK-LABEL: @sub_sgt0( +; CHECK-NEXT: [[SS:%.*]] = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 [[X:%.*]], i8 [[Y:%.*]]) +; CHECK-NEXT: [[OV:%.*]] = extractvalue { i8, i1 } [[SS]], 1 +; CHECK-NEXT: call void @use(i1 [[OV]]) +; CHECK-NEXT: [[SUB:%.*]] = extractvalue { i8, i1 } [[SS]], 0 +; CHECK-NEXT: [[SGT0:%.*]] = icmp sgt i8 [[SUB]], 0 +; CHECK-NEXT: ret i1 [[SGT0]] +; + %ss = call { i8, i1 } @llvm.usub.with.overflow.i8(i8 %x, i8 %y) + %ov = extractvalue { i8, i1 } %ss, 1 + call void @use(i1 %ov) + %sub = extractvalue { i8, i1 } %ss, 0 + %sgt0 = icmp sgt i8 %sub, 0 + ret i1 %sgt0 +}