llvm/llvm/test/Transforms/InstCombine/ldexp.ll

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

declare float @llvm.ldexp.f32.i32(float, i32)
declare <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float>, <2 x i32>)
declare float @llvm.ldexp.f32.i64(float, i64)

; select c, (ldexp val, e0), (ldexp val, e1) -> ldexp val, (select c, e0, e1)
define float @select_ldexp_f32_sameval_differentexp(i1 %cond, float %val, i32 %exp0, i32 %exp1) {
; CHECK-LABEL: define float @select_ldexp_f32_sameval_differentexp
; CHECK-SAME: (i1 [[COND:%.*]], float [[VAL:%.*]], i32 [[EXP0:%.*]], i32 [[EXP1:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[COND]], i32 [[EXP0]], i32 [[EXP1]]
; CHECK-NEXT:    [[SELECT:%.*]] = call float @llvm.ldexp.f32.i32(float [[VAL]], i32 [[TMP1]])
; CHECK-NEXT:    ret float [[SELECT]]
;
  %ldexp0 = call float @llvm.ldexp.f32.i32(float %val, i32 %exp0)
  %ldexp1 = call float @llvm.ldexp.f32.i32(float %val, i32 %exp1)
  %select = select i1 %cond, float %ldexp0, float %ldexp1
  ret float %select
}

define float @select_ldexp_f32_sameval_differentexp_selectflags(i1 %cond, float %val, i32 %exp0, i32 %exp1) {
; CHECK-LABEL: define float @select_ldexp_f32_sameval_differentexp_selectflags
; CHECK-SAME: (i1 [[COND:%.*]], float [[VAL:%.*]], i32 [[EXP0:%.*]], i32 [[EXP1:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[COND]], i32 [[EXP0]], i32 [[EXP1]]
; CHECK-NEXT:    [[SELECT:%.*]] = call nnan float @llvm.ldexp.f32.i32(float [[VAL]], i32 [[TMP1]])
; CHECK-NEXT:    ret float [[SELECT]]
;
  %ldexp0 = call float @llvm.ldexp.f32.i32(float %val, i32 %exp0)
  %ldexp1 = call float @llvm.ldexp.f32.i32(float %val, i32 %exp1)
  %select = select nnan i1 %cond, float %ldexp0, float %ldexp1
  ret float %select
}

define float @select_ldexp_f32_sameval_differentexp_ldexp_intersect_flags(i1 %cond, float %val, i32 %exp0, i32 %exp1) {
; CHECK-LABEL: define float @select_ldexp_f32_sameval_differentexp_ldexp_intersect_flags
; CHECK-SAME: (i1 [[COND:%.*]], float [[VAL:%.*]], i32 [[EXP0:%.*]], i32 [[EXP1:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[COND]], i32 [[EXP0]], i32 [[EXP1]]
; CHECK-NEXT:    [[SELECT:%.*]] = call nnan float @llvm.ldexp.f32.i32(float [[VAL]], i32 [[TMP1]])
; CHECK-NEXT:    ret float [[SELECT]]
;
  %ldexp0 = call nnan nsz float @llvm.ldexp.f32.i32(float %val, i32 %exp0)
  %ldexp1 = call nnan float @llvm.ldexp.f32.i32(float %val, i32 %exp1)
  %select = select i1 %cond, float %ldexp0, float %ldexp1
  ret float %select
}

define float @select_ldexp_f32_sameval_differentexp_ldexp_intersect_flags_union_select(i1 %cond, float %val, i32 %exp0, i32 %exp1) {
; CHECK-LABEL: define float @select_ldexp_f32_sameval_differentexp_ldexp_intersect_flags_union_select
; CHECK-SAME: (i1 [[COND:%.*]], float [[VAL:%.*]], i32 [[EXP0:%.*]], i32 [[EXP1:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[COND]], i32 [[EXP0]], i32 [[EXP1]]
; CHECK-NEXT:    [[SELECT:%.*]] = call nnan ninf float @llvm.ldexp.f32.i32(float [[VAL]], i32 [[TMP1]])
; CHECK-NEXT:    ret float [[SELECT]]
;
  %ldexp0 = call nnan nsz float @llvm.ldexp.f32.i32(float %val, i32 %exp0)
  %ldexp1 = call nnan float @llvm.ldexp.f32.i32(float %val, i32 %exp1)
  %select = select ninf i1 %cond, float %ldexp0, float %ldexp1
  ret float %select
}

define float @select_ldexp_f32_sameval_differentexp_multiuse0(i1 %cond, float %val, i32 %exp0, i32 %exp1, ptr %ptr) {
; CHECK-LABEL: define float @select_ldexp_f32_sameval_differentexp_multiuse0
; CHECK-SAME: (i1 [[COND:%.*]], float [[VAL:%.*]], i32 [[EXP0:%.*]], i32 [[EXP1:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT:    [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[VAL]], i32 [[EXP0]])
; CHECK-NEXT:    store float [[LDEXP0]], ptr [[PTR]], align 4
; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[COND]], i32 [[EXP0]], i32 [[EXP1]]
; CHECK-NEXT:    [[SELECT:%.*]] = call float @llvm.ldexp.f32.i32(float [[VAL]], i32 [[TMP1]])
; CHECK-NEXT:    ret float [[SELECT]]
;
  %ldexp0 = call float @llvm.ldexp.f32.i32(float %val, i32 %exp0)
  store float %ldexp0, ptr %ptr
  %ldexp1 = call float @llvm.ldexp.f32.i32(float %val, i32 %exp1)
  %select = select i1 %cond, float %ldexp0, float %ldexp1
  ret float %select
}

define float @select_ldexp_f32_sameval_differentexp_multiuse1(i1 %cond, float %val, i32 %exp0, i32 %exp1, ptr %ptr) {
; CHECK-LABEL: define float @select_ldexp_f32_sameval_differentexp_multiuse1
; CHECK-SAME: (i1 [[COND:%.*]], float [[VAL:%.*]], i32 [[EXP0:%.*]], i32 [[EXP1:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT:    [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[VAL]], i32 [[EXP1]])
; CHECK-NEXT:    store float [[LDEXP1]], ptr [[PTR]], align 4
; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[COND]], i32 [[EXP0]], i32 [[EXP1]]
; CHECK-NEXT:    [[SELECT:%.*]] = call float @llvm.ldexp.f32.i32(float [[VAL]], i32 [[TMP1]])
; CHECK-NEXT:    ret float [[SELECT]]
;
  %ldexp0 = call float @llvm.ldexp.f32.i32(float %val, i32 %exp0)
  %ldexp1 = call float @llvm.ldexp.f32.i32(float %val, i32 %exp1)
  store float %ldexp1, ptr %ptr
  %select = select i1 %cond, float %ldexp0, float %ldexp1
  ret float %select
}

define float @select_ldexp_f32_sameval_differentexp_multiuse_both(i1 %cond, float %val, i32 %exp0, i32 %exp1, ptr %ptr0, ptr %ptr1) {
; CHECK-LABEL: define float @select_ldexp_f32_sameval_differentexp_multiuse_both
; CHECK-SAME: (i1 [[COND:%.*]], float [[VAL:%.*]], i32 [[EXP0:%.*]], i32 [[EXP1:%.*]], ptr [[PTR0:%.*]], ptr [[PTR1:%.*]]) {
; CHECK-NEXT:    [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[VAL]], i32 [[EXP0]])
; CHECK-NEXT:    store float [[LDEXP0]], ptr [[PTR0]], align 4
; CHECK-NEXT:    [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[VAL]], i32 [[EXP1]])
; CHECK-NEXT:    store float [[LDEXP1]], ptr [[PTR1]], align 4
; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[LDEXP0]], float [[LDEXP1]]
; CHECK-NEXT:    ret float [[SELECT]]
;
  %ldexp0 = call float @llvm.ldexp.f32.i32(float %val, i32 %exp0)
  store float %ldexp0, ptr %ptr0
  %ldexp1 = call float @llvm.ldexp.f32.i32(float %val, i32 %exp1)
  store float %ldexp1, ptr %ptr1
  %select = select i1 %cond, float %ldexp0, float %ldexp1
  ret float %select
}

; select c, (ldexp val0, e), (ldexp val1, ee) -> ldexp (select c, val0, val1), e
define float @select_ldexp_f32_differentval_sameexp(i1 %cond, float %val0, float %val1, i32 %exp) {
; CHECK-LABEL: define float @select_ldexp_f32_differentval_sameexp
; CHECK-SAME: (i1 [[COND:%.*]], float [[VAL0:%.*]], float [[VAL1:%.*]], i32 [[EXP:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[COND]], float [[VAL0]], float [[VAL1]]
; CHECK-NEXT:    [[SELECT:%.*]] = call float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[EXP]])
; CHECK-NEXT:    ret float [[SELECT]]
;
  %ldexp0 = call float @llvm.ldexp.f32.i32(float %val0, i32 %exp)
  %ldexp1 = call float @llvm.ldexp.f32.i32(float %val1, i32 %exp)
  %select = select i1 %cond, float %ldexp0, float %ldexp1
  ret float %select
}

define float @select_ldexp_f32_differentval_sameexp_selectflags(i1 %cond, float %val0, float %val1, i32 %exp) {
; CHECK-LABEL: define float @select_ldexp_f32_differentval_sameexp_selectflags
; CHECK-SAME: (i1 [[COND:%.*]], float [[VAL0:%.*]], float [[VAL1:%.*]], i32 [[EXP:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[COND]], float [[VAL0]], float [[VAL1]]
; CHECK-NEXT:    [[SELECT:%.*]] = call nnan float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[EXP]])
; CHECK-NEXT:    ret float [[SELECT]]
;
  %ldexp0 = call float @llvm.ldexp.f32.i32(float %val0, i32 %exp)
  %ldexp1 = call float @llvm.ldexp.f32.i32(float %val1, i32 %exp)
  %select = select nnan i1 %cond, float %ldexp0, float %ldexp1
  ret float %select
}

define float @select_ldexp_f32_differentval_sameexp_ldexp_intersect_flags(i1 %cond, float %val0, float %val1, i32 %exp) {
; CHECK-LABEL: define float @select_ldexp_f32_differentval_sameexp_ldexp_intersect_flags
; CHECK-SAME: (i1 [[COND:%.*]], float [[VAL0:%.*]], float [[VAL1:%.*]], i32 [[EXP:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[COND]], float [[VAL0]], float [[VAL1]]
; CHECK-NEXT:    [[SELECT:%.*]] = call nnan float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[EXP]])
; CHECK-NEXT:    ret float [[SELECT]]
;
  %ldexp0 = call nnan nsz float @llvm.ldexp.f32.i32(float %val0, i32 %exp)
  %ldexp1 = call nnan float @llvm.ldexp.f32.i32(float %val1, i32 %exp)
  %select = select i1 %cond, float %ldexp0, float %ldexp1
  ret float %select
}

define float @select_ldexp_f32_differentval_sameexp_ldexp_intersect_flags_unino_select(i1 %cond, float %val0, float %val1, i32 %exp) {
; CHECK-LABEL: define float @select_ldexp_f32_differentval_sameexp_ldexp_intersect_flags_unino_select
; CHECK-SAME: (i1 [[COND:%.*]], float [[VAL0:%.*]], float [[VAL1:%.*]], i32 [[EXP:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[COND]], float [[VAL0]], float [[VAL1]]
; CHECK-NEXT:    [[SELECT:%.*]] = call nnan ninf float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[EXP]])
; CHECK-NEXT:    ret float [[SELECT]]
;
  %ldexp0 = call nnan nsz float @llvm.ldexp.f32.i32(float %val0, i32 %exp)
  %ldexp1 = call nnan float @llvm.ldexp.f32.i32(float %val1, i32 %exp)
  %select = select ninf i1 %cond, float %ldexp0, float %ldexp1
  ret float %select
}

define float @select_ldexp_f32_differentval_sameexp_multiuse0(i1 %cond, float %val0, float %val1, i32 %exp, ptr %ptr) {
; CHECK-LABEL: define float @select_ldexp_f32_differentval_sameexp_multiuse0
; CHECK-SAME: (i1 [[COND:%.*]], float [[VAL0:%.*]], float [[VAL1:%.*]], i32 [[EXP:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT:    [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[VAL0]], i32 [[EXP]])
; CHECK-NEXT:    store float [[LDEXP0]], ptr [[PTR]], align 4
; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[COND]], float [[VAL0]], float [[VAL1]]
; CHECK-NEXT:    [[SELECT:%.*]] = call float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[EXP]])
; CHECK-NEXT:    ret float [[SELECT]]
;
  %ldexp0 = call float @llvm.ldexp.f32.i32(float %val0, i32 %exp)
  store float %ldexp0, ptr %ptr
  %ldexp1 = call float @llvm.ldexp.f32.i32(float %val1, i32 %exp)
  %select = select i1 %cond, float %ldexp0, float %ldexp1
  ret float %select
}

define float @select_ldexp_f32_differentval_sameexp_multiuse1(i1 %cond, float %val0, float %val1, i32 %exp, ptr %ptr) {
; CHECK-LABEL: define float @select_ldexp_f32_differentval_sameexp_multiuse1
; CHECK-SAME: (i1 [[COND:%.*]], float [[VAL0:%.*]], float [[VAL1:%.*]], i32 [[EXP:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT:    [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[VAL1]], i32 [[EXP]])
; CHECK-NEXT:    store float [[LDEXP1]], ptr [[PTR]], align 4
; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[COND]], float [[VAL0]], float [[VAL1]]
; CHECK-NEXT:    [[SELECT:%.*]] = call float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[EXP]])
; CHECK-NEXT:    ret float [[SELECT]]
;
  %ldexp0 = call float @llvm.ldexp.f32.i32(float %val0, i32 %exp)
  %ldexp1 = call float @llvm.ldexp.f32.i32(float %val1, i32 %exp)
  store float %ldexp1, ptr %ptr
  %select = select i1 %cond, float %ldexp0, float %ldexp1
  ret float %select
}

define float @select_ldexp_f32_differentval_differentexp(i1 %cond, float %val0, float %val1, i32 %exp0, i32 %exp1) {
; CHECK-LABEL: define float @select_ldexp_f32_differentval_differentexp
; CHECK-SAME: (i1 [[COND:%.*]], float [[VAL0:%.*]], float [[VAL1:%.*]], i32 [[EXP0:%.*]], i32 [[EXP1:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[COND]], float [[VAL0]], float [[VAL1]]
; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[COND]], i32 [[EXP0]], i32 [[EXP1]]
; CHECK-NEXT:    [[SELECT:%.*]] = call float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[TMP2]])
; CHECK-NEXT:    ret float [[SELECT]]
;
  %ldexp0 = call float @llvm.ldexp.f32.i32(float %val0, i32 %exp0)
  %ldexp1 = call float @llvm.ldexp.f32.i32(float %val1, i32 %exp1)
  %select = select i1 %cond, float %ldexp0, float %ldexp1
  ret float %select
}

define float @select_ldexp_f32_differentval_differentexp_multiuse0(i1 %cond, float %val0, float %val1, i32 %exp0, i32 %exp1, ptr %ptr) {
; CHECK-LABEL: define float @select_ldexp_f32_differentval_differentexp_multiuse0
; CHECK-SAME: (i1 [[COND:%.*]], float [[VAL0:%.*]], float [[VAL1:%.*]], i32 [[EXP0:%.*]], i32 [[EXP1:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT:    [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[VAL0]], i32 [[EXP0]])
; CHECK-NEXT:    store float [[LDEXP0]], ptr [[PTR]], align 4
; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[COND]], float [[VAL0]], float [[VAL1]]
; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[COND]], i32 [[EXP0]], i32 [[EXP1]]
; CHECK-NEXT:    [[SELECT:%.*]] = call float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[TMP2]])
; CHECK-NEXT:    ret float [[SELECT]]
;
  %ldexp0 = call float @llvm.ldexp.f32.i32(float %val0, i32 %exp0)
  store float %ldexp0, ptr %ptr
  %ldexp1 = call float @llvm.ldexp.f32.i32(float %val1, i32 %exp1)
  %select = select i1 %cond, float %ldexp0, float %ldexp1
  ret float %select
}

define float @select_ldexp_f32_differentval_differentexp_multiuse1(i1 %cond, float %val0, float %val1, i32 %exp0, i32 %exp1, ptr %ptr) {
; CHECK-LABEL: define float @select_ldexp_f32_differentval_differentexp_multiuse1
; CHECK-SAME: (i1 [[COND:%.*]], float [[VAL0:%.*]], float [[VAL1:%.*]], i32 [[EXP0:%.*]], i32 [[EXP1:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT:    [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[VAL1]], i32 [[EXP1]])
; CHECK-NEXT:    store float [[LDEXP1]], ptr [[PTR]], align 4
; CHECK-NEXT:    [[TMP1:%.*]] = select i1 [[COND]], float [[VAL0]], float [[VAL1]]
; CHECK-NEXT:    [[TMP2:%.*]] = select i1 [[COND]], i32 [[EXP0]], i32 [[EXP1]]
; CHECK-NEXT:    [[SELECT:%.*]] = call float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[TMP2]])
; CHECK-NEXT:    ret float [[SELECT]]
;
  %ldexp0 = call float @llvm.ldexp.f32.i32(float %val0, i32 %exp0)
  %ldexp1 = call float @llvm.ldexp.f32.i32(float %val1, i32 %exp1)
  store float %ldexp1, ptr %ptr
  %select = select i1 %cond, float %ldexp0, float %ldexp1
  ret float %select
}

define float @select_ldexp_f32_differentval_differentexp_multiuse_both(i1 %cond, float %val0, float %val1, i32 %exp0, i32 %exp1, ptr %ptr0, ptr %ptr1) {
; CHECK-LABEL: define float @select_ldexp_f32_differentval_differentexp_multiuse_both
; CHECK-SAME: (i1 [[COND:%.*]], float [[VAL0:%.*]], float [[VAL1:%.*]], i32 [[EXP0:%.*]], i32 [[EXP1:%.*]], ptr [[PTR0:%.*]], ptr [[PTR1:%.*]]) {
; CHECK-NEXT:    [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[VAL0]], i32 [[EXP0]])
; CHECK-NEXT:    store float [[LDEXP0]], ptr [[PTR0]], align 4
; CHECK-NEXT:    [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[VAL1]], i32 [[EXP1]])
; CHECK-NEXT:    store float [[LDEXP1]], ptr [[PTR1]], align 4
; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[LDEXP0]], float [[LDEXP1]]
; CHECK-NEXT:    ret float [[SELECT]]
;
  %ldexp0 = call float @llvm.ldexp.f32.i32(float %val0, i32 %exp0)
  store float %ldexp0, ptr %ptr0
  %ldexp1 = call float @llvm.ldexp.f32.i32(float %val1, i32 %exp1)
  store float %ldexp1, ptr %ptr1
  %select = select i1 %cond, float %ldexp0, float %ldexp1
  ret float %select
}

define <2 x float> @select_ldexp_v2f32_sameval_differentexp(<2 x i1> %cond, <2 x float> %val, <2 x i32> %exp0, <2 x i32> %exp1) {
; CHECK-LABEL: define <2 x float> @select_ldexp_v2f32_sameval_differentexp
; CHECK-SAME: (<2 x i1> [[COND:%.*]], <2 x float> [[VAL:%.*]], <2 x i32> [[EXP0:%.*]], <2 x i32> [[EXP1:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = select <2 x i1> [[COND]], <2 x i32> [[EXP0]], <2 x i32> [[EXP1]]
; CHECK-NEXT:    [[SELECT:%.*]] = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[VAL]], <2 x i32> [[TMP1]])
; CHECK-NEXT:    ret <2 x float> [[SELECT]]
;
  %ldexp0 = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> %val, <2 x i32> %exp0)
  %ldexp1 = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> %val, <2 x i32> %exp1)
  %select = select <2 x i1> %cond, <2 x float> %ldexp0, <2 x float> %ldexp1
  ret <2 x float> %select
}

define <2 x float> @select_ldexp_v2f32_differentval_sameexp(<2 x i1> %cond, <2 x float> %val0, <2 x float> %val1, <2 x i32> %exp) {
; CHECK-LABEL: define <2 x float> @select_ldexp_v2f32_differentval_sameexp
; CHECK-SAME: (<2 x i1> [[COND:%.*]], <2 x float> [[VAL0:%.*]], <2 x float> [[VAL1:%.*]], <2 x i32> [[EXP:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = select <2 x i1> [[COND]], <2 x float> [[VAL0]], <2 x float> [[VAL1]]
; CHECK-NEXT:    [[SELECT:%.*]] = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[TMP1]], <2 x i32> [[EXP]])
; CHECK-NEXT:    ret <2 x float> [[SELECT]]
;
  %ldexp0 = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> %val0, <2 x i32> %exp)
  %ldexp1 = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> %val1, <2 x i32> %exp)
  %select = select <2 x i1> %cond, <2 x float> %ldexp0, <2 x float> %ldexp1
  ret <2 x float> %select
}

define <2 x float> @select_ldexp_v2f32_differentval_differentexp(<2 x i1> %cond, <2 x float> %val0, <2 x float> %val1, <2 x i32> %exp0, <2 x i32> %exp1) {
; CHECK-LABEL: define <2 x float> @select_ldexp_v2f32_differentval_differentexp
; CHECK-SAME: (<2 x i1> [[COND:%.*]], <2 x float> [[VAL0:%.*]], <2 x float> [[VAL1:%.*]], <2 x i32> [[EXP0:%.*]], <2 x i32> [[EXP1:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = select <2 x i1> [[COND]], <2 x float> [[VAL0]], <2 x float> [[VAL1]]
; CHECK-NEXT:    [[TMP2:%.*]] = select <2 x i1> [[COND]], <2 x i32> [[EXP0]], <2 x i32> [[EXP1]]
; CHECK-NEXT:    [[SELECT:%.*]] = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[TMP1]], <2 x i32> [[TMP2]])
; CHECK-NEXT:    ret <2 x float> [[SELECT]]
;
  %ldexp0 = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> %val0, <2 x i32> %exp0)
  %ldexp1 = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> %val1, <2 x i32> %exp1)
  %select = select <2 x i1> %cond, <2 x float> %ldexp0, <2 x float> %ldexp1
  ret <2 x float> %select
}

define float @select_ldexp_f32_same(i1 %cond, float %val, i32 %exp) {
; CHECK-LABEL: define float @select_ldexp_f32_same
; CHECK-SAME: (i1 [[COND:%.*]], float [[VAL:%.*]], i32 [[EXP:%.*]]) {
; CHECK-NEXT:    [[SELECT:%.*]] = call float @llvm.ldexp.f32.i32(float [[VAL]], i32 [[EXP]])
; CHECK-NEXT:    ret float [[SELECT]]
;
  %ldexp0 = call float @llvm.ldexp.f32.i32(float %val, i32 %exp)
  %ldexp1 = call float @llvm.ldexp.f32.i32(float %val, i32 %exp)
  %select = select i1 %cond, float %ldexp0, float %ldexp1
  ret float %select
}

define float @select_ldexp_f32_sameval_differentexp_types(i1 %cond, float %val, i32 %exp0, i64 %exp1) {
; CHECK-LABEL: define float @select_ldexp_f32_sameval_differentexp_types
; CHECK-SAME: (i1 [[COND:%.*]], float [[VAL:%.*]], i32 [[EXP0:%.*]], i64 [[EXP1:%.*]]) {
; CHECK-NEXT:    [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[VAL]], i32 [[EXP0]])
; CHECK-NEXT:    [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i64(float [[VAL]], i64 [[EXP1]])
; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], float [[LDEXP0]], float [[LDEXP1]]
; CHECK-NEXT:    ret float [[SELECT]]
;
  %ldexp0 = call float @llvm.ldexp.f32.i32(float %val, i32 %exp0)
  %ldexp1 = call float @llvm.ldexp.f32.i64(float %val, i64 %exp1)
  %select = select i1 %cond, float %ldexp0, float %ldexp1
  ret float %select
}

;---------------------------------------------------------------------
; ldexp(ldexp(x, a), b) -> ldexp(x, a + b)
;---------------------------------------------------------------------

define float @ldexp_ldexp(float %x, i32 %a, i32 %b) {
; CHECK-LABEL: define float @ldexp_ldexp
; CHECK-SAME: (float [[X:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]) {
; CHECK-NEXT:    [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 [[A]])
; CHECK-NEXT:    [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[LDEXP0]], i32 [[B]])
; CHECK-NEXT:    ret float [[LDEXP1]]
;
  %ldexp0 = call float @llvm.ldexp.f32.i32(float %x, i32 %a)
  %ldexp1 = call float @llvm.ldexp.f32.i32(float %ldexp0, i32 %b)
  ret float %ldexp1
}

define float @ldexp_reassoc_ldexp(float %x, i32 %a, i32 %b) {
; CHECK-LABEL: define float @ldexp_reassoc_ldexp
; CHECK-SAME: (float [[X:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]) {
; CHECK-NEXT:    [[LDEXP0:%.*]] = call reassoc float @llvm.ldexp.f32.i32(float [[X]], i32 [[A]])
; CHECK-NEXT:    [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[LDEXP0]], i32 [[B]])
; CHECK-NEXT:    ret float [[LDEXP1]]
;
  %ldexp0 = call reassoc float @llvm.ldexp.f32.i32(float %x, i32 %a)
  %ldexp1 = call float @llvm.ldexp.f32.i32(float %ldexp0, i32 %b)
  ret float %ldexp1
}

define float @ldexp_ldexp_reassoc(float %x, i32 %a, i32 %b) {
; CHECK-LABEL: define float @ldexp_ldexp_reassoc
; CHECK-SAME: (float [[X:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]) {
; CHECK-NEXT:    [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 [[A]])
; CHECK-NEXT:    [[LDEXP1:%.*]] = call reassoc float @llvm.ldexp.f32.i32(float [[LDEXP0]], i32 [[B]])
; CHECK-NEXT:    ret float [[LDEXP1]]
;
  %ldexp0 = call float @llvm.ldexp.f32.i32(float %x, i32 %a)
  %ldexp1 = call reassoc float @llvm.ldexp.f32.i32(float %ldexp0, i32 %b)
  ret float %ldexp1
}

define float @ldexp_reassoc_ldexp_reassoc(float %x, i32 %a, i32 %b) {
; CHECK-LABEL: define float @ldexp_reassoc_ldexp_reassoc
; CHECK-SAME: (float [[X:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[A]], [[B]]
; CHECK-NEXT:    [[LDEXP1:%.*]] = call reassoc float @llvm.ldexp.f32.i32(float [[X]], i32 [[TMP1]])
; CHECK-NEXT:    ret float [[LDEXP1]]
;
  %ldexp0 = call reassoc float @llvm.ldexp.f32.i32(float %x, i32 %a)
  %ldexp1 = call reassoc float @llvm.ldexp.f32.i32(float %ldexp0, i32 %b)
  ret float %ldexp1
}

define float @ldexp_reassoc_nsz_ldexp_reassoc_nsz(float %x, i32 %a, i32 %b) {
; CHECK-LABEL: define float @ldexp_reassoc_nsz_ldexp_reassoc_nsz
; CHECK-SAME: (float [[X:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[A]], [[B]]
; CHECK-NEXT:    [[LDEXP1:%.*]] = call reassoc nsz float @llvm.ldexp.f32.i32(float [[X]], i32 [[TMP1]])
; CHECK-NEXT:    ret float [[LDEXP1]]
;
  %ldexp0 = call reassoc nsz float @llvm.ldexp.f32.i32(float %x, i32 %a)
  %ldexp1 = call reassoc nsz float @llvm.ldexp.f32.i32(float %ldexp0, i32 %b)
  ret float %ldexp1
}

; Test that we or the inner and outer flags
define float @ldexp_reassoc_ldexp_reassoc_preserve_flags(float %x, i32 %a, i32 %b) {
; CHECK-LABEL: define float @ldexp_reassoc_ldexp_reassoc_preserve_flags
; CHECK-SAME: (float [[X:%.*]], i32 [[A:%.*]], i32 [[B:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = add i32 [[A]], [[B]]
; CHECK-NEXT:    [[LDEXP1:%.*]] = call reassoc nnan ninf float @llvm.ldexp.f32.i32(float [[X]], i32 [[TMP1]])
; CHECK-NEXT:    ret float [[LDEXP1]]
;
  %ldexp0 = call reassoc ninf float @llvm.ldexp.f32.i32(float %x, i32 %a)
  %ldexp1 = call reassoc nnan float @llvm.ldexp.f32.i32(float %ldexp0, i32 %b)
  ret float %ldexp1
}

define <2 x float> @ldexp_reassoc_ldexp_reassoc_vec(<2 x float> %x, <2 x i32> %a, <2 x i32> %b) {
; CHECK-LABEL: define <2 x float> @ldexp_reassoc_ldexp_reassoc_vec
; CHECK-SAME: (<2 x float> [[X:%.*]], <2 x i32> [[A:%.*]], <2 x i32> [[B:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = add <2 x i32> [[A]], [[B]]
; CHECK-NEXT:    [[LDEXP1:%.*]] = call reassoc <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[X]], <2 x i32> [[TMP1]])
; CHECK-NEXT:    ret <2 x float> [[LDEXP1]]
;
  %ldexp0 = call reassoc <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> %x, <2 x i32> %a)
  %ldexp1 = call reassoc <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> %ldexp0, <2 x i32> %b)
  ret <2 x float> %ldexp1
}

define float @ldexp_multi_use_ldexp(float %x, i32 %a, i32 %b, ptr %ptr) {
; CHECK-LABEL: define float @ldexp_multi_use_ldexp
; CHECK-SAME: (float [[X:%.*]], i32 [[A:%.*]], i32 [[B:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT:    [[LDEXP0:%.*]] = call reassoc float @llvm.ldexp.f32.i32(float [[X]], i32 [[A]])
; CHECK-NEXT:    store float [[LDEXP0]], ptr [[PTR]], align 4
; CHECK-NEXT:    [[LDEXP1:%.*]] = call reassoc float @llvm.ldexp.f32.i32(float [[LDEXP0]], i32 [[B]])
; CHECK-NEXT:    ret float [[LDEXP1]]
;
  %ldexp0 = call reassoc float @llvm.ldexp.f32.i32(float %x, i32 %a)
  store float %ldexp0, ptr %ptr
  %ldexp1 = call reassoc float @llvm.ldexp.f32.i32(float %ldexp0, i32 %b)
  ret float %ldexp1
}

; Test edge case where the intrinsic is declared with different int types.
define float @ldexp_ldexp_different_exp_type(float %x, i32 %a, i64 %b) {
; CHECK-LABEL: define float @ldexp_ldexp_different_exp_type
; CHECK-SAME: (float [[X:%.*]], i32 [[A:%.*]], i64 [[B:%.*]]) {
; CHECK-NEXT:    [[LDEXP0:%.*]] = call reassoc float @llvm.ldexp.f32.i32(float [[X]], i32 [[A]])
; CHECK-NEXT:    [[LDEXP1:%.*]] = call reassoc float @llvm.ldexp.f32.i64(float [[LDEXP0]], i64 [[B]])
; CHECK-NEXT:    ret float [[LDEXP1]]
;
  %ldexp0 = call reassoc float @llvm.ldexp.f32.i32(float %x, i32 %a)
  %ldexp1 = call reassoc float @llvm.ldexp.f32.i64(float %ldexp0, i64 %b)
  ret float %ldexp1
}

define float @ldexp_ldexp_constants(float %x) {
; CHECK-LABEL: define float @ldexp_ldexp_constants
; CHECK-SAME: (float [[X:%.*]]) {
; CHECK-NEXT:    [[LDEXP1:%.*]] = call reassoc float @llvm.ldexp.f32.i32(float [[X]], i32 32)
; CHECK-NEXT:    ret float [[LDEXP1]]
;
  %ldexp0 = call reassoc float @llvm.ldexp.f32.i32(float %x, i32 8)
  %ldexp1 = call reassoc float @llvm.ldexp.f32.i32(float %ldexp0, i32 24)
  ret float %ldexp1
}

define float @ldexp_ldexp_constants_nsz(float %x) {
; CHECK-LABEL: define float @ldexp_ldexp_constants_nsz
; CHECK-SAME: (float [[X:%.*]]) {
; CHECK-NEXT:    [[LDEXP1:%.*]] = call reassoc nsz float @llvm.ldexp.f32.i32(float [[X]], i32 32)
; CHECK-NEXT:    ret float [[LDEXP1]]
;
  %ldexp0 = call reassoc nsz float @llvm.ldexp.f32.i32(float %x, i32 8)
  %ldexp1 = call reassoc nsz float @llvm.ldexp.f32.i32(float %ldexp0, i32 24)
  ret float %ldexp1
}

define float @ldexp_ldexp_constants_nsz0(float %x) {
; CHECK-LABEL: define float @ldexp_ldexp_constants_nsz0
; CHECK-SAME: (float [[X:%.*]]) {
; CHECK-NEXT:    [[LDEXP1:%.*]] = call reassoc nsz float @llvm.ldexp.f32.i32(float [[X]], i32 32)
; CHECK-NEXT:    ret float [[LDEXP1]]
;
  %ldexp0 = call reassoc nsz float @llvm.ldexp.f32.i32(float %x, i32 8)
  %ldexp1 = call reassoc float @llvm.ldexp.f32.i32(float %ldexp0, i32 24)
  ret float %ldexp1
}

define float @ldexp_ldexp_constants_nsz1(float %x) {
; CHECK-LABEL: define float @ldexp_ldexp_constants_nsz1
; CHECK-SAME: (float [[X:%.*]]) {
; CHECK-NEXT:    [[LDEXP1:%.*]] = call reassoc nsz float @llvm.ldexp.f32.i32(float [[X]], i32 32)
; CHECK-NEXT:    ret float [[LDEXP1]]
;
  %ldexp0 = call reassoc float @llvm.ldexp.f32.i32(float %x, i32 8)
  %ldexp1 = call reassoc nsz float @llvm.ldexp.f32.i32(float %ldexp0, i32 24)
  ret float %ldexp1
}

define float @ldexp_ldexp_opposite_constants(float %x) {
; CHECK-LABEL: define float @ldexp_ldexp_opposite_constants
; CHECK-SAME: (float [[X:%.*]]) {
; CHECK-NEXT:    ret float [[X]]
;
  %ldexp0 = call reassoc float @llvm.ldexp.f32.i32(float %x, i32 8)
  %ldexp1 = call reassoc float @llvm.ldexp.f32.i32(float %ldexp0, i32 -8)
  ret float %ldexp1
}

define float @ldexp_ldexp_negated_variable_reassoc(float %x, i32 %a) {
; CHECK-LABEL: define float @ldexp_ldexp_negated_variable_reassoc
; CHECK-SAME: (float [[X:%.*]], i32 [[A:%.*]]) {
; CHECK-NEXT:    ret float [[X]]
;
  %ldexp0 = call reassoc float @llvm.ldexp.f32.i32(float %x, i32 %a)
  %neg.a = sub i32 0, %a
  %ldexp1 = call reassoc float @llvm.ldexp.f32.i32(float %ldexp0, i32 %neg.a)
  ret float %ldexp1
}

define float @ldexp_ldexp_negated_variable(float %x, i32 %a) {
; CHECK-LABEL: define float @ldexp_ldexp_negated_variable
; CHECK-SAME: (float [[X:%.*]], i32 [[A:%.*]]) {
; CHECK-NEXT:    [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 [[A]])
; CHECK-NEXT:    [[NEG_A:%.*]] = sub i32 0, [[A]]
; CHECK-NEXT:    [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[LDEXP0]], i32 [[NEG_A]])
; CHECK-NEXT:    ret float [[LDEXP1]]
;
  %ldexp0 = call float @llvm.ldexp.f32.i32(float %x, i32 %a)
  %neg.a = sub i32 0, %a
  %ldexp1 = call float @llvm.ldexp.f32.i32(float %ldexp0, i32 %neg.a)
  ret float %ldexp1
}

define float @ldexp_ldexp_first_exp_known_positive(float %x, i32 %a.arg, i32 %b) {
; CHECK-LABEL: define float @ldexp_ldexp_first_exp_known_positive
; CHECK-SAME: (float [[X:%.*]], i32 [[A_ARG:%.*]], i32 [[B:%.*]]) {
; CHECK-NEXT:    [[A:%.*]] = and i32 [[A_ARG]], 127
; CHECK-NEXT:    [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 [[A]])
; CHECK-NEXT:    [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[LDEXP0]], i32 [[B]])
; CHECK-NEXT:    ret float [[LDEXP1]]
;
  %a = and i32 %a.arg, 127
  %ldexp0 = call float @llvm.ldexp.f32.i32(float %x, i32 %a)
  %ldexp1 = call float @llvm.ldexp.f32.i32(float %ldexp0, i32 %b)
  ret float %ldexp1
}

define float @ldexp_ldexp_first_second_known_positive(float %x, i32 %a, i32 %b.arg) {
; CHECK-LABEL: define float @ldexp_ldexp_first_second_known_positive
; CHECK-SAME: (float [[X:%.*]], i32 [[A:%.*]], i32 [[B_ARG:%.*]]) {
; CHECK-NEXT:    [[B:%.*]] = and i32 [[B_ARG]], 127
; CHECK-NEXT:    [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 [[A]])
; CHECK-NEXT:    [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[LDEXP0]], i32 [[B]])
; CHECK-NEXT:    ret float [[LDEXP1]]
;
  %b = and i32 %b.arg, 127
  %ldexp0 = call float @llvm.ldexp.f32.i32(float %x, i32 %a)
  %ldexp1 = call float @llvm.ldexp.f32.i32(float %ldexp0, i32 %b)
  ret float %ldexp1
}

define float @ldexp_ldexp_both_exp_known_positive(float %x, i32 %a.arg, i32 %b.arg) {
; CHECK-LABEL: define float @ldexp_ldexp_both_exp_known_positive
; CHECK-SAME: (float [[X:%.*]], i32 [[A_ARG:%.*]], i32 [[B_ARG:%.*]]) {
; CHECK-NEXT:    [[A:%.*]] = and i32 [[A_ARG]], 127
; CHECK-NEXT:    [[B:%.*]] = and i32 [[B_ARG]], 127
; CHECK-NEXT:    [[TMP1:%.*]] = add nuw nsw i32 [[A]], [[B]]
; CHECK-NEXT:    [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 [[TMP1]])
; CHECK-NEXT:    ret float [[LDEXP1]]
;
  %a = and i32 %a.arg, 127
  %b = and i32 %b.arg, 127
  %ldexp0 = call float @llvm.ldexp.f32.i32(float %x, i32 %a)
  %ldexp1 = call float @llvm.ldexp.f32.i32(float %ldexp0, i32 %b)
  ret float %ldexp1
}

define float @ldexp_ldexp_both_exp_known_negative(float %x, ptr %a.ptr, ptr %b.ptr) {
; CHECK-LABEL: define float @ldexp_ldexp_both_exp_known_negative
; CHECK-SAME: (float [[X:%.*]], ptr [[A_PTR:%.*]], ptr [[B_PTR:%.*]]) {
; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[A_PTR]], align 4, !range [[RNG0:![0-9]+]]
; CHECK-NEXT:    [[B:%.*]] = load i32, ptr [[B_PTR]], align 4, !range [[RNG0]]
; CHECK-NEXT:    [[TMP1:%.*]] = add nsw i32 [[A]], [[B]]
; CHECK-NEXT:    [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 [[TMP1]])
; CHECK-NEXT:    ret float [[LDEXP1]]
;
  %a = load i32, ptr %a.ptr, !range !0
  %b = load i32, ptr %b.ptr, !range !0
  %ldexp0 = call float @llvm.ldexp.f32.i32(float %x, i32 %a)
  %ldexp1 = call float @llvm.ldexp.f32.i32(float %ldexp0, i32 %b)
  ret float %ldexp1
}

define float @ldexp_ldexp_exp_known_negative_and_positive(float %x, ptr %a.ptr, ptr %b.ptr) {
; CHECK-LABEL: define float @ldexp_ldexp_exp_known_negative_and_positive
; CHECK-SAME: (float [[X:%.*]], ptr [[A_PTR:%.*]], ptr [[B_PTR:%.*]]) {
; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[A_PTR]], align 4, !range [[RNG0]]
; CHECK-NEXT:    [[B:%.*]] = load i32, ptr [[B_PTR]], align 4, !range [[RNG1:![0-9]+]]
; CHECK-NEXT:    [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 [[A]])
; CHECK-NEXT:    [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[LDEXP0]], i32 [[B]])
; CHECK-NEXT:    ret float [[LDEXP1]]
;
  %a = load i32, ptr %a.ptr, !range !0
  %b = load i32, ptr %b.ptr, !range !1
  %ldexp0 = call float @llvm.ldexp.f32.i32(float %x, i32 %a)
  %ldexp1 = call float @llvm.ldexp.f32.i32(float %ldexp0, i32 %b)
  ret float %ldexp1
}

define float @ldexp_ldexp_exp_known_positive_and_negative(float %x, ptr %a.ptr, ptr %b.ptr) {
; CHECK-LABEL: define float @ldexp_ldexp_exp_known_positive_and_negative
; CHECK-SAME: (float [[X:%.*]], ptr [[A_PTR:%.*]], ptr [[B_PTR:%.*]]) {
; CHECK-NEXT:    [[A:%.*]] = load i32, ptr [[A_PTR]], align 4, !range [[RNG1]]
; CHECK-NEXT:    [[B:%.*]] = load i32, ptr [[B_PTR]], align 4, !range [[RNG0]]
; CHECK-NEXT:    [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 [[A]])
; CHECK-NEXT:    [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[LDEXP0]], i32 [[B]])
; CHECK-NEXT:    ret float [[LDEXP1]]
;
  %a = load i32, ptr %a.ptr, !range !1
  %b = load i32, ptr %b.ptr, !range !0
  %ldexp0 = call float @llvm.ldexp.f32.i32(float %x, i32 %a)
  %ldexp1 = call float @llvm.ldexp.f32.i32(float %ldexp0, i32 %b)
  ret float %ldexp1
}

define float @ldexp_reassoc_ldexp_reassoc_0(float %x, i32 %y) {
; CHECK-LABEL: define float @ldexp_reassoc_ldexp_reassoc_0
; CHECK-SAME: (float [[X:%.*]], i32 [[Y:%.*]]) {
; CHECK-NEXT:    [[LDEXP1:%.*]] = call reassoc float @llvm.ldexp.f32.i32(float [[X]], i32 [[Y]])
; CHECK-NEXT:    ret float [[LDEXP1]]
;
  %ldexp0 = call reassoc float @llvm.ldexp.f32.i32(float %x, i32 0)
  %ldexp1 = call reassoc float @llvm.ldexp.f32.i32(float %ldexp0, i32 %y)
  ret float %ldexp1
}

define float @ldexp_ldexp_0(float %x, i32 %y) {
; CHECK-LABEL: define float @ldexp_ldexp_0
; CHECK-SAME: (float [[X:%.*]], i32 [[Y:%.*]]) {
; CHECK-NEXT:    [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 [[Y]])
; CHECK-NEXT:    ret float [[LDEXP1]]
;
  %ldexp0 = call float @llvm.ldexp.f32.i32(float %x, i32 0)
  %ldexp1 = call float @llvm.ldexp.f32.i32(float %ldexp0, i32 %y)
  ret float %ldexp1
}

;---------------------------------------------------------------------
; ldexp(x, k) -> fmul x, 2**k
;---------------------------------------------------------------------

define float @ldexp_neg150(float %x) {
; CHECK-LABEL: define float @ldexp_neg150
; CHECK-SAME: (float [[X:%.*]]) {
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 -150)
; CHECK-NEXT:    ret float [[LDEXP]]
;
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 -150)
  ret float %ldexp
}

define float @ldexp_neg149(float %x) {
; CHECK-LABEL: define float @ldexp_neg149
; CHECK-SAME: (float [[X:%.*]]) {
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 -149)
; CHECK-NEXT:    ret float [[LDEXP]]
;
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 -149)
  ret float %ldexp
}

define float @ldexp_neg148(float %x) {
; CHECK-LABEL: define float @ldexp_neg148
; CHECK-SAME: (float [[X:%.*]]) {
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 -148)
; CHECK-NEXT:    ret float [[LDEXP]]
;
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 -148)
  ret float %ldexp
}

define float @ldexp_neg127(float %x) {
; CHECK-LABEL: define float @ldexp_neg127
; CHECK-SAME: (float [[X:%.*]]) {
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 -127)
; CHECK-NEXT:    ret float [[LDEXP]]
;
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 -127)
  ret float %ldexp
}

define float @ldexp_neg126(float %x) {
; CHECK-LABEL: define float @ldexp_neg126
; CHECK-SAME: (float [[X:%.*]]) {
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 -126)
; CHECK-NEXT:    ret float [[LDEXP]]
;
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 -126)
  ret float %ldexp
}

define float @ldexp_neg125(float %x) {
; CHECK-LABEL: define float @ldexp_neg125
; CHECK-SAME: (float [[X:%.*]]) {
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 -125)
; CHECK-NEXT:    ret float [[LDEXP]]
;
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 -125)
  ret float %ldexp
}

define float @ldexp_neg16(float %x) {
; CHECK-LABEL: define float @ldexp_neg16
; CHECK-SAME: (float [[X:%.*]]) {
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 -16)
; CHECK-NEXT:    ret float [[LDEXP]]
;
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 -16)
  ret float %ldexp
}

define float @ldexp_neg8(float %x) {
; CHECK-LABEL: define float @ldexp_neg8
; CHECK-SAME: (float [[X:%.*]]) {
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 -8)
; CHECK-NEXT:    ret float [[LDEXP]]
;
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 -8)
  ret float %ldexp
}

define float @ldexp_neg4(float %x) {
; CHECK-LABEL: define float @ldexp_neg4
; CHECK-SAME: (float [[X:%.*]]) {
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 -4)
; CHECK-NEXT:    ret float [[LDEXP]]
;
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 -4)
  ret float %ldexp
}

define float @ldexp_neg2(float %x) {
; CHECK-LABEL: define float @ldexp_neg2
; CHECK-SAME: (float [[X:%.*]]) {
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 -2)
; CHECK-NEXT:    ret float [[LDEXP]]
;
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 -2)
  ret float %ldexp
}

define float @ldexp_neg1(float %x) {
; CHECK-LABEL: define float @ldexp_neg1
; CHECK-SAME: (float [[X:%.*]]) {
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 -1)
; CHECK-NEXT:    ret float [[LDEXP]]
;
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 -1)
  ret float %ldexp
}

define float @ldexp_0(float %x) {
; CHECK-LABEL: define float @ldexp_0
; CHECK-SAME: (float [[X:%.*]]) {
; CHECK-NEXT:    ret float [[X]]
;
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 0)
  ret float %ldexp
}

define float @ldexp_1(float %x) {
; CHECK-LABEL: define float @ldexp_1
; CHECK-SAME: (float [[X:%.*]]) {
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 1)
; CHECK-NEXT:    ret float [[LDEXP]]
;
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 1)
  ret float %ldexp
}

define float @ldexp_2(float %x) {
; CHECK-LABEL: define float @ldexp_2
; CHECK-SAME: (float [[X:%.*]]) {
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 2)
; CHECK-NEXT:    ret float [[LDEXP]]
;
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 2)
  ret float %ldexp
}

define float @ldexp_3(float %x) {
; CHECK-LABEL: define float @ldexp_3
; CHECK-SAME: (float [[X:%.*]]) {
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 3)
; CHECK-NEXT:    ret float [[LDEXP]]
;
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 3)
  ret float %ldexp
}

define float @ldexp_10(float %x) {
; CHECK-LABEL: define float @ldexp_10
; CHECK-SAME: (float [[X:%.*]]) {
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 10)
; CHECK-NEXT:    ret float [[LDEXP]]
;
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 10)
  ret float %ldexp
}

define float @ldexp_125(float %x) {
; CHECK-LABEL: define float @ldexp_125
; CHECK-SAME: (float [[X:%.*]]) {
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 125)
; CHECK-NEXT:    ret float [[LDEXP]]
;
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 125)
  ret float %ldexp
}

define float @ldexp_126(float %x) {
; CHECK-LABEL: define float @ldexp_126
; CHECK-SAME: (float [[X:%.*]]) {
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 126)
; CHECK-NEXT:    ret float [[LDEXP]]
;
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 126)
  ret float %ldexp
}

define float @ldexp_127(float %x) {
; CHECK-LABEL: define float @ldexp_127
; CHECK-SAME: (float [[X:%.*]]) {
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 127)
; CHECK-NEXT:    ret float [[LDEXP]]
;
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 127)
  ret float %ldexp
}

define <2 x float> @ldexp_3_vector(<2 x float> %x) {
; CHECK-LABEL: define <2 x float> @ldexp_3_vector
; CHECK-SAME: (<2 x float> [[X:%.*]]) {
; CHECK-NEXT:    [[LDEXP:%.*]] = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[X]], <2 x i32> <i32 3, i32 3>)
; CHECK-NEXT:    ret <2 x float> [[LDEXP]]
;
  %ldexp = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> %x, <2 x i32> <i32 3, i32 3>)
  ret <2 x float> %ldexp
}

define <2 x float> @ldexp_3_undef_vector(<2 x float> %x) {
; CHECK-LABEL: define <2 x float> @ldexp_3_undef_vector
; CHECK-SAME: (<2 x float> [[X:%.*]]) {
; CHECK-NEXT:    [[LDEXP:%.*]] = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[X]], <2 x i32> <i32 3, i32 poison>)
; CHECK-NEXT:    ret <2 x float> [[LDEXP]]
;
  %ldexp = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> %x, <2 x i32> <i32 3, i32 poison>)
  ret <2 x float> %ldexp
}

define <2 x float> @ldexp_3_4_vector(<2 x float> %x) {
; CHECK-LABEL: define <2 x float> @ldexp_3_4_vector
; CHECK-SAME: (<2 x float> [[X:%.*]]) {
; CHECK-NEXT:    [[LDEXP:%.*]] = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[X]], <2 x i32> <i32 3, i32 4>)
; CHECK-NEXT:    ret <2 x float> [[LDEXP]]
;
  %ldexp = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> %x, <2 x i32> <i32 3, i32 4>)
  ret <2 x float> %ldexp
}

define float @ldexp_2_flags(float %x) {
; CHECK-LABEL: define float @ldexp_2_flags
; CHECK-SAME: (float [[X:%.*]]) {
; CHECK-NEXT:    [[LDEXP:%.*]] = call nsz contract float @llvm.ldexp.f32.i32(float [[X]], i32 2)
; CHECK-NEXT:    ret float [[LDEXP]]
;
  %ldexp = call contract nsz float @llvm.ldexp.f32.i32(float %x, i32 2)
  ret float %ldexp
}

define float @ldexp_metadata(float %x) {
; CHECK-LABEL: define float @ldexp_metadata
; CHECK-SAME: (float [[X:%.*]]) {
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 2), !foo [[META2:![0-9]+]]
; CHECK-NEXT:    ret float [[LDEXP]]
;
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 2), !foo !2
  ret float %ldexp
}

define float @ldexp_8_contractable(float %x, float %y) {
; CHECK-LABEL: define float @ldexp_8_contractable
; CHECK-SAME: (float [[X:%.*]], float [[Y:%.*]]) {
; CHECK-NEXT:    [[LDEXP:%.*]] = call contract float @llvm.ldexp.f32.i32(float [[X]], i32 2)
; CHECK-NEXT:    [[FADD:%.*]] = fadd contract float [[LDEXP]], [[Y]]
; CHECK-NEXT:    ret float [[FADD]]
;
  %ldexp = call contract float @llvm.ldexp.f32.i32(float %x, i32 2)
  %fadd = fadd contract float %ldexp, %y
  ret float %fadd
}

define float @ldexp_f32_mask_select_0(i1 %cond, float %x, i32 %y) {
; CHECK-LABEL: define float @ldexp_f32_mask_select_0
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], i32 [[Y:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 [[Y]])
; CHECK-NEXT:    [[LDEXP:%.*]] = select i1 [[COND]], float [[TMP1]], float [[X]]
; CHECK-NEXT:    ret float [[LDEXP]]
;
  %select = select i1 %cond, i32 %y, i32 0
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 %select)
  ret float %ldexp
}

define float @ldexp_nnan_f32_mask_select_0(i1 %cond, float %x, i32 %y) {
; CHECK-LABEL: define float @ldexp_nnan_f32_mask_select_0
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], i32 [[Y:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = call nnan float @llvm.ldexp.f32.i32(float [[X]], i32 [[Y]])
; CHECK-NEXT:    [[LDEXP:%.*]] = select i1 [[COND]], float [[TMP1]], float [[X]]
; CHECK-NEXT:    ret float [[LDEXP]]
;
  %select = select i1 %cond, i32 %y, i32 0
  %ldexp = call nnan float @llvm.ldexp.f32.i32(float %x, i32 %select)
  ret float %ldexp
}

define float @ldexp_flags_f32_mask_select_0(i1 %cond, float %x, i32 %y) {
; CHECK-LABEL: define float @ldexp_flags_f32_mask_select_0
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], i32 [[Y:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = call ninf nsz float @llvm.ldexp.f32.i32(float [[X]], i32 [[Y]])
; CHECK-NEXT:    [[LDEXP:%.*]] = select i1 [[COND]], float [[TMP1]], float [[X]]
; CHECK-NEXT:    ret float [[LDEXP]]
;
  %select = select i1 %cond, i32 %y, i32 0
  %ldexp = call nsz ninf float @llvm.ldexp.f32.i32(float %x, i32 %select)
  ret float %ldexp
}

define float @ldexp_f32_mask_select_0_swap(i1 %cond, float %x, i32 %y) {
; CHECK-LABEL: define float @ldexp_f32_mask_select_0_swap
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], i32 [[Y:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 [[Y]])
; CHECK-NEXT:    [[LDEXP:%.*]] = select i1 [[COND]], float [[X]], float [[TMP1]]
; CHECK-NEXT:    ret float [[LDEXP]]
;
  %select = select i1 %cond, i32 0, i32 %y
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 %select)
  ret float %ldexp
}

define float @ldexp_f32_mask_select_1(i1 %cond, float %x, i32 %y) {
; CHECK-LABEL: define float @ldexp_f32_mask_select_1
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], i32 [[Y:%.*]]) {
; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], i32 [[Y]], i32 1
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 [[SELECT]])
; CHECK-NEXT:    ret float [[LDEXP]]
;
  %select = select i1 %cond, i32 %y, i32 1
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 %select)
  ret float %ldexp
}

define float @ldexp_f32_mask_select_0_multi_use(i1 %cond, float %x, i32 %y, ptr %ptr) {
; CHECK-LABEL: define float @ldexp_f32_mask_select_0_multi_use
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], i32 [[Y:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], i32 [[Y]], i32 0
; CHECK-NEXT:    store i32 [[SELECT]], ptr [[PTR]], align 4
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 [[SELECT]])
; CHECK-NEXT:    ret float [[LDEXP]]
;
  %select = select i1 %cond, i32 %y, i32 0
  store i32 %select, ptr %ptr
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 %select)
  ret float %ldexp
}

define float @ldexp_f32_mask_select_0_swap_multi_use(i1 %cond, float %x, i32 %y, ptr %ptr) {
; CHECK-LABEL: define float @ldexp_f32_mask_select_0_swap_multi_use
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], i32 [[Y:%.*]], ptr [[PTR:%.*]]) {
; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], i32 0, i32 [[Y]]
; CHECK-NEXT:    store i32 [[SELECT]], ptr [[PTR]], align 4
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 [[SELECT]])
; CHECK-NEXT:    ret float [[LDEXP]]
;
  %select = select i1 %cond, i32 0, i32 %y
  store i32 %select, ptr %ptr
  %ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 %select)
  ret float %ldexp
}

define float @ldexp_f32_mask_select_0_strictfp(i1 %cond, float %x, i32 %y) #0 {
; CHECK-LABEL: define float @ldexp_f32_mask_select_0_strictfp
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], i32 [[Y:%.*]]) #[[ATTR1:[0-9]+]] {
; CHECK-NEXT:    [[SELECT:%.*]] = select i1 [[COND]], i32 [[Y]], i32 0
; CHECK-NEXT:    [[LDEXP:%.*]] = call float @llvm.experimental.constrained.ldexp.f32.i32(float [[X]], i32 [[SELECT]], metadata !"round.dynamic", metadata !"fpexcept.strict")
; CHECK-NEXT:    ret float [[LDEXP]]
;
  %select = select i1 %cond, i32 %y, i32 0
  %ldexp = call float @llvm.experimental.constrained.ldexp.f32.i32(float %x, i32 %select, metadata !"round.dynamic", metadata !"fpexcept.strict")
  ret float %ldexp
}

define <2 x float> @ldexp_v2f32_mask_select_0(<2 x i1> %cond, <2 x float> %x, <2 x i32> %y) {
; CHECK-LABEL: define <2 x float> @ldexp_v2f32_mask_select_0
; CHECK-SAME: (<2 x i1> [[COND:%.*]], <2 x float> [[X:%.*]], <2 x i32> [[Y:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = call nnan nsz <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[X]], <2 x i32> [[Y]])
; CHECK-NEXT:    [[LDEXP:%.*]] = select <2 x i1> [[COND]], <2 x float> [[TMP1]], <2 x float> [[X]]
; CHECK-NEXT:    ret <2 x float> [[LDEXP]]
;
  %select = select <2 x i1> %cond, <2 x i32> %y, <2 x i32> zeroinitializer
  %ldexp = call nsz nnan <2 x float> @llvm.ldexp.f32.v2i32(<2 x float> %x, <2 x i32> %select)
  ret <2 x float> %ldexp
}

define <2 x float> @ldexp_v2f32_mask_select_0_swap(<2 x i1> %cond, <2 x float> %x, <2 x i32> %y) {
; CHECK-LABEL: define <2 x float> @ldexp_v2f32_mask_select_0_swap
; CHECK-SAME: (<2 x i1> [[COND:%.*]], <2 x float> [[X:%.*]], <2 x i32> [[Y:%.*]]) {
; CHECK-NEXT:    [[TMP1:%.*]] = call nnan nsz <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[X]], <2 x i32> [[Y]])
; CHECK-NEXT:    [[LDEXP:%.*]] = select <2 x i1> [[COND]], <2 x float> [[X]], <2 x float> [[TMP1]]
; CHECK-NEXT:    ret <2 x float> [[LDEXP]]
;
  %select = select <2 x i1> %cond, <2 x i32> zeroinitializer, <2 x i32> %y
  %ldexp = call nsz nnan <2 x float> @llvm.ldexp.f32.v2i32(<2 x float> %x, <2 x i32> %select)
  ret <2 x float> %ldexp
}

attributes #0 = { strictfp }

!0 = !{i32 -127, i32 0}
!1 = !{i32 0, i32 127}
!2 = !{}