llvm/llvm/test/Transforms/InstCombine/commutative-operation-over-selects.ll

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
; RUN: opt -passes=instcombine -S < %s | FileCheck %s

declare float @llvm.maxnum.f32(float %a, float %b)
declare float @llvm.minnum.f32(float %a, float %b)
declare float @llvm.maximum.f32(float %a, float %b)
declare float @llvm.minimum.f32(float %a, float %b)
declare i32 @llvm.smax.i32(i32 %a, i32 %b)
declare i32 @llvm.smin.i32(i32 %a, i32 %b)
declare i32 @llvm.umax.i32(i32 %a, i32 %b)
declare i32 @llvm.umin.i32(i32 %a, i32 %b)
declare i16 @llvm.sadd.sat.i16(i16 %a, i16 %b)
declare i16 @llvm.uadd.sat.i16(i16 %a, i16 %b)
declare {i16, i1} @llvm.sadd.with.overflow.i16(i16 %a, i16 %b)
declare {i16, i1} @llvm.uadd.with.overflow.i16(i16 %a, i16 %b)
declare {i16, i1} @llvm.smul.with.overflow.i16(i16 %a, i16 %b)
declare {i16, i1} @llvm.umul.with.overflow.i16(i16 %a, i16 %b)
declare i16 @llvm.smul.fix.i16(i16 %a, i16 %b, i32 %scale)
declare i16 @llvm.umul.fix.i16(i16 %a, i16 %b, i32 %scale)
declare i16 @llvm.smul.fix.sat.i16(i16 %a, i16 %b, i32 %scale)
declare i16 @llvm.umul.fix.sat.i16(i16 %a, i16 %b, i32 %scale)
declare float @llvm.fma.f32(float %a, float %b, float %c)
declare float @llvm.fmuladd.f32(float %a, float %b, float %c)

define i8 @fold_select_mul(i1 %c, i8 %a, i8 %b) {
; CHECK-LABEL: define i8 @fold_select_mul(
; CHECK-SAME: i1 [[C:%.*]], i8 [[A:%.*]], i8 [[B:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = mul i8 [[B]], [[A]]
; CHECK-NEXT:    ret i8 [[RET]]
;
  %s0 = select i1 %c, i8 %a, i8 %b
  %s1 = select i1 %c, i8 %b, i8 %a
  %ret = mul i8 %s1, %s0
  ret i8 %ret
}

define i8 @fold_select_mul_nsw_nuw_preserve(i1 %c, i8 %a, i8 %b) {
; CHECK-LABEL: define i8 @fold_select_mul_nsw_nuw_preserve(
; CHECK-SAME: i1 [[C:%.*]], i8 [[A:%.*]], i8 [[B:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = mul nuw nsw i8 [[B]], [[A]]
; CHECK-NEXT:    ret i8 [[RET]]
;
  %s0 = select i1 %c, i8 %a, i8 %b
  %s1 = select i1 %c, i8 %b, i8 %a
  %ret = mul nsw nuw i8 %s1, %s0
  ret i8 %ret
}

define <2 x i4> @fold_select_mul_vec2(i1 %c, <2 x i4> %a, <2 x i4> %b) {
; CHECK-LABEL: define <2 x i4> @fold_select_mul_vec2(
; CHECK-SAME: i1 [[C:%.*]], <2 x i4> [[A:%.*]], <2 x i4> [[B:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = mul <2 x i4> [[B]], [[A]]
; CHECK-NEXT:    ret <2 x i4> [[RET]]
;
  %s0 = select i1 %c, <2 x i4> %a, <2 x i4> %b
  %s1 = select i1 %c, <2 x i4> %b, <2 x i4> %a
  %ret = mul <2 x i4> %s1, %s0
  ret <2 x i4> %ret
}

define i8 @fold_select_add(i1 %c, i8 %a, i8 %b) {
; CHECK-LABEL: define i8 @fold_select_add(
; CHECK-SAME: i1 [[C:%.*]], i8 [[A:%.*]], i8 [[B:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = add i8 [[B]], [[A]]
; CHECK-NEXT:    ret i8 [[RET]]
;
  %s0 = select i1 %c, i8 %a, i8 %b
  %s1 = select i1 %c, i8 %b, i8 %a
  %ret = add i8 %s1, %s0
  ret i8 %ret
}

define <2 x i4> @fold_select_add_vec2(i1 %c, <2 x i4> %a, <2 x i4> %b) {
; CHECK-LABEL: define <2 x i4> @fold_select_add_vec2(
; CHECK-SAME: i1 [[C:%.*]], <2 x i4> [[A:%.*]], <2 x i4> [[B:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = add <2 x i4> [[B]], [[A]]
; CHECK-NEXT:    ret <2 x i4> [[RET]]
;
  %s0 = select i1 %c, <2 x i4> %a, <2 x i4> %b
  %s1 = select i1 %c, <2 x i4> %b, <2 x i4> %a
  %ret = add <2 x i4> %s1, %s0
  ret <2 x i4> %ret
}

define i8 @fold_select_and(i1 %c, i8 %a, i8 %b) {
; CHECK-LABEL: define i8 @fold_select_and(
; CHECK-SAME: i1 [[C:%.*]], i8 [[A:%.*]], i8 [[B:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = and i8 [[B]], [[A]]
; CHECK-NEXT:    ret i8 [[RET]]
;
  %s0 = select i1 %c, i8 %a, i8 %b
  %s1 = select i1 %c, i8 %b, i8 %a
  %ret = and i8 %s1, %s0
  ret i8 %ret
}

define <2 x i4> @fold_select_and_vec2(i1 %c, <2 x i4> %a, <2 x i4> %b) {
; CHECK-LABEL: define <2 x i4> @fold_select_and_vec2(
; CHECK-SAME: i1 [[C:%.*]], <2 x i4> [[A:%.*]], <2 x i4> [[B:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = and <2 x i4> [[B]], [[A]]
; CHECK-NEXT:    ret <2 x i4> [[RET]]
;
  %s0 = select i1 %c, <2 x i4> %a, <2 x i4> %b
  %s1 = select i1 %c, <2 x i4> %b, <2 x i4> %a
  %ret = and <2 x i4> %s1, %s0
  ret <2 x i4> %ret
}

define i8 @fold_select_or(i1 %c, i8 %a, i8 %b) {
; CHECK-LABEL: define i8 @fold_select_or(
; CHECK-SAME: i1 [[C:%.*]], i8 [[A:%.*]], i8 [[B:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = or i8 [[B]], [[A]]
; CHECK-NEXT:    ret i8 [[RET]]
;
  %s0 = select i1 %c, i8 %a, i8 %b
  %s1 = select i1 %c, i8 %b, i8 %a
  %ret = or i8 %s1, %s0
  ret i8 %ret
}

define <2 x i4> @fold_select_or_vec2(i1 %c, <2 x i4> %a, <2 x i4> %b) {
; CHECK-LABEL: define <2 x i4> @fold_select_or_vec2(
; CHECK-SAME: i1 [[C:%.*]], <2 x i4> [[A:%.*]], <2 x i4> [[B:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = or <2 x i4> [[B]], [[A]]
; CHECK-NEXT:    ret <2 x i4> [[RET]]
;
  %s0 = select i1 %c, <2 x i4> %a, <2 x i4> %b
  %s1 = select i1 %c, <2 x i4> %b, <2 x i4> %a
  %ret = or <2 x i4> %s1, %s0
  ret <2 x i4> %ret
}

define i8 @fold_select_xor(i1 %c, i8 %a, i8 %b) {
; CHECK-LABEL: define i8 @fold_select_xor(
; CHECK-SAME: i1 [[C:%.*]], i8 [[A:%.*]], i8 [[B:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = xor i8 [[B]], [[A]]
; CHECK-NEXT:    ret i8 [[RET]]
;
  %s0 = select i1 %c, i8 %a, i8 %b
  %s1 = select i1 %c, i8 %b, i8 %a
  %ret = xor i8 %s1, %s0
  ret i8 %ret
}

define <2 x i4> @fold_select_xor_vec2(i1 %c, <2 x i4> %a, <2 x i4> %b) {
; CHECK-LABEL: define <2 x i4> @fold_select_xor_vec2(
; CHECK-SAME: i1 [[C:%.*]], <2 x i4> [[A:%.*]], <2 x i4> [[B:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = xor <2 x i4> [[B]], [[A]]
; CHECK-NEXT:    ret <2 x i4> [[RET]]
;
  %s0 = select i1 %c, <2 x i4> %a, <2 x i4> %b
  %s1 = select i1 %c, <2 x i4> %b, <2 x i4> %a
  %ret = xor <2 x i4> %s1, %s0
  ret <2 x i4> %ret
}

define float @fold_select_fadd(i1 %c, float %a, float %b) {
; CHECK-LABEL: define float @fold_select_fadd(
; CHECK-SAME: i1 [[C:%.*]], float [[A:%.*]], float [[B:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = fadd float [[B]], [[A]]
; CHECK-NEXT:    ret float [[RET]]
;
  %s0 = select i1 %c, float %a, float %b
  %s1 = select i1 %c, float %b, float %a
  %ret = fadd float %s1, %s0
  ret float %ret
}

define float @fold_select_fadd_nnan(i1 %c, float %a, float %b) {
; CHECK-LABEL: define float @fold_select_fadd_nnan(
; CHECK-SAME: i1 [[C:%.*]], float [[A:%.*]], float [[B:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = fadd nnan float [[B]], [[A]]
; CHECK-NEXT:    ret float [[RET]]
;
  %s0 = select i1 %c, float %a, float %b
  %s1 = select i1 %c, float %b, float %a
  %ret = fadd nnan float %s1, %s0
  ret float %ret
}

define <2 x float> @fold_select_fadd_vec2(i1 %c, <2 x float> %a, <2 x float> %b) {
; CHECK-LABEL: define <2 x float> @fold_select_fadd_vec2(
; CHECK-SAME: i1 [[C:%.*]], <2 x float> [[A:%.*]], <2 x float> [[B:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = fadd <2 x float> [[B]], [[A]]
; CHECK-NEXT:    ret <2 x float> [[RET]]
;
  %s0 = select i1 %c, <2 x float> %a, <2 x float> %b
  %s1 = select i1 %c, <2 x float> %b, <2 x float> %a
  %ret = fadd <2 x float> %s1, %s0
  ret <2 x float> %ret
}

define float @fold_select_fmul(i1 %c, float %a, float %b) {
; CHECK-LABEL: define float @fold_select_fmul(
; CHECK-SAME: i1 [[C:%.*]], float [[A:%.*]], float [[B:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = fmul float [[B]], [[A]]
; CHECK-NEXT:    ret float [[RET]]
;
  %s0 = select i1 %c, float %a, float %b
  %s1 = select i1 %c, float %b, float %a
  %ret = fmul float %s1, %s0
  ret float %ret
}

define <2 x float> @fold_select_fmul_vec2(i1 %c, <2 x float> %a, <2 x float> %b) {
; CHECK-LABEL: define <2 x float> @fold_select_fmul_vec2(
; CHECK-SAME: i1 [[C:%.*]], <2 x float> [[A:%.*]], <2 x float> [[B:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = fmul <2 x float> [[B]], [[A]]
; CHECK-NEXT:    ret <2 x float> [[RET]]
;
  %s0 = select i1 %c, <2 x float> %a, <2 x float> %b
  %s1 = select i1 %c, <2 x float> %b, <2 x float> %a
  %ret = fmul <2 x float> %s1, %s0
  ret <2 x float> %ret
}

;

define float @fold_select_maxnum(i1 %c, float %a, float %b) {
; CHECK-LABEL: define float @fold_select_maxnum(
; CHECK-SAME: i1 [[C:%.*]], float [[A:%.*]], float [[B:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.maxnum.f32(float [[B]], float [[A]])
; CHECK-NEXT:    ret float [[RET]]
;
  %s0 = select i1 %c, float %a, float %b
  %s1 = select i1 %c, float %b, float %a
  %ret = call float @llvm.maxnum.f32(float %s1, float %s0)
  ret float %ret
}

define float @fold_select_minnum(i1 %c, float %a, float %b) {
; CHECK-LABEL: define float @fold_select_minnum(
; CHECK-SAME: i1 [[C:%.*]], float [[A:%.*]], float [[B:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.minnum.f32(float [[B]], float [[A]])
; CHECK-NEXT:    ret float [[RET]]
;
  %s0 = select i1 %c, float %a, float %b
  %s1 = select i1 %c, float %b, float %a
  %ret = call float @llvm.minnum.f32(float %s1, float %s0)
  ret float %ret
}

define float @fold_select_maximum(i1 %c, float %a, float %b) {
; CHECK-LABEL: define float @fold_select_maximum(
; CHECK-SAME: i1 [[C:%.*]], float [[A:%.*]], float [[B:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.maximum.f32(float [[B]], float [[A]])
; CHECK-NEXT:    ret float [[RET]]
;
  %s0 = select i1 %c, float %a, float %b
  %s1 = select i1 %c, float %b, float %a
  %ret = call float @llvm.maximum.f32(float %s1, float %s0)
  ret float %ret
}

define float @fold_select_minimum(i1 %c, float %a, float %b) {
; CHECK-LABEL: define float @fold_select_minimum(
; CHECK-SAME: i1 [[C:%.*]], float [[A:%.*]], float [[B:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.minimum.f32(float [[B]], float [[A]])
; CHECK-NEXT:    ret float [[RET]]
;
  %s0 = select i1 %c, float %a, float %b
  %s1 = select i1 %c, float %b, float %a
  %ret = call float @llvm.minimum.f32(float %s1, float %s0)
  ret float %ret
}

define i32 @fold_select_smax(i1 %c, i32 %a, i32 %b) {
; CHECK-LABEL: define i32 @fold_select_smax(
; CHECK-SAME: i1 [[C:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = call i32 @llvm.smax.i32(i32 [[B]], i32 [[A]])
; CHECK-NEXT:    ret i32 [[RET]]
;
  %s0 = select i1 %c, i32 %a, i32 %b
  %s1 = select i1 %c, i32 %b, i32 %a
  %ret = call i32 @llvm.smax.i32(i32 %s1, i32 %s0)
  ret i32 %ret
}

define i32 @fold_select_smin(i1 %c, i32 %a, i32 %b) {
; CHECK-LABEL: define i32 @fold_select_smin(
; CHECK-SAME: i1 [[C:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = call i32 @llvm.smin.i32(i32 [[B]], i32 [[A]])
; CHECK-NEXT:    ret i32 [[RET]]
;
  %s0 = select i1 %c, i32 %a, i32 %b
  %s1 = select i1 %c, i32 %b, i32 %a
  %ret = call i32 @llvm.smin.i32(i32 %s1, i32 %s0)
  ret i32 %ret
}

define i32 @fold_select_umax(i1 %c, i32 %a, i32 %b) {
; CHECK-LABEL: define i32 @fold_select_umax(
; CHECK-SAME: i1 [[C:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = call i32 @llvm.umax.i32(i32 [[B]], i32 [[A]])
; CHECK-NEXT:    ret i32 [[RET]]
;
  %s0 = select i1 %c, i32 %a, i32 %b
  %s1 = select i1 %c, i32 %b, i32 %a
  %ret = call i32 @llvm.umax.i32(i32 %s1, i32 %s0)
  ret i32 %ret
}

define i32 @fold_select_umin(i1 %c, i32 %a, i32 %b) {
; CHECK-LABEL: define i32 @fold_select_umin(
; CHECK-SAME: i1 [[C:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = call i32 @llvm.umin.i32(i32 [[B]], i32 [[A]])
; CHECK-NEXT:    ret i32 [[RET]]
;
  %s0 = select i1 %c, i32 %a, i32 %b
  %s1 = select i1 %c, i32 %b, i32 %a
  %ret = call i32 @llvm.umin.i32(i32 %s1, i32 %s0)
  ret i32 %ret
}

define i16 @fold_select_sadd_sat(i1 %c, i16 %a, i16 %b) {
; CHECK-LABEL: define i16 @fold_select_sadd_sat(
; CHECK-SAME: i1 [[C:%.*]], i16 [[A:%.*]], i16 [[B:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = call i16 @llvm.sadd.sat.i16(i16 [[B]], i16 [[A]])
; CHECK-NEXT:    ret i16 [[RET]]
;
  %s0 = select i1 %c, i16 %a, i16 %b
  %s1 = select i1 %c, i16 %b, i16 %a
  %ret = call i16 @llvm.sadd.sat.i16(i16 %s1, i16 %s0)
  ret i16 %ret
}

define i16 @fold_select_uadd_sat(i1 %c, i16 %a, i16 %b) {
; CHECK-LABEL: define i16 @fold_select_uadd_sat(
; CHECK-SAME: i1 [[C:%.*]], i16 [[A:%.*]], i16 [[B:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = call i16 @llvm.uadd.sat.i16(i16 [[B]], i16 [[A]])
; CHECK-NEXT:    ret i16 [[RET]]
;
  %s0 = select i1 %c, i16 %a, i16 %b
  %s1 = select i1 %c, i16 %b, i16 %a
  %ret = call i16 @llvm.uadd.sat.i16(i16 %s1, i16 %s0)
  ret i16 %ret
}

define i16 @fold_select_sadd_with_overflow(i1 %c, i16 %a, i16 %b) {
; CHECK-LABEL: define i16 @fold_select_sadd_with_overflow(
; CHECK-SAME: i1 [[C:%.*]], i16 [[A:%.*]], i16 [[B:%.*]]) {
; CHECK-NEXT:    [[RES:%.*]] = call { i16, i1 } @llvm.sadd.with.overflow.i16(i16 [[B]], i16 [[A]])
; CHECK-NEXT:    [[OBIT:%.*]] = extractvalue { i16, i1 } [[RES]], 1
; CHECK-NEXT:    br i1 [[OBIT]], label [[OVERFLOW:%.*]], label [[NORMAL:%.*]]
; CHECK:       overflow:
; CHECK-NEXT:    ret i16 0
; CHECK:       normal:
; CHECK-NEXT:    [[SUM:%.*]] = extractvalue { i16, i1 } [[RES]], 0
; CHECK-NEXT:    ret i16 [[SUM]]
;
  %s0 = select i1 %c, i16 %a, i16 %b
  %s1 = select i1 %c, i16 %b, i16 %a
  %res = call {i16, i1} @llvm.sadd.with.overflow.i16(i16 %s1, i16 %s0)
  %obit = extractvalue {i16, i1} %res, 1
  br i1 %obit, label %overflow, label %normal
overflow:
  ret i16 0
normal:
  %sum = extractvalue {i16, i1} %res, 0
  ret i16 %sum
}

define i16 @fold_select_uadd_with_overflow(i1 %c, i16 %a, i16 %b) {
; CHECK-LABEL: define i16 @fold_select_uadd_with_overflow(
; CHECK-SAME: i1 [[C:%.*]], i16 [[A:%.*]], i16 [[B:%.*]]) {
; CHECK-NEXT:    [[RES:%.*]] = call { i16, i1 } @llvm.uadd.with.overflow.i16(i16 [[B]], i16 [[A]])
; CHECK-NEXT:    [[OBIT:%.*]] = extractvalue { i16, i1 } [[RES]], 1
; CHECK-NEXT:    br i1 [[OBIT]], label [[OVERFLOW:%.*]], label [[NORMAL:%.*]]
; CHECK:       overflow:
; CHECK-NEXT:    ret i16 0
; CHECK:       normal:
; CHECK-NEXT:    [[SUM:%.*]] = extractvalue { i16, i1 } [[RES]], 0
; CHECK-NEXT:    ret i16 [[SUM]]
;
  %s0 = select i1 %c, i16 %a, i16 %b
  %s1 = select i1 %c, i16 %b, i16 %a
  %res = call {i16, i1} @llvm.uadd.with.overflow.i16(i16 %s1, i16 %s0)
  %obit = extractvalue {i16, i1} %res, 1
  br i1 %obit, label %overflow, label %normal
overflow:
  ret i16 0
normal:
  %sum = extractvalue {i16, i1} %res, 0
  ret i16 %sum
}

define i16 @fold_select_smul_with_overflow(i1 %c, i16 %a, i16 %b) {
; CHECK-LABEL: define i16 @fold_select_smul_with_overflow(
; CHECK-SAME: i1 [[C:%.*]], i16 [[A:%.*]], i16 [[B:%.*]]) {
; CHECK-NEXT:    [[RES:%.*]] = call { i16, i1 } @llvm.smul.with.overflow.i16(i16 [[B]], i16 [[A]])
; CHECK-NEXT:    [[OBIT:%.*]] = extractvalue { i16, i1 } [[RES]], 1
; CHECK-NEXT:    br i1 [[OBIT]], label [[OVERFLOW:%.*]], label [[NORMAL:%.*]]
; CHECK:       overflow:
; CHECK-NEXT:    ret i16 0
; CHECK:       normal:
; CHECK-NEXT:    [[MUL:%.*]] = extractvalue { i16, i1 } [[RES]], 0
; CHECK-NEXT:    ret i16 [[MUL]]
;
  %s0 = select i1 %c, i16 %a, i16 %b
  %s1 = select i1 %c, i16 %b, i16 %a
  %res = call {i16, i1} @llvm.smul.with.overflow.i16(i16 %s1, i16 %s0)
  %obit = extractvalue {i16, i1} %res, 1
  br i1 %obit, label %overflow, label %normal
overflow:
  ret i16 0
normal:
  %mul = extractvalue {i16, i1} %res, 0
  ret i16 %mul
}

define i16 @fold_select_umul_with_overflow(i1 %c, i16 %a, i16 %b) {
; CHECK-LABEL: define i16 @fold_select_umul_with_overflow(
; CHECK-SAME: i1 [[C:%.*]], i16 [[A:%.*]], i16 [[B:%.*]]) {
; CHECK-NEXT:    [[RES:%.*]] = call { i16, i1 } @llvm.umul.with.overflow.i16(i16 [[B]], i16 [[A]])
; CHECK-NEXT:    [[OBIT:%.*]] = extractvalue { i16, i1 } [[RES]], 1
; CHECK-NEXT:    br i1 [[OBIT]], label [[OVERFLOW:%.*]], label [[NORMAL:%.*]]
; CHECK:       overflow:
; CHECK-NEXT:    ret i16 0
; CHECK:       normal:
; CHECK-NEXT:    [[MUL:%.*]] = extractvalue { i16, i1 } [[RES]], 0
; CHECK-NEXT:    ret i16 [[MUL]]
;
  %s0 = select i1 %c, i16 %a, i16 %b
  %s1 = select i1 %c, i16 %b, i16 %a
  %res = call {i16, i1} @llvm.umul.with.overflow.i16(i16 %s1, i16 %s0)
  %obit = extractvalue {i16, i1} %res, 1
  br i1 %obit, label %overflow, label %normal
overflow:
  ret i16 0
normal:
  %mul = extractvalue {i16, i1} %res, 0
  ret i16 %mul
}

define i16 @fold_select_smul_fix(i1 %c, i16 %a, i16 %b, i32 %y) {
; CHECK-LABEL: define i16 @fold_select_smul_fix(
; CHECK-SAME: i1 [[C:%.*]], i16 [[A:%.*]], i16 [[B:%.*]], i32 [[Y:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = call i16 @llvm.smul.fix.i16(i16 [[B]], i16 [[A]], i32 1)
; CHECK-NEXT:    ret i16 [[RET]]
;
  %s0 = select i1 %c, i16 %a, i16 %b
  %s1 = select i1 %c, i16 %b, i16 %a
  %ret = call i16 @llvm.smul.fix.i16(i16 %s1, i16 %s0, i32 1)
  ret i16 %ret
}

define i16 @fold_select_umul_fix(i1 %c, i16 %a, i16 %b, i32 %y) {
; CHECK-LABEL: define i16 @fold_select_umul_fix(
; CHECK-SAME: i1 [[C:%.*]], i16 [[A:%.*]], i16 [[B:%.*]], i32 [[Y:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = call i16 @llvm.umul.fix.i16(i16 [[B]], i16 [[A]], i32 1)
; CHECK-NEXT:    ret i16 [[RET]]
;
  %s0 = select i1 %c, i16 %a, i16 %b
  %s1 = select i1 %c, i16 %b, i16 %a
  %ret = call i16 @llvm.umul.fix.i16(i16 %s1, i16 %s0, i32 1)
  ret i16 %ret
}

define i16 @fold_select_smul_fix_sat(i1 %c, i16 %a, i16 %b, i32 %y) {
; CHECK-LABEL: define i16 @fold_select_smul_fix_sat(
; CHECK-SAME: i1 [[C:%.*]], i16 [[A:%.*]], i16 [[B:%.*]], i32 [[Y:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = call i16 @llvm.smul.fix.sat.i16(i16 [[B]], i16 [[A]], i32 1)
; CHECK-NEXT:    ret i16 [[RET]]
;
  %s0 = select i1 %c, i16 %a, i16 %b
  %s1 = select i1 %c, i16 %b, i16 %a
  %ret = call i16 @llvm.smul.fix.sat.i16(i16 %s1, i16 %s0, i32 1)
  ret i16 %ret
}

define i16 @fold_select_umul_fix_sat(i1 %c, i16 %a, i16 %b, i32 %y) {
; CHECK-LABEL: define i16 @fold_select_umul_fix_sat(
; CHECK-SAME: i1 [[C:%.*]], i16 [[A:%.*]], i16 [[B:%.*]], i32 [[Y:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = call i16 @llvm.umul.fix.sat.i16(i16 [[B]], i16 [[A]], i32 1)
; CHECK-NEXT:    ret i16 [[RET]]
;
  %s0 = select i1 %c, i16 %a, i16 %b
  %s1 = select i1 %c, i16 %b, i16 %a
  %ret = call i16 @llvm.umul.fix.sat.i16(i16 %s1, i16 %s0, i32 1)
  ret i16 %ret
}

define float @fold_select_fma(i1 %c, float %a, float %b, float %y) {
; CHECK-LABEL: define float @fold_select_fma(
; CHECK-SAME: i1 [[C:%.*]], float [[A:%.*]], float [[B:%.*]], float [[Y:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.fma.f32(float [[B]], float [[A]], float [[Y]])
; CHECK-NEXT:    ret float [[RET]]
;
  %s0 = select i1 %c, float %a, float %b
  %s1 = select i1 %c, float %b, float %a
  %ret = call float @llvm.fma.f32(float %s1, float %s0, float %y)
  ret float %ret
}

define float @fold_select_fmuladd(i1 %c, float %a, float %b, float %y) {
; CHECK-LABEL: define float @fold_select_fmuladd(
; CHECK-SAME: i1 [[C:%.*]], float [[A:%.*]], float [[B:%.*]], float [[Y:%.*]]) {
; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.fmuladd.f32(float [[B]], float [[A]], float [[Y]])
; CHECK-NEXT:    ret float [[RET]]
;
  %s0 = select i1 %c, float %a, float %b
  %s1 = select i1 %c, float %b, float %a
  %ret = call float @llvm.fmuladd.f32(float %s1, float %s0, float %y)
  ret float %ret
}

;negative tests:

define i8 @fold_select_unmatch_mul_neg(i1 %c, i1 %c1, i8 %a, i8 %b) {
; CHECK-LABEL: define i8 @fold_select_unmatch_mul_neg(
; CHECK-SAME: i1 [[C:%.*]], i1 [[C1:%.*]], i8 [[A:%.*]], i8 [[B:%.*]]) {
; CHECK-NEXT:    [[S0:%.*]] = select i1 [[C]], i8 [[A]], i8 [[B]]
; CHECK-NEXT:    [[S1:%.*]] = select i1 [[C1]], i8 [[B]], i8 [[A]]
; CHECK-NEXT:    [[RET:%.*]] = mul i8 [[S1]], [[S0]]
; CHECK-NEXT:    ret i8 [[RET]]
;
  %s0 = select i1 %c, i8 %a, i8 %b
  %s1 = select i1 %c1, i8 %b, i8 %a
  %ret = mul i8 %s1, %s0
  ret i8 %ret
}

define i8 @fold_select_sub_neg(i1 %c, i8 %a, i8 %b) {
; CHECK-LABEL: define i8 @fold_select_sub_neg(
; CHECK-SAME: i1 [[C:%.*]], i8 [[A:%.*]], i8 [[B:%.*]]) {
; CHECK-NEXT:    [[S0:%.*]] = select i1 [[C]], i8 [[A]], i8 [[B]]
; CHECK-NEXT:    [[S1:%.*]] = select i1 [[C]], i8 [[B]], i8 [[A]]
; CHECK-NEXT:    [[RET:%.*]] = sub i8 [[S1]], [[S0]]
; CHECK-NEXT:    ret i8 [[RET]]
;
  %s0 = select i1 %c, i8 %a, i8 %b
  %s1 = select i1 %c, i8 %b, i8 %a
  %ret = sub i8 %s1, %s0
  ret i8 %ret
}

define float @fold_select_fma_neg(i1 %c, i1 %c1, float %a, float %b, float %y) {
; CHECK-LABEL: define float @fold_select_fma_neg(
; CHECK-SAME: i1 [[C:%.*]], i1 [[C1:%.*]], float [[A:%.*]], float [[B:%.*]], float [[Y:%.*]]) {
; CHECK-NEXT:    [[S0:%.*]] = select i1 [[C]], float [[A]], float [[B]]
; CHECK-NEXT:    [[S1:%.*]] = select i1 [[C1]], float [[B]], float [[A]]
; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.fma.f32(float [[S1]], float [[S0]], float [[Y]])
; CHECK-NEXT:    ret float [[RET]]
;
  %s0 = select i1 %c, float %a, float %b
  %s1 = select i1 %c1, float %b, float %a
  %ret = call float @llvm.fma.f32(float %s1, float %s0, float %y)
  ret float %ret
}

define float @fold_select_fma_match_neg(i1 %c, float %a, float %b, float %y) {
; CHECK-LABEL: define float @fold_select_fma_match_neg(
; CHECK-SAME: i1 [[C:%.*]], float [[A:%.*]], float [[B:%.*]], float [[Y:%.*]]) {
; CHECK-NEXT:    [[S0:%.*]] = select i1 [[C]], float [[A]], float [[B]]
; CHECK-NEXT:    [[S1:%.*]] = select i1 [[C]], float [[B]], float [[A]]
; CHECK-NEXT:    [[RET:%.*]] = call float @llvm.fma.f32(float [[Y]], float [[S0]], float [[S1]])
; CHECK-NEXT:    ret float [[RET]]
;
  %s0 = select i1 %c, float %a, float %b
  %s1 = select i1 %c, float %b, float %a
  %ret = call float @llvm.fma.f32(float %y, float %s0, float %s1)
  ret float %ret
}