Index: llvm/lib/Analysis/ConstantFolding.cpp =================================================================== --- llvm/lib/Analysis/ConstantFolding.cpp +++ llvm/lib/Analysis/ConstantFolding.cpp @@ -1587,6 +1587,7 @@ case Intrinsic::powi: case Intrinsic::fma: case Intrinsic::fmuladd: + case Intrinsic::frexp: case Intrinsic::fptoui_sat: case Intrinsic::fptosi_sat: case Intrinsic::convert_from_fp16: @@ -3294,6 +3295,69 @@ return nullptr; } +static std::pair +ConstantFoldScalarFrexpCall(Constant *Op, Type *IntTy) { + if (isa(Op)) + return {Op, PoisonValue::get(IntTy)}; + + auto *ConstFP = dyn_cast(Op); + if (!ConstFP) + return {}; + + const APFloat &U = ConstFP->getValueAPF(); + int FrexpExp; + APFloat FrexpMant = frexp(U, FrexpExp, APFloat::rmNearestTiesToEven); + Constant *Result0 = ConstantFP::get(ConstFP->getType(), FrexpMant); + + // The exponent is an "unspecified value" for inf/nan. We use zero to avoid + // using undef. + Constant *Result1 = FrexpMant.isFinite() ? ConstantInt::get(IntTy, FrexpExp) + : ConstantInt::getNullValue(IntTy); + return {Result0, Result1}; +} + +/// Handle intrinsics that return tuples, which may be tuples of vectors. +static Constant * +ConstantFoldStructCall(StringRef Name, Intrinsic::ID IntrinsicID, + StructType *StTy, ArrayRef Operands, + const DataLayout &DL, const TargetLibraryInfo *TLI, + const CallBase *Call) { + + switch (IntrinsicID) { + case Intrinsic::frexp: { + Type *Ty0 = StTy->getContainedType(0); + Type *Ty1 = StTy->getContainedType(1)->getScalarType(); + + if (auto *FVTy0 = dyn_cast(Ty0)) { + SmallVector Results0(FVTy0->getNumElements()); + SmallVector Results1(FVTy0->getNumElements()); + + for (unsigned I = 0, E = FVTy0->getNumElements(); I != E; ++I) { + Constant *Lane = Operands[0]->getAggregateElement(I); + std::tie(Results0[I], Results1[I]) = + ConstantFoldScalarFrexpCall(Lane, Ty1); + if (!Results0[I]) + return nullptr; + } + + return ConstantStruct::get(StTy, ConstantVector::get(Results0), + ConstantVector::get(Results1)); + } + + auto [Result0, Result1] = ConstantFoldScalarFrexpCall(Operands[0], Ty1); + if (!Result0) + return nullptr; + return ConstantStruct::get(StTy, Result0, Result1); + } + default: + // TODO: Constant folding of vector intrinsics that fall through here does + // not work (e.g. overflow intrinsics) + return ConstantFoldScalarCall(Name, IntrinsicID, StTy, Operands, TLI, Call); + } + + return nullptr; +} + } // end anonymous namespace Constant *llvm::ConstantFoldCall(const CallBase *Call, Function *F, @@ -3305,7 +3369,8 @@ return nullptr; // If this is not an intrinsic and not recognized as a library call, bail out. - if (F->getIntrinsicID() == Intrinsic::not_intrinsic) { + Intrinsic::ID IID = F->getIntrinsicID(); + if (IID == Intrinsic::not_intrinsic) { if (!TLI) return nullptr; LibFunc LibF; @@ -3317,19 +3382,20 @@ Type *Ty = F->getReturnType(); if (auto *FVTy = dyn_cast(Ty)) return ConstantFoldFixedVectorCall( - Name, F->getIntrinsicID(), FVTy, Operands, - F->getParent()->getDataLayout(), TLI, Call); + Name, IID, FVTy, Operands, F->getParent()->getDataLayout(), TLI, Call); if (auto *SVTy = dyn_cast(Ty)) return ConstantFoldScalableVectorCall( - Name, F->getIntrinsicID(), SVTy, Operands, - F->getParent()->getDataLayout(), TLI, Call); + Name, IID, SVTy, Operands, F->getParent()->getDataLayout(), TLI, Call); + + if (auto *StTy = dyn_cast(Ty)) + return ConstantFoldStructCall(Name, IID, StTy, Operands, + F->getParent()->getDataLayout(), TLI, Call); // TODO: If this is a library function, we already discovered that above, // so we should pass the LibFunc, not the name (and it might be better // still to separate intrinsic handling from libcalls). - return ConstantFoldScalarCall(Name, F->getIntrinsicID(), Ty, Operands, TLI, - Call); + return ConstantFoldScalarCall(Name, IID, Ty, Operands, TLI, Call); } bool llvm::isMathLibCallNoop(const CallBase *Call, Index: llvm/lib/Analysis/InstructionSimplify.cpp =================================================================== --- llvm/lib/Analysis/InstructionSimplify.cpp +++ llvm/lib/Analysis/InstructionSimplify.cpp @@ -6159,6 +6159,15 @@ if (isSplatValue(Op0)) return Op0; break; + case Intrinsic::frexp: { + // Frexp is idempotent with the added complication of the struct return. + if (match(Op0, m_ExtractValue<0>(m_Value(X)))) { + if (match(X, m_Intrinsic(m_Value()))) + return X; + } + + break; + } default: break; } Index: llvm/test/Transforms/InstSimplify/frexp.ll =================================================================== --- llvm/test/Transforms/InstSimplify/frexp.ll +++ llvm/test/Transforms/InstSimplify/frexp.ll @@ -12,9 +12,7 @@ ; CHECK-LABEL: define { float, i32 } @frexp_frexp ; CHECK-SAME: (float [[X:%.*]]) { ; CHECK-NEXT: [[FREXP0:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float [[X]]) -; CHECK-NEXT: [[FREXP0_0:%.*]] = extractvalue { float, i32 } [[FREXP0]], 0 -; CHECK-NEXT: [[FREXP1:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float [[FREXP0_0]]) -; CHECK-NEXT: ret { float, i32 } [[FREXP1]] +; CHECK-NEXT: ret { float, i32 } [[FREXP0]] ; %frexp0 = call { float, i32 } @llvm.frexp.f32.i32(float %x) %frexp0.0 = extractvalue { float, i32 } %frexp0, 0 @@ -26,9 +24,7 @@ ; CHECK-LABEL: define { <2 x float>, <2 x i32> } @frexp_frexp_vector ; CHECK-SAME: (<2 x float> [[X:%.*]]) { ; CHECK-NEXT: [[FREXP0:%.*]] = call { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> [[X]]) -; CHECK-NEXT: [[FREXP0_0:%.*]] = extractvalue { <2 x float>, <2 x i32> } [[FREXP0]], 0 -; CHECK-NEXT: [[FREXP1:%.*]] = call { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> [[FREXP0_0]]) -; CHECK-NEXT: ret { <2 x float>, <2 x i32> } [[FREXP1]] +; CHECK-NEXT: ret { <2 x float>, <2 x i32> } [[FREXP0]] ; %frexp0 = call { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> %x) %frexp0.0 = extractvalue { <2 x float>, <2 x i32> } %frexp0, 0 @@ -39,10 +35,7 @@ define { float, i32 } @frexp_frexp_const(float %x) { ; CHECK-LABEL: define { float, i32 } @frexp_frexp_const ; CHECK-SAME: (float [[X:%.*]]) { -; CHECK-NEXT: [[FREXP0:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float 4.200000e+01) -; CHECK-NEXT: [[FREXP0_0:%.*]] = extractvalue { float, i32 } [[FREXP0]], 0 -; CHECK-NEXT: [[FREXP1:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float [[FREXP0_0]]) -; CHECK-NEXT: ret { float, i32 } [[FREXP1]] +; CHECK-NEXT: ret { float, i32 } { float 6.562500e-01, i32 0 } ; %frexp0 = call { float, i32 } @llvm.frexp.f32.i32(float 42.0) %frexp0.0 = extractvalue { float, i32 } %frexp0, 0 @@ -54,9 +47,7 @@ ; CHECK-LABEL: define { , } @frexp_frexp_scalable_vector ; CHECK-SAME: ( [[X:%.*]]) { ; CHECK-NEXT: [[FREXP0:%.*]] = call { , } @llvm.frexp.nxv2f32.nxv2i32( [[X]]) -; CHECK-NEXT: [[FREXP0_0:%.*]] = extractvalue { , } [[FREXP0]], 0 -; CHECK-NEXT: [[FREXP1:%.*]] = call { , } @llvm.frexp.nxv2f32.nxv2i32( [[FREXP0_0]]) -; CHECK-NEXT: ret { , } [[FREXP1]] +; CHECK-NEXT: ret { , } [[FREXP0]] ; %frexp0 = call { , } @llvm.frexp.nxv2f32.nxv2i32( %x) %frexp0.0 = extractvalue { , } %frexp0, 0 @@ -66,8 +57,7 @@ define { float, i32 } @frexp_poison() { ; CHECK-LABEL: define { float, i32 } @frexp_poison() { -; CHECK-NEXT: [[RET:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float poison) -; CHECK-NEXT: ret { float, i32 } [[RET]] +; CHECK-NEXT: ret { float, i32 } poison ; %ret = call { float, i32 } @llvm.frexp.f32.i32(float poison) ret { float, i32 } %ret @@ -75,8 +65,7 @@ define { <2 x float>, <2 x i32> } @frexp_poison_vector() { ; CHECK-LABEL: define { <2 x float>, <2 x i32> } @frexp_poison_vector() { -; CHECK-NEXT: [[RET:%.*]] = call { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> poison) -; CHECK-NEXT: ret { <2 x float>, <2 x i32> } [[RET]] +; CHECK-NEXT: ret { <2 x float>, <2 x i32> } poison ; %ret = call { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> poison) ret { <2 x float>, <2 x i32> } %ret @@ -84,8 +73,7 @@ define { , } @frexp_poison_scaleable_vector() { ; CHECK-LABEL: define { , } @frexp_poison_scaleable_vector() { -; CHECK-NEXT: [[RET:%.*]] = call { , } @llvm.frexp.nxv2f32.nxv2i32( poison) -; CHECK-NEXT: ret { , } [[RET]] +; CHECK-NEXT: ret { , } poison ; %ret = call { , } @llvm.frexp.nxv2f32.nxv2i32( poison) ret { , } %ret @@ -110,8 +98,7 @@ define { <2 x float>, <2 x i32> } @frexp_zero_vector() { ; CHECK-LABEL: define { <2 x float>, <2 x i32> } @frexp_zero_vector() { -; CHECK-NEXT: [[RET:%.*]] = call { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> zeroinitializer) -; CHECK-NEXT: ret { <2 x float>, <2 x i32> } [[RET]] +; CHECK-NEXT: ret { <2 x float>, <2 x i32> } zeroinitializer ; %ret = call { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> zeroinitializer) ret { <2 x float>, <2 x i32> } %ret @@ -128,8 +115,7 @@ define { <2 x float>, <2 x i32> } @frexp_zero_negzero_vector() { ; CHECK-LABEL: define { <2 x float>, <2 x i32> } @frexp_zero_negzero_vector() { -; CHECK-NEXT: [[RET:%.*]] = call { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> ) -; CHECK-NEXT: ret { <2 x float>, <2 x i32> } [[RET]] +; CHECK-NEXT: ret { <2 x float>, <2 x i32> } { <2 x float> , <2 x i32> zeroinitializer } ; %ret = call { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> ) ret { <2 x float>, <2 x i32> } %ret @@ -146,8 +132,7 @@ define { float, i32 } @frexp_zero() { ; CHECK-LABEL: define { float, i32 } @frexp_zero() { -; CHECK-NEXT: [[RET:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float 0.000000e+00) -; CHECK-NEXT: ret { float, i32 } [[RET]] +; CHECK-NEXT: ret { float, i32 } zeroinitializer ; %ret = call { float, i32 } @llvm.frexp.f32.i32(float 0.0) ret { float, i32 } %ret @@ -155,8 +140,7 @@ define { float, i32 } @frexp_negzero() { ; CHECK-LABEL: define { float, i32 } @frexp_negzero() { -; CHECK-NEXT: [[RET:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float -0.000000e+00) -; CHECK-NEXT: ret { float, i32 } [[RET]] +; CHECK-NEXT: ret { float, i32 } { float -0.000000e+00, i32 0 } ; %ret = call { float, i32 } @llvm.frexp.f32.i32(float -0.0) ret { float, i32 } %ret @@ -164,8 +148,7 @@ define { float, i32 } @frexp_one() { ; CHECK-LABEL: define { float, i32 } @frexp_one() { -; CHECK-NEXT: [[RET:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float 1.000000e+00) -; CHECK-NEXT: ret { float, i32 } [[RET]] +; CHECK-NEXT: ret { float, i32 } { float 5.000000e-01, i32 1 } ; %ret = call { float, i32 } @llvm.frexp.f32.i32(float 1.0) ret { float, i32 } %ret @@ -173,8 +156,7 @@ define { float, i32 } @frexp_negone() { ; CHECK-LABEL: define { float, i32 } @frexp_negone() { -; CHECK-NEXT: [[RET:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float -1.000000e+00) -; CHECK-NEXT: ret { float, i32 } [[RET]] +; CHECK-NEXT: ret { float, i32 } { float -5.000000e-01, i32 1 } ; %ret = call { float, i32 } @llvm.frexp.f32.i32(float -1.0) ret { float, i32 } %ret @@ -182,8 +164,7 @@ define { float, i32 } @frexp_two() { ; CHECK-LABEL: define { float, i32 } @frexp_two() { -; CHECK-NEXT: [[RET:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float 2.000000e+00) -; CHECK-NEXT: ret { float, i32 } [[RET]] +; CHECK-NEXT: ret { float, i32 } { float 5.000000e-01, i32 2 } ; %ret = call { float, i32 } @llvm.frexp.f32.i32(float 2.0) ret { float, i32 } %ret @@ -191,8 +172,7 @@ define { float, i32 } @frexp_negtwo() { ; CHECK-LABEL: define { float, i32 } @frexp_negtwo() { -; CHECK-NEXT: [[RET:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float -2.000000e+00) -; CHECK-NEXT: ret { float, i32 } [[RET]] +; CHECK-NEXT: ret { float, i32 } { float -5.000000e-01, i32 2 } ; %ret = call { float, i32 } @llvm.frexp.f32.i32(float -2.0) ret { float, i32 } %ret @@ -200,8 +180,7 @@ define { float, i32 } @frexp_inf() { ; CHECK-LABEL: define { float, i32 } @frexp_inf() { -; CHECK-NEXT: [[RET:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float 0x7FF0000000000000) -; CHECK-NEXT: ret { float, i32 } [[RET]] +; CHECK-NEXT: ret { float, i32 } { float 0x7FF0000000000000, i32 0 } ; %ret = call { float, i32 } @llvm.frexp.f32.i32(float 0x7FF0000000000000) ret { float, i32 } %ret @@ -209,8 +188,7 @@ define { float, i32 } @frexp_neginf() { ; CHECK-LABEL: define { float, i32 } @frexp_neginf() { -; CHECK-NEXT: [[RET:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float 0xFFF0000000000000) -; CHECK-NEXT: ret { float, i32 } [[RET]] +; CHECK-NEXT: ret { float, i32 } { float 0xFFF0000000000000, i32 0 } ; %ret = call { float, i32 } @llvm.frexp.f32.i32(float 0xFFF0000000000000) ret { float, i32 } %ret @@ -218,8 +196,7 @@ define { float, i32 } @frexp_qnan() { ; CHECK-LABEL: define { float, i32 } @frexp_qnan() { -; CHECK-NEXT: [[RET:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float 0x7FF8000000000000) -; CHECK-NEXT: ret { float, i32 } [[RET]] +; CHECK-NEXT: ret { float, i32 } { float 0x7FF8000000000000, i32 0 } ; %ret = call { float, i32 } @llvm.frexp.f32.i32(float 0x7FF8000000000000) ret { float, i32 } %ret @@ -227,8 +204,7 @@ define { float, i32 } @frexp_snan() { ; CHECK-LABEL: define { float, i32 } @frexp_snan() { -; CHECK-NEXT: [[RET:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float 0x7FF0000020000000) -; CHECK-NEXT: ret { float, i32 } [[RET]] +; CHECK-NEXT: ret { float, i32 } { float 0x7FF8000020000000, i32 0 } ; %ret = call { float, i32 } @llvm.frexp.f32.i32(float bitcast (i32 2139095041 to float)) ret { float, i32 } %ret @@ -236,8 +212,7 @@ define { float, i32 } @frexp_pos_denorm() { ; CHECK-LABEL: define { float, i32 } @frexp_pos_denorm() { -; CHECK-NEXT: [[RET:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float 0x380FFFFFC0000000) -; CHECK-NEXT: ret { float, i32 } [[RET]] +; CHECK-NEXT: ret { float, i32 } { float 0x3FEFFFFFC0000000, i32 -126 } ; %ret = call { float, i32 } @llvm.frexp.f32.i32(float bitcast (i32 8388607 to float)) ret { float, i32 } %ret @@ -245,8 +220,7 @@ define { float, i32 } @frexp_neg_denorm() { ; CHECK-LABEL: define { float, i32 } @frexp_neg_denorm() { -; CHECK-NEXT: [[RET:%.*]] = call { float, i32 } @llvm.frexp.f32.i32(float 0xB80FFFFFC0000000) -; CHECK-NEXT: ret { float, i32 } [[RET]] +; CHECK-NEXT: ret { float, i32 } { float 0xBFEFFFFFC0000000, i32 -126 } ; %ret = call { float, i32 } @llvm.frexp.f32.i32(float bitcast (i32 -2139095041 to float)) ret { float, i32 } %ret @@ -254,8 +228,7 @@ define { ppc_fp128, i32 } @frexp_one_ppcf128() { ; CHECK-LABEL: define { ppc_fp128, i32 } @frexp_one_ppcf128() { -; CHECK-NEXT: [[RET:%.*]] = call { ppc_fp128, i32 } @llvm.frexp.ppcf128.i32(ppc_fp128 0xM3FF00000000000000000000000000000) -; CHECK-NEXT: ret { ppc_fp128, i32 } [[RET]] +; CHECK-NEXT: ret { ppc_fp128, i32 } { ppc_fp128 0xM3FE00000000000000000000000000000, i32 1 } ; %ret = call { ppc_fp128, i32 } @llvm.frexp.ppcf128.i32(ppc_fp128 0xM3FF00000000000000000000000000000) ret { ppc_fp128, i32 } %ret @@ -263,8 +236,7 @@ define { ppc_fp128, i32 } @frexp_negone_ppcf128() { ; CHECK-LABEL: define { ppc_fp128, i32 } @frexp_negone_ppcf128() { -; CHECK-NEXT: [[RET:%.*]] = call { ppc_fp128, i32 } @llvm.frexp.ppcf128.i32(ppc_fp128 0xMBFF00000000000000000000000000000) -; CHECK-NEXT: ret { ppc_fp128, i32 } [[RET]] +; CHECK-NEXT: ret { ppc_fp128, i32 } { ppc_fp128 0xMBFE00000000000000000000000000000, i32 1 } ; %ret = call { ppc_fp128, i32 } @llvm.frexp.ppcf128.i32(ppc_fp128 0xMBFF00000000000000000000000000000) ret { ppc_fp128, i32 } %ret @@ -272,8 +244,7 @@ define { ppc_fp128, i32} @canonicalize_noncanonical_zero_1_ppcf128() { ; CHECK-LABEL: define { ppc_fp128, i32 } @canonicalize_noncanonical_zero_1_ppcf128() { -; CHECK-NEXT: [[RET:%.*]] = call { ppc_fp128, i32 } @llvm.frexp.ppcf128.i32(ppc_fp128 0xM00000000000000000000000000000001) -; CHECK-NEXT: ret { ppc_fp128, i32 } [[RET]] +; CHECK-NEXT: ret { ppc_fp128, i32 } { ppc_fp128 0xM00000000000000000000000000000001, i32 0 } ; %ret = call { ppc_fp128, i32 } @llvm.frexp.ppcf128.i32(ppc_fp128 0xM00000000000000000000000000000001) ret { ppc_fp128, i32 } %ret @@ -281,8 +252,7 @@ define { <2 x float>, <2 x i32> } @frexp_splat_4() { ; CHECK-LABEL: define { <2 x float>, <2 x i32> } @frexp_splat_4() { -; CHECK-NEXT: [[RET:%.*]] = call { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> ) -; CHECK-NEXT: ret { <2 x float>, <2 x i32> } [[RET]] +; CHECK-NEXT: ret { <2 x float>, <2 x i32> } { <2 x float> , <2 x i32> } ; %ret = call { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> ) ret { <2 x float>, <2 x i32> } %ret @@ -290,8 +260,7 @@ define { <2 x float>, <2 x i32> } @frexp_splat_qnan() { ; CHECK-LABEL: define { <2 x float>, <2 x i32> } @frexp_splat_qnan() { -; CHECK-NEXT: [[RET:%.*]] = call { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> ) -; CHECK-NEXT: ret { <2 x float>, <2 x i32> } [[RET]] +; CHECK-NEXT: ret { <2 x float>, <2 x i32> } { <2 x float> , <2 x i32> zeroinitializer } ; %ret = call { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> ) ret { <2 x float>, <2 x i32> } %ret @@ -299,8 +268,7 @@ define { <2 x float>, <2 x i32> } @frexp_splat_inf() { ; CHECK-LABEL: define { <2 x float>, <2 x i32> } @frexp_splat_inf() { -; CHECK-NEXT: [[RET:%.*]] = call { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> ) -; CHECK-NEXT: ret { <2 x float>, <2 x i32> } [[RET]] +; CHECK-NEXT: ret { <2 x float>, <2 x i32> } { <2 x float> , <2 x i32> zeroinitializer } ; %ret = call { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> ) ret { <2 x float>, <2 x i32> } %ret @@ -308,8 +276,7 @@ define { <2 x float>, <2 x i32> } @frexp_splat_neginf() { ; CHECK-LABEL: define { <2 x float>, <2 x i32> } @frexp_splat_neginf() { -; CHECK-NEXT: [[RET:%.*]] = call { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> ) -; CHECK-NEXT: ret { <2 x float>, <2 x i32> } [[RET]] +; CHECK-NEXT: ret { <2 x float>, <2 x i32> } { <2 x float> , <2 x i32> zeroinitializer } ; %ret = call { <2 x float>, <2 x i32> } @llvm.frexp.v2f32.v2i32(<2 x float> ) ret { <2 x float>, <2 x i32> } %ret