Skip to content

Commit d768626

Browse files
committed
InstCombine: Try to fold ldexp with select of power operand
This makes it more likely a constant value can fold into the source operand.
1 parent d8ef055 commit d768626

File tree

3 files changed

+44
-12
lines changed

3 files changed

+44
-12
lines changed

llvm/include/llvm/IR/IRBuilder.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1023,6 +1023,13 @@ class IRBuilderBase {
10231023
Name);
10241024
}
10251025

1026+
/// Create call to the ldexp intrinsic.
1027+
Value *CreateLdexp(Value *Src, Value *Exp, const Twine &Name = "") {
1028+
assert(!IsFPConstrained && "TODO: Support strictfp");
1029+
return CreateIntrinsic(Intrinsic::ldexp, {Src->getType(), Exp->getType()},
1030+
{Src, Exp}, nullptr, Name);
1031+
}
1032+
10261033
/// Create a call to the arithmetic_fence intrinsic.
10271034
CallInst *CreateArithmeticFence(Value *Val, Type *DstType,
10281035
const Twine &Name = "") {

llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2641,6 +2641,31 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
26412641
return BinaryOperator::CreateFMulFMF(Src, Select, II);
26422642
}
26432643

2644+
// ldexp(x, c ? exp : 0) -> c ? ldexp(x, exp) : x
2645+
// ldexp(x, c ? 0 : exp) -> c ? x : ldexp(x, exp)
2646+
///
2647+
// TODO: If we cared, should insert a canonicalize for x
2648+
Value *SelectCond, *SelectLHS, *SelectRHS;
2649+
if (match(II->getArgOperand(1),
2650+
m_OneUse(m_Select(m_Value(SelectCond), m_Value(SelectLHS),
2651+
m_Value(SelectRHS))))) {
2652+
Value *NewLdexp = nullptr;
2653+
Value *Select = nullptr;
2654+
if (match(SelectRHS, m_ZeroInt())) {
2655+
NewLdexp = Builder.CreateLdexp(Src, SelectLHS);
2656+
Select = Builder.CreateSelect(SelectCond, NewLdexp, Src);
2657+
} else if (match(SelectLHS, m_ZeroInt())) {
2658+
NewLdexp = Builder.CreateLdexp(Src, SelectRHS);
2659+
Select = Builder.CreateSelect(SelectCond, Src, NewLdexp);
2660+
}
2661+
2662+
if (NewLdexp) {
2663+
Select->takeName(II);
2664+
cast<Instruction>(NewLdexp)->copyIRFlags(II);
2665+
return replaceInstUsesWith(*II, Select);
2666+
}
2667+
}
2668+
26442669
break;
26452670
}
26462671
case Intrinsic::ptrauth_auth:

llvm/test/Transforms/InstCombine/ldexp.ll

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -892,8 +892,8 @@ define float @ldexp_8_contractable(float %x, float %y) {
892892
define float @ldexp_f32_mask_select_0(i1 %cond, float %x, i32 %y) {
893893
; CHECK-LABEL: define float @ldexp_f32_mask_select_0
894894
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], i32 [[Y:%.*]]) {
895-
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], i32 [[Y]], i32 0
896-
; CHECK-NEXT: [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 [[SELECT]])
895+
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 [[Y]])
896+
; CHECK-NEXT: [[LDEXP:%.*]] = select i1 [[COND]], float [[TMP1]], float [[X]]
897897
; CHECK-NEXT: ret float [[LDEXP]]
898898
;
899899
%select = select i1 %cond, i32 %y, i32 0
@@ -904,8 +904,8 @@ define float @ldexp_f32_mask_select_0(i1 %cond, float %x, i32 %y) {
904904
define float @ldexp_nnan_f32_mask_select_0(i1 %cond, float %x, i32 %y) {
905905
; CHECK-LABEL: define float @ldexp_nnan_f32_mask_select_0
906906
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], i32 [[Y:%.*]]) {
907-
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], i32 [[Y]], i32 0
908-
; CHECK-NEXT: [[LDEXP:%.*]] = call nnan float @llvm.ldexp.f32.i32(float [[X]], i32 [[SELECT]])
907+
; CHECK-NEXT: [[TMP1:%.*]] = call nnan float @llvm.ldexp.f32.i32(float [[X]], i32 [[Y]])
908+
; CHECK-NEXT: [[LDEXP:%.*]] = select i1 [[COND]], float [[TMP1]], float [[X]]
909909
; CHECK-NEXT: ret float [[LDEXP]]
910910
;
911911
%select = select i1 %cond, i32 %y, i32 0
@@ -916,8 +916,8 @@ define float @ldexp_nnan_f32_mask_select_0(i1 %cond, float %x, i32 %y) {
916916
define float @ldexp_flags_f32_mask_select_0(i1 %cond, float %x, i32 %y) {
917917
; CHECK-LABEL: define float @ldexp_flags_f32_mask_select_0
918918
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], i32 [[Y:%.*]]) {
919-
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], i32 [[Y]], i32 0
920-
; CHECK-NEXT: [[LDEXP:%.*]] = call ninf nsz float @llvm.ldexp.f32.i32(float [[X]], i32 [[SELECT]])
919+
; CHECK-NEXT: [[TMP1:%.*]] = call ninf nsz float @llvm.ldexp.f32.i32(float [[X]], i32 [[Y]])
920+
; CHECK-NEXT: [[LDEXP:%.*]] = select i1 [[COND]], float [[TMP1]], float [[X]]
921921
; CHECK-NEXT: ret float [[LDEXP]]
922922
;
923923
%select = select i1 %cond, i32 %y, i32 0
@@ -928,8 +928,8 @@ define float @ldexp_flags_f32_mask_select_0(i1 %cond, float %x, i32 %y) {
928928
define float @ldexp_f32_mask_select_0_swap(i1 %cond, float %x, i32 %y) {
929929
; CHECK-LABEL: define float @ldexp_f32_mask_select_0_swap
930930
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], i32 [[Y:%.*]]) {
931-
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], i32 0, i32 [[Y]]
932-
; CHECK-NEXT: [[LDEXP:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 [[SELECT]])
931+
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.ldexp.f32.i32(float [[X]], i32 [[Y]])
932+
; CHECK-NEXT: [[LDEXP:%.*]] = select i1 [[COND]], float [[X]], float [[TMP1]]
933933
; CHECK-NEXT: ret float [[LDEXP]]
934934
;
935935
%select = select i1 %cond, i32 0, i32 %y
@@ -992,8 +992,8 @@ define float @ldexp_f32_mask_select_0_strictfp(i1 %cond, float %x, i32 %y) #0 {
992992
define <2 x float> @ldexp_v2f32_mask_select_0(<2 x i1> %cond, <2 x float> %x, <2 x i32> %y) {
993993
; CHECK-LABEL: define <2 x float> @ldexp_v2f32_mask_select_0
994994
; CHECK-SAME: (<2 x i1> [[COND:%.*]], <2 x float> [[X:%.*]], <2 x i32> [[Y:%.*]]) {
995-
; CHECK-NEXT: [[SELECT:%.*]] = select <2 x i1> [[COND]], <2 x i32> [[Y]], <2 x i32> zeroinitializer
996-
; CHECK-NEXT: [[LDEXP:%.*]] = call nnan nsz <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[X]], <2 x i32> [[SELECT]])
995+
; CHECK-NEXT: [[TMP1:%.*]] = call nnan nsz <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[X]], <2 x i32> [[Y]])
996+
; CHECK-NEXT: [[LDEXP:%.*]] = select <2 x i1> [[COND]], <2 x float> [[TMP1]], <2 x float> [[X]]
997997
; CHECK-NEXT: ret <2 x float> [[LDEXP]]
998998
;
999999
%select = select <2 x i1> %cond, <2 x i32> %y, <2 x i32> zeroinitializer
@@ -1004,8 +1004,8 @@ define <2 x float> @ldexp_v2f32_mask_select_0(<2 x i1> %cond, <2 x float> %x, <2
10041004
define <2 x float> @ldexp_v2f32_mask_select_0_swap(<2 x i1> %cond, <2 x float> %x, <2 x i32> %y) {
10051005
; CHECK-LABEL: define <2 x float> @ldexp_v2f32_mask_select_0_swap
10061006
; CHECK-SAME: (<2 x i1> [[COND:%.*]], <2 x float> [[X:%.*]], <2 x i32> [[Y:%.*]]) {
1007-
; CHECK-NEXT: [[SELECT:%.*]] = select <2 x i1> [[COND]], <2 x i32> zeroinitializer, <2 x i32> [[Y]]
1008-
; CHECK-NEXT: [[LDEXP:%.*]] = call nnan nsz <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[X]], <2 x i32> [[SELECT]])
1007+
; CHECK-NEXT: [[TMP1:%.*]] = call nnan nsz <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> [[X]], <2 x i32> [[Y]])
1008+
; CHECK-NEXT: [[LDEXP:%.*]] = select <2 x i1> [[COND]], <2 x float> [[X]], <2 x float> [[TMP1]]
10091009
; CHECK-NEXT: ret <2 x float> [[LDEXP]]
10101010
;
10111011
%select = select <2 x i1> %cond, <2 x i32> zeroinitializer, <2 x i32> %y

0 commit comments

Comments
 (0)