forked from OSchip/llvm-project
[InstCombine] form copysign from select of FP constants (PR44153)
This should be the last step needed to solve the problem in the description of PR44153: https://bugs.llvm.org/show_bug.cgi?id=44153 If we're casting an FP value to int, testing its signbit, and then choosing between a value and its negated value, that's a complicated way of saying "copysign": (bitcast X) < 0 ? -TC : TC --> copysign(TC, X) Differential Revision: https://reviews.llvm.org/D72643
This commit is contained in:
parent
9ecfaad757
commit
7bee94410c
|
@ -2317,6 +2317,48 @@ static Instruction *foldSelectRotate(SelectInst &Sel) {
|
|||
return IntrinsicInst::Create(F, { TVal, TVal, ShAmt });
|
||||
}
|
||||
|
||||
static Instruction *foldSelectToCopysign(SelectInst &Sel,
|
||||
InstCombiner::BuilderTy &Builder) {
|
||||
Value *Cond = Sel.getCondition();
|
||||
Value *TVal = Sel.getTrueValue();
|
||||
Value *FVal = Sel.getFalseValue();
|
||||
Type *SelType = Sel.getType();
|
||||
|
||||
// Match select ?, TC, FC where the constants are equal but negated.
|
||||
// TODO: Generalize to handle a negated variable operand?
|
||||
const APFloat *TC, *FC;
|
||||
if (!match(TVal, m_APFloat(TC)) || !match(FVal, m_APFloat(FC)) ||
|
||||
!abs(*TC).bitwiseIsEqual(abs(*FC)))
|
||||
return nullptr;
|
||||
|
||||
assert(TC != FC && "Expected equal select arms to simplify");
|
||||
|
||||
Value *X;
|
||||
const APInt *C;
|
||||
bool IsTrueIfSignSet;
|
||||
ICmpInst::Predicate Pred;
|
||||
if (!match(Cond, m_OneUse(m_ICmp(Pred, m_BitCast(m_Value(X)), m_APInt(C)))) ||
|
||||
!isSignBitCheck(Pred, *C, IsTrueIfSignSet) || X->getType() != SelType)
|
||||
return nullptr;
|
||||
|
||||
// If needed, negate the value that will be the sign argument of the copysign:
|
||||
// (bitcast X) < 0 ? -TC : TC --> copysign(TC, X)
|
||||
// (bitcast X) < 0 ? TC : -TC --> copysign(TC, -X)
|
||||
// (bitcast X) >= 0 ? -TC : TC --> copysign(TC, -X)
|
||||
// (bitcast X) >= 0 ? TC : -TC --> copysign(TC, X)
|
||||
if (IsTrueIfSignSet ^ TC->isNegative())
|
||||
X = Builder.CreateFNegFMF(X, &Sel);
|
||||
|
||||
// Canonicalize the magnitude argument as the positive constant since we do
|
||||
// not care about its sign.
|
||||
Value *MagArg = TC->isNegative() ? FVal : TVal;
|
||||
Function *F = Intrinsic::getDeclaration(Sel.getModule(), Intrinsic::copysign,
|
||||
Sel.getType());
|
||||
Instruction *CopySign = IntrinsicInst::Create(F, { MagArg, X });
|
||||
CopySign->setFastMathFlags(Sel.getFastMathFlags());
|
||||
return CopySign;
|
||||
}
|
||||
|
||||
Instruction *InstCombiner::visitSelectInst(SelectInst &SI) {
|
||||
Value *CondVal = SI.getCondition();
|
||||
Value *TrueVal = SI.getTrueValue();
|
||||
|
@ -2785,5 +2827,8 @@ Instruction *InstCombiner::visitSelectInst(SelectInst &SI) {
|
|||
if (Instruction *Rot = foldSelectRotate(SI))
|
||||
return Rot;
|
||||
|
||||
if (Instruction *Copysign = foldSelectToCopysign(SI, Builder))
|
||||
return Copysign;
|
||||
|
||||
return nullptr;
|
||||
}
|
||||
|
|
|
@ -1535,9 +1535,7 @@ define <2 x i32> @test_shl_zext_bool_vec(<2 x i1> %t) {
|
|||
|
||||
define float @copysign1(float %x) {
|
||||
; CHECK-LABEL: @copysign1(
|
||||
; CHECK-NEXT: [[I:%.*]] = bitcast float [[X:%.*]] to i32
|
||||
; CHECK-NEXT: [[ISPOS:%.*]] = icmp sgt i32 [[I]], -1
|
||||
; CHECK-NEXT: [[R:%.*]] = select i1 [[ISPOS]], float 1.000000e+00, float -1.000000e+00
|
||||
; CHECK-NEXT: [[R:%.*]] = call float @llvm.copysign.f32(float 1.000000e+00, float [[X:%.*]])
|
||||
; CHECK-NEXT: ret float [[R]]
|
||||
;
|
||||
%i = bitcast float %x to i32
|
||||
|
@ -1548,9 +1546,8 @@ define float @copysign1(float %x) {
|
|||
|
||||
define <2 x float> @copysign2(<2 x float> %x) {
|
||||
; CHECK-LABEL: @copysign2(
|
||||
; CHECK-NEXT: [[I:%.*]] = bitcast <2 x float> [[X:%.*]] to <2 x i32>
|
||||
; CHECK-NEXT: [[ISNEG:%.*]] = icmp slt <2 x i32> [[I]], zeroinitializer
|
||||
; CHECK-NEXT: [[R:%.*]] = select nsz <2 x i1> [[ISNEG]], <2 x float> <float 4.200000e+01, float 4.200000e+01>, <2 x float> <float -4.200000e+01, float -4.200000e+01>
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = fneg nsz <2 x float> [[X:%.*]]
|
||||
; CHECK-NEXT: [[R:%.*]] = call nsz <2 x float> @llvm.copysign.v2f32(<2 x float> <float 4.200000e+01, float 4.200000e+01>, <2 x float> [[TMP1]])
|
||||
; CHECK-NEXT: ret <2 x float> [[R]]
|
||||
;
|
||||
%i = bitcast <2 x float> %x to <2 x i32>
|
||||
|
@ -1561,9 +1558,8 @@ define <2 x float> @copysign2(<2 x float> %x) {
|
|||
|
||||
define float @copysign3(float %x) {
|
||||
; CHECK-LABEL: @copysign3(
|
||||
; CHECK-NEXT: [[I:%.*]] = bitcast float [[X:%.*]] to i32
|
||||
; CHECK-NEXT: [[ISPOS:%.*]] = icmp sgt i32 [[I]], -1
|
||||
; CHECK-NEXT: [[R:%.*]] = select fast i1 [[ISPOS]], float -4.300000e+01, float 4.300000e+01
|
||||
; CHECK-NEXT: [[TMP1:%.*]] = fneg fast float [[X:%.*]]
|
||||
; CHECK-NEXT: [[R:%.*]] = call fast float @llvm.copysign.f32(float 4.300000e+01, float [[TMP1]])
|
||||
; CHECK-NEXT: ret float [[R]]
|
||||
;
|
||||
%i = bitcast float %x to i32
|
||||
|
@ -1572,6 +1568,8 @@ define float @copysign3(float %x) {
|
|||
ret float %r
|
||||
}
|
||||
|
||||
; TODO: Allow undefs when matching vectors.
|
||||
|
||||
define <2 x float> @copysign4(<2 x float> %x) {
|
||||
; CHECK-LABEL: @copysign4(
|
||||
; CHECK-NEXT: [[I:%.*]] = bitcast <2 x float> [[X:%.*]] to <2 x i32>
|
||||
|
@ -1587,6 +1585,8 @@ define <2 x float> @copysign4(<2 x float> %x) {
|
|||
|
||||
declare void @use1(i1)
|
||||
|
||||
; Negative test
|
||||
|
||||
define float @copysign_extra_use(float %x) {
|
||||
; CHECK-LABEL: @copysign_extra_use(
|
||||
; CHECK-NEXT: [[I:%.*]] = bitcast float [[X:%.*]] to i32
|
||||
|
@ -1602,6 +1602,8 @@ define float @copysign_extra_use(float %x) {
|
|||
ret float %r
|
||||
}
|
||||
|
||||
; Negative test
|
||||
|
||||
define float @copysign_type_mismatch(double %x) {
|
||||
; CHECK-LABEL: @copysign_type_mismatch(
|
||||
; CHECK-NEXT: [[I:%.*]] = bitcast double [[X:%.*]] to i64
|
||||
|
@ -1615,6 +1617,8 @@ define float @copysign_type_mismatch(double %x) {
|
|||
ret float %r
|
||||
}
|
||||
|
||||
; Negative test
|
||||
|
||||
define float @copysign_wrong_cmp(float %x) {
|
||||
; CHECK-LABEL: @copysign_wrong_cmp(
|
||||
; CHECK-NEXT: [[I:%.*]] = bitcast float [[X:%.*]] to i32
|
||||
|
@ -1628,6 +1632,8 @@ define float @copysign_wrong_cmp(float %x) {
|
|||
ret float %r
|
||||
}
|
||||
|
||||
; Negative test
|
||||
|
||||
define float @copysign_wrong_const(float %x) {
|
||||
; CHECK-LABEL: @copysign_wrong_const(
|
||||
; CHECK-NEXT: [[I:%.*]] = bitcast float [[X:%.*]] to i32
|
||||
|
|
Loading…
Reference in New Issue