1
0
mirror of https://github.com/RPCS3/llvm-mirror.git synced 2024-11-25 12:12:47 +01:00

[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
This commit is contained in:
Bjorn Pettersson 2021-03-26 12:49:38 +01:00
parent 8a32a3f1a2
commit 1f980badb2
6 changed files with 272 additions and 45 deletions

View File

@ -52,6 +52,7 @@ class TargetLibraryInfoImpl {
llvm::DenseMap<unsigned, std::string> 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

View File

@ -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:

View File

@ -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<SIToFPInst>(I2F) || isa<UIToFPInst>(I2F)) {
Value *Op = cast<Instruction>(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<SIToFPInst>(I2F)))
return isa<SIToFPInst>(I2F) ? B.CreateSExt(Op, B.getInt32Ty())
: B.CreateZExt(Op, B.getInt32Ty());
if (BitWidth < DstWidth ||
(BitWidth == DstWidth && isa<SIToFPInst>(I2F)))
return isa<SIToFPInst>(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<SIToFPInst>(Expo) || isa<UIToFPInst>(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<SIToFPInst>(Expo) || isa<UIToFPInst>(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<SIToFPInst>(Op) || isa<UIToFPInst>(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);

View File

@ -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
}

View File

@ -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

View File

@ -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 }