From 1f980badb2c1ab15b419b6699234e1e332d58813 Mon Sep 17 00:00:00 2001 From: Bjorn Pettersson Date: Fri, 26 Mar 2021 12:49:38 +0100 Subject: [PATCH] [SimplifyLibCalls] Take size of int into consideration when emitting ldexp/ldexpf When rewriting powf(2.0, itofp(x)) -> ldexpf(1.0, x) exp2(sitofp(x)) -> ldexp(1.0, sext(x)) exp2(uitofp(x)) -> ldexp(1.0, zext(x)) the wrong type was used for the second argument in the ldexp/ldexpf libc call, for target architectures with 16 bit "int" type. The transform incorrectly used a bitcasted function pointer with a 32-bit argument when emitting the ldexp/ldexpf call for such targets. The fault is solved by using the correct function prototype in the call, by asking TargetLibraryInfo about the size of "int". TargetLibraryInfo by default derives the size of the int type by assuming that it is 16 bits for 16-bit architectures, and 32 bits otherwise. If this isn't true for a target it should be possible to override that default in the TargetLibraryInfo initializer. Differential Revision: https://reviews.llvm.org/D99438 --- include/llvm/Analysis/TargetLibraryInfo.h | 16 ++ lib/Analysis/TargetLibraryInfo.cpp | 15 +- lib/Transforms/Utils/SimplifyLibCalls.cpp | 30 ++- test/Transforms/InstCombine/exp2-1.ll | 226 ++++++++++++++++-- test/Transforms/InstCombine/pow_fp_int.ll | 2 +- .../InstCombine/simplify-libcalls.ll | 28 ++- 6 files changed, 272 insertions(+), 45 deletions(-) diff --git a/include/llvm/Analysis/TargetLibraryInfo.h b/include/llvm/Analysis/TargetLibraryInfo.h index a7ad218356a..22bfeda0efd 100644 --- a/include/llvm/Analysis/TargetLibraryInfo.h +++ b/include/llvm/Analysis/TargetLibraryInfo.h @@ -52,6 +52,7 @@ class TargetLibraryInfoImpl { llvm::DenseMap CustomNames; static StringLiteral const StandardNames[NumLibFuncs]; bool ShouldExtI32Param, ShouldExtI32Return, ShouldSignExtI32Param; + unsigned SizeOfInt; enum AvailabilityState { StandardName = 3, // (memset to all ones) @@ -189,6 +190,16 @@ public: /// This queries the 'wchar_size' metadata. unsigned getWCharSize(const Module &M) const; + /// Get size of a C-level int or unsigned int, in bits. + unsigned getIntSize() const { + return SizeOfInt; + } + + /// Initialize the C-level size of an integer. + void setIntSize(unsigned Bits) { + SizeOfInt = Bits; + } + /// Returns the largest vectorization factor used in the list of /// vector functions. void getWidestVF(StringRef ScalarF, ElementCount &FixedVF, @@ -390,6 +401,11 @@ public: return Impl->getWCharSize(M); } + /// \copydoc TargetLibraryInfoImpl::getIntSize() + unsigned getIntSize() const { + return Impl->getIntSize(); + } + /// Handle invalidation from the pass manager. /// /// If we try to invalidate this info, just return false. It cannot become diff --git a/lib/Analysis/TargetLibraryInfo.cpp b/lib/Analysis/TargetLibraryInfo.cpp index 05088c189ca..d078cce5e8e 100644 --- a/lib/Analysis/TargetLibraryInfo.cpp +++ b/lib/Analysis/TargetLibraryInfo.cpp @@ -151,6 +151,11 @@ static void initialize(TargetLibraryInfoImpl &TLI, const Triple &T, TLI.setShouldExtI32Return(ShouldExtI32Return); TLI.setShouldSignExtI32Param(ShouldSignExtI32Param); + // Let's assume by default that the size of int is 32 bits, unless the target + // is a 16-bit architecture because then it most likely is 16 bits. If that + // isn't true for a target those defaults should be overridden below. + TLI.setIntSize(T.isArch16Bit() ? 16 : 32); + if (T.isAMDGPU()) TLI.disableAllFunctions(); @@ -639,7 +644,8 @@ TargetLibraryInfoImpl::TargetLibraryInfoImpl(const Triple &T) { TargetLibraryInfoImpl::TargetLibraryInfoImpl(const TargetLibraryInfoImpl &TLI) : CustomNames(TLI.CustomNames), ShouldExtI32Param(TLI.ShouldExtI32Param), ShouldExtI32Return(TLI.ShouldExtI32Return), - ShouldSignExtI32Param(TLI.ShouldSignExtI32Param) { + ShouldSignExtI32Param(TLI.ShouldSignExtI32Param), + SizeOfInt(TLI.SizeOfInt) { memcpy(AvailableArray, TLI.AvailableArray, sizeof(AvailableArray)); VectorDescs = TLI.VectorDescs; ScalarDescs = TLI.ScalarDescs; @@ -649,7 +655,8 @@ TargetLibraryInfoImpl::TargetLibraryInfoImpl(TargetLibraryInfoImpl &&TLI) : CustomNames(std::move(TLI.CustomNames)), ShouldExtI32Param(TLI.ShouldExtI32Param), ShouldExtI32Return(TLI.ShouldExtI32Return), - ShouldSignExtI32Param(TLI.ShouldSignExtI32Param) { + ShouldSignExtI32Param(TLI.ShouldSignExtI32Param), + SizeOfInt(TLI.SizeOfInt) { std::move(std::begin(TLI.AvailableArray), std::end(TLI.AvailableArray), AvailableArray); VectorDescs = TLI.VectorDescs; @@ -661,6 +668,7 @@ TargetLibraryInfoImpl &TargetLibraryInfoImpl::operator=(const TargetLibraryInfoI ShouldExtI32Param = TLI.ShouldExtI32Param; ShouldExtI32Return = TLI.ShouldExtI32Return; ShouldSignExtI32Param = TLI.ShouldSignExtI32Param; + SizeOfInt = TLI.SizeOfInt; memcpy(AvailableArray, TLI.AvailableArray, sizeof(AvailableArray)); return *this; } @@ -670,6 +678,7 @@ TargetLibraryInfoImpl &TargetLibraryInfoImpl::operator=(TargetLibraryInfoImpl && ShouldExtI32Param = TLI.ShouldExtI32Param; ShouldExtI32Return = TLI.ShouldExtI32Return; ShouldSignExtI32Param = TLI.ShouldSignExtI32Param; + SizeOfInt = TLI.SizeOfInt; std::move(std::begin(TLI.AvailableArray), std::end(TLI.AvailableArray), AvailableArray); return *this; @@ -1498,7 +1507,7 @@ bool TargetLibraryInfoImpl::isValidProtoForLibFunc(const FunctionType &FTy, case LibFunc_ldexpl: return (NumParams == 2 && FTy.getReturnType()->isFloatingPointTy() && FTy.getReturnType() == FTy.getParamType(0) && - FTy.getParamType(1)->isIntegerTy(32)); + FTy.getParamType(1)->isIntegerTy(getIntSize())); case LibFunc_ffs: case LibFunc_ffsl: diff --git a/lib/Transforms/Utils/SimplifyLibCalls.cpp b/lib/Transforms/Utils/SimplifyLibCalls.cpp index e9f777faf9c..5b650f8c5dd 100644 --- a/lib/Transforms/Utils/SimplifyLibCalls.cpp +++ b/lib/Transforms/Utils/SimplifyLibCalls.cpp @@ -1424,17 +1424,18 @@ static Value *getPow(Value *InnerChain[33], unsigned Exp, IRBuilderBase &B) { return InnerChain[Exp]; } -// Return a properly extended 32-bit integer if the operation is an itofp. -static Value *getIntToFPVal(Value *I2F, IRBuilderBase &B) { +// Return a properly extended integer (DstWidth bits wide) if the operation is +// an itofp. +static Value *getIntToFPVal(Value *I2F, IRBuilderBase &B, unsigned DstWidth) { if (isa(I2F) || isa(I2F)) { Value *Op = cast(I2F)->getOperand(0); - // Make sure that the exponent fits inside an int32_t, + // Make sure that the exponent fits inside an "int" of size DstWidth, // thus avoiding any range issues that FP has not. unsigned BitWidth = Op->getType()->getPrimitiveSizeInBits(); - if (BitWidth < 32 || - (BitWidth == 32 && isa(I2F))) - return isa(I2F) ? B.CreateSExt(Op, B.getInt32Ty()) - : B.CreateZExt(Op, B.getInt32Ty()); + if (BitWidth < DstWidth || + (BitWidth == DstWidth && isa(I2F))) + return isa(I2F) ? B.CreateSExt(Op, B.getIntNTy(DstWidth)) + : B.CreateZExt(Op, B.getIntNTy(DstWidth)); } return nullptr; @@ -1524,7 +1525,7 @@ Value *LibCallSimplifier::replacePowWithExp(CallInst *Pow, IRBuilderBase &B) { if (match(Base, m_SpecificFP(2.0)) && (isa(Expo) || isa(Expo)) && hasFloatFn(TLI, Ty, LibFunc_ldexp, LibFunc_ldexpf, LibFunc_ldexpl)) { - if (Value *ExpoI = getIntToFPVal(Expo, B)) + if (Value *ExpoI = getIntToFPVal(Expo, B, TLI->getIntSize())) return emitBinaryFloatFnCall(ConstantFP::get(Ty, 1.0), ExpoI, TLI, LibFunc_ldexp, LibFunc_ldexpf, LibFunc_ldexpl, B, Attrs); @@ -1776,7 +1777,12 @@ Value *LibCallSimplifier::optimizePow(CallInst *Pow, IRBuilderBase &B) { // powf(x, itofp(y)) -> powi(x, y) if (AllowApprox && (isa(Expo) || isa(Expo))) { - if (Value *ExpoI = getIntToFPVal(Expo, B)) + // FIXME: Currently we always use 32 bits for the exponent in llvm.powi. In + // the future we want to use the target dependent "size of int", or + // otherwise we could end up using the wrong type for the exponent when + // mapping llvm.powi back to an rtlib call. See + // https://reviews.llvm.org/D99439 for such a fix. + if (Value *ExpoI = getIntToFPVal(Expo, B, 32)) return createPowWithIntegerExponent(Base, ExpoI, M, B); } @@ -1803,11 +1809,11 @@ Value *LibCallSimplifier::optimizeExp2(CallInst *CI, IRBuilderBase &B) { Type *Ty = CI->getType(); Value *Op = CI->getArgOperand(0); - // Turn exp2(sitofp(x)) -> ldexp(1.0, sext(x)) if sizeof(x) <= 32 - // Turn exp2(uitofp(x)) -> ldexp(1.0, zext(x)) if sizeof(x) < 32 + // Turn exp2(sitofp(x)) -> ldexp(1.0, sext(x)) if sizeof(x) <= IntSize + // Turn exp2(uitofp(x)) -> ldexp(1.0, zext(x)) if sizeof(x) < IntSize if ((isa(Op) || isa(Op)) && hasFloatFn(TLI, Ty, LibFunc_ldexp, LibFunc_ldexpf, LibFunc_ldexpl)) { - if (Value *Exp = getIntToFPVal(Op, B)) + if (Value *Exp = getIntToFPVal(Op, B, TLI->getIntSize())) return emitBinaryFloatFnCall(ConstantFP::get(Ty, 1.0), Exp, TLI, LibFunc_ldexp, LibFunc_ldexpf, LibFunc_ldexpl, B, Attrs); diff --git a/test/Transforms/InstCombine/exp2-1.ll b/test/Transforms/InstCombine/exp2-1.ll index b6a56b9a9a7..afb104ffe81 100644 --- a/test/Transforms/InstCombine/exp2-1.ll +++ b/test/Transforms/InstCombine/exp2-1.ll @@ -1,8 +1,10 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py ; Test that the exp2 library call simplifier works correctly. ; -; RUN: opt < %s -instcombine -S | FileCheck %s -check-prefix=CHECK -check-prefix=INTRINSIC -check-prefix=LDEXP -check-prefix=LDEXPF -; RUN: opt < %s -instcombine -S -mtriple=i386-pc-win32 | FileCheck %s -check-prefix=INTRINSIC -check-prefix=LDEXP -check-prefix=NOLDEXPF -; RUN: opt < %s -instcombine -S -mtriple=amdgcn-unknown-unknown | FileCheck %s -check-prefix=INTRINSIC -check-prefix=NOLDEXP -check-prefix=NOLDEXPF +; RUN: opt < %s -instcombine -S -mtriple=unknown | FileCheck %s -check-prefixes=LDEXP32 +; RUN: opt < %s -instcombine -S -mtriple=msp430 | FileCheck %s -check-prefixes=LDEXP16 +; RUN: opt < %s -instcombine -S -mtriple=i386-pc-win32 | FileCheck %s -check-prefixes=NOLDEXPF +; RUN: opt < %s -instcombine -S -mtriple=amdgcn-unknown-unknown | FileCheck %s -check-prefixes=NOLDEXP target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128" @@ -12,68 +14,208 @@ declare float @exp2f(float) ; Check exp2(sitofp(x)) -> ldexp(1.0, sext(x)). define double @test_simplify1(i32 %x) { -; CHECK-LABEL: @test_simplify1( +; LDEXP32-LABEL: @test_simplify1( +; LDEXP32-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 [[X:%.*]]) +; LDEXP32-NEXT: ret double [[LDEXP]] +; +; LDEXP16-LABEL: @test_simplify1( +; LDEXP16-NEXT: [[CONV:%.*]] = sitofp i32 [[X:%.*]] to double +; LDEXP16-NEXT: [[RET:%.*]] = call double @exp2(double [[CONV]]) +; LDEXP16-NEXT: ret double [[RET]] +; +; NOLDEXPF-LABEL: @test_simplify1( +; NOLDEXPF-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 [[X:%.*]]) +; NOLDEXPF-NEXT: ret double [[LDEXP]] +; +; NOLDEXP-LABEL: @test_simplify1( +; NOLDEXP-NEXT: [[CONV:%.*]] = sitofp i32 [[X:%.*]] to double +; NOLDEXP-NEXT: [[RET:%.*]] = call double @exp2(double [[CONV]]) +; NOLDEXP-NEXT: ret double [[RET]] +; %conv = sitofp i32 %x to double %ret = call double @exp2(double %conv) -; CHECK: call double @ldexp ret double %ret } define double @test_simplify2(i16 signext %x) { -; CHECK-LABEL: @test_simplify2( +; LDEXP32-LABEL: @test_simplify2( +; LDEXP32-NEXT: [[TMP1:%.*]] = sext i16 [[X:%.*]] to i32 +; LDEXP32-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 [[TMP1]]) +; LDEXP32-NEXT: ret double [[LDEXP]] +; +; LDEXP16-LABEL: @test_simplify2( +; LDEXP16-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i16 [[X:%.*]]) +; LDEXP16-NEXT: ret double [[LDEXP]] +; +; NOLDEXPF-LABEL: @test_simplify2( +; NOLDEXPF-NEXT: [[TMP1:%.*]] = sext i16 [[X:%.*]] to i32 +; NOLDEXPF-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 [[TMP1]]) +; NOLDEXPF-NEXT: ret double [[LDEXP]] +; +; NOLDEXP-LABEL: @test_simplify2( +; NOLDEXP-NEXT: [[CONV:%.*]] = sitofp i16 [[X:%.*]] to double +; NOLDEXP-NEXT: [[RET:%.*]] = call double @exp2(double [[CONV]]) +; NOLDEXP-NEXT: ret double [[RET]] +; %conv = sitofp i16 %x to double %ret = call double @exp2(double %conv) -; CHECK: call double @ldexp ret double %ret } define double @test_simplify3(i8 signext %x) { -; CHECK-LABEL: @test_simplify3( +; LDEXP32-LABEL: @test_simplify3( +; LDEXP32-NEXT: [[TMP1:%.*]] = sext i8 [[X:%.*]] to i32 +; LDEXP32-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 [[TMP1]]) +; LDEXP32-NEXT: ret double [[LDEXP]] +; +; LDEXP16-LABEL: @test_simplify3( +; LDEXP16-NEXT: [[TMP1:%.*]] = sext i8 [[X:%.*]] to i16 +; LDEXP16-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i16 [[TMP1]]) +; LDEXP16-NEXT: ret double [[LDEXP]] +; +; NOLDEXPF-LABEL: @test_simplify3( +; NOLDEXPF-NEXT: [[TMP1:%.*]] = sext i8 [[X:%.*]] to i32 +; NOLDEXPF-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 [[TMP1]]) +; NOLDEXPF-NEXT: ret double [[LDEXP]] +; +; NOLDEXP-LABEL: @test_simplify3( +; NOLDEXP-NEXT: [[CONV:%.*]] = sitofp i8 [[X:%.*]] to double +; NOLDEXP-NEXT: [[RET:%.*]] = call double @exp2(double [[CONV]]) +; NOLDEXP-NEXT: ret double [[RET]] +; %conv = sitofp i8 %x to double %ret = call double @exp2(double %conv) -; CHECK: call double @ldexp ret double %ret } define float @test_simplify4(i32 %x) { -; CHECK-LABEL: @test_simplify4( +; LDEXP32-LABEL: @test_simplify4( +; LDEXP32-NEXT: [[LDEXPF:%.*]] = call float @ldexpf(float 1.000000e+00, i32 [[X:%.*]]) +; LDEXP32-NEXT: ret float [[LDEXPF]] +; +; LDEXP16-LABEL: @test_simplify4( +; LDEXP16-NEXT: [[CONV:%.*]] = sitofp i32 [[X:%.*]] to float +; LDEXP16-NEXT: [[RET:%.*]] = call float @exp2f(float [[CONV]]) +; LDEXP16-NEXT: ret float [[RET]] +; +; NOLDEXPF-LABEL: @test_simplify4( +; NOLDEXPF-NEXT: [[CONV:%.*]] = sitofp i32 [[X:%.*]] to float +; NOLDEXPF-NEXT: [[RET:%.*]] = call float @exp2f(float [[CONV]]) +; NOLDEXPF-NEXT: ret float [[RET]] +; +; NOLDEXP-LABEL: @test_simplify4( +; NOLDEXP-NEXT: [[CONV:%.*]] = sitofp i32 [[X:%.*]] to float +; NOLDEXP-NEXT: [[RET:%.*]] = call float @exp2f(float [[CONV]]) +; NOLDEXP-NEXT: ret float [[RET]] +; %conv = sitofp i32 %x to float %ret = call float @exp2f(float %conv) -; CHECK: call float @ldexpf ret float %ret } ; Check exp2(uitofp(x)) -> ldexp(1.0, zext(x)). define double @test_no_simplify1(i32 %x) { -; CHECK-LABEL: @test_no_simplify1( +; LDEXP32-LABEL: @test_no_simplify1( +; LDEXP32-NEXT: [[CONV:%.*]] = uitofp i32 [[X:%.*]] to double +; LDEXP32-NEXT: [[RET:%.*]] = call double @exp2(double [[CONV]]) +; LDEXP32-NEXT: ret double [[RET]] +; +; LDEXP16-LABEL: @test_no_simplify1( +; LDEXP16-NEXT: [[CONV:%.*]] = uitofp i32 [[X:%.*]] to double +; LDEXP16-NEXT: [[RET:%.*]] = call double @exp2(double [[CONV]]) +; LDEXP16-NEXT: ret double [[RET]] +; +; NOLDEXPF-LABEL: @test_no_simplify1( +; NOLDEXPF-NEXT: [[CONV:%.*]] = uitofp i32 [[X:%.*]] to double +; NOLDEXPF-NEXT: [[RET:%.*]] = call double @exp2(double [[CONV]]) +; NOLDEXPF-NEXT: ret double [[RET]] +; +; NOLDEXP-LABEL: @test_no_simplify1( +; NOLDEXP-NEXT: [[CONV:%.*]] = uitofp i32 [[X:%.*]] to double +; NOLDEXP-NEXT: [[RET:%.*]] = call double @exp2(double [[CONV]]) +; NOLDEXP-NEXT: ret double [[RET]] +; %conv = uitofp i32 %x to double %ret = call double @exp2(double %conv) -; CHECK: call double @exp2 ret double %ret } define double @test_simplify6(i16 zeroext %x) { -; CHECK-LABEL: @test_simplify6( +; LDEXP32-LABEL: @test_simplify6( +; LDEXP32-NEXT: [[TMP1:%.*]] = zext i16 [[X:%.*]] to i32 +; LDEXP32-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 [[TMP1]]) +; LDEXP32-NEXT: ret double [[LDEXP]] +; +; LDEXP16-LABEL: @test_simplify6( +; LDEXP16-NEXT: [[CONV:%.*]] = uitofp i16 [[X:%.*]] to double +; LDEXP16-NEXT: [[RET:%.*]] = call double @exp2(double [[CONV]]) +; LDEXP16-NEXT: ret double [[RET]] +; +; NOLDEXPF-LABEL: @test_simplify6( +; NOLDEXPF-NEXT: [[TMP1:%.*]] = zext i16 [[X:%.*]] to i32 +; NOLDEXPF-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 [[TMP1]]) +; NOLDEXPF-NEXT: ret double [[LDEXP]] +; +; NOLDEXP-LABEL: @test_simplify6( +; NOLDEXP-NEXT: [[CONV:%.*]] = uitofp i16 [[X:%.*]] to double +; NOLDEXP-NEXT: [[RET:%.*]] = call double @exp2(double [[CONV]]) +; NOLDEXP-NEXT: ret double [[RET]] +; %conv = uitofp i16 %x to double %ret = call double @exp2(double %conv) -; CHECK: call double @ldexp ret double %ret } define double @test_simplify7(i8 zeroext %x) { -; CHECK-LABEL: @test_simplify7( +; LDEXP32-LABEL: @test_simplify7( +; LDEXP32-NEXT: [[TMP1:%.*]] = zext i8 [[X:%.*]] to i32 +; LDEXP32-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 [[TMP1]]) +; LDEXP32-NEXT: ret double [[LDEXP]] +; +; LDEXP16-LABEL: @test_simplify7( +; LDEXP16-NEXT: [[TMP1:%.*]] = zext i8 [[X:%.*]] to i16 +; LDEXP16-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i16 [[TMP1]]) +; LDEXP16-NEXT: ret double [[LDEXP]] +; +; NOLDEXPF-LABEL: @test_simplify7( +; NOLDEXPF-NEXT: [[TMP1:%.*]] = zext i8 [[X:%.*]] to i32 +; NOLDEXPF-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 [[TMP1]]) +; NOLDEXPF-NEXT: ret double [[LDEXP]] +; +; NOLDEXP-LABEL: @test_simplify7( +; NOLDEXP-NEXT: [[CONV:%.*]] = uitofp i8 [[X:%.*]] to double +; NOLDEXP-NEXT: [[RET:%.*]] = call double @exp2(double [[CONV]]) +; NOLDEXP-NEXT: ret double [[RET]] +; %conv = uitofp i8 %x to double %ret = call double @exp2(double %conv) -; CHECK: call double @ldexp ret double %ret } define float @test_simplify8(i8 zeroext %x) { -; CHECK-LABEL: @test_simplify8( +; LDEXP32-LABEL: @test_simplify8( +; LDEXP32-NEXT: [[TMP1:%.*]] = zext i8 [[X:%.*]] to i32 +; LDEXP32-NEXT: [[LDEXPF:%.*]] = call float @ldexpf(float 1.000000e+00, i32 [[TMP1]]) +; LDEXP32-NEXT: ret float [[LDEXPF]] +; +; LDEXP16-LABEL: @test_simplify8( +; LDEXP16-NEXT: [[TMP1:%.*]] = zext i8 [[X:%.*]] to i16 +; LDEXP16-NEXT: [[LDEXPF:%.*]] = call float @ldexpf(float 1.000000e+00, i16 [[TMP1]]) +; LDEXP16-NEXT: ret float [[LDEXPF]] +; +; NOLDEXPF-LABEL: @test_simplify8( +; NOLDEXPF-NEXT: [[CONV:%.*]] = uitofp i8 [[X:%.*]] to float +; NOLDEXPF-NEXT: [[RET:%.*]] = call float @exp2f(float [[CONV]]) +; NOLDEXPF-NEXT: ret float [[RET]] +; +; NOLDEXP-LABEL: @test_simplify8( +; NOLDEXP-NEXT: [[CONV:%.*]] = uitofp i8 [[X:%.*]] to float +; NOLDEXP-NEXT: [[RET:%.*]] = call float @exp2f(float [[CONV]]) +; NOLDEXP-NEXT: ret float [[RET]] +; %conv = uitofp i8 %x to float %ret = call float @exp2f(float %conv) -; CHECK: call float @ldexpf ret float %ret } @@ -81,19 +223,53 @@ declare double @llvm.exp2.f64(double) declare float @llvm.exp2.f32(float) define double @test_simplify9(i8 zeroext %x) { -; INTRINSIC-LABEL: @test_simplify9( +; LDEXP32-LABEL: @test_simplify9( +; LDEXP32-NEXT: [[TMP1:%.*]] = zext i8 [[X:%.*]] to i32 +; LDEXP32-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 [[TMP1]]) +; LDEXP32-NEXT: ret double [[LDEXP]] +; +; LDEXP16-LABEL: @test_simplify9( +; LDEXP16-NEXT: [[TMP1:%.*]] = zext i8 [[X:%.*]] to i16 +; LDEXP16-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i16 [[TMP1]]) +; LDEXP16-NEXT: ret double [[LDEXP]] +; +; NOLDEXPF-LABEL: @test_simplify9( +; NOLDEXPF-NEXT: [[TMP1:%.*]] = zext i8 [[X:%.*]] to i32 +; NOLDEXPF-NEXT: [[LDEXP:%.*]] = call double @ldexp(double 1.000000e+00, i32 [[TMP1]]) +; NOLDEXPF-NEXT: ret double [[LDEXP]] +; +; NOLDEXP-LABEL: @test_simplify9( +; NOLDEXP-NEXT: [[CONV:%.*]] = uitofp i8 [[X:%.*]] to double +; NOLDEXP-NEXT: [[RET:%.*]] = call double @llvm.exp2.f64(double [[CONV]]) +; NOLDEXP-NEXT: ret double [[RET]] +; %conv = uitofp i8 %x to double %ret = call double @llvm.exp2.f64(double %conv) -; LDEXP: call double @ldexp -; NOLDEXP-NOT: call double @ldexp ret double %ret } define float @test_simplify10(i8 zeroext %x) { -; INTRINSIC-LABEL: @test_simplify10( +; LDEXP32-LABEL: @test_simplify10( +; LDEXP32-NEXT: [[TMP1:%.*]] = zext i8 [[X:%.*]] to i32 +; LDEXP32-NEXT: [[LDEXPF:%.*]] = call float @ldexpf(float 1.000000e+00, i32 [[TMP1]]) +; LDEXP32-NEXT: ret float [[LDEXPF]] +; +; LDEXP16-LABEL: @test_simplify10( +; LDEXP16-NEXT: [[TMP1:%.*]] = zext i8 [[X:%.*]] to i16 +; LDEXP16-NEXT: [[LDEXPF:%.*]] = call float @ldexpf(float 1.000000e+00, i16 [[TMP1]]) +; LDEXP16-NEXT: ret float [[LDEXPF]] +; +; NOLDEXPF-LABEL: @test_simplify10( +; NOLDEXPF-NEXT: [[CONV:%.*]] = uitofp i8 [[X:%.*]] to float +; NOLDEXPF-NEXT: [[RET:%.*]] = call float @llvm.exp2.f32(float [[CONV]]) +; 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: ret float [[RET]] +; %conv = uitofp i8 %x to float %ret = call float @llvm.exp2.f32(float %conv) -; LDEXPF: call float @ldexpf -; NOLDEXPF-NOT: call float @ldexpf ret float %ret } diff --git a/test/Transforms/InstCombine/pow_fp_int.ll b/test/Transforms/InstCombine/pow_fp_int.ll index 48297589ad9..e0e13c642ba 100644 --- a/test/Transforms/InstCombine/pow_fp_int.ll +++ b/test/Transforms/InstCombine/pow_fp_int.ll @@ -1,5 +1,5 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py -; RUN: opt -instcombine -S < %s | FileCheck %s +; RUN: opt -mtriple unknown -instcombine -S < %s | FileCheck %s ; PR42190 diff --git a/test/Transforms/InstCombine/simplify-libcalls.ll b/test/Transforms/InstCombine/simplify-libcalls.ll index d212bcd8ff7..25b168515cb 100644 --- a/test/Transforms/InstCombine/simplify-libcalls.ll +++ b/test/Transforms/InstCombine/simplify-libcalls.ll @@ -1,4 +1,5 @@ -; RUN: opt -S < %s -instcombine -instcombine-infinite-loop-threshold=2 | FileCheck %s +; RUN: opt -S < %s -mtriple=unknown -instcombine -instcombine-infinite-loop-threshold=2 | FileCheck -check-prefixes=CHECK,CHECK32 %s +; RUN: opt -S < %s -mtriple=msp430 -instcombine -instcombine-infinite-loop-threshold=2 | FileCheck -check-prefixes=CHECK,CHECK16 %s target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:64:64-f32:32:32-f64:64:64-f80:128:128-v64:64:64-v128:128:128-a0:0:64-f80:32:32-n8:16:32-S32" @G = constant [3 x i8] c"%s\00" ; <[3 x i8]*> [#uses=1] @@ -188,14 +189,33 @@ define double @fake_exp2(double %x) { ret double %y } define double @fake_ldexp(i32 %x) { -; CHECK-LABEL: @fake_ldexp( -; CHECK-NEXT: [[Z:%.*]] = call double @ldexp(double 1.0{{.*}}, i32 %x) -; CHECK-NEXT: ret double [[Z]] +; CHECK32-LABEL: @fake_ldexp( +; CHECK32-NEXT: [[Z:%.*]] = call double @ldexp(double 1.0{{.*}}, i32 %x) +; CHECK32-NEXT: ret double [[Z]] + +; CHECK16-LABEL: @fake_ldexp( +; CHECK16-NEXT: [[Y:%.*]] = sitofp i32 %x to double +; CHECK16-NEXT: [[Z:%.*]] = call inreg double @exp2(double [[Y]]) +; CHECK16-NEXT: ret double [[Z]] %y = sitofp i32 %x to double %z = call inreg double @exp2(double %y) ret double %z } +define double @fake_ldexp_16(i16 %x) { +; CHECK32-LABEL: @fake_ldexp_16( +; CHECK32-NEXT: [[Y:%.*]] = sext i16 %x to i32 +; CHECK32-NEXT: [[Z:%.*]] = call double @ldexp(double 1.0{{.*}}, i32 [[Y]]) +; CHECK32-NEXT: ret double [[Z]] + +; CHECK16-LABEL: @fake_ldexp_16( +; CHECK16-NEXT: [[Z:%.*]] = call double @ldexp(double 1.0{{.*}}, i16 %x) +; CHECK16-NEXT: ret double [[Z]] + + %y = sitofp i16 %x to double + %z = call inreg double @exp2(double %y) + ret double %z +} attributes #0 = { nobuiltin }