if (auto *II = dyn_cast<IntrinsicInst>(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<Intrinsic::ssub_with_overflow>(
+ m_Value(X), m_Value(Y)))) ||
+ match(Cmp0,
+ m_ExtractValue<0>(m_Intrinsic<Intrinsic::usub_with_overflow>(
+ m_Value(X), m_Value(Y))))))
+ return new ICmpInst(Cmp.getPredicate(), X, Y);
}
if (match(Cmp.getOperand(1), m_APIntAllowUndef(C)))
; 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)
; 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)
%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
+}
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)
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)
%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
+}