return nullptr;
}
-static Instruction *foldICmpWithZextOrSext(ICmpInst &ICmp) {
+static Instruction *foldICmpWithZextOrSext(ICmpInst &ICmp,
+ InstCombiner::BuilderTy &Builder) {
assert(isa<CastInst>(ICmp.getOperand(0)) && "Expected cast for operand 0");
auto *CastOp0 = cast<CastInst>(ICmp.getOperand(0));
Value *X;
if (auto *CastOp1 = dyn_cast<CastInst>(ICmp.getOperand(1))) {
// If the signedness of the two casts doesn't agree (i.e. one is a sext
// and the other is a zext), then we can't handle this.
+ // TODO: This is too strict. We can handle some predicates (equality?).
if (CastOp0->getOpcode() != CastOp1->getOpcode())
return nullptr;
// Not an extension from the same type?
- // TODO: Handle this by extending the narrower operand to the type of
- // the wider operand.
Value *Y = CastOp1->getOperand(0);
- if (X->getType() != Y->getType())
- return nullptr;
+ Type *XTy = X->getType(), *YTy = Y->getType();
+ if (XTy != YTy) {
+ // One of the casts must have one use because we are creating a new cast.
+ if (!CastOp0->hasOneUse() && !CastOp1->hasOneUse())
+ return nullptr;
+ // Extend the narrower operand to the type of the wider operand.
+ if (XTy->getScalarSizeInBits() < YTy->getScalarSizeInBits())
+ X = Builder.CreateCast(CastOp0->getOpcode(), X, YTy);
+ else if (YTy->getScalarSizeInBits() < XTy->getScalarSizeInBits())
+ Y = Builder.CreateCast(CastOp0->getOpcode(), Y, XTy);
+ else
+ return nullptr;
+ }
// (zext X) == (zext Y) --> X == Y
// (sext X) == (sext Y) --> X == Y
return new ICmpInst(ICmp.getPredicate(), Op0Src, NewOp1);
}
- return foldICmpWithZextOrSext(ICmp);
+ return foldICmpWithZextOrSext(ICmp, Builder);
}
static bool isNeutralValue(Instruction::BinaryOps BinaryOp, Value *RHS) {
define i1 @different_size_zext_zext_ugt(i7 %x, i4 %y) {
; CHECK-LABEL: @different_size_zext_zext_ugt(
-; CHECK-NEXT: [[ZX:%.*]] = zext i7 [[X:%.*]] to i25
-; CHECK-NEXT: [[ZY:%.*]] = zext i4 [[Y:%.*]] to i25
-; CHECK-NEXT: [[R:%.*]] = icmp ugt i25 [[ZX]], [[ZY]]
+; CHECK-NEXT: [[TMP1:%.*]] = zext i4 [[Y:%.*]] to i7
+; CHECK-NEXT: [[R:%.*]] = icmp ult i7 [[TMP1]], [[X:%.*]]
; CHECK-NEXT: ret i1 [[R]]
;
%zx = zext i7 %x to i25
define <2 x i1> @different_size_zext_zext_ugt_commute(<2 x i4> %x, <2 x i7> %y) {
; CHECK-LABEL: @different_size_zext_zext_ugt_commute(
-; CHECK-NEXT: [[ZX:%.*]] = zext <2 x i4> [[X:%.*]] to <2 x i25>
-; CHECK-NEXT: [[ZY:%.*]] = zext <2 x i7> [[Y:%.*]] to <2 x i25>
-; CHECK-NEXT: [[R:%.*]] = icmp ugt <2 x i25> [[ZX]], [[ZY]]
+; CHECK-NEXT: [[TMP1:%.*]] = zext <2 x i4> [[X:%.*]] to <2 x i7>
+; CHECK-NEXT: [[R:%.*]] = icmp ugt <2 x i7> [[TMP1]], [[Y:%.*]]
; CHECK-NEXT: ret <2 x i1> [[R]]
;
%zx = zext <2 x i4> %x to <2 x i25>
define i1 @different_size_zext_zext_ult(i4 %x, i7 %y) {
; CHECK-LABEL: @different_size_zext_zext_ult(
-; CHECK-NEXT: [[ZX:%.*]] = zext i4 [[X:%.*]] to i25
-; CHECK-NEXT: [[ZY:%.*]] = zext i7 [[Y:%.*]] to i25
-; CHECK-NEXT: [[R:%.*]] = icmp ult i25 [[ZX]], [[ZY]]
+; CHECK-NEXT: [[TMP1:%.*]] = zext i4 [[X:%.*]] to i7
+; CHECK-NEXT: [[R:%.*]] = icmp ult i7 [[TMP1]], [[Y:%.*]]
; CHECK-NEXT: ret i1 [[R]]
;
%zx = zext i4 %x to i25
define i1 @different_size_zext_zext_eq(i4 %x, i7 %y) {
; CHECK-LABEL: @different_size_zext_zext_eq(
-; CHECK-NEXT: [[ZX:%.*]] = zext i4 [[X:%.*]] to i25
-; CHECK-NEXT: [[ZY:%.*]] = zext i7 [[Y:%.*]] to i25
-; CHECK-NEXT: [[R:%.*]] = icmp eq i25 [[ZX]], [[ZY]]
+; CHECK-NEXT: [[TMP1:%.*]] = zext i4 [[X:%.*]] to i7
+; CHECK-NEXT: [[R:%.*]] = icmp eq i7 [[TMP1]], [[Y:%.*]]
; CHECK-NEXT: ret i1 [[R]]
;
%zx = zext i4 %x to i25
define i1 @different_size_zext_zext_ne_commute(i7 %x, i4 %y) {
; CHECK-LABEL: @different_size_zext_zext_ne_commute(
-; CHECK-NEXT: [[ZX:%.*]] = zext i7 [[X:%.*]] to i25
-; CHECK-NEXT: [[ZY:%.*]] = zext i4 [[Y:%.*]] to i25
-; CHECK-NEXT: [[R:%.*]] = icmp ne i25 [[ZX]], [[ZY]]
+; CHECK-NEXT: [[TMP1:%.*]] = zext i4 [[Y:%.*]] to i7
+; CHECK-NEXT: [[R:%.*]] = icmp ne i7 [[TMP1]], [[X:%.*]]
; CHECK-NEXT: ret i1 [[R]]
;
%zx = zext i7 %x to i25
define i1 @different_size_zext_zext_slt(i7 %x, i4 %y) {
; CHECK-LABEL: @different_size_zext_zext_slt(
-; CHECK-NEXT: [[ZX:%.*]] = zext i7 [[X:%.*]] to i25
-; CHECK-NEXT: [[ZY:%.*]] = zext i4 [[Y:%.*]] to i25
-; CHECK-NEXT: [[R:%.*]] = icmp ult i25 [[ZX]], [[ZY]]
+; CHECK-NEXT: [[TMP1:%.*]] = zext i4 [[Y:%.*]] to i7
+; CHECK-NEXT: [[R:%.*]] = icmp ugt i7 [[TMP1]], [[X:%.*]]
; CHECK-NEXT: ret i1 [[R]]
;
%zx = zext i7 %x to i25
define i1 @different_size_zext_zext_sgt(i7 %x, i4 %y) {
; CHECK-LABEL: @different_size_zext_zext_sgt(
-; CHECK-NEXT: [[ZX:%.*]] = zext i7 [[X:%.*]] to i25
-; CHECK-NEXT: [[ZY:%.*]] = zext i4 [[Y:%.*]] to i25
-; CHECK-NEXT: [[R:%.*]] = icmp ugt i25 [[ZX]], [[ZY]]
+; CHECK-NEXT: [[TMP1:%.*]] = zext i4 [[Y:%.*]] to i7
+; CHECK-NEXT: [[R:%.*]] = icmp ult i7 [[TMP1]], [[X:%.*]]
; CHECK-NEXT: ret i1 [[R]]
;
%zx = zext i7 %x to i25
define i1 @different_size_sext_sext_sgt(i7 %x, i4 %y) {
; CHECK-LABEL: @different_size_sext_sext_sgt(
-; CHECK-NEXT: [[SX:%.*]] = sext i7 [[X:%.*]] to i25
-; CHECK-NEXT: [[SY:%.*]] = sext i4 [[Y:%.*]] to i25
-; CHECK-NEXT: [[R:%.*]] = icmp sgt i25 [[SX]], [[SY]]
+; CHECK-NEXT: [[TMP1:%.*]] = sext i4 [[Y:%.*]] to i7
+; CHECK-NEXT: [[R:%.*]] = icmp slt i7 [[TMP1]], [[X:%.*]]
; CHECK-NEXT: ret i1 [[R]]
;
%sx = sext i7 %x to i25
define i1 @different_size_sext_sext_sle(i7 %x, i4 %y) {
; CHECK-LABEL: @different_size_sext_sext_sle(
-; CHECK-NEXT: [[SX:%.*]] = sext i7 [[X:%.*]] to i25
-; CHECK-NEXT: [[SY:%.*]] = sext i4 [[Y:%.*]] to i25
-; CHECK-NEXT: [[R:%.*]] = icmp sle i25 [[SX]], [[SY]]
+; CHECK-NEXT: [[TMP1:%.*]] = sext i4 [[Y:%.*]] to i7
+; CHECK-NEXT: [[R:%.*]] = icmp sge i7 [[TMP1]], [[X:%.*]]
; CHECK-NEXT: ret i1 [[R]]
;
%sx = sext i7 %x to i25
define i1 @different_size_sext_sext_eq(i7 %x, i4 %y) {
; CHECK-LABEL: @different_size_sext_sext_eq(
-; CHECK-NEXT: [[SX:%.*]] = sext i7 [[X:%.*]] to i25
-; CHECK-NEXT: [[SY:%.*]] = sext i4 [[Y:%.*]] to i25
-; CHECK-NEXT: [[R:%.*]] = icmp eq i25 [[SX]], [[SY]]
+; CHECK-NEXT: [[TMP1:%.*]] = sext i4 [[Y:%.*]] to i7
+; CHECK-NEXT: [[R:%.*]] = icmp eq i7 [[TMP1]], [[X:%.*]]
; CHECK-NEXT: ret i1 [[R]]
;
%sx = sext i7 %x to i25
define i1 @different_size_sext_sext_ule(i7 %x, i4 %y) {
; CHECK-LABEL: @different_size_sext_sext_ule(
-; CHECK-NEXT: [[SX:%.*]] = sext i7 [[X:%.*]] to i25
-; CHECK-NEXT: [[SY:%.*]] = sext i4 [[Y:%.*]] to i25
-; CHECK-NEXT: [[R:%.*]] = icmp ule i25 [[SX]], [[SY]]
+; CHECK-NEXT: [[TMP1:%.*]] = sext i4 [[Y:%.*]] to i7
+; CHECK-NEXT: [[R:%.*]] = icmp uge i7 [[TMP1]], [[X:%.*]]
; CHECK-NEXT: ret i1 [[R]]
;
%sx = sext i7 %x to i25
ret i1 %r
}
+; TODO: This can be reduced.
+
define i1 @different_size_sext_zext_ne(i7 %x, i4 %y) {
; CHECK-LABEL: @different_size_sext_zext_ne(
; CHECK-NEXT: [[SX:%.*]] = sext i7 [[X:%.*]] to i25
define i1 @different_size_sext_sext_ule_extra_use1(i7 %x, i4 %y) {
; CHECK-LABEL: @different_size_sext_sext_ule_extra_use1(
-; CHECK-NEXT: [[SX:%.*]] = sext i7 [[X:%.*]] to i25
; CHECK-NEXT: [[SY:%.*]] = sext i4 [[Y:%.*]] to i25
; CHECK-NEXT: call void @use(i25 [[SY]])
-; CHECK-NEXT: [[R:%.*]] = icmp ule i25 [[SX]], [[SY]]
+; CHECK-NEXT: [[TMP1:%.*]] = sext i4 [[Y]] to i7
+; CHECK-NEXT: [[R:%.*]] = icmp uge i7 [[TMP1]], [[X:%.*]]
; CHECK-NEXT: ret i1 [[R]]
;
%sx = sext i7 %x to i25
; CHECK-LABEL: @different_size_sext_sext_ule_extra_use2(
; CHECK-NEXT: [[SX:%.*]] = sext i7 [[X:%.*]] to i25
; CHECK-NEXT: call void @use(i25 [[SX]])
-; CHECK-NEXT: [[SY:%.*]] = sext i4 [[Y:%.*]] to i25
-; CHECK-NEXT: [[R:%.*]] = icmp ule i25 [[SX]], [[SY]]
+; CHECK-NEXT: [[TMP1:%.*]] = sext i4 [[Y:%.*]] to i7
+; CHECK-NEXT: [[R:%.*]] = icmp uge i7 [[TMP1]], [[X]]
; CHECK-NEXT: ret i1 [[R]]
;
%sx = sext i7 %x to i25
ret i1 %r
}
+; Negative test - extra uses on both casts is too much.
+
define i1 @different_size_sext_sext_ule_extra_use3(i7 %x, i4 %y) {
; CHECK-LABEL: @different_size_sext_sext_ule_extra_use3(
; CHECK-NEXT: [[SX:%.*]] = sext i7 [[X:%.*]] to i25