Skip to content

SimplifyLibCalls: Don't require ldexp to emit intrinsic in exp2 combine #92707

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 9 additions & 4 deletions llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2376,7 +2376,13 @@ Value *LibCallSimplifier::optimizeExp2(CallInst *CI, IRBuilderBase &B) {
hasFloatVersion(M, Name))
Ret = optimizeUnaryDoubleFP(CI, B, TLI, true);

const bool UseIntrinsic = CI->doesNotAccessMemory();
// If we have an llvm.exp2 intrinsic, emit the llvm.ldexp intrinsic. If we
// have the libcall, emit the libcall.
//
// TODO: In principle we should be able to just always use the intrinsic for
// any doesNotAccessMemory callsite.

const bool UseIntrinsic = Callee->isIntrinsic();
// Bail out for vectors because the code below only expects scalars.
Type *Ty = CI->getType();
if (!UseIntrinsic && Ty->isVectorTy())
Expand All @@ -2386,12 +2392,11 @@ Value *LibCallSimplifier::optimizeExp2(CallInst *CI, IRBuilderBase &B) {
// exp2(uitofp(x)) -> ldexp(1.0, zext(x)) if sizeof(x) < IntSize
Value *Op = CI->getArgOperand(0);
if ((isa<SIToFPInst>(Op) || isa<UIToFPInst>(Op)) &&
hasFloatFn(M, TLI, Ty, LibFunc_ldexp, LibFunc_ldexpf, LibFunc_ldexpl)) {
(UseIntrinsic ||
hasFloatFn(M, TLI, Ty, LibFunc_ldexp, LibFunc_ldexpf, LibFunc_ldexpl))) {
if (Value *Exp = getIntToFPVal(Op, B, TLI->getIntSize())) {
Constant *One = ConstantFP::get(Ty, 1.0);

// TODO: Emitting the intrinsic should not depend on whether the libcall
// is available.
if (UseIntrinsic) {
return copyFlags(*CI, B.CreateIntrinsic(Intrinsic::ldexp,
{Ty, Exp->getType()},
Expand Down
11 changes: 5 additions & 6 deletions llvm/test/LTO/X86/triple-init2.ll
Original file line number Diff line number Diff line change
Expand Up @@ -11,21 +11,20 @@
; RUN: llvm-lto2 run -r %t1,main,plx -o %t2 %t1
; RUN: llvm-nm %t2.1 | FileCheck %s

; We check that LTO will be aware of target triple and prevent exp2 to ldexpf
; We check that LTO will be aware of target triple and prevent pow to exp10
; transformation on Windows.
; CHECK: U exp2f
; CHECK: U powf

target datalayout = "e-m:w-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128"
target triple = "x86_64-pc-windows-msvc19.11.0"

declare float @llvm.pow.f32(float, float)

define dso_local i32 @main(i32 %argc, ptr nocapture readnone %argv) local_unnamed_addr {
entry:
%conv = sitofp i32 %argc to float
%exp2 = tail call float @llvm.exp2.f32(float %conv)
%exp2 = tail call float @llvm.pow.f32(float 10.0, float %conv)
%conv1 = fptosi float %exp2 to i32
ret i32 %conv1
}

; Function Attrs: nounwind readnone speculatable
declare float @llvm.exp2.f32(float)

29 changes: 17 additions & 12 deletions llvm/test/Transforms/InstCombine/exp2-1.ll
Original file line number Diff line number Diff line change
Expand Up @@ -242,8 +242,8 @@ define double @test_simplify9(i8 zeroext %x) {
; NOLDEXPF-NEXT: ret double [[RET]]
;
; NOLDEXP-LABEL: @test_simplify9(
; NOLDEXP-NEXT: [[CONV:%.*]] = uitofp i8 [[X:%.*]] to double
; NOLDEXP-NEXT: [[RET:%.*]] = call double @llvm.exp2.f64(double [[CONV]])
; NOLDEXP-NEXT: [[TMP1:%.*]] = zext i8 [[X:%.*]] to i32
; NOLDEXP-NEXT: [[RET:%.*]] = call double @llvm.ldexp.f64.i32(double 1.000000e+00, i32 [[TMP1]])
; NOLDEXP-NEXT: ret double [[RET]]
;
%conv = uitofp i8 %x to double
Expand All @@ -263,13 +263,13 @@ define float @test_simplify10(i8 zeroext %x) {
; LDEXP16-NEXT: ret float [[RET]]
;
; NOLDEXPF-LABEL: @test_simplify10(
; NOLDEXPF-NEXT: [[CONV:%.*]] = uitofp i8 [[X:%.*]] to float
; NOLDEXPF-NEXT: [[RET:%.*]] = call float @llvm.exp2.f32(float [[CONV]])
; NOLDEXPF-NEXT: [[TMP1:%.*]] = zext i8 [[X:%.*]] to i32
; NOLDEXPF-NEXT: [[RET:%.*]] = call float @llvm.ldexp.f32.i32(float 1.000000e+00, i32 [[TMP1]])
; NOLDEXPF-NEXT: ret float [[RET]]
;
; NOLDEXP-LABEL: @test_simplify10(
; NOLDEXP-NEXT: [[CONV:%.*]] = uitofp i8 [[X:%.*]] to float
; NOLDEXP-NEXT: [[RET:%.*]] = call float @llvm.exp2.f32(float [[CONV]])
; NOLDEXP-NEXT: [[TMP1:%.*]] = zext i8 [[X:%.*]] to i32
; NOLDEXP-NEXT: [[RET:%.*]] = call float @llvm.ldexp.f32.i32(float 1.000000e+00, i32 [[TMP1]])
; NOLDEXP-NEXT: ret float [[RET]]
;
%conv = uitofp i8 %x to float
Expand All @@ -289,13 +289,13 @@ define float @sitofp_scalar_intrinsic_with_FMF(i8 %x) {
; LDEXP16-NEXT: ret float [[R]]
;
; NOLDEXPF-LABEL: @sitofp_scalar_intrinsic_with_FMF(
; NOLDEXPF-NEXT: [[S:%.*]] = sitofp i8 [[X:%.*]] to float
; NOLDEXPF-NEXT: [[R:%.*]] = tail call nnan float @llvm.exp2.f32(float [[S]])
; NOLDEXPF-NEXT: [[TMP1:%.*]] = sext i8 [[X:%.*]] to i32
; NOLDEXPF-NEXT: [[R:%.*]] = tail call nnan float @llvm.ldexp.f32.i32(float 1.000000e+00, i32 [[TMP1]])
; NOLDEXPF-NEXT: ret float [[R]]
;
; NOLDEXP-LABEL: @sitofp_scalar_intrinsic_with_FMF(
; NOLDEXP-NEXT: [[S:%.*]] = sitofp i8 [[X:%.*]] to float
; NOLDEXP-NEXT: [[R:%.*]] = tail call nnan float @llvm.exp2.f32(float [[S]])
; NOLDEXP-NEXT: [[TMP1:%.*]] = sext i8 [[X:%.*]] to i32
; NOLDEXP-NEXT: [[R:%.*]] = tail call nnan float @llvm.ldexp.f32.i32(float 1.000000e+00, i32 [[TMP1]])
; NOLDEXP-NEXT: ret float [[R]]
;
%s = sitofp i8 %x to float
Expand All @@ -317,9 +317,14 @@ define <2 x float> @sitofp_vector_intrinsic_with_FMF(<2 x i8> %x) {
; LDEXP16-NEXT: [[R:%.*]] = call nnan <2 x float> @llvm.ldexp.v2f32.v2i16(<2 x float> <float 1.000000e+00, float 1.000000e+00>, <2 x i16> [[TMP1]])
; LDEXP16-NEXT: ret <2 x float> [[R]]
;
; NOLDEXPF-LABEL: @sitofp_vector_intrinsic_with_FMF(
; NOLDEXPF-NEXT: [[TMP1:%.*]] = sext <2 x i8> [[X:%.*]] to <2 x i32>
; NOLDEXPF-NEXT: [[R:%.*]] = call nnan <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> <float 1.000000e+00, float 1.000000e+00>, <2 x i32> [[TMP1]])
; NOLDEXPF-NEXT: ret <2 x float> [[R]]
;
; NOLDEXP-LABEL: @sitofp_vector_intrinsic_with_FMF(
; NOLDEXP-NEXT: [[S:%.*]] = sitofp <2 x i8> [[X:%.*]] to <2 x float>
; NOLDEXP-NEXT: [[R:%.*]] = call nnan <2 x float> @llvm.exp2.v2f32(<2 x float> [[S]])
; NOLDEXP-NEXT: [[TMP1:%.*]] = sext <2 x i8> [[X:%.*]] to <2 x i32>
; NOLDEXP-NEXT: [[R:%.*]] = call nnan <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> <float 1.000000e+00, float 1.000000e+00>, <2 x i32> [[TMP1]])
; NOLDEXP-NEXT: ret <2 x float> [[R]]
;
%s = sitofp <2 x i8> %x to <2 x float>
Expand Down
120 changes: 39 additions & 81 deletions llvm/test/Transforms/InstCombine/exp2-to-ldexp.ll
Original file line number Diff line number Diff line change
@@ -1,73 +1,49 @@
; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
; RUN: opt -S -passes=instcombine %s | FileCheck -check-prefixes=CHECK,LDEXP %s
; RUN: opt -S -passes=instcombine -disable-builtin=ldexpf -disable-builtin=ldexp -disable-builtin=ldexpl %s | FileCheck -check-prefixes=CHECK,NOLDEXP %s
; RUN: opt -S -passes=instcombine %s | FileCheck %s
; RUN: opt -S -passes=instcombine -disable-builtin=ldexpf -disable-builtin=ldexp -disable-builtin=ldexpl %s | FileCheck %s

define float @exp2_f32_sitofp_i8(i8 %x) {
; LDEXP-LABEL: define float @exp2_f32_sitofp_i8(
; LDEXP-SAME: i8 [[X:%.*]]) {
; LDEXP-NEXT: [[TMP1:%.*]] = sext i8 [[X]] to i32
; LDEXP-NEXT: [[LDEXPF:%.*]] = call float @llvm.ldexp.f32.i32(float 1.000000e+00, i32 [[TMP1]])
; LDEXP-NEXT: ret float [[LDEXPF]]
;
; NOLDEXP-LABEL: define float @exp2_f32_sitofp_i8(
; NOLDEXP-SAME: i8 [[X:%.*]]) {
; NOLDEXP-NEXT: [[ITOFP:%.*]] = sitofp i8 [[X]] to float
; NOLDEXP-NEXT: [[EXP2:%.*]] = call float @llvm.exp2.f32(float [[ITOFP]])
; NOLDEXP-NEXT: ret float [[EXP2]]
; CHECK-LABEL: define float @exp2_f32_sitofp_i8(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = sext i8 [[X]] to i32
; CHECK-NEXT: [[EXP2:%.*]] = call float @llvm.ldexp.f32.i32(float 1.000000e+00, i32 [[TMP1]])
; CHECK-NEXT: ret float [[EXP2]]
;
%itofp = sitofp i8 %x to float
%exp2 = call float @llvm.exp2.f32(float %itofp)
ret float %exp2
}

define float @exp2_f32_sitofp_i8_flags(i8 %x) {
; LDEXP-LABEL: define float @exp2_f32_sitofp_i8_flags(
; LDEXP-SAME: i8 [[X:%.*]]) {
; LDEXP-NEXT: [[TMP1:%.*]] = sext i8 [[X]] to i32
; LDEXP-NEXT: [[LDEXPF:%.*]] = call nnan ninf float @llvm.ldexp.f32.i32(float 1.000000e+00, i32 [[TMP1]])
; LDEXP-NEXT: ret float [[LDEXPF]]
;
; NOLDEXP-LABEL: define float @exp2_f32_sitofp_i8_flags(
; NOLDEXP-SAME: i8 [[X:%.*]]) {
; NOLDEXP-NEXT: [[ITOFP:%.*]] = sitofp i8 [[X]] to float
; NOLDEXP-NEXT: [[EXP2:%.*]] = call nnan ninf float @llvm.exp2.f32(float [[ITOFP]])
; NOLDEXP-NEXT: ret float [[EXP2]]
; CHECK-LABEL: define float @exp2_f32_sitofp_i8_flags(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = sext i8 [[X]] to i32
; CHECK-NEXT: [[EXP2:%.*]] = call nnan ninf float @llvm.ldexp.f32.i32(float 1.000000e+00, i32 [[TMP1]])
; CHECK-NEXT: ret float [[EXP2]]
;
%itofp = sitofp i8 %x to float
%exp2 = call nnan ninf float @llvm.exp2.f32(float %itofp)
ret float %exp2
}

define <2 x float> @exp2_v2f32_sitofp_v2i8(<2 x i8> %x) {
; LDEXP-LABEL: define <2 x float> @exp2_v2f32_sitofp_v2i8(
; LDEXP-SAME: <2 x i8> [[X:%.*]]) {
; LDEXP-NEXT: [[TMP1:%.*]] = sext <2 x i8> [[X]] to <2 x i32>
; LDEXP-NEXT: [[EXP2:%.*]] = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> <float 1.000000e+00, float 1.000000e+00>, <2 x i32> [[TMP1]])
; LDEXP-NEXT: ret <2 x float> [[EXP2]]
;
; NOLDEXP-LABEL: define <2 x float> @exp2_v2f32_sitofp_v2i8(
; NOLDEXP-SAME: <2 x i8> [[X:%.*]]) {
; NOLDEXP-NEXT: [[ITOFP:%.*]] = sitofp <2 x i8> [[X]] to <2 x float>
; NOLDEXP-NEXT: [[EXP2:%.*]] = call <2 x float> @llvm.exp2.v2f32(<2 x float> [[ITOFP]])
; NOLDEXP-NEXT: ret <2 x float> [[EXP2]]
; CHECK-LABEL: define <2 x float> @exp2_v2f32_sitofp_v2i8(
; CHECK-SAME: <2 x i8> [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = sext <2 x i8> [[X]] to <2 x i32>
; CHECK-NEXT: [[EXP2:%.*]] = call <2 x float> @llvm.ldexp.v2f32.v2i32(<2 x float> <float 1.000000e+00, float 1.000000e+00>, <2 x i32> [[TMP1]])
; CHECK-NEXT: ret <2 x float> [[EXP2]]
;
%itofp = sitofp <2 x i8> %x to <2 x float>
%exp2 = call <2 x float> @llvm.exp2.v2f32(<2 x float> %itofp)
ret <2 x float> %exp2
}

define float @exp2_f32_uitofp_i8(i8 %x) {
; LDEXP-LABEL: define float @exp2_f32_uitofp_i8(
; LDEXP-SAME: i8 [[X:%.*]]) {
; LDEXP-NEXT: [[TMP1:%.*]] = zext i8 [[X]] to i32
; LDEXP-NEXT: [[LDEXPF:%.*]] = call float @llvm.ldexp.f32.i32(float 1.000000e+00, i32 [[TMP1]])
; LDEXP-NEXT: ret float [[LDEXPF]]
;
; NOLDEXP-LABEL: define float @exp2_f32_uitofp_i8(
; NOLDEXP-SAME: i8 [[X:%.*]]) {
; NOLDEXP-NEXT: [[ITOFP:%.*]] = uitofp i8 [[X]] to float
; NOLDEXP-NEXT: [[EXP2:%.*]] = call float @llvm.exp2.f32(float [[ITOFP]])
; NOLDEXP-NEXT: ret float [[EXP2]]
; CHECK-LABEL: define float @exp2_f32_uitofp_i8(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = zext i8 [[X]] to i32
; CHECK-NEXT: [[EXP2:%.*]] = call float @llvm.ldexp.f32.i32(float 1.000000e+00, i32 [[TMP1]])
; CHECK-NEXT: ret float [[EXP2]]
;
%itofp = uitofp i8 %x to float
%exp2 = call float @llvm.exp2.f32(float %itofp)
Expand All @@ -77,8 +53,8 @@ define float @exp2_f32_uitofp_i8(i8 %x) {
define half @exp2_f16_sitofp_i8(i8 %x) {
; CHECK-LABEL: define half @exp2_f16_sitofp_i8(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[ITOFP:%.*]] = sitofp i8 [[X]] to half
; CHECK-NEXT: [[EXP2:%.*]] = call half @llvm.exp2.f16(half [[ITOFP]])
; CHECK-NEXT: [[TMP1:%.*]] = sext i8 [[X]] to i32
; CHECK-NEXT: [[EXP2:%.*]] = call half @llvm.ldexp.f16.i32(half 0xH3C00, i32 [[TMP1]])
; CHECK-NEXT: ret half [[EXP2]]
;
%itofp = sitofp i8 %x to half
Expand All @@ -87,53 +63,35 @@ define half @exp2_f16_sitofp_i8(i8 %x) {
}

define double @exp2_f64_sitofp_i8(i8 %x) {
; LDEXP-LABEL: define double @exp2_f64_sitofp_i8(
; LDEXP-SAME: i8 [[X:%.*]]) {
; LDEXP-NEXT: [[TMP1:%.*]] = sext i8 [[X]] to i32
; LDEXP-NEXT: [[LDEXP:%.*]] = call double @llvm.ldexp.f64.i32(double 1.000000e+00, i32 [[TMP1]])
; LDEXP-NEXT: ret double [[LDEXP]]
;
; NOLDEXP-LABEL: define double @exp2_f64_sitofp_i8(
; NOLDEXP-SAME: i8 [[X:%.*]]) {
; NOLDEXP-NEXT: [[ITOFP:%.*]] = sitofp i8 [[X]] to double
; NOLDEXP-NEXT: [[EXP2:%.*]] = call double @llvm.exp2.f64(double [[ITOFP]])
; NOLDEXP-NEXT: ret double [[EXP2]]
; CHECK-LABEL: define double @exp2_f64_sitofp_i8(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = sext i8 [[X]] to i32
; CHECK-NEXT: [[EXP2:%.*]] = call double @llvm.ldexp.f64.i32(double 1.000000e+00, i32 [[TMP1]])
; CHECK-NEXT: ret double [[EXP2]]
;
%itofp = sitofp i8 %x to double
%exp2 = call double @llvm.exp2.f64(double %itofp)
ret double %exp2
}

define fp128 @exp2_fp128_sitofp_i8(i8 %x) {
; LDEXP-LABEL: define fp128 @exp2_fp128_sitofp_i8(
; LDEXP-SAME: i8 [[X:%.*]]) {
; LDEXP-NEXT: [[TMP1:%.*]] = sext i8 [[X]] to i32
; LDEXP-NEXT: [[LDEXPL:%.*]] = call fp128 @llvm.ldexp.f128.i32(fp128 0xL00000000000000003FFF000000000000, i32 [[TMP1]])
; LDEXP-NEXT: ret fp128 [[LDEXPL]]
;
; NOLDEXP-LABEL: define fp128 @exp2_fp128_sitofp_i8(
; NOLDEXP-SAME: i8 [[X:%.*]]) {
; NOLDEXP-NEXT: [[ITOFP:%.*]] = sitofp i8 [[X]] to fp128
; NOLDEXP-NEXT: [[EXP2:%.*]] = call fp128 @llvm.exp2.f128(fp128 [[ITOFP]])
; NOLDEXP-NEXT: ret fp128 [[EXP2]]
; CHECK-LABEL: define fp128 @exp2_fp128_sitofp_i8(
; CHECK-SAME: i8 [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = sext i8 [[X]] to i32
; CHECK-NEXT: [[EXP2:%.*]] = call fp128 @llvm.ldexp.f128.i32(fp128 0xL00000000000000003FFF000000000000, i32 [[TMP1]])
; CHECK-NEXT: ret fp128 [[EXP2]]
;
%itofp = sitofp i8 %x to fp128
%exp2 = call fp128 @llvm.exp2.fp128(fp128 %itofp)
ret fp128 %exp2
}

define <vscale x 4 x float> @exp2_nxv4f32_sitofp_i8(<vscale x 4 x i8> %x) {
; LDEXP-LABEL: define <vscale x 4 x float> @exp2_nxv4f32_sitofp_i8(
; LDEXP-SAME: <vscale x 4 x i8> [[X:%.*]]) {
; LDEXP-NEXT: [[TMP1:%.*]] = sext <vscale x 4 x i8> [[X]] to <vscale x 4 x i32>
; LDEXP-NEXT: [[EXP2:%.*]] = call <vscale x 4 x float> @llvm.ldexp.nxv4f32.nxv4i32(<vscale x 4 x float> shufflevector (<vscale x 4 x float> insertelement (<vscale x 4 x float> poison, float 1.000000e+00, i64 0), <vscale x 4 x float> poison, <vscale x 4 x i32> zeroinitializer), <vscale x 4 x i32> [[TMP1]])
; LDEXP-NEXT: ret <vscale x 4 x float> [[EXP2]]
;
; NOLDEXP-LABEL: define <vscale x 4 x float> @exp2_nxv4f32_sitofp_i8(
; NOLDEXP-SAME: <vscale x 4 x i8> [[X:%.*]]) {
; NOLDEXP-NEXT: [[ITOFP:%.*]] = sitofp <vscale x 4 x i8> [[X]] to <vscale x 4 x float>
; NOLDEXP-NEXT: [[EXP2:%.*]] = call <vscale x 4 x float> @llvm.exp2.nxv4f32(<vscale x 4 x float> [[ITOFP]])
; NOLDEXP-NEXT: ret <vscale x 4 x float> [[EXP2]]
; CHECK-LABEL: define <vscale x 4 x float> @exp2_nxv4f32_sitofp_i8(
; CHECK-SAME: <vscale x 4 x i8> [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = sext <vscale x 4 x i8> [[X]] to <vscale x 4 x i32>
; CHECK-NEXT: [[EXP2:%.*]] = call <vscale x 4 x float> @llvm.ldexp.nxv4f32.nxv4i32(<vscale x 4 x float> shufflevector (<vscale x 4 x float> insertelement (<vscale x 4 x float> poison, float 1.000000e+00, i64 0), <vscale x 4 x float> poison, <vscale x 4 x i32> zeroinitializer), <vscale x 4 x i32> [[TMP1]])
; CHECK-NEXT: ret <vscale x 4 x float> [[EXP2]]
;
%itofp = sitofp <vscale x 4 x i8> %x to <vscale x 4 x float>
%exp2 = call <vscale x 4 x float> @llvm.exp2.nxv4f32(<vscale x 4 x float> %itofp)
Expand Down
Loading
Loading