diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp index 922f3bbbd9904..eecec4764af0b 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp @@ -2455,6 +2455,25 @@ Instruction *InstCombinerImpl::visitAnd(BinaryOperator &I) { } } + // If we are clearing the sign bit of a floating-point value, convert this to + // fabs, then cast back to integer. + // + // Assumes any IEEE-represented type has the sign bit in the high bit. + // TODO: Unify with APInt matcher. This version allows undef unlike m_APInt + Value *CastOp; + if (match(Op0, m_BitCast(m_Value(CastOp))) && + match(Op1, m_MaxSignedValue()) && + !Builder.GetInsertBlock()->getParent()->hasFnAttribute( + Attribute::NoImplicitFloat)) { + Type *EltTy = CastOp->getType()->getScalarType(); + if (EltTy->isFloatingPointTy() && EltTy->isIEEE() && + EltTy->getPrimitiveSizeInBits() == + I.getType()->getScalarType()->getPrimitiveSizeInBits()) { + Value *FAbs = Builder.CreateUnaryIntrinsic(Intrinsic::fabs, CastOp); + return new BitCastInst(FAbs, I.getType()); + } + } + if (match(&I, m_And(m_OneUse(m_Shl(m_ZExt(m_Value(X)), m_Value(Y))), m_SignMask())) && match(Y, m_SpecificInt_ICMP( @@ -4470,6 +4489,9 @@ Instruction *InstCombinerImpl::visitXor(BinaryOperator &I) { // If we are XORing the sign bit of a floating-point value, convert // this to fneg, then cast back to integer. // + // This is generous interpretation of noimplicitfloat, this is not a true + // floating-point operation. + // // Assumes any IEEE-represented type has the sign bit in the high bit. // TODO: Unify with APInt matcher. This version allows undef unlike m_APInt Value *CastOp; diff --git a/llvm/test/Transforms/InstCombine/fabs-as-int.ll b/llvm/test/Transforms/InstCombine/fabs-as-int.ll index 1b0ce274a09a9..f32c00e453f22 100644 --- a/llvm/test/Transforms/InstCombine/fabs-as-int.ll +++ b/llvm/test/Transforms/InstCombine/fabs-as-int.ll @@ -30,10 +30,8 @@ define <2 x i32> @fabs_as_int_v2f32_noimplicitfloat(<2 x float> %x) noimplicitfl define float @fabs_as_int_f32_castback(float %val) { ; CHECK-LABEL: define float @fabs_as_int_f32_castback ; CHECK-SAME: (float [[VAL:%.*]]) { -; CHECK-NEXT: [[BITCAST:%.*]] = bitcast float [[VAL]] to i32 -; CHECK-NEXT: [[AND:%.*]] = and i32 [[BITCAST]], 2147483647 -; CHECK-NEXT: [[FABS:%.*]] = bitcast i32 [[AND]] to float -; CHECK-NEXT: ret float [[FABS]] +; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[VAL]]) +; CHECK-NEXT: ret float [[TMP1]] ; %bitcast = bitcast float %val to i32 %and = and i32 %bitcast, 2147483647 @@ -44,10 +42,8 @@ define float @fabs_as_int_f32_castback(float %val) { define float @not_fabs_as_int_f32_castback_wrongconst(float %val) { ; CHECK-LABEL: define float @not_fabs_as_int_f32_castback_wrongconst ; CHECK-SAME: (float [[VAL:%.*]]) { -; CHECK-NEXT: [[BITCAST:%.*]] = bitcast float [[VAL]] to i32 -; CHECK-NEXT: [[AND:%.*]] = and i32 [[BITCAST]], 2147483647 -; CHECK-NEXT: [[FABS:%.*]] = bitcast i32 [[AND]] to float -; CHECK-NEXT: ret float [[FABS]] +; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[VAL]]) +; CHECK-NEXT: ret float [[TMP1]] ; %bitcast = bitcast float %val to i32 %and = and i32 %bitcast, 2147483647 @@ -58,11 +54,9 @@ define float @not_fabs_as_int_f32_castback_wrongconst(float %val) { define float @fabs_as_int_f32_castback_multi_use(float %val, ptr %ptr) { ; CHECK-LABEL: define float @fabs_as_int_f32_castback_multi_use ; CHECK-SAME: (float [[VAL:%.*]], ptr [[PTR:%.*]]) { -; CHECK-NEXT: [[BITCAST:%.*]] = bitcast float [[VAL]] to i32 -; CHECK-NEXT: [[AND:%.*]] = and i32 [[BITCAST]], 2147483647 -; CHECK-NEXT: store i32 [[AND]], ptr [[PTR]], align 4 -; CHECK-NEXT: [[FABS:%.*]] = bitcast i32 [[AND]] to float -; CHECK-NEXT: ret float [[FABS]] +; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[VAL]]) +; CHECK-NEXT: store float [[TMP1]], ptr [[PTR]], align 4 +; CHECK-NEXT: ret float [[TMP1]] ; %bitcast = bitcast float %val to i32 %and = and i32 %bitcast, 2147483647 @@ -74,8 +68,8 @@ define float @fabs_as_int_f32_castback_multi_use(float %val, ptr %ptr) { define i64 @fabs_as_int_f64(double %x) { ; CHECK-LABEL: define i64 @fabs_as_int_f64 ; CHECK-SAME: (double [[X:%.*]]) { -; CHECK-NEXT: [[BC:%.*]] = bitcast double [[X]] to i64 -; CHECK-NEXT: [[AND:%.*]] = and i64 [[BC]], 9223372036854775807 +; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.fabs.f64(double [[X]]) +; CHECK-NEXT: [[AND:%.*]] = bitcast double [[TMP1]] to i64 ; CHECK-NEXT: ret i64 [[AND]] ; %bc = bitcast double %x to i64 @@ -86,8 +80,8 @@ define i64 @fabs_as_int_f64(double %x) { define <2 x i64> @fabs_as_int_v2f64(<2 x double> %x) { ; CHECK-LABEL: define <2 x i64> @fabs_as_int_v2f64 ; CHECK-SAME: (<2 x double> [[X:%.*]]) { -; CHECK-NEXT: [[BC:%.*]] = bitcast <2 x double> [[X]] to <2 x i64> -; CHECK-NEXT: [[AND:%.*]] = and <2 x i64> [[BC]], +; CHECK-NEXT: [[TMP1:%.*]] = call <2 x double> @llvm.fabs.v2f64(<2 x double> [[X]]) +; CHECK-NEXT: [[AND:%.*]] = bitcast <2 x double> [[TMP1]] to <2 x i64> ; CHECK-NEXT: ret <2 x i64> [[AND]] ; %bc = bitcast <2 x double> %x to <2 x i64> @@ -98,8 +92,8 @@ define <2 x i64> @fabs_as_int_v2f64(<2 x double> %x) { define i64 @fabs_as_int_f64_swap(double %x) { ; CHECK-LABEL: define i64 @fabs_as_int_f64_swap ; CHECK-SAME: (double [[X:%.*]]) { -; CHECK-NEXT: [[BC:%.*]] = bitcast double [[X]] to i64 -; CHECK-NEXT: [[AND:%.*]] = and i64 [[BC]], 9223372036854775807 +; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.fabs.f64(double [[X]]) +; CHECK-NEXT: [[AND:%.*]] = bitcast double [[TMP1]] to i64 ; CHECK-NEXT: ret i64 [[AND]] ; %bc = bitcast double %x to i64 @@ -110,8 +104,8 @@ define i64 @fabs_as_int_f64_swap(double %x) { define i32 @fabs_as_int_f32(float %x) { ; CHECK-LABEL: define i32 @fabs_as_int_f32 ; CHECK-SAME: (float [[X:%.*]]) { -; CHECK-NEXT: [[BC:%.*]] = bitcast float [[X]] to i32 -; CHECK-NEXT: [[AND:%.*]] = and i32 [[BC]], 2147483647 +; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]]) +; CHECK-NEXT: [[AND:%.*]] = bitcast float [[TMP1]] to i32 ; CHECK-NEXT: ret i32 [[AND]] ; %bc = bitcast float %x to i32 @@ -122,8 +116,8 @@ define i32 @fabs_as_int_f32(float %x) { define <2 x i32> @fabs_as_int_v2f32(<2 x float> %x) { ; CHECK-LABEL: define <2 x i32> @fabs_as_int_v2f32 ; CHECK-SAME: (<2 x float> [[X:%.*]]) { -; CHECK-NEXT: [[BC:%.*]] = bitcast <2 x float> [[X]] to <2 x i32> -; CHECK-NEXT: [[AND:%.*]] = and <2 x i32> [[BC]], +; CHECK-NEXT: [[TMP1:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> [[X]]) +; CHECK-NEXT: [[AND:%.*]] = bitcast <2 x float> [[TMP1]] to <2 x i32> ; CHECK-NEXT: ret <2 x i32> [[AND]] ; %bc = bitcast <2 x float> %x to <2 x i32> @@ -146,8 +140,8 @@ define <2 x i32> @not_fabs_as_int_v2f32_nonsplat(<2 x float> %x) { define <3 x i32> @fabs_as_int_v3f32_undef(<3 x float> %x) { ; CHECK-LABEL: define <3 x i32> @fabs_as_int_v3f32_undef ; CHECK-SAME: (<3 x float> [[X:%.*]]) { -; CHECK-NEXT: [[BC:%.*]] = bitcast <3 x float> [[X]] to <3 x i32> -; CHECK-NEXT: [[AND:%.*]] = and <3 x i32> [[BC]], +; CHECK-NEXT: [[TMP1:%.*]] = call <3 x float> @llvm.fabs.v3f32(<3 x float> [[X]]) +; CHECK-NEXT: [[AND:%.*]] = bitcast <3 x float> [[TMP1]] to <3 x i32> ; CHECK-NEXT: ret <3 x i32> [[AND]] ; %bc = bitcast <3 x float> %x to <3 x i32> @@ -199,8 +193,8 @@ define float @not_fabs_as_int_f32_bitcast_from_v2i16(<2 x i16> %val) { define i128 @fabs_as_int_fp128_f64_mask(fp128 %x) { ; CHECK-LABEL: define i128 @fabs_as_int_fp128_f64_mask ; CHECK-SAME: (fp128 [[X:%.*]]) { -; CHECK-NEXT: [[BC:%.*]] = bitcast fp128 [[X]] to i128 -; CHECK-NEXT: [[AND:%.*]] = and i128 [[BC]], 170141183460469231731687303715884105727 +; CHECK-NEXT: [[TMP1:%.*]] = call fp128 @llvm.fabs.f128(fp128 [[X]]) +; CHECK-NEXT: [[AND:%.*]] = bitcast fp128 [[TMP1]] to i128 ; CHECK-NEXT: ret i128 [[AND]] ; %bc = bitcast fp128 %x to i128 @@ -211,8 +205,8 @@ define i128 @fabs_as_int_fp128_f64_mask(fp128 %x) { define i128 @fabs_as_int_fp128_f128_mask(fp128 %x) { ; CHECK-LABEL: define i128 @fabs_as_int_fp128_f128_mask ; CHECK-SAME: (fp128 [[X:%.*]]) { -; CHECK-NEXT: [[BC:%.*]] = bitcast fp128 [[X]] to i128 -; CHECK-NEXT: [[AND:%.*]] = and i128 [[BC]], 170141183460469231731687303715884105727 +; CHECK-NEXT: [[TMP1:%.*]] = call fp128 @llvm.fabs.f128(fp128 [[X]]) +; CHECK-NEXT: [[AND:%.*]] = bitcast fp128 [[TMP1]] to i128 ; CHECK-NEXT: ret i128 [[AND]] ; %bc = bitcast fp128 %x to i128 @@ -223,8 +217,8 @@ define i128 @fabs_as_int_fp128_f128_mask(fp128 %x) { define i16 @fabs_as_int_f16(half %x) { ; CHECK-LABEL: define i16 @fabs_as_int_f16 ; CHECK-SAME: (half [[X:%.*]]) { -; CHECK-NEXT: [[BC:%.*]] = bitcast half [[X]] to i16 -; CHECK-NEXT: [[AND:%.*]] = and i16 [[BC]], 32767 +; CHECK-NEXT: [[TMP1:%.*]] = call half @llvm.fabs.f16(half [[X]]) +; CHECK-NEXT: [[AND:%.*]] = bitcast half [[TMP1]] to i16 ; CHECK-NEXT: ret i16 [[AND]] ; %bc = bitcast half %x to i16 @@ -235,8 +229,8 @@ define i16 @fabs_as_int_f16(half %x) { define <2 x i16> @fabs_as_int_v2f16(<2 x half> %x) { ; CHECK-LABEL: define <2 x i16> @fabs_as_int_v2f16 ; CHECK-SAME: (<2 x half> [[X:%.*]]) { -; CHECK-NEXT: [[BC:%.*]] = bitcast <2 x half> [[X]] to <2 x i16> -; CHECK-NEXT: [[AND:%.*]] = and <2 x i16> [[BC]], +; CHECK-NEXT: [[TMP1:%.*]] = call <2 x half> @llvm.fabs.v2f16(<2 x half> [[X]]) +; CHECK-NEXT: [[AND:%.*]] = bitcast <2 x half> [[TMP1]] to <2 x i16> ; CHECK-NEXT: ret <2 x i16> [[AND]] ; %bc = bitcast <2 x half> %x to <2 x i16> @@ -247,8 +241,8 @@ define <2 x i16> @fabs_as_int_v2f16(<2 x half> %x) { define i16 @fabs_as_int_bf16(bfloat %x) { ; CHECK-LABEL: define i16 @fabs_as_int_bf16 ; CHECK-SAME: (bfloat [[X:%.*]]) { -; CHECK-NEXT: [[BC:%.*]] = bitcast bfloat [[X]] to i16 -; CHECK-NEXT: [[AND:%.*]] = and i16 [[BC]], 32767 +; CHECK-NEXT: [[TMP1:%.*]] = call bfloat @llvm.fabs.bf16(bfloat [[X]]) +; CHECK-NEXT: [[AND:%.*]] = bitcast bfloat [[TMP1]] to i16 ; CHECK-NEXT: ret i16 [[AND]] ; %bc = bitcast bfloat %x to i16 @@ -259,8 +253,8 @@ define i16 @fabs_as_int_bf16(bfloat %x) { define <2 x i16> @fabs_as_int_v2bf16(<2 x bfloat> %x) { ; CHECK-LABEL: define <2 x i16> @fabs_as_int_v2bf16 ; CHECK-SAME: (<2 x bfloat> [[X:%.*]]) { -; CHECK-NEXT: [[BC:%.*]] = bitcast <2 x bfloat> [[X]] to <2 x i16> -; CHECK-NEXT: [[AND:%.*]] = and <2 x i16> [[BC]], +; CHECK-NEXT: [[TMP1:%.*]] = call <2 x bfloat> @llvm.fabs.v2bf16(<2 x bfloat> [[X]]) +; CHECK-NEXT: [[AND:%.*]] = bitcast <2 x bfloat> [[TMP1]] to <2 x i16> ; CHECK-NEXT: ret <2 x i16> [[AND]] ; %bc = bitcast <2 x bfloat> %x to <2 x i16> diff --git a/llvm/test/Transforms/InstCombine/fneg-fabs-as-int.ll b/llvm/test/Transforms/InstCombine/fneg-fabs-as-int.ll index eae8ed2670660..908cb4dec9a4d 100644 --- a/llvm/test/Transforms/InstCombine/fneg-fabs-as-int.ll +++ b/llvm/test/Transforms/InstCombine/fneg-fabs-as-int.ll @@ -28,8 +28,9 @@ define <2 x i32> @fneg_fabs_as_int_v2f32_noimplicitfloat(<2 x float> %x) noimpli define float @fneg_fabs_fabs_as_int_f32_and_or(float %val) { ; CHECK-LABEL: define float @fneg_fabs_fabs_as_int_f32_and_or ; CHECK-SAME: (float [[VAL:%.*]]) { -; CHECK-NEXT: [[BITCAST:%.*]] = bitcast float [[VAL]] to i32 -; CHECK-NEXT: [[OR:%.*]] = or i32 [[BITCAST]], -2147483648 +; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[VAL]]) +; CHECK-NEXT: [[AND:%.*]] = bitcast float [[TMP1]] to i32 +; CHECK-NEXT: [[OR:%.*]] = or i32 [[AND]], -2147483648 ; CHECK-NEXT: [[FNEG_FABS:%.*]] = bitcast i32 [[OR]] to float ; CHECK-NEXT: ret float [[FNEG_FABS]] ; diff --git a/llvm/test/Transforms/SLPVectorizer/X86/alternate-cast-inseltpoison.ll b/llvm/test/Transforms/SLPVectorizer/X86/alternate-cast-inseltpoison.ll index d818f0f111670..e24c52ba81ddf 100644 --- a/llvm/test/Transforms/SLPVectorizer/X86/alternate-cast-inseltpoison.ll +++ b/llvm/test/Transforms/SLPVectorizer/X86/alternate-cast-inseltpoison.ll @@ -76,12 +76,10 @@ define <8 x i32> @fptosi_fptoui(<8 x float> %a) { define <8 x float> @fneg_fabs(<8 x float> %a) { ; CHECK-LABEL: @fneg_fabs( -; CHECK-NEXT: [[TMP1:%.*]] = bitcast <8 x float> [[A:%.*]] to <8 x i32> -; CHECK-NEXT: [[TMP2:%.*]] = fneg <8 x float> [[A]] -; CHECK-NEXT: [[TMP3:%.*]] = and <8 x i32> [[TMP1]], -; CHECK-NEXT: [[TMP4:%.*]] = bitcast <8 x i32> [[TMP3]] to <8 x float> -; CHECK-NEXT: [[TMP5:%.*]] = shufflevector <8 x float> [[TMP2]], <8 x float> [[TMP4]], <8 x i32> -; CHECK-NEXT: ret <8 x float> [[TMP5]] +; CHECK-NEXT: [[TMP1:%.*]] = fneg <8 x float> [[A:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = call <8 x float> @llvm.fabs.v8f32(<8 x float> [[A]]) +; CHECK-NEXT: [[DOTUNCASTED:%.*]] = shufflevector <8 x float> [[TMP1]], <8 x float> [[TMP2]], <8 x i32> +; CHECK-NEXT: ret <8 x float> [[DOTUNCASTED]] ; %a0 = extractelement <8 x float> %a, i32 0 %a1 = extractelement <8 x float> %a, i32 1 diff --git a/llvm/test/Transforms/SLPVectorizer/X86/alternate-cast.ll b/llvm/test/Transforms/SLPVectorizer/X86/alternate-cast.ll index 7ab02f55fc927..0f8751a6da7f5 100644 --- a/llvm/test/Transforms/SLPVectorizer/X86/alternate-cast.ll +++ b/llvm/test/Transforms/SLPVectorizer/X86/alternate-cast.ll @@ -76,12 +76,10 @@ define <8 x i32> @fptosi_fptoui(<8 x float> %a) { define <8 x float> @fneg_fabs(<8 x float> %a) { ; CHECK-LABEL: @fneg_fabs( -; CHECK-NEXT: [[TMP1:%.*]] = bitcast <8 x float> [[A:%.*]] to <8 x i32> -; CHECK-NEXT: [[TMP2:%.*]] = fneg <8 x float> [[A]] -; CHECK-NEXT: [[TMP3:%.*]] = and <8 x i32> [[TMP1]], -; CHECK-NEXT: [[TMP4:%.*]] = bitcast <8 x i32> [[TMP3]] to <8 x float> -; CHECK-NEXT: [[TMP5:%.*]] = shufflevector <8 x float> [[TMP2]], <8 x float> [[TMP4]], <8 x i32> -; CHECK-NEXT: ret <8 x float> [[TMP5]] +; CHECK-NEXT: [[TMP1:%.*]] = fneg <8 x float> [[A:%.*]] +; CHECK-NEXT: [[TMP2:%.*]] = call <8 x float> @llvm.fabs.v8f32(<8 x float> [[A]]) +; CHECK-NEXT: [[DOTUNCASTED:%.*]] = shufflevector <8 x float> [[TMP1]], <8 x float> [[TMP2]], <8 x i32> +; CHECK-NEXT: ret <8 x float> [[DOTUNCASTED]] ; %a0 = extractelement <8 x float> %a, i32 0 %a1 = extractelement <8 x float> %a, i32 1