From 03413139be5f006859c933203922c7f63bfd2a60 Mon Sep 17 00:00:00 2001 From: Kerry McLaughlin Date: Thu, 17 Jul 2025 08:49:24 +0000 Subject: [PATCH 1/4] - Add a test for extractelement from scalable vector_extract at index 0 --- .../InstCombine/scalable-extract-subvec-elt.ll | 14 ++++++++++++++ 1 file changed, 14 insertions(+) create mode 100644 llvm/test/Transforms/InstCombine/scalable-extract-subvec-elt.ll diff --git a/llvm/test/Transforms/InstCombine/scalable-extract-subvec-elt.ll b/llvm/test/Transforms/InstCombine/scalable-extract-subvec-elt.ll new file mode 100644 index 0000000000000..d0cfc48420b43 --- /dev/null +++ b/llvm/test/Transforms/InstCombine/scalable-extract-subvec-elt.ll @@ -0,0 +1,14 @@ +; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 +; RUN: opt -S -passes=instcombine < %s | FileCheck %s + +define i1 @scalable_test( %a) { +; CHECK-LABEL: define i1 @scalable_test( +; CHECK-SAME: [[A:%.*]]) { +; CHECK-NEXT: [[SUBVEC:%.*]] = call @llvm.vector.extract.nxv2i1.nxv4i1( [[A]], i64 0) +; CHECK-NEXT: [[ELT:%.*]] = extractelement [[SUBVEC]], i64 1 +; CHECK-NEXT: ret i1 [[ELT]] +; + %subvec = call @llvm.vector.extract.nxv2i1.nxv4i1.i64( %a, i64 0) + %elt = extractelement %subvec, i32 1 + ret i1 %elt +} From d93bdead6c6d36907c3ed539407736070792f92b Mon Sep 17 00:00:00 2001 From: Kerry McLaughlin Date: Thu, 17 Jul 2025 08:51:47 +0000 Subject: [PATCH 2/4] [Instcombine] Combine extractelement from a vector_extract at index 0 Extracting any element from a subvector starting at index 0 is equivalent to extracting from the original vector, i.e. extract_elt(vector_extract(x, 0), y) -> extract_elt(x, y) --- llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp | 6 +++++- .../Transforms/InstCombine/scalable-extract-subvec-elt.ll | 3 +-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp b/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp index 00b877b8a07ef..6f2adba9e3f6b 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp @@ -444,7 +444,11 @@ Instruction *InstCombinerImpl::visitExtractElementInst(ExtractElementInst &EI) { else Idx = PoisonValue::get(Ty); return replaceInstUsesWith(EI, Idx); - } + } else if (IID == Intrinsic::vector_extract) + // If II is a subvector starting at index 0, extract from the wider + // source vector + if (cast(II->getArgOperand(1))->getZExtValue() == 0) + return ExtractElementInst::Create(II->getArgOperand(0), Index); } // InstSimplify should handle cases where the index is invalid. diff --git a/llvm/test/Transforms/InstCombine/scalable-extract-subvec-elt.ll b/llvm/test/Transforms/InstCombine/scalable-extract-subvec-elt.ll index d0cfc48420b43..38cbeb0df98bd 100644 --- a/llvm/test/Transforms/InstCombine/scalable-extract-subvec-elt.ll +++ b/llvm/test/Transforms/InstCombine/scalable-extract-subvec-elt.ll @@ -4,8 +4,7 @@ define i1 @scalable_test( %a) { ; CHECK-LABEL: define i1 @scalable_test( ; CHECK-SAME: [[A:%.*]]) { -; CHECK-NEXT: [[SUBVEC:%.*]] = call @llvm.vector.extract.nxv2i1.nxv4i1( [[A]], i64 0) -; CHECK-NEXT: [[ELT:%.*]] = extractelement [[SUBVEC]], i64 1 +; CHECK-NEXT: [[ELT:%.*]] = extractelement [[A]], i64 1 ; CHECK-NEXT: ret i1 [[ELT]] ; %subvec = call @llvm.vector.extract.nxv2i1.nxv4i1.i64( %a, i64 0) From d9b7aa9557075c166a34ac7dc9ba4d77c2ac36d4 Mon Sep 17 00:00:00 2001 From: Kerry McLaughlin Date: Thu, 31 Jul 2025 12:26:50 +0000 Subject: [PATCH 3/4] - Add variable index & negative tests --- .../InstCombine/InstCombineVectorOps.cpp | 15 ++++++----- .../scalable-extract-subvec-elt.ll | 27 +++++++++++++++++-- 2 files changed, 34 insertions(+), 8 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp b/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp index 6f2adba9e3f6b..cb188ea9a68ec 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp @@ -419,6 +419,7 @@ Instruction *InstCombinerImpl::visitExtractElementInst(ExtractElementInst &EI) { // If extracting a specified index from the vector, see if we can recursively // find a previously computed scalar that was inserted into the vector. auto *IndexC = dyn_cast(Index); + auto *II = dyn_cast(SrcVec); bool HasKnownValidIndex = false; if (IndexC) { // Canonicalize type of constant indices to i64 to simplify CSE @@ -429,7 +430,7 @@ Instruction *InstCombinerImpl::visitExtractElementInst(ExtractElementInst &EI) { unsigned NumElts = EC.getKnownMinValue(); HasKnownValidIndex = IndexC->getValue().ult(NumElts); - if (IntrinsicInst *II = dyn_cast(SrcVec)) { + if (II) { Intrinsic::ID IID = II->getIntrinsicID(); // Index needs to be lower than the minimum size of the vector, because // for scalable vector, the vector size is known at run time. @@ -444,11 +445,7 @@ Instruction *InstCombinerImpl::visitExtractElementInst(ExtractElementInst &EI) { else Idx = PoisonValue::get(Ty); return replaceInstUsesWith(EI, Idx); - } else if (IID == Intrinsic::vector_extract) - // If II is a subvector starting at index 0, extract from the wider - // source vector - if (cast(II->getArgOperand(1))->getZExtValue() == 0) - return ExtractElementInst::Create(II->getArgOperand(0), Index); + } } // InstSimplify should handle cases where the index is invalid. @@ -466,6 +463,12 @@ Instruction *InstCombinerImpl::visitExtractElementInst(ExtractElementInst &EI) { return ScalarPHI; } + // If SrcVec is a subvector starting at index 0, extract from the + // wider source vector + if (II && II->getIntrinsicID() == Intrinsic::vector_extract) + if (cast(II->getArgOperand(1))->isZero()) + return ExtractElementInst::Create(II->getArgOperand(0), Index); + // TODO come up with a n-ary matcher that subsumes both unary and // binary matchers. UnaryOperator *UO; diff --git a/llvm/test/Transforms/InstCombine/scalable-extract-subvec-elt.ll b/llvm/test/Transforms/InstCombine/scalable-extract-subvec-elt.ll index 38cbeb0df98bd..1e089e1168f66 100644 --- a/llvm/test/Transforms/InstCombine/scalable-extract-subvec-elt.ll +++ b/llvm/test/Transforms/InstCombine/scalable-extract-subvec-elt.ll @@ -1,8 +1,8 @@ ; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 5 ; RUN: opt -S -passes=instcombine < %s | FileCheck %s -define i1 @scalable_test( %a) { -; CHECK-LABEL: define i1 @scalable_test( +define i1 @extract_const_idx( %a) { +; CHECK-LABEL: define i1 @extract_const_idx( ; CHECK-SAME: [[A:%.*]]) { ; CHECK-NEXT: [[ELT:%.*]] = extractelement [[A]], i64 1 ; CHECK-NEXT: ret i1 [[ELT]] @@ -11,3 +11,26 @@ define i1 @scalable_test( %a) { %elt = extractelement %subvec, i32 1 ret i1 %elt } + +define float @extract_variable_idx( %a, i32 %idx) { +; CHECK-LABEL: define float @extract_variable_idx( +; CHECK-SAME: [[A:%.*]], i32 [[IDX:%.*]]) { +; CHECK-NEXT: [[ELT:%.*]] = extractelement [[A]], i32 [[IDX]] +; CHECK-NEXT: ret float [[ELT]] +; + %subvec = call @llvm.vector.extract.nxv2f32.nxv4f32.i64( %a, i64 0) + %elt = extractelement %subvec, i32 %idx + ret float %elt +} + +define float @negative_test( %a) { +; CHECK-LABEL: define float @negative_test( +; CHECK-SAME: [[A:%.*]]) { +; CHECK-NEXT: [[SUBVEC:%.*]] = call @llvm.vector.extract.nxv2f32.nxv4f32( [[A]], i64 2) +; CHECK-NEXT: [[ELT:%.*]] = extractelement [[SUBVEC]], i64 1 +; CHECK-NEXT: ret float [[ELT]] +; + %subvec = call @llvm.vector.extract.nxv2f32.nxv4f32.i64( %a, i64 2) + %elt = extractelement %subvec, i32 1 + ret float %elt +} From c43f8836fedf16c7dff4dca0684c8010bf691e77 Mon Sep 17 00:00:00 2001 From: Kerry McLaughlin Date: Thu, 31 Jul 2025 15:22:14 +0000 Subject: [PATCH 4/4] - Use PatternMatch --- .../Transforms/InstCombine/InstCombineVectorOps.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp b/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp index cb188ea9a68ec..fe0f308223387 100644 --- a/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp +++ b/llvm/lib/Transforms/InstCombine/InstCombineVectorOps.cpp @@ -419,7 +419,6 @@ Instruction *InstCombinerImpl::visitExtractElementInst(ExtractElementInst &EI) { // If extracting a specified index from the vector, see if we can recursively // find a previously computed scalar that was inserted into the vector. auto *IndexC = dyn_cast(Index); - auto *II = dyn_cast(SrcVec); bool HasKnownValidIndex = false; if (IndexC) { // Canonicalize type of constant indices to i64 to simplify CSE @@ -430,7 +429,7 @@ Instruction *InstCombinerImpl::visitExtractElementInst(ExtractElementInst &EI) { unsigned NumElts = EC.getKnownMinValue(); HasKnownValidIndex = IndexC->getValue().ult(NumElts); - if (II) { + if (IntrinsicInst *II = dyn_cast(SrcVec)) { Intrinsic::ID IID = II->getIntrinsicID(); // Index needs to be lower than the minimum size of the vector, because // for scalable vector, the vector size is known at run time. @@ -465,9 +464,10 @@ Instruction *InstCombinerImpl::visitExtractElementInst(ExtractElementInst &EI) { // If SrcVec is a subvector starting at index 0, extract from the // wider source vector - if (II && II->getIntrinsicID() == Intrinsic::vector_extract) - if (cast(II->getArgOperand(1))->isZero()) - return ExtractElementInst::Create(II->getArgOperand(0), Index); + Value *V; + if (match(SrcVec, + m_Intrinsic(m_Value(V), m_Zero()))) + return ExtractElementInst::Create(V, Index); // TODO come up with a n-ary matcher that subsumes both unary and // binary matchers.