diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp index 74df67a4ff9b4..c0104d2bc2611 100644 --- a/llvm/lib/Analysis/ConstantFolding.cpp +++ b/llvm/lib/Analysis/ConstantFolding.cpp @@ -1677,6 +1677,8 @@ bool llvm::canConstantFoldCallTo(const CallBase *Call, const Function *F) { return Name == "fabs" || Name == "fabsf" || Name == "floor" || Name == "floorf" || Name == "fmod" || Name == "fmodf"; + case 'i': + return Name == "ilogb" || Name == "ilogbf"; case 'l': return Name == "log" || Name == "logf" || Name == "logl" || Name == "log2" || Name == "log2f" || Name == "log10" || @@ -2131,7 +2133,8 @@ static Constant *ConstantFoldScalarCall1(StringRef Name, } #endif - if (!Ty->isHalfTy() && !Ty->isFloatTy() && !Ty->isDoubleTy()) + if (!Ty->isHalfTy() && !Ty->isFloatTy() && !Ty->isDoubleTy() && + !Ty->isIntegerTy()) return nullptr; // Use internal versions of these intrinsics. @@ -2391,6 +2394,11 @@ static Constant *ConstantFoldScalarCall1(StringRef Name, // TODO: What about hosts that lack a C99 library? return ConstantFoldFP(log10, APF, Ty); break; + case LibFunc_ilogb: + case LibFunc_ilogbf: + if (!APF.isZero() && TLI->has(Func)) + return ConstantInt::get(Ty, ilogb(APF), true); + break; case LibFunc_logb: case LibFunc_logbf: if (!APF.isZero() && TLI->has(Func)) diff --git a/llvm/test/Transforms/InstCombine/ilogb.ll b/llvm/test/Transforms/InstCombine/ilogb.ll new file mode 100644 index 0000000000000..e30791fe68e7b --- /dev/null +++ b/llvm/test/Transforms/InstCombine/ilogb.ll @@ -0,0 +1,203 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt < %s -passes=instcombine -S | FileCheck %s + +define i32 @ilogbf_const1() { +; CHECK-LABEL: define i32 @ilogbf_const1() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogbf(float 7.000000e+00) +; CHECK-NEXT: ret i32 2 +; + %r = call i32 @ilogbf(float 7.000000e+00) + ret i32 %r +} + +define i32 @ilogb_const1() { +; CHECK-LABEL: define i32 @ilogb_const1() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogb(double -7.000000e+00) +; CHECK-NEXT: ret i32 2 +; + %r = call i32 @ilogb(double -7.000000e+00) + ret i32 %r +} + +define i32 @ilogbf_const2() { +; CHECK-LABEL: define i32 @ilogbf_const2() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogbf(float 5.000000e-01) +; CHECK-NEXT: ret i32 -1 +; + %r = call i32 @ilogbf(float 5.000000e-01) + ret i32 %r +} + +define i32 @ilogb_const2() { +; CHECK-LABEL: define i32 @ilogb_const2() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogb(double -5.000000e-01) +; CHECK-NEXT: ret i32 -1 +; + %r = call i32 @ilogb(double -5.000000e-01) + ret i32 %r +} + +define i32 @ilogbf_zero() { +; CHECK-LABEL: define i32 @ilogbf_zero() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogbf(float 0.000000e+00) +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogbf(float 0.000000e+00) + ret i32 %r +} + +define i32 @ilogb_zero() { +; CHECK-LABEL: define i32 @ilogb_zero() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogb(double 0.000000e+00) +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogb(double 0.000000e+00) + ret i32 %r +} + +define i32 @ilogbf_neg_zero() { +; CHECK-LABEL: define i32 @ilogbf_neg_zero() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogbf(float -0.000000e+00) +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogbf(float -0.000000e+00) + ret i32 %r +} + +define i32 @ilogb_neg_zero() { +; CHECK-LABEL: define i32 @ilogb_neg_zero() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogb(double -0.000000e+00) +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogb(double -0.000000e+00) + ret i32 %r +} + +define i32 @ilogbf_inf() { +; CHECK-LABEL: define i32 @ilogbf_inf() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogbf(float 0x7FF0000000000000) +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogbf(float 0x7FF0000000000000) + ret i32 %r +} + +define i32 @ilogb_inf() { +; CHECK-LABEL: define i32 @ilogb_inf() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogb(double 0x7FF0000000000000) +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogb(double 0x7FF0000000000000) + ret i32 %r +} + +define i32 @ilogbf_nan() { +; CHECK-LABEL: define i32 @ilogbf_nan() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogbf(float 0x7FF8000000000000) +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogbf(float 0x7FF8000000000000) + ret i32 %r +} + +define i32 @ilogb_nan() { +; CHECK-LABEL: define i32 @ilogb_nan() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogb(double 0x7FF8000000000000) +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogb(double 0x7FF8000000000000) + ret i32 %r +} + +define i32 @ilogbf_zero_readnone() { +; CHECK-LABEL: define i32 @ilogbf_zero_readnone() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogbf(float 0.000000e+00) #[[ATTR0:[0-9]+]] +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogbf(float 0.000000e+00) readnone + ret i32 %r +} + +define i32 @ilogb_zero_readnone() { +; CHECK-LABEL: define i32 @ilogb_zero_readnone() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogb(double 0.000000e+00) #[[ATTR0]] +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogb(double 0.000000e+00) readnone + ret i32 %r +} + +define i32 @ilogbf_neg_zero_readnone() { +; CHECK-LABEL: define i32 @ilogbf_neg_zero_readnone() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogbf(float -0.000000e+00) #[[ATTR0]] +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogbf(float -0.000000e+00) readnone + ret i32 %r +} + +define i32 @ilogb_neg_zero_readnone() { +; CHECK-LABEL: define i32 @ilogb_neg_zero_readnone() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogb(double -0.000000e+00) #[[ATTR0]] +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogb(double -0.000000e+00) readnone + ret i32 %r +} + +define i32 @ilogbf_inf_readnone() { +; CHECK-LABEL: define i32 @ilogbf_inf_readnone() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogbf(float 0x7FF0000000000000) #[[ATTR0]] +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogbf(float 0x7FF0000000000000) readnone + ret i32 %r +} + +define i32 @ilogb_inf_readnone() { +; CHECK-LABEL: define i32 @ilogb_inf_readnone() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogb(double 0x7FF0000000000000) #[[ATTR0]] +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogb(double 0x7FF0000000000000) readnone + ret i32 %r +} + +define i32 @ilogbf_nan_readnone() { +; CHECK-LABEL: define i32 @ilogbf_nan_readnone() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogbf(float 0x7FF8000000000000) #[[ATTR0]] +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogbf(float 0x7FF8000000000000) readnone + ret i32 %r +} + +define i32 @ilogb_nan_readnone() { +; CHECK-LABEL: define i32 @ilogb_nan_readnone() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogb(double 0x7FF8000000000000) #[[ATTR0]] +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogb(double 0x7FF8000000000000) readnone + ret i32 %r +} + +define i32 @ilogbf_poison() { +; CHECK-LABEL: define i32 @ilogbf_poison() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogbf(float poison) +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogbf(float poison) + ret i32 %r +} + +define i32 @ilogb_poison() { +; CHECK-LABEL: define i32 @ilogb_poison() { +; CHECK-NEXT: [[R:%.*]] = call i32 @ilogb(double poison) +; CHECK-NEXT: ret i32 [[R]] +; + %r = call i32 @ilogb(double poison) + ret i32 %r +} + +declare i32 @ilogbf(float) +declare i32 @ilogb(double)