Index: include/llvm/IR/Constants.h =================================================================== --- include/llvm/IR/Constants.h +++ include/llvm/IR/Constants.h @@ -285,6 +285,7 @@ static Constant *get(Type* Ty, double V); static Constant *get(Type* Ty, StringRef Str); static ConstantFP *get(LLVMContext &Context, const APFloat &V); + static Constant *get(Type *Ty, const APFloat &V); static Constant *getNaN(Type *Ty, bool Negative = false, unsigned type = 0); static Constant *getNegativeZero(Type *Ty); static Constant *getInfinity(Type *Ty, bool Negative = false); Index: lib/Analysis/InstructionSimplify.cpp =================================================================== --- lib/Analysis/InstructionSimplify.cpp +++ lib/Analysis/InstructionSimplify.cpp @@ -4385,6 +4385,29 @@ return true; } +static Value *simplifyCanonicalize(Value *Src) { + // Any bit value is necessarily a valid canonical value, but 0 is always + // canonical. + if (isa(Src)) + return ConstantFP::get(Src->getType(), 0.0); + + const APFloat *C; + + if (!match(Src, m_APFloat(C))) + return nullptr; + + // Zero is always canonical and the sign must be preserved. + if (C->isZero()) + return ConstantFP::get(Src->getType(), *C); + + // Denorms and special values may have special rules, but it should be OK to + // fold a totally average number. + if (C->isNormal()) + return ConstantFP::get(Src->getType(), *C); + + return nullptr; +} + template static Value *SimplifyIntrinsic(Function *F, IterTy ArgBegin, IterTy ArgEnd, const SimplifyQuery &Q, unsigned MaxRecurse) { @@ -4407,6 +4430,8 @@ return *ArgBegin; return nullptr; } + case Intrinsic::canonicalize: + return simplifyCanonicalize(*ArgBegin); default: return nullptr; } Index: lib/IR/Constants.cpp =================================================================== --- lib/IR/Constants.cpp +++ lib/IR/Constants.cpp @@ -710,6 +710,15 @@ return Slot.get(); } +Constant* ConstantFP::get(Type *Ty, const APFloat& V) { + ConstantFP *C = get(Ty->getContext(), V); + + if (VectorType *VTy = dyn_cast(Ty)) + return ConstantVector::getSplat(VTy->getNumElements(), C); + + return C; +} + Constant *ConstantFP::getInfinity(Type *Ty, bool Negative) { const fltSemantics &Semantics = *TypeToFloatSemantics(Ty->getScalarType()); Constant *C = get(Ty->getContext(), APFloat::getInf(Semantics, Negative)); Index: test/Transforms/InstCombine/maxnum.ll =================================================================== --- test/Transforms/InstCombine/maxnum.ll +++ test/Transforms/InstCombine/maxnum.ll @@ -137,8 +137,7 @@ } ; CHECK-LABEL: @fold_maxnum_f32_undef_undef -; CHECK-NEXT: %1 = call float @llvm.canonicalize.f32(float undef) -; CHECK-NEXT: ret float %1 +; CHECK-NEXT: ret float 0.000000e+00 define float @fold_maxnum_f32_undef_undef() nounwind { %val = call float @llvm.maxnum.f32(float undef, float undef) #0 ret float %val Index: test/Transforms/InstCombine/minnum.ll =================================================================== --- test/Transforms/InstCombine/minnum.ll +++ test/Transforms/InstCombine/minnum.ll @@ -139,8 +139,7 @@ } ; CHECK-LABEL: @fold_minnum_f32_undef_undef -; CHECK-NEXT: %1 = call float @llvm.canonicalize.f32(float undef) -; CHECK-NEXT: ret float %1 +; CHECK-NEXT: ret float 0.000000e+00 define float @fold_minnum_f32_undef_undef() nounwind { %val = call float @llvm.minnum.f32(float undef, float undef) #0 ret float %val Index: test/Transforms/InstSimplify/canonicalize.ll =================================================================== --- /dev/null +++ test/Transforms/InstSimplify/canonicalize.ll @@ -0,0 +1,94 @@ +; RUN: opt -instsimplify -S < %s | FileCheck %s + +declare float @llvm.canonicalize.f32(float) +declare <2 x float> @llvm.canonicalize.v2f32(<2 x float>) + +; CHECK-LABEL: @fold_zero( +; CHECK-NEXT: ret float 0.000000e+00 +define float @fold_zero() { + %ret = call float @llvm.canonicalize.f32(float 0.0) + ret float %ret +} + +; CHECK-LABEL: @fold_negzero( +; CHECK-NEXT: ret float -0.000000e+00 +define float @fold_negzero() { + %ret = call float @llvm.canonicalize.f32(float -0.0) + ret float %ret +} + +; CHECK-LABEL: @fold_zero_vector( +; CHECK-NEXT: ret <2 x float> zeroinitializer +define <2 x float> @fold_zero_vector() { + %ret = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> zeroinitializer) + ret <2 x float> %ret +} + +; CHECK-LABEL: @fold_negzero_vector( +; CHECK-NEXT: ret <2 x float> +define <2 x float> @fold_negzero_vector() { + %ret = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> ) + ret <2 x float> %ret +} + +; FIXME: Fold to -0.0 splat +; CHECK-LABEL: @fold_negzero_vector_partialundef( +; CHECK-NEXT: %ret = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> ) +; CHECK-NEXT: ret <2 x float> %ret +define <2 x float> @fold_negzero_vector_partialundef() { + %ret = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> ) + ret <2 x float> %ret +} + +; CHECK-LABEL: @fold_undef( +; CHECK-NEXT: ret float 0.000000e+00 +define float @fold_undef() { + %ret = call float @llvm.canonicalize.f32(float undef) + ret float %ret +} + +; CHECK-LABEL: @fold_undef_vector( +; CHECK-NEXT: ret <2 x float> zeroinitializer +define <2 x float> @fold_undef_vector() { + %ret = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> undef) + ret <2 x float> %ret +} + +; CHECK-LABEL: @no_fold_denorm( +; CHECK-NEXT: %ret = call float @llvm.canonicalize.f32(float 0x380FFFFFC0000000) +; CHECK-NEXT: ret float %ret +define float @no_fold_denorm() { + %ret = call float @llvm.canonicalize.f32(float bitcast (i32 8388607 to float)) + ret float %ret +} + +; CHECK-LABEL: @no_fold_inf( +; CHECK-NEXT: %ret = call float @llvm.canonicalize.f32(float 0x7FF0000000000000) +; CHECK-NEXT: ret float %ret +define float @no_fold_inf() { + %ret = call float @llvm.canonicalize.f32(float 0x7FF0000000000000) + ret float %ret +} + +; CHECK-LABEL: @no_fold_qnan( +; CHECK-NEXT: %ret = call float @llvm.canonicalize.f32(float 0x7FF8000000000000) +; CHECK-NEXT: ret float %ret +define float @no_fold_qnan() { + %ret = call float @llvm.canonicalize.f32(float 0x7FF8000000000000) + ret float %ret +} + +; CHECK-LABEL: @no_fold_snan( +; CHECK-NEXT: %ret = call float @llvm.canonicalize.f32(float 0x7FF0000020000000) +; CHECK-NEXT: ret float %ret +define float @no_fold_snan() { + %ret = call float @llvm.canonicalize.f32(float bitcast (i32 2139095041 to float)) + ret float %ret +} + +; CHECK-LABEL: @fold_normal( +; CHECK-NEXT: ret float 4.000000e+00 +define float @fold_normal() { + %ret = call float @llvm.canonicalize.f32(float 4.0) + ret float %ret +}