Files
clang-p2996/llvm/test/Transforms/InstCombine/ldexp.ll
Matt Arsenault 4f9aad964f InstCombine: Fold ldexp(ldexp(x, a), b) -> ldexp(x, a + b)
The problem here is overflow or underflow which would have occurred in
the inner operation, which the exponent offsetting avoids. We can do
this if we know the two exponents are in the same direction, or
reassoc flags allow unsafe reassociates.
2023-07-07 08:15:09 -04:00

597 lines
31 KiB
LLVM

; 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
}
; 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_opposite_constants(float %x) {
; CHECK-LABEL: define float @ldexp_ldexp_opposite_constants
; CHECK-SAME: (float [[X:%.*]]) {
; CHECK-NEXT: [[LDEXP1:%.*]] = call reassoc float @llvm.ldexp.f32.i32(float [[X]], i32 0)
; 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 -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: [[LDEXP1:%.*]] = call reassoc float @llvm.ldexp.f32.i32(float [[X]], i32 0)
; CHECK-NEXT: ret float [[LDEXP1]]
;
%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: [[LDEXP0:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 0)
; CHECK-NEXT: [[LDEXP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[LDEXP0]], 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
}
!0 = !{i32 -127, i32 0}
!1 = !{i32 0, i32 127}