llvm / llvm-project

The LLVM Project is a collection of modular and reusable compiler and toolchain technologies.
http://llvm.org
Other
28.78k stars 11.9k forks source link

InstCombine: Try to use exp10 intrinsic instead of libcall #92287

Closed arsenm closed 5 months ago

arsenm commented 5 months ago

Addresses old TODO about the exp10 intrinsic not existing.

llvmbot commented 5 months ago

@llvm/pr-subscribers-llvm-transforms

Author: Matt Arsenault (arsenm)

Changes Addresses old TODO about the exp10 intrinsic not existing. --- Full diff: https://github.com/llvm/llvm-project/pull/92287.diff 2 Files Affected: - (modified) llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp (+9-2) - (modified) llvm/test/Transforms/InstCombine/pow-1.ll (+131) ``````````diff diff --git a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp index 9cb8e20b4806f..69b0f78530d7d 100644 --- a/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ b/llvm/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -2134,12 +2134,19 @@ Value *LibCallSimplifier::replacePowWithExp(CallInst *Pow, IRBuilderBase &B) { } // pow(10.0, x) -> exp10(x) - // TODO: There is no exp10() intrinsic yet, but some day there shall be one. if (match(Base, m_SpecificFP(10.0)) && - hasFloatFn(M, TLI, Ty, LibFunc_exp10, LibFunc_exp10f, LibFunc_exp10l)) + hasFloatFn(M, TLI, Ty, LibFunc_exp10, LibFunc_exp10f, LibFunc_exp10l)) { + + if (Pow->doesNotAccessMemory()) { + CallInst *NewExp10 = + B.CreateIntrinsic(Intrinsic::exp10, {Ty}, {Expo}, Pow, "exp10"); + return copyFlags(*Pow, NewExp10); + } + return copyFlags(*Pow, emitUnaryFloatFnCall(Expo, TLI, LibFunc_exp10, LibFunc_exp10f, LibFunc_exp10l, B, NoAttrs)); + } // pow(x, y) -> exp2(log2(x) * y) if (Pow->hasApproxFunc() && Pow->hasNoNaNs() && BaseF->isFiniteNonZero() && diff --git a/llvm/test/Transforms/InstCombine/pow-1.ll b/llvm/test/Transforms/InstCombine/pow-1.ll index 7a72902126f84..c52b97c38893b 100644 --- a/llvm/test/Transforms/InstCombine/pow-1.ll +++ b/llvm/test/Transforms/InstCombine/pow-1.ll @@ -893,3 +893,134 @@ define double @test_simplify19(double %x) { %retval = call double @pow(double 10.0, double %x) ret double %retval } + +define float @test_libcall_powf_10_f32_noerrno(float %x) { +; CHECK-EXP10-LABEL: define float @test_libcall_powf_10_f32_noerrno( +; CHECK-EXP10-SAME: float [[X:%.*]]) { +; CHECK-EXP10-NEXT: [[__EXP10F:%.*]] = call float @llvm.exp10.f32(float [[X]]) +; CHECK-EXP10-NEXT: ret float [[__EXP10F]] +; +; CHECK-NO-EXP10-LABEL: define float @test_libcall_powf_10_f32_noerrno( +; CHECK-NO-EXP10-SAME: float [[X:%.*]]) { +; CHECK-NO-EXP10-NEXT: [[RETVAL:%.*]] = call float @powf(float 1.000000e+01, float [[X]]) #[[ATTR3:[0-9]+]] +; CHECK-NO-EXP10-NEXT: ret float [[RETVAL]] +; + %retval = call float @powf(float 10.0, float %x) memory(none) + ret float %retval +} + +define double @test_libcall_pow_10_f64_noerrno(double %x) { +; CHECK-EXP10-LABEL: define double @test_libcall_pow_10_f64_noerrno( +; CHECK-EXP10-SAME: double [[X:%.*]]) { +; CHECK-EXP10-NEXT: [[__EXP10:%.*]] = call double @llvm.exp10.f64(double [[X]]) +; CHECK-EXP10-NEXT: ret double [[__EXP10]] +; +; CHECK-NO-EXP10-LABEL: define double @test_libcall_pow_10_f64_noerrno( +; CHECK-NO-EXP10-SAME: double [[X:%.*]]) { +; CHECK-NO-EXP10-NEXT: [[RETVAL:%.*]] = call double @pow(double 1.000000e+01, double [[X]]) #[[ATTR3]] +; CHECK-NO-EXP10-NEXT: ret double [[RETVAL]] +; + %retval = call double @pow(double 10.0, double %x) memory(none) + ret double %retval +} + +define half @test_pow_10_f16(half %x) { +; CHECK-LABEL: define half @test_pow_10_f16( +; CHECK-SAME: half [[X:%.*]]) { +; CHECK-NEXT: [[RETVAL:%.*]] = call half @llvm.pow.f16(half 0xH4900, half [[X]]) +; CHECK-NEXT: ret half [[RETVAL]] +; + %retval = call half @llvm.pow.f16(half 10.0, half %x) + ret half %retval +} + +define float @test_pow_10_f32(float %x) { +; CHECK-EXP10-LABEL: define float @test_pow_10_f32( +; CHECK-EXP10-SAME: float [[X:%.*]]) { +; CHECK-EXP10-NEXT: [[__EXP10F:%.*]] = call float @llvm.exp10.f32(float [[X]]) +; CHECK-EXP10-NEXT: ret float [[__EXP10F]] +; +; CHECK-NO-EXP10-LABEL: define float @test_pow_10_f32( +; CHECK-NO-EXP10-SAME: float [[X:%.*]]) { +; CHECK-NO-EXP10-NEXT: [[RETVAL:%.*]] = call float @llvm.pow.f32(float 1.000000e+01, float [[X]]) +; CHECK-NO-EXP10-NEXT: ret float [[RETVAL]] +; + %retval = call float @llvm.pow.f32(float 10.0, float %x) + ret float %retval +} + +define double @test_pow_10_f64(double %x) { +; CHECK-EXP10-LABEL: define double @test_pow_10_f64( +; CHECK-EXP10-SAME: double [[X:%.*]]) { +; CHECK-EXP10-NEXT: [[__EXP10:%.*]] = call double @llvm.exp10.f64(double [[X]]) +; CHECK-EXP10-NEXT: ret double [[__EXP10]] +; +; CHECK-NO-EXP10-LABEL: define double @test_pow_10_f64( +; CHECK-NO-EXP10-SAME: double [[X:%.*]]) { +; CHECK-NO-EXP10-NEXT: [[RETVAL:%.*]] = call double @llvm.pow.f64(double 1.000000e+01, double [[X]]) +; CHECK-NO-EXP10-NEXT: ret double [[RETVAL]] +; + %retval = call double @llvm.pow.f64(double 10.0, double %x) + ret double %retval +} + +define fp128 @test_pow_10_fp128(fp128 %x) { +; CHECK-LABEL: define fp128 @test_pow_10_fp128( +; CHECK-SAME: fp128 [[X:%.*]]) { +; CHECK-NEXT: [[RETVAL:%.*]] = call fp128 @llvm.pow.f128(fp128 0xL00000000000000004002400000000000, fp128 [[X]]) +; CHECK-NEXT: ret fp128 [[RETVAL]] +; + %ten = fpext double 10.0 to fp128 + %retval = call fp128 @llvm.pow.fp128(fp128 %ten, fp128 %x) + ret fp128 %retval +} + +define bfloat @test_pow_10_bf16(bfloat %x) { +; CHECK-LABEL: define bfloat @test_pow_10_bf16( +; CHECK-SAME: bfloat [[X:%.*]]) { +; CHECK-NEXT: [[RETVAL:%.*]] = call bfloat @llvm.pow.bf16(bfloat 0xR4120, bfloat [[X]]) +; CHECK-NEXT: ret bfloat [[RETVAL]] +; + %retval = call bfloat @llvm.pow.bf16(bfloat 10.0, bfloat %x) + ret bfloat %retval +} + +define <2 x half> @test_pow_10_v2f16(<2 x half> %x) { +; CHECK-LABEL: define <2 x half> @test_pow_10_v2f16( +; CHECK-SAME: <2 x half> [[X:%.*]]) { +; CHECK-NEXT: [[RETVAL:%.*]] = call <2 x half> @llvm.pow.v2f16(<2 x half> , <2 x half> [[X]]) +; CHECK-NEXT: ret <2 x half> [[RETVAL]] +; + %retval = call <2 x half> @llvm.pow.v2f16(<2 x half> , <2 x half> %x) + ret <2 x half> %retval +} + +define <2 x float> @test_pow_10_v2f32(<2 x float> %x) { +; CHECK-LABEL: define <2 x float> @test_pow_10_v2f32( +; CHECK-SAME: <2 x float> [[X:%.*]]) { +; CHECK-NEXT: [[RETVAL:%.*]] = call <2 x float> @llvm.pow.v2f32(<2 x float> , <2 x float> [[X]]) +; CHECK-NEXT: ret <2 x float> [[RETVAL]] +; + %retval = call <2 x float> @llvm.pow.v2f32(<2 x float> , <2 x float> %x) + ret <2 x float> %retval +} + +define <2 x double> @test_pow_10_v2f64(<2 x double> %x) { +; CHECK-LABEL: define <2 x double> @test_pow_10_v2f64( +; CHECK-SAME: <2 x double> [[X:%.*]]) { +; CHECK-NEXT: [[RETVAL:%.*]] = call <2 x double> @llvm.pow.v2f64(<2 x double> , <2 x double> [[X]]) +; CHECK-NEXT: ret <2 x double> [[RETVAL]] +; + %retval = call <2 x double> @llvm.pow.v2f64(<2 x double> , <2 x double> %x) + ret <2 x double> %retval +} + +define <2 x bfloat> @test_pow_10_v2bf16(<2 x bfloat> %x) { +; CHECK-LABEL: define <2 x bfloat> @test_pow_10_v2bf16( +; CHECK-SAME: <2 x bfloat> [[X:%.*]]) { +; CHECK-NEXT: [[RETVAL:%.*]] = call <2 x bfloat> @llvm.pow.v2bf16(<2 x bfloat> , <2 x bfloat> [[X]]) +; CHECK-NEXT: ret <2 x bfloat> [[RETVAL]] +; + %retval = call <2 x bfloat> @llvm.pow.v2bf16(<2 x bfloat> , <2 x bfloat> %x) + ret <2 x bfloat> %retval +} ``````````
glandium commented 5 months ago

This broke mac and ios targets, with a missing exp10 symbol at link time.

arsenm commented 5 months ago

This broke mac and ios targets, with a missing exp10 symbol at link time.

Testcase? That suggest TargetLibraryInfo is incorrectly reporting exp10 as available

arsenm commented 5 months ago

This broke mac and ios targets, with a missing exp10 symbol at link time.

Testcase? That suggest TargetLibraryInfo is incorrectly reporting exp10 as available

This seems pretty well covered already: https://github.com/llvm/llvm-project/blob/e0a293d12f3fe1c2a284e2e116cfa77d894da49f/llvm/lib/Analysis/TargetLibraryInfo.cpp#L537

glandium commented 5 months ago

It's complaining about exp10 being missing, not __exp10, so I guess the information from there is not correctly used.

glandium commented 5 months ago

Here's a reproducer

long n, x;
void foo() { x = __builtin_powl(10, n); }

Build with clang -O1 -o libfoo.dylib -shared foo.c --target=aarch64-apple-darwin -isysroot /path/to/MacOSX.sdk/

glandium commented 5 months ago

Before the change, this compiled to use __exp10, now, it uses exp10.

fhahn commented 5 months ago

As this is breaking builds on Darwin platforms I am planning to revert this soon to unbreak builds until https://github.com/llvm/llvm-project/pull/92520 lands

arsenm commented 5 months ago

As this is breaking builds on Darwin platforms I am planning to revert this soon to unbreak builds until #92520 lands

How about just review it instead