Index: llvm/lib/Analysis/ConstantFolding.cpp =================================================================== --- llvm/lib/Analysis/ConstantFolding.cpp +++ llvm/lib/Analysis/ConstantFolding.cpp @@ -1626,6 +1626,7 @@ case Intrinsic::trunc: case Intrinsic::nearbyint: case Intrinsic::rint: + case Intrinsic::canonicalize: // Constrained intrinsics can be folded if FP environment is known // to compiler. case Intrinsic::experimental_constrained_fma: @@ -1941,6 +1942,33 @@ return *ORM; } +/// Try to constant fold llvm.canonicalize for the given caller and value. +static Constant *constantFoldCanonicalize(const CallBase *CI, + const APFloat &Src) { + // Zero is always canonical and the sign must be preserved. + // + // Denorms and special values may have special rules, but it should be OK to + // fold a totally average number. + if (Src.isZero() || Src.isNormal()) + return ConstantFP::get(CI->getContext(), Src); + + if (Src.isDenormal()) { + DenormalMode DenormMode = + CI->getFunction()->getDenormalMode(Src.getSemantics()); + if (DenormMode == DenormalMode::getIEEE()) + return nullptr; + + bool IsPositive = !Src.isNegative() || + DenormMode.Input == DenormalMode::PositiveZero || + DenormMode.Output == DenormalMode::PositiveZero; + return ConstantFP::get(CI->getContext(), + APFloat::getZero(Src.getSemantics(), !IsPositive)); + } + + // TODO: Handle special values? + return nullptr; +} + static Constant *ConstantFoldScalarCall1(StringRef Name, Intrinsic::ID IntrinsicID, Type *Ty, @@ -1964,7 +1992,8 @@ if (IntrinsicID == Intrinsic::cos || IntrinsicID == Intrinsic::ctpop || IntrinsicID == Intrinsic::fptoui_sat || - IntrinsicID == Intrinsic::fptosi_sat) + IntrinsicID == Intrinsic::fptosi_sat || + IntrinsicID == Intrinsic::canonicalize) return Constant::getNullValue(Ty); if (IntrinsicID == Intrinsic::bswap || IntrinsicID == Intrinsic::bitreverse || @@ -2072,6 +2101,9 @@ return ConstantFP::get(Ty->getContext(), U); } + if (IntrinsicID == Intrinsic::canonicalize) + return constantFoldCanonicalize(Call, U); + if (IntrinsicID == Intrinsic::amdgcn_fract) { // The v_fract instruction behaves like the OpenCL spec, which defines // fract(x) as fmin(x - floor(x), 0x1.fffffep-1f): "The min() operator is Index: llvm/test/Transforms/InstSimplify/canonicalize.ll =================================================================== --- llvm/test/Transforms/InstSimplify/canonicalize.ll +++ llvm/test/Transforms/InstSimplify/canonicalize.ll @@ -3,8 +3,7 @@ define float @canonicalize_zero() { ; CHECK-LABEL: @canonicalize_zero( -; CHECK-NEXT: [[RET:%.*]] = call float @llvm.canonicalize.f32(float 0.000000e+00) -; CHECK-NEXT: ret float [[RET]] +; CHECK-NEXT: ret float 0.000000e+00 ; %ret = call float @llvm.canonicalize.f32(float 0.0) ret float %ret @@ -12,8 +11,7 @@ define float @canonicalize_negzero() { ; CHECK-LABEL: @canonicalize_negzero( -; CHECK-NEXT: [[RET:%.*]] = call float @llvm.canonicalize.f32(float -0.000000e+00) -; CHECK-NEXT: ret float [[RET]] +; CHECK-NEXT: ret float -0.000000e+00 ; %ret = call float @llvm.canonicalize.f32(float -0.0) ret float %ret @@ -21,8 +19,7 @@ define <2 x float> @canonicalize_zero_vector() { ; CHECK-LABEL: @canonicalize_zero_vector( -; CHECK-NEXT: [[RET:%.*]] = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> zeroinitializer) -; CHECK-NEXT: ret <2 x float> [[RET]] +; CHECK-NEXT: ret <2 x float> zeroinitializer ; %ret = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> zeroinitializer) ret <2 x float> %ret @@ -30,8 +27,7 @@ define <2 x float> @canonicalize_negzero_vector() { ; CHECK-LABEL: @canonicalize_negzero_vector( -; CHECK-NEXT: [[RET:%.*]] = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> ) -; CHECK-NEXT: ret <2 x float> [[RET]] +; CHECK-NEXT: ret <2 x float> ; %ret = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> ) ret <2 x float> %ret @@ -39,8 +35,7 @@ define <2 x float> @canonicalize_negzero_vector_partialundef() { ; CHECK-LABEL: @canonicalize_negzero_vector_partialundef( -; CHECK-NEXT: [[RET:%.*]] = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> ) -; CHECK-NEXT: ret <2 x float> [[RET]] +; CHECK-NEXT: ret <2 x float> ; %ret = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> ) ret <2 x float> %ret @@ -48,8 +43,7 @@ define float @canonicalize_undef() { ; CHECK-LABEL: @canonicalize_undef( -; CHECK-NEXT: [[RET:%.*]] = call float @llvm.canonicalize.f32(float undef) -; CHECK-NEXT: ret float [[RET]] +; CHECK-NEXT: ret float 0.000000e+00 ; %ret = call float @llvm.canonicalize.f32(float undef) ret float %ret @@ -57,8 +51,7 @@ define <2 x float> @canonicalize_undef_vector() { ; CHECK-LABEL: @canonicalize_undef_vector( -; CHECK-NEXT: [[RET:%.*]] = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> undef) -; CHECK-NEXT: ret <2 x float> [[RET]] +; CHECK-NEXT: ret <2 x float> zeroinitializer ; %ret = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> undef) ret <2 x float> %ret @@ -75,8 +68,7 @@ define float @canonicalize_pos_denorm_preserve_sign_output() "denormal-fp-math"="preserve-sign,ieee" { ; CHECK-LABEL: @canonicalize_pos_denorm_preserve_sign_output( -; CHECK-NEXT: [[RET:%.*]] = call float @llvm.canonicalize.f32(float 0x380FFFFFC0000000) -; CHECK-NEXT: ret float [[RET]] +; CHECK-NEXT: ret float 0.000000e+00 ; %ret = call float @llvm.canonicalize.f32(float bitcast (i32 8388607 to float)) ret float %ret @@ -84,8 +76,7 @@ define float @canonicalize_pos_denorm_preserve_sign_input() "denormal-fp-math"="ieee,preserve-sign" { ; CHECK-LABEL: @canonicalize_pos_denorm_preserve_sign_input( -; CHECK-NEXT: [[RET:%.*]] = call float @llvm.canonicalize.f32(float 0x380FFFFFC0000000) -; CHECK-NEXT: ret float [[RET]] +; CHECK-NEXT: ret float 0.000000e+00 ; %ret = call float @llvm.canonicalize.f32(float bitcast (i32 8388607 to float)) ret float %ret @@ -93,8 +84,7 @@ define float @canonicalize_neg_denorm_preserve_sign_output() "denormal-fp-math"="preserve-sign,ieee" { ; CHECK-LABEL: @canonicalize_neg_denorm_preserve_sign_output( -; CHECK-NEXT: [[RET:%.*]] = call float @llvm.canonicalize.f32(float 0xB80FFFFFC0000000) -; CHECK-NEXT: ret float [[RET]] +; CHECK-NEXT: ret float -0.000000e+00 ; %ret = call float @llvm.canonicalize.f32(float bitcast (i32 -2139095041 to float)) ret float %ret @@ -102,8 +92,7 @@ define float @canonicalize_neg_denorm_preserve_sign_input() "denormal-fp-math"="ieee,preserve-sign" { ; CHECK-LABEL: @canonicalize_neg_denorm_preserve_sign_input( -; CHECK-NEXT: [[RET:%.*]] = call float @llvm.canonicalize.f32(float 0xB80FFFFFC0000000) -; CHECK-NEXT: ret float [[RET]] +; CHECK-NEXT: ret float -0.000000e+00 ; %ret = call float @llvm.canonicalize.f32(float bitcast (i32 -2139095041 to float)) ret float %ret @@ -111,8 +100,7 @@ define float @canonicalize_pos_denorm_positive_zero_output() "denormal-fp-math"="positive-zero,ieee" { ; CHECK-LABEL: @canonicalize_pos_denorm_positive_zero_output( -; CHECK-NEXT: [[RET:%.*]] = call float @llvm.canonicalize.f32(float 0x380FFFFFC0000000) -; CHECK-NEXT: ret float [[RET]] +; CHECK-NEXT: ret float 0.000000e+00 ; %ret = call float @llvm.canonicalize.f32(float bitcast (i32 8388607 to float)) ret float %ret @@ -120,8 +108,7 @@ define float @canonicalize_pos_denorm_positive_zero_input() "denormal-fp-math"="ieee,positive-zero" { ; CHECK-LABEL: @canonicalize_pos_denorm_positive_zero_input( -; CHECK-NEXT: [[RET:%.*]] = call float @llvm.canonicalize.f32(float 0x380FFFFFC0000000) -; CHECK-NEXT: ret float [[RET]] +; CHECK-NEXT: ret float 0.000000e+00 ; %ret = call float @llvm.canonicalize.f32(float bitcast (i32 8388607 to float)) ret float %ret @@ -129,8 +116,7 @@ define float @canonicalize_neg_denorm_positive_zero_output() "denormal-fp-math"="positive-zero,ieee" { ; CHECK-LABEL: @canonicalize_neg_denorm_positive_zero_output( -; CHECK-NEXT: [[RET:%.*]] = call float @llvm.canonicalize.f32(float 0xB80FFFFFC0000000) -; CHECK-NEXT: ret float [[RET]] +; CHECK-NEXT: ret float 0.000000e+00 ; %ret = call float @llvm.canonicalize.f32(float bitcast (i32 -2139095041 to float)) ret float %ret @@ -138,8 +124,7 @@ define float @canonicalize_neg_denorm_positive_zero_input() "denormal-fp-math"="ieee,positive-zero" { ; CHECK-LABEL: @canonicalize_neg_denorm_positive_zero_input( -; CHECK-NEXT: [[RET:%.*]] = call float @llvm.canonicalize.f32(float 0xB80FFFFFC0000000) -; CHECK-NEXT: ret float [[RET]] +; CHECK-NEXT: ret float 0.000000e+00 ; %ret = call float @llvm.canonicalize.f32(float bitcast (i32 -2139095041 to float)) ret float %ret @@ -174,8 +159,7 @@ define float @canonicalize_pos_normal() { ; CHECK-LABEL: @canonicalize_pos_normal( -; CHECK-NEXT: [[RET:%.*]] = call float @llvm.canonicalize.f32(float 4.000000e+00) -; CHECK-NEXT: ret float [[RET]] +; CHECK-NEXT: ret float 4.000000e+00 ; %ret = call float @llvm.canonicalize.f32(float 4.0) ret float %ret @@ -183,8 +167,7 @@ define float @canonicalize_neg_normal() { ; CHECK-LABEL: @canonicalize_neg_normal( -; CHECK-NEXT: [[RET:%.*]] = call float @llvm.canonicalize.f32(float -4.000000e+00) -; CHECK-NEXT: ret float [[RET]] +; CHECK-NEXT: ret float -4.000000e+00 ; %ret = call float @llvm.canonicalize.f32(float -4.0) ret float %ret @@ -192,8 +175,7 @@ define <2 x float> @canonicalize_pos_denorm_preserve_sign_output_mixed_vector() "denormal-fp-math"="preserve-sign,ieee" { ; CHECK-LABEL: @canonicalize_pos_denorm_preserve_sign_output_mixed_vector( -; CHECK-NEXT: [[RET:%.*]] = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> ) -; CHECK-NEXT: ret <2 x float> [[RET]] +; CHECK-NEXT: ret <2 x float> ; %ret = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> ) ret <2 x float> %ret @@ -201,8 +183,7 @@ define <2 x float> @canonicalize_pos_denorm_preserve_sign_input_mixed_vector() "denormal-fp-math"="ieee,preserve-sign" { ; CHECK-LABEL: @canonicalize_pos_denorm_preserve_sign_input_mixed_vector( -; CHECK-NEXT: [[RET:%.*]] = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> ) -; CHECK-NEXT: ret <2 x float> [[RET]] +; CHECK-NEXT: ret <2 x float> ; %ret = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> ) ret <2 x float> %ret @@ -210,8 +191,7 @@ define <2 x float> @canonicalize_pos_denorm_positive_zero_output_mixed_vector() "denormal-fp-math"="positive-zero,ieee" { ; CHECK-LABEL: @canonicalize_pos_denorm_positive_zero_output_mixed_vector( -; CHECK-NEXT: [[RET:%.*]] = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> ) -; CHECK-NEXT: ret <2 x float> [[RET]] +; CHECK-NEXT: ret <2 x float> zeroinitializer ; %ret = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> ) ret <2 x float> %ret @@ -219,8 +199,7 @@ define <2 x float> @canonicalize_pos_denorm_positive_zero_input_mixed_vector() "denormal-fp-math"="ieee,positive-zero" { ; CHECK-LABEL: @canonicalize_pos_denorm_positive_zero_input_mixed_vector( -; CHECK-NEXT: [[RET:%.*]] = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> ) -; CHECK-NEXT: ret <2 x float> [[RET]] +; CHECK-NEXT: ret <2 x float> zeroinitializer ; %ret = call <2 x float> @llvm.canonicalize.v2f32(<2 x float> ) ret <2 x float> %ret @@ -228,8 +207,7 @@ define float @canonicalize_neg_denorm_preserve_sign_output_positive_zero_input() "denormal-fp-math"="preserve-sign,positive-zero" { ; CHECK-LABEL: @canonicalize_neg_denorm_preserve_sign_output_positive_zero_input( -; CHECK-NEXT: [[RET:%.*]] = call float @llvm.canonicalize.f32(float 0xB80FFFFFC0000000) -; CHECK-NEXT: ret float [[RET]] +; CHECK-NEXT: ret float 0.000000e+00 ; %ret = call float @llvm.canonicalize.f32(float bitcast (i32 -2139095041 to float)) ret float %ret @@ -237,8 +215,7 @@ define float @canonicalize_neg_denorm_positive_zero_output_preserve_sign_input() "denormal-fp-math"="positive-zero,preserve-sign" { ; CHECK-LABEL: @canonicalize_neg_denorm_positive_zero_output_preserve_sign_input( -; CHECK-NEXT: [[RET:%.*]] = call float @llvm.canonicalize.f32(float 0xB80FFFFFC0000000) -; CHECK-NEXT: ret float [[RET]] +; CHECK-NEXT: ret float 0.000000e+00 ; %ret = call float @llvm.canonicalize.f32(float bitcast (i32 -2139095041 to float)) ret float %ret