Skip to content

Commit

Permalink
[InstCombine] Fix a cycle when folding fneg(select) with scalable vec…
Browse files Browse the repository at this point in the history
…tor types (#112465)

The two folding operations are causing a cycle for the following case
with
scalable vector types:

define <vscale x 2 x double> @test_fneg_select_abs(<vscale x 2 x i1>
%cond, <vscale x 2 x double> %b) {
%1 = select <vscale x 2 x i1> %cond, <vscale x 2 x double>
zeroinitializer, <vscale x 2 x double> %b
  %2 = fneg fast <vscale x 2 x double> %1
  ret <vscale x 2 x double> %2
}

1) fold fneg:  -(Cond ? C : Y) -> Cond ? -C : -Y

2) fold select: (Cond ? -X : -Y) -> -(Cond ? X : Y)

1) results in the following since '<vscale x 2 x double>
zeroinitializer' passes
the check for the immediate constant:

%.neg = fneg fast <vscale x 2 x double> zeroinitializer
%b.neg = fneg fast <vscale x 2 x double> %b
%1 = select fast <vscale x 2 x i1> %cond, <vscale x 2 x double> %.neg,
<vscale x 2 x double> %b.neg

and so we end up going back and forth between 1) and 2).

Attempt to fold scalable vector constants, so that we end up with a
splat instead:

define <vscale x 2 x double> @test_fneg_select_abs(<vscale x 2 x i1>
%cond, <vscale x 2 x double> %b) {
  %b.neg = fneg fast <vscale x 2 x double> %b
%1 = select fast <vscale x 2 x i1> %cond, <vscale x 2 x double>
shufflevector (<vscale x 2 x double> insertelement (<vscale x 2 x
double> poison, double -0.000000e+00, i64 0), <vscale x 2 x double>
poison, <vscale x 2 x i32> zeroinitializer), <vscale x 2 x double>
%b.neg
  ret <vscale x 2 x double> %1
}
  • Loading branch information
ssijaric-nv authored Oct 25, 2024
1 parent ac4bd74 commit 14db069
Show file tree
Hide file tree
Showing 3 changed files with 49 additions and 18 deletions.
29 changes: 15 additions & 14 deletions llvm/lib/IR/ConstantFold.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -581,26 +581,27 @@ Constant *llvm::ConstantFoldUnaryInstruction(unsigned Opcode, Constant *C) {
case Instruction::FNeg:
return ConstantFP::get(C->getContext(), neg(CV));
}
} else if (auto *VTy = dyn_cast<FixedVectorType>(C->getType())) {

Type *Ty = IntegerType::get(VTy->getContext(), 32);
} else if (auto *VTy = dyn_cast<VectorType>(C->getType())) {
// Fast path for splatted constants.
if (Constant *Splat = C->getSplatValue())
if (Constant *Elt = ConstantFoldUnaryInstruction(Opcode, Splat))
return ConstantVector::getSplat(VTy->getElementCount(), Elt);

// Fold each element and create a vector constant from those constants.
SmallVector<Constant *, 16> Result;
for (unsigned i = 0, e = VTy->getNumElements(); i != e; ++i) {
Constant *ExtractIdx = ConstantInt::get(Ty, i);
Constant *Elt = ConstantExpr::getExtractElement(C, ExtractIdx);
Constant *Res = ConstantFoldUnaryInstruction(Opcode, Elt);
if (!Res)
return nullptr;
Result.push_back(Res);
}
if (auto *FVTy = dyn_cast<FixedVectorType>(VTy)) {
// Fold each element and create a vector constant from those constants.
Type *Ty = IntegerType::get(FVTy->getContext(), 32);
SmallVector<Constant *, 16> Result;
for (unsigned i = 0, e = FVTy->getNumElements(); i != e; ++i) {
Constant *ExtractIdx = ConstantInt::get(Ty, i);
Constant *Elt = ConstantExpr::getExtractElement(C, ExtractIdx);
Constant *Res = ConstantFoldUnaryInstruction(Opcode, Elt);
if (!Res)
return nullptr;
Result.push_back(Res);
}

return ConstantVector::get(Result);
return ConstantVector::get(Result);
}
}

// We don't know how to fold this.
Expand Down
32 changes: 32 additions & 0 deletions llvm/test/Transforms/InstCombine/fneg.ll
Original file line number Diff line number Diff line change
Expand Up @@ -1109,4 +1109,36 @@ define float @test_fneg_select_maxnum(float %x) {
ret float %neg
}

; Check that there's no infinite loop.
define <vscale x 2 x double> @test_fneg_select_svec(<vscale x 2 x i1> %cond, <vscale x 2 x double> %b) {
; CHECK-LABEL: @test_fneg_select_svec(
; CHECK-NEXT: [[TMP2:%.*]] = fneg fast <vscale x 2 x double> [[TMP1:%.*]]
; CHECK-NEXT: [[TMP3:%.*]] = select fast <vscale x 2 x i1> [[COND:%.*]], <vscale x 2 x double> shufflevector (<vscale x 2 x double> insertelement (<vscale x 2 x double> poison, double -0.000000e+00, i64 0), <vscale x 2 x double> poison, <vscale x 2 x i32> zeroinitializer), <vscale x 2 x double> [[TMP2]]
; CHECK-NEXT: ret <vscale x 2 x double> [[TMP3]]
;
%1 = select <vscale x 2 x i1> %cond, <vscale x 2 x double> zeroinitializer, <vscale x 2 x double> %b
%2 = fneg fast <vscale x 2 x double> %1
ret <vscale x 2 x double> %2
}

define <vscale x 2 x double> @test_fneg_select_svec_2(<vscale x 2 x i1> %cond, <vscale x 2 x double> %a) {
; CHECK-LABEL: @test_fneg_select_svec_2(
; CHECK-NEXT: [[A_NEG:%.*]] = fneg fast <vscale x 2 x double> [[A:%.*]]
; CHECK-NEXT: [[TMP1:%.*]] = select fast <vscale x 2 x i1> [[COND:%.*]], <vscale x 2 x double> [[A_NEG]], <vscale x 2 x double> shufflevector (<vscale x 2 x double> insertelement (<vscale x 2 x double> poison, double -0.000000e+00, i64 0), <vscale x 2 x double> poison, <vscale x 2 x i32> zeroinitializer)
; CHECK-NEXT: ret <vscale x 2 x double> [[TMP1]]
;
%1 = select <vscale x 2 x i1> %cond, <vscale x 2 x double> %a, <vscale x 2 x double> zeroinitializer
%2 = fneg fast <vscale x 2 x double> %1
ret <vscale x 2 x double> %2
}

define <vscale x 2 x double> @test_fneg_select_svec_3(<vscale x 2 x i1> %cond, <vscale x 2 x double> %b) {
; CHECK-LABEL: @test_fneg_select_svec_3(
; CHECK-NEXT: ret <vscale x 2 x double> shufflevector (<vscale x 2 x double> insertelement (<vscale x 2 x double> poison, double -0.000000e+00, i64 0), <vscale x 2 x double> poison, <vscale x 2 x i32> zeroinitializer)
;
%1 = select <vscale x 2 x i1> %cond, <vscale x 2 x double> zeroinitializer, <vscale x 2 x double> zeroinitializer
%2 = fneg fast <vscale x 2 x double> %1
ret <vscale x 2 x double> %2
}

!0 = !{}
6 changes: 2 additions & 4 deletions llvm/test/Transforms/InstSimplify/fp-nan.ll
Original file line number Diff line number Diff line change
Expand Up @@ -237,8 +237,7 @@ define <2 x double> @unary_fneg_nan_2(<2 x double> %x) {
; FIXME: This doesn't behave the same way as the fixed-length vectors above
define <vscale x 1 x double> @unary_fneg_nan_2_scalable_vec_0() {
; CHECK-LABEL: @unary_fneg_nan_2_scalable_vec_0(
; CHECK-NEXT: [[R:%.*]] = fneg <vscale x 1 x double> shufflevector (<vscale x 1 x double> insertelement (<vscale x 1 x double> poison, double 0xFFF1234567890ABC, i64 0), <vscale x 1 x double> poison, <vscale x 1 x i32> zeroinitializer)
; CHECK-NEXT: ret <vscale x 1 x double> [[R]]
; CHECK-NEXT: ret <vscale x 1 x double> shufflevector (<vscale x 1 x double> insertelement (<vscale x 1 x double> poison, double 0x7FF1234567890ABC, i64 0), <vscale x 1 x double> poison, <vscale x 1 x i32> zeroinitializer)
;
%r = fneg <vscale x 1 x double> splat (double 0xFFF1234567890ABC)
ret <vscale x 1 x double> %r
Expand All @@ -247,8 +246,7 @@ define <vscale x 1 x double> @unary_fneg_nan_2_scalable_vec_0() {
; FIXME: This doesn't behave the same way as the fixed-length vectors above
define <vscale x 1 x double> @unary_fneg_nan_2_scalable_vec_1() {
; CHECK-LABEL: @unary_fneg_nan_2_scalable_vec_1(
; CHECK-NEXT: [[R:%.*]] = fneg <vscale x 1 x double> shufflevector (<vscale x 1 x double> insertelement (<vscale x 1 x double> poison, double 0x7FF0000000000001, i64 0), <vscale x 1 x double> poison, <vscale x 1 x i32> zeroinitializer)
; CHECK-NEXT: ret <vscale x 1 x double> [[R]]
; CHECK-NEXT: ret <vscale x 1 x double> shufflevector (<vscale x 1 x double> insertelement (<vscale x 1 x double> poison, double 0xFFF0000000000001, i64 0), <vscale x 1 x double> poison, <vscale x 1 x i32> zeroinitializer)
;
%r = fneg <vscale x 1 x double> splat (double 0x7FF0000000000001)
ret <vscale x 1 x double> %r
Expand Down

0 comments on commit 14db069

Please sign in to comment.