[llvm] [AArch64][GlobalISel] Add legalisation to G_EXRACT_SUBVECTOR (PR #207956)
Joshua Rodriguez via llvm-commits
llvm-commits at lists.llvm.org
Thu Jul 16 06:57:06 PDT 2026
https://github.com/JoshdRod updated https://github.com/llvm/llvm-project/pull/207956
>From 5f106231380ecb74ffd9952bd3e7617c26d23492 Mon Sep 17 00:00:00 2001
From: Josh Rodriguez <josh.rodriguez at arm.com>
Date: Fri, 26 Jun 2026 15:47:57 +0000
Subject: [PATCH 01/10] [AArch64][GlobalISel]! Add legalisation for
G_EXTRACT_SUBVECTOR
TODO: Fix test checks. A lot of test are failing now, even though the legalisation should only affect cases which were failing to begin with. Might be to do with returning Legalized if V is 2x S, becuase idk why that was working previously.
Also, I tried adding dbgs lines in to see what code points the failing tests were hitting - but apparently they weren't hitting them at all? It might be worth running lldb over this.
---
.../CodeGen/GlobalISel/LegalizerHelper.cpp | 32 +++++++++++++++++++
.../AArch64/GISel/AArch64LegalizerInfo.cpp | 8 ++---
2 files changed, 36 insertions(+), 4 deletions(-)
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index 021f7233ce3b7..f6a767c0ea479 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -4928,6 +4928,38 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
return Legalized;
}
}
+ case G_EXTRACT_SUBVECTOR: {
+ // Check that subvector is half size of main vector
+ Register Subvector = MI.getOperand(0).getReg();
+ Register Vector = MI.getOperand(1).getReg();
+ auto ExtractionPointImm = MI.getOperand(2).getImm();
+
+ LLT VectorTy = MRI.getType(Vector);
+ LLT SubvectorTy = MRI.getType(Subvector);
+
+ if (VectorTy.isScalable() ||
+ SubvectorTy.isScalable())
+ return UnableToLegalize;
+
+ if (VectorTy.getScalarType() != SubvectorTy.getScalarType())
+ return UnableToLegalize;
+
+ // X = extract(Y, 0) -> X = Y, iff Type(x) == Type(Y)
+ if (VectorTy == SubvectorTy && ExtractionPointImm == 0)
+ {
+ // Some sort of copy here
+ MIRBuilder.buildCopy(Subvector, Vector);
+ MI.eraseFromParent();
+ return Legalized;
+ }
+ // Else, if V is 2x size of S, then lower (idk why this works?)
+ else if (VectorTy.getNumElements() == SubvectorTy.getNumElements() * 2)
+ {
+ return Legalized;
+ }
+ // Else else.. return unable to legalize
+ return UnableToLegalize;
+ }
case G_STACKSAVE:
return lowerStackSave(MI);
case G_STACKRESTORE:
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
index 1d08ce1312263..1ee009e639636 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
@@ -1341,10 +1341,10 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST)
SrcTy.getNumElements())));
});
- getActionDefinitionsBuilder(G_EXTRACT_SUBVECTOR)
- .legalFor({{v8s8, v16s8}, {v4s16, v8s16}, {v2s32, v4s32}})
- .widenScalarOrEltToNextPow2(0)
- .immIdx(0); // Inform verifier imm idx 0 is handled.
+ getActionDefinitionsBuilder(G_EXTRACT_SUBVECTOR).lower();
+ //.legalFor({{v8s8, v16s8}, {v4s16, v8s16}, {v2s32, v4s32}})
+ //.widenScalarOrEltToNextPow2(0)
+ //.immIdx(0); // Inform verifier imm idx 0 is handled.
// TODO: {nxv16s8, s8}, {nxv8s16, s16}
getActionDefinitionsBuilder(G_SPLAT_VECTOR)
>From 9f33fa5128e4e50f467f9a7c0aca493957b42444 Mon Sep 17 00:00:00 2001
From: Josh Rodriguez <josh.rodriguez at arm.com>
Date: Wed, 1 Jul 2026 16:08:32 +0000
Subject: [PATCH 02/10] [AArch64][GlobalISel]! Convert non-trivial
extract_subvectors into build_vector(extract_element() ...)
Trivial extract_subvector intrinsics occur when the subvector is half the size of the original vector.
If not, then the instruction must be converted into a series of extract_element's, and a build_vector taking these elements in.
Unsure why this is the case though.
TODO: One test file still fails. The tests only fail when fullfp16 is enabled - why?
---
.../CodeGen/GlobalISel/LegalizerHelper.cpp | 37 ++++++++++---------
.../AArch64/GISel/AArch64LegalizerInfo.cpp | 9 +++--
.../GlobalISel/legalizer-info-validation.mir | 4 +-
3 files changed, 26 insertions(+), 24 deletions(-)
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index f6a767c0ea479..5c88a7e567c90 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -4929,36 +4929,37 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
}
}
case G_EXTRACT_SUBVECTOR: {
- // Check that subvector is half size of main vector
Register Subvector = MI.getOperand(0).getReg();
Register Vector = MI.getOperand(1).getReg();
- auto ExtractionPointImm = MI.getOperand(2).getImm();
+ uint64_t ExtractionPointImm = MI.getOperand(2).getImm();
LLT VectorTy = MRI.getType(Vector);
LLT SubvectorTy = MRI.getType(Subvector);
- if (VectorTy.isScalable() ||
- SubvectorTy.isScalable())
+ if (VectorTy.isScalable() || SubvectorTy.isScalable())
return UnableToLegalize;
if (VectorTy.getScalarType() != SubvectorTy.getScalarType())
- return UnableToLegalize;
+ return UnableToLegalize;
- // X = extract(Y, 0) -> X = Y, iff Type(x) == Type(Y)
- if (VectorTy == SubvectorTy && ExtractionPointImm == 0)
- {
- // Some sort of copy here
- MIRBuilder.buildCopy(Subvector, Vector);
- MI.eraseFromParent();
- return Legalized;
- }
- // Else, if V is 2x size of S, then lower (idk why this works?)
- else if (VectorTy.getNumElements() == SubvectorTy.getNumElements() * 2)
+ if (VectorTy.getNumElements() <= SubvectorTy.getNumElements())
+ return UnableToLegalize;
+
+ // extract_subvector = build_vector(extract_element, extract_element, ...)
+ SmallVector<Register> ExtractedElements;
+ for (uint64_t i = 0; i < SubvectorTy.getNumElements(); i++)
{
- return Legalized;
+ dbgs() << Vector << "\n" << ExtractionPointImm << "\n";
+ ExtractedElements.push_back(
+ MIRBuilder
+ .buildExtractVectorElement(VectorTy.getScalarType(), Vector,
+ ExtractionPointImm + i)
+ .getReg(0));
}
- // Else else.. return unable to legalize
- return UnableToLegalize;
+
+ MIRBuilder.buildBuildVector(Subvector, ExtractedElements);
+ MI.eraseFromParent();
+ return Legalized;
}
case G_STACKSAVE:
return lowerStackSave(MI);
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
index 1ee009e639636..78bdcf594a266 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
@@ -1341,10 +1341,11 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST)
SrcTy.getNumElements())));
});
- getActionDefinitionsBuilder(G_EXTRACT_SUBVECTOR).lower();
- //.legalFor({{v8s8, v16s8}, {v4s16, v8s16}, {v2s32, v4s32}})
- //.widenScalarOrEltToNextPow2(0)
- //.immIdx(0); // Inform verifier imm idx 0 is handled.
+ getActionDefinitionsBuilder(G_EXTRACT_SUBVECTOR)
+ .legalFor({{v8s8, v16s8}, {v4s16, v8s16}, {v2s32, v4s32}})
+ .widenScalarOrEltToNextPow2(0)
+ //.immIdx(0) // Inform verifier imm idx 0 is handled.
+ .lower();
// TODO: {nxv16s8, s8}, {nxv8s16, s16}
getActionDefinitionsBuilder(G_SPLAT_VECTOR)
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
index 26c0aaa3bb3c9..4a88a30d56e01 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
@@ -727,8 +727,8 @@
# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
# DEBUG-NEXT: G_EXTRACT_SUBVECTOR (opcode {{[0-9]+}}): 2 type indices, 1 imm index
-# DEBUG-NEXT: .. the first uncovered type index: 2, OK
-# DEBUG-NEXT: .. the first uncovered imm index: 1, OK
+# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
+# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
# DEBUG-NEXT: G_INSERT_VECTOR_ELT (opcode {{[0-9]+}}): 3 type indices, 0 imm indices
# DEBUG-NEXT: .. type index coverage check SKIPPED: user-defined predicate detected
# DEBUG-NEXT: .. imm index coverage check SKIPPED: user-defined predicate detected
>From 9dad8a8ec9555da5ca306cc4e9484512c97497fb Mon Sep 17 00:00:00 2001
From: Josh Rodriguez <josh.rodriguez at arm.com>
Date: Thu, 2 Jul 2026 10:09:27 +0000
Subject: [PATCH 03/10] [AArch64][GlobalISel] Change buildExtractVectorElement
to buildExtractVectorElementConstant
Previously, reaching this line would cause code generation to fail, as buildExtractVectorElement expects a SrcOp (Register/LLT Type).
Change to the constant version, to allow this constant to be passed in.
Note that the GlobalISel generated code is significantly larger than the SDAG equivalent.
---
.../CodeGen/GlobalISel/LegalizerHelper.cpp | 8 +-
.../AArch64/complex-deinterleaving-f16-add.ll | 226 ++++++++++++++++--
2 files changed, 208 insertions(+), 26 deletions(-)
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index 5c88a7e567c90..e32d870722a45 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -4947,13 +4947,11 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
// extract_subvector = build_vector(extract_element, extract_element, ...)
SmallVector<Register> ExtractedElements;
- for (uint64_t i = 0; i < SubvectorTy.getNumElements(); i++)
- {
- dbgs() << Vector << "\n" << ExtractionPointImm << "\n";
+ for (uint64_t i = 0; i < SubvectorTy.getNumElements(); i++) {
ExtractedElements.push_back(
MIRBuilder
- .buildExtractVectorElement(VectorTy.getScalarType(), Vector,
- ExtractionPointImm + i)
+ .buildExtractVectorElementConstant(VectorTy.getScalarType(),
+ Vector, ExtractionPointImm + i)
.getReg(0));
}
diff --git a/llvm/test/CodeGen/AArch64/complex-deinterleaving-f16-add.ll b/llvm/test/CodeGen/AArch64/complex-deinterleaving-f16-add.ll
index bb043ecb5ecb3..5bd7ed492d74b 100644
--- a/llvm/test/CodeGen/AArch64/complex-deinterleaving-f16-add.ll
+++ b/llvm/test/CodeGen/AArch64/complex-deinterleaving-f16-add.ll
@@ -6,10 +6,6 @@
; RUN: llc < %s -mtriple=aarch64 --global-isel --global-isel-abort=2 --mattr=+complxnum,+neon,+fullfp16,+sve -o - 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-GI
; RUN: llc < %s -mtriple=aarch64 --global-isel --global-isel-abort=2 --mattr=+complxnum,+neon,+fullfp16,+sve2 -o - 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-GI
-; CHECK-GI: warning: Instruction selection used fallback path for complex_add_v16f16
-; CHECK-GI-NEXT: warning: Instruction selection used fallback path for complex_add_v32f16
-; CHECK-GI-NEXT: warning: Instruction selection used fallback path for complex_add_v16f16_with_intrinsic
-
; Expected to not transform
define <2 x half> @complex_add_v2f16(<2 x half> %a, <2 x half> %b) {
; CHECK-SD-LABEL: complex_add_v2f16:
@@ -82,11 +78,57 @@ entry:
; Expected to transform
define <16 x half> @complex_add_v16f16(<16 x half> %a, <16 x half> %b) {
-; CHECK-LABEL: complex_add_v16f16:
-; CHECK: // %bb.0: // %entry
-; CHECK-NEXT: fcadd v1.8h, v3.8h, v1.8h, #90
-; CHECK-NEXT: fcadd v0.8h, v2.8h, v0.8h, #90
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: complex_add_v16f16:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: fcadd v1.8h, v3.8h, v1.8h, #90
+; CHECK-SD-NEXT: fcadd v0.8h, v2.8h, v0.8h, #90
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: complex_add_v16f16:
+; CHECK-GI: // %bb.0: // %entry
+; CHECK-GI-NEXT: mov h4, v2.h[0]
+; CHECK-GI-NEXT: mov h5, v0.h[0]
+; CHECK-GI-NEXT: mov h6, v1.h[0]
+; CHECK-GI-NEXT: mov v4.h[1], v2.h[1]
+; CHECK-GI-NEXT: mov v5.h[1], v0.h[1]
+; CHECK-GI-NEXT: mov v6.h[1], v1.h[1]
+; CHECK-GI-NEXT: mov v4.h[2], v2.h[2]
+; CHECK-GI-NEXT: mov v5.h[2], v0.h[2]
+; CHECK-GI-NEXT: mov v6.h[2], v1.h[2]
+; CHECK-GI-NEXT: mov v4.h[3], v2.h[3]
+; CHECK-GI-NEXT: mov v5.h[3], v0.h[3]
+; CHECK-GI-NEXT: mov v6.h[3], v1.h[3]
+; CHECK-GI-NEXT: mov v4.h[4], v2.h[4]
+; CHECK-GI-NEXT: mov v5.h[4], v0.h[4]
+; CHECK-GI-NEXT: mov v6.h[4], v1.h[4]
+; CHECK-GI-NEXT: mov v4.h[5], v2.h[5]
+; CHECK-GI-NEXT: mov v5.h[5], v0.h[5]
+; CHECK-GI-NEXT: mov v6.h[5], v1.h[5]
+; CHECK-GI-NEXT: mov v4.h[6], v2.h[6]
+; CHECK-GI-NEXT: mov v5.h[6], v0.h[6]
+; CHECK-GI-NEXT: mov v6.h[6], v1.h[6]
+; CHECK-GI-NEXT: mov v4.h[7], v2.h[7]
+; CHECK-GI-NEXT: mov v5.h[7], v0.h[7]
+; CHECK-GI-NEXT: mov h2, v3.h[0]
+; CHECK-GI-NEXT: mov v6.h[7], v1.h[7]
+; CHECK-GI-NEXT: fcadd v4.8h, v4.8h, v5.8h, #90
+; CHECK-GI-NEXT: mov v2.h[1], v3.h[1]
+; CHECK-GI-NEXT: mov h0, v4.h[0]
+; CHECK-GI-NEXT: mov v2.h[2], v3.h[2]
+; CHECK-GI-NEXT: mov v0.h[1], v4.h[1]
+; CHECK-GI-NEXT: mov v2.h[3], v3.h[3]
+; CHECK-GI-NEXT: mov v0.h[2], v4.h[2]
+; CHECK-GI-NEXT: mov v2.h[4], v3.h[4]
+; CHECK-GI-NEXT: mov v0.h[3], v4.h[3]
+; CHECK-GI-NEXT: mov v2.h[5], v3.h[5]
+; CHECK-GI-NEXT: mov v0.h[4], v4.h[4]
+; CHECK-GI-NEXT: mov v2.h[6], v3.h[6]
+; CHECK-GI-NEXT: mov v0.h[5], v4.h[5]
+; CHECK-GI-NEXT: mov v2.h[7], v3.h[7]
+; CHECK-GI-NEXT: mov v0.h[6], v4.h[6]
+; CHECK-GI-NEXT: fcadd v1.8h, v2.8h, v6.8h, #90
+; CHECK-GI-NEXT: mov v0.h[7], v4.h[7]
+; CHECK-GI-NEXT: ret
entry:
%a.real = shufflevector <16 x half> %a, <16 x half> zeroinitializer, <8 x i32> <i32 0, i32 2, i32 4, i32 6, i32 8, i32 10, i32 12, i32 14>
%a.imag = shufflevector <16 x half> %a, <16 x half> zeroinitializer, <8 x i32> <i32 1, i32 3, i32 5, i32 7, i32 9, i32 11, i32 13, i32 15>
@@ -100,13 +142,109 @@ entry:
; Expected to transform
define <32 x half> @complex_add_v32f16(<32 x half> %a, <32 x half> %b) {
-; CHECK-LABEL: complex_add_v32f16:
-; CHECK: // %bb.0: // %entry
-; CHECK-NEXT: fcadd v2.8h, v6.8h, v2.8h, #90
-; CHECK-NEXT: fcadd v0.8h, v4.8h, v0.8h, #90
-; CHECK-NEXT: fcadd v1.8h, v5.8h, v1.8h, #90
-; CHECK-NEXT: fcadd v3.8h, v7.8h, v3.8h, #90
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: complex_add_v32f16:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: fcadd v2.8h, v6.8h, v2.8h, #90
+; CHECK-SD-NEXT: fcadd v0.8h, v4.8h, v0.8h, #90
+; CHECK-SD-NEXT: fcadd v1.8h, v5.8h, v1.8h, #90
+; CHECK-SD-NEXT: fcadd v3.8h, v7.8h, v3.8h, #90
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: complex_add_v32f16:
+; CHECK-GI: // %bb.0: // %entry
+; CHECK-GI-NEXT: mov h16, v4.h[0]
+; CHECK-GI-NEXT: mov h18, v0.h[0]
+; CHECK-GI-NEXT: mov h17, v5.h[0]
+; CHECK-GI-NEXT: mov h19, v1.h[0]
+; CHECK-GI-NEXT: mov h20, v6.h[0]
+; CHECK-GI-NEXT: mov h21, v2.h[0]
+; CHECK-GI-NEXT: mov v16.h[1], v4.h[1]
+; CHECK-GI-NEXT: mov v18.h[1], v0.h[1]
+; CHECK-GI-NEXT: mov v17.h[1], v5.h[1]
+; CHECK-GI-NEXT: mov v19.h[1], v1.h[1]
+; CHECK-GI-NEXT: mov v20.h[1], v6.h[1]
+; CHECK-GI-NEXT: mov v21.h[1], v2.h[1]
+; CHECK-GI-NEXT: mov v16.h[2], v4.h[2]
+; CHECK-GI-NEXT: mov v18.h[2], v0.h[2]
+; CHECK-GI-NEXT: mov v17.h[2], v5.h[2]
+; CHECK-GI-NEXT: mov v19.h[2], v1.h[2]
+; CHECK-GI-NEXT: mov v20.h[2], v6.h[2]
+; CHECK-GI-NEXT: mov v21.h[2], v2.h[2]
+; CHECK-GI-NEXT: mov v16.h[3], v4.h[3]
+; CHECK-GI-NEXT: mov v18.h[3], v0.h[3]
+; CHECK-GI-NEXT: mov v17.h[3], v5.h[3]
+; CHECK-GI-NEXT: mov v19.h[3], v1.h[3]
+; CHECK-GI-NEXT: mov v20.h[3], v6.h[3]
+; CHECK-GI-NEXT: mov v21.h[3], v2.h[3]
+; CHECK-GI-NEXT: mov v16.h[4], v4.h[4]
+; CHECK-GI-NEXT: mov v18.h[4], v0.h[4]
+; CHECK-GI-NEXT: mov v17.h[4], v5.h[4]
+; CHECK-GI-NEXT: mov v19.h[4], v1.h[4]
+; CHECK-GI-NEXT: mov v20.h[4], v6.h[4]
+; CHECK-GI-NEXT: mov v21.h[4], v2.h[4]
+; CHECK-GI-NEXT: mov v16.h[5], v4.h[5]
+; CHECK-GI-NEXT: mov v18.h[5], v0.h[5]
+; CHECK-GI-NEXT: mov v17.h[5], v5.h[5]
+; CHECK-GI-NEXT: mov v19.h[5], v1.h[5]
+; CHECK-GI-NEXT: mov v20.h[5], v6.h[5]
+; CHECK-GI-NEXT: mov v21.h[5], v2.h[5]
+; CHECK-GI-NEXT: mov v16.h[6], v4.h[6]
+; CHECK-GI-NEXT: mov v18.h[6], v0.h[6]
+; CHECK-GI-NEXT: mov v17.h[6], v5.h[6]
+; CHECK-GI-NEXT: mov v19.h[6], v1.h[6]
+; CHECK-GI-NEXT: mov v20.h[6], v6.h[6]
+; CHECK-GI-NEXT: mov v21.h[6], v2.h[6]
+; CHECK-GI-NEXT: mov v16.h[7], v4.h[7]
+; CHECK-GI-NEXT: mov v18.h[7], v0.h[7]
+; CHECK-GI-NEXT: mov v17.h[7], v5.h[7]
+; CHECK-GI-NEXT: mov v19.h[7], v1.h[7]
+; CHECK-GI-NEXT: mov v20.h[7], v6.h[7]
+; CHECK-GI-NEXT: mov v21.h[7], v2.h[7]
+; CHECK-GI-NEXT: mov h4, v7.h[0]
+; CHECK-GI-NEXT: fcadd v5.8h, v16.8h, v18.8h, #90
+; CHECK-GI-NEXT: mov h16, v3.h[0]
+; CHECK-GI-NEXT: fcadd v6.8h, v17.8h, v19.8h, #90
+; CHECK-GI-NEXT: fcadd v17.8h, v20.8h, v21.8h, #90
+; CHECK-GI-NEXT: mov v4.h[1], v7.h[1]
+; CHECK-GI-NEXT: mov h0, v5.h[0]
+; CHECK-GI-NEXT: mov v16.h[1], v3.h[1]
+; CHECK-GI-NEXT: mov h2, v17.h[0]
+; CHECK-GI-NEXT: mov h1, v6.h[0]
+; CHECK-GI-NEXT: mov v4.h[2], v7.h[2]
+; CHECK-GI-NEXT: mov v0.h[1], v5.h[1]
+; CHECK-GI-NEXT: mov v16.h[2], v3.h[2]
+; CHECK-GI-NEXT: mov v2.h[1], v17.h[1]
+; CHECK-GI-NEXT: mov v1.h[1], v6.h[1]
+; CHECK-GI-NEXT: mov v4.h[3], v7.h[3]
+; CHECK-GI-NEXT: mov v0.h[2], v5.h[2]
+; CHECK-GI-NEXT: mov v16.h[3], v3.h[3]
+; CHECK-GI-NEXT: mov v2.h[2], v17.h[2]
+; CHECK-GI-NEXT: mov v1.h[2], v6.h[2]
+; CHECK-GI-NEXT: mov v4.h[4], v7.h[4]
+; CHECK-GI-NEXT: mov v0.h[3], v5.h[3]
+; CHECK-GI-NEXT: mov v16.h[4], v3.h[4]
+; CHECK-GI-NEXT: mov v2.h[3], v17.h[3]
+; CHECK-GI-NEXT: mov v1.h[3], v6.h[3]
+; CHECK-GI-NEXT: mov v4.h[5], v7.h[5]
+; CHECK-GI-NEXT: mov v0.h[4], v5.h[4]
+; CHECK-GI-NEXT: mov v16.h[5], v3.h[5]
+; CHECK-GI-NEXT: mov v2.h[4], v17.h[4]
+; CHECK-GI-NEXT: mov v1.h[4], v6.h[4]
+; CHECK-GI-NEXT: mov v4.h[6], v7.h[6]
+; CHECK-GI-NEXT: mov v0.h[5], v5.h[5]
+; CHECK-GI-NEXT: mov v16.h[6], v3.h[6]
+; CHECK-GI-NEXT: mov v2.h[5], v17.h[5]
+; CHECK-GI-NEXT: mov v1.h[5], v6.h[5]
+; CHECK-GI-NEXT: mov v4.h[7], v7.h[7]
+; CHECK-GI-NEXT: mov v0.h[6], v5.h[6]
+; CHECK-GI-NEXT: mov v16.h[7], v3.h[7]
+; CHECK-GI-NEXT: mov v2.h[6], v17.h[6]
+; CHECK-GI-NEXT: mov v1.h[6], v6.h[6]
+; CHECK-GI-NEXT: mov v0.h[7], v5.h[7]
+; CHECK-GI-NEXT: fcadd v3.8h, v4.8h, v16.8h, #90
+; CHECK-GI-NEXT: mov v2.h[7], v17.h[7]
+; CHECK-GI-NEXT: mov v1.h[7], v6.h[7]
+; CHECK-GI-NEXT: ret
entry:
%a.real = shufflevector <32 x half> %a, <32 x half> zeroinitializer, <16 x i32> <i32 0, i32 2, i32 4, i32 6, i32 8, i32 10, i32 12, i32 14, i32 16, i32 18, i32 20, i32 22, i32 24, i32 26, i32 28, i32 30>
%a.imag = shufflevector <32 x half> %a, <32 x half> zeroinitializer, <16 x i32> <i32 1, i32 3, i32 5, i32 7, i32 9, i32 11, i32 13, i32 15, i32 17, i32 19, i32 21, i32 23, i32 25, i32 27, i32 29, i32 31>
@@ -158,11 +296,57 @@ entry:
; Expected to transform
define <16 x half> @complex_add_v16f16_with_intrinsic(<16 x half> %a, <16 x half> %b) {
-; CHECK-LABEL: complex_add_v16f16_with_intrinsic:
-; CHECK: // %bb.0: // %entry
-; CHECK-NEXT: fcadd v1.8h, v3.8h, v1.8h, #90
-; CHECK-NEXT: fcadd v0.8h, v2.8h, v0.8h, #90
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: complex_add_v16f16_with_intrinsic:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: fcadd v1.8h, v3.8h, v1.8h, #90
+; CHECK-SD-NEXT: fcadd v0.8h, v2.8h, v0.8h, #90
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: complex_add_v16f16_with_intrinsic:
+; CHECK-GI: // %bb.0: // %entry
+; CHECK-GI-NEXT: mov h4, v2.h[0]
+; CHECK-GI-NEXT: mov h5, v0.h[0]
+; CHECK-GI-NEXT: mov h6, v1.h[0]
+; CHECK-GI-NEXT: mov v4.h[1], v2.h[1]
+; CHECK-GI-NEXT: mov v5.h[1], v0.h[1]
+; CHECK-GI-NEXT: mov v6.h[1], v1.h[1]
+; CHECK-GI-NEXT: mov v4.h[2], v2.h[2]
+; CHECK-GI-NEXT: mov v5.h[2], v0.h[2]
+; CHECK-GI-NEXT: mov v6.h[2], v1.h[2]
+; CHECK-GI-NEXT: mov v4.h[3], v2.h[3]
+; CHECK-GI-NEXT: mov v5.h[3], v0.h[3]
+; CHECK-GI-NEXT: mov v6.h[3], v1.h[3]
+; CHECK-GI-NEXT: mov v4.h[4], v2.h[4]
+; CHECK-GI-NEXT: mov v5.h[4], v0.h[4]
+; CHECK-GI-NEXT: mov v6.h[4], v1.h[4]
+; CHECK-GI-NEXT: mov v4.h[5], v2.h[5]
+; CHECK-GI-NEXT: mov v5.h[5], v0.h[5]
+; CHECK-GI-NEXT: mov v6.h[5], v1.h[5]
+; CHECK-GI-NEXT: mov v4.h[6], v2.h[6]
+; CHECK-GI-NEXT: mov v5.h[6], v0.h[6]
+; CHECK-GI-NEXT: mov v6.h[6], v1.h[6]
+; CHECK-GI-NEXT: mov v4.h[7], v2.h[7]
+; CHECK-GI-NEXT: mov v5.h[7], v0.h[7]
+; CHECK-GI-NEXT: mov h2, v3.h[0]
+; CHECK-GI-NEXT: mov v6.h[7], v1.h[7]
+; CHECK-GI-NEXT: fcadd v4.8h, v4.8h, v5.8h, #90
+; CHECK-GI-NEXT: mov v2.h[1], v3.h[1]
+; CHECK-GI-NEXT: mov h0, v4.h[0]
+; CHECK-GI-NEXT: mov v2.h[2], v3.h[2]
+; CHECK-GI-NEXT: mov v0.h[1], v4.h[1]
+; CHECK-GI-NEXT: mov v2.h[3], v3.h[3]
+; CHECK-GI-NEXT: mov v0.h[2], v4.h[2]
+; CHECK-GI-NEXT: mov v2.h[4], v3.h[4]
+; CHECK-GI-NEXT: mov v0.h[3], v4.h[3]
+; CHECK-GI-NEXT: mov v2.h[5], v3.h[5]
+; CHECK-GI-NEXT: mov v0.h[4], v4.h[4]
+; CHECK-GI-NEXT: mov v2.h[6], v3.h[6]
+; CHECK-GI-NEXT: mov v0.h[5], v4.h[5]
+; CHECK-GI-NEXT: mov v2.h[7], v3.h[7]
+; CHECK-GI-NEXT: mov v0.h[6], v4.h[6]
+; CHECK-GI-NEXT: fcadd v1.8h, v2.8h, v6.8h, #90
+; CHECK-GI-NEXT: mov v0.h[7], v4.h[7]
+; CHECK-GI-NEXT: ret
entry:
%a.deinterleaved = tail call { <8 x half>, <8 x half> } @llvm.vector.deinterleave2.v16f16(<16 x half> %a)
%a.real = extractvalue { <8 x half>, <8 x half> } %a.deinterleaved, 0
>From 9913f502f286a94d4bc2b0081fda58e9b7584196 Mon Sep 17 00:00:00 2001
From: Josh Rodriguez <josh.rodriguez at arm.com>
Date: Tue, 7 Jul 2026 10:10:16 +0000
Subject: [PATCH 04/10] [AArch64][GlobalISel] Update test checks
---
.../AArch64/GlobalISel/insert-subvector.ll | 39 +++++++++++++------
1 file changed, 28 insertions(+), 11 deletions(-)
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/insert-subvector.ll b/llvm/test/CodeGen/AArch64/GlobalISel/insert-subvector.ll
index a6a42fb6887e2..4bb7bddd2105d 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/insert-subvector.ll
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/insert-subvector.ll
@@ -2,9 +2,6 @@
; RUN: llc -mtriple=aarch64 %s -o - | FileCheck --check-prefix=CHECK --check-prefix=CHECK-SD %s
; RUN: llc -mtriple=aarch64 -global-isel -global-isel-abort=2 %s -o - 2>&1 | FileCheck --check-prefix=CHECK --check-prefix=CHECK-GI %s
-; CHECK-GI: warning: Instruction selection used fallback path for insert_v8i32_v4i32_high
-; CHECK-GI-NEXT: warning: Instruction selection used fallback path for insert_v8i32_v4i32_low
-
define <4 x i32> @insert_v4i32_v2i32_high(<4 x i32> %a, <2 x i32> %b) {
; CHECK-LABEL: insert_v4i32_v2i32_high:
; CHECK: // %bb.0: // %entry
@@ -29,20 +26,40 @@ entry:
}
define <8 x i32> @insert_v8i32_v4i32_high(<8 x i32> %a, <4 x i32> %b) {
-; CHECK-LABEL: insert_v8i32_v4i32_high:
-; CHECK: // %bb.0: // %entry
-; CHECK-NEXT: mov v0.16b, v2.16b
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: insert_v8i32_v4i32_high:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: mov v0.16b, v2.16b
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: insert_v8i32_v4i32_high:
+; CHECK-GI: // %bb.0: // %entry
+; CHECK-GI-NEXT: mov s3, v1.s[0]
+; CHECK-GI-NEXT: mov v0.16b, v2.16b
+; CHECK-GI-NEXT: mov v3.s[1], v1.s[1]
+; CHECK-GI-NEXT: mov v3.s[2], v1.s[2]
+; CHECK-GI-NEXT: mov v3.s[3], v1.s[3]
+; CHECK-GI-NEXT: mov v1.16b, v3.16b
+; CHECK-GI-NEXT: ret
entry:
%vector = call <8 x i32> @llvm.vector.insert.v8i32.v4i32(<8 x i32> %a, <4 x i32> %b, i64 0)
ret <8 x i32> %vector
}
define <8 x i32> @insert_v8i32_v4i32_low(<8 x i32> %a, <4 x i32> %b) {
-; CHECK-LABEL: insert_v8i32_v4i32_low:
-; CHECK: // %bb.0: // %entry
-; CHECK-NEXT: mov v1.16b, v2.16b
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: insert_v8i32_v4i32_low:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: mov v1.16b, v2.16b
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: insert_v8i32_v4i32_low:
+; CHECK-GI: // %bb.0: // %entry
+; CHECK-GI-NEXT: mov s1, v0.s[0]
+; CHECK-GI-NEXT: mov v1.s[1], v0.s[1]
+; CHECK-GI-NEXT: mov v1.s[2], v0.s[2]
+; CHECK-GI-NEXT: mov v1.s[3], v0.s[3]
+; CHECK-GI-NEXT: mov v0.16b, v1.16b
+; CHECK-GI-NEXT: mov v1.16b, v2.16b
+; CHECK-GI-NEXT: ret
entry:
%vector = call <8 x i32> @llvm.vector.insert.v8i32.v4i32(<8 x i32> %a, <4 x i32> %b, i64 4)
ret <8 x i32> %vector
>From 4ebb1e567ca790ca806a69e9508cc843ca9dca2c Mon Sep 17 00:00:00 2001
From: Josh Rodriguez <josh.rodriguez at arm.com>
Date: Tue, 7 Jul 2026 10:26:02 +0000
Subject: [PATCH 05/10] [AArch64][GlobalISel] Re-add note to verifier that imm
idx 0 is handled
This informs the verifier that the first immediate operand (immediate index 0 / operand index 2) is validated in .lower().
---
llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
index 78bdcf594a266..9750b5c61fb50 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
@@ -1344,8 +1344,8 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST)
getActionDefinitionsBuilder(G_EXTRACT_SUBVECTOR)
.legalFor({{v8s8, v16s8}, {v4s16, v8s16}, {v2s32, v4s32}})
.widenScalarOrEltToNextPow2(0)
- //.immIdx(0) // Inform verifier imm idx 0 is handled.
- .lower();
+ .lower()
+ .immIdx(0); // Inform verifier imm idx 0 is handled.
// TODO: {nxv16s8, s8}, {nxv8s16, s16}
getActionDefinitionsBuilder(G_SPLAT_VECTOR)
>From c9861020e4342aed6cd63b533511ab6b428221df Mon Sep 17 00:00:00 2001
From: Josh Rodriguez <josh.rodriguez at arm.com>
Date: Wed, 8 Jul 2026 10:23:32 +0000
Subject: [PATCH 06/10] [AArch64][GlobalISel] Add fewerElementsVector for x
G_EXTRACT_SUBVECTOR 2x case
When the vector is double the size of the subvector, and is too large to be stored in a 128-bit register, the instruction can be converted to a copy of the correct half of the vector.
Write a fewerElementsVector legalisation pass that implements this.
---
.../CodeGen/GlobalISel/LegalizerHelper.cpp | 25 +++
.../AArch64/GISel/AArch64LegalizerInfo.cpp | 13 ++
.../AArch64/GlobalISel/insert-subvector.ll | 24 +--
.../AArch64/complex-deinterleaving-f16-add.ll | 198 +-----------------
4 files changed, 54 insertions(+), 206 deletions(-)
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index e32d870722a45..87403423dc5cb 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -5826,6 +5826,31 @@ LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx,
if (TypeIdx != 1) // TODO: This probably does work as expected already.
return UnableToLegalize;
return fewerElementsVectorMerge(MI, TypeIdx, NarrowTy);
+ case G_EXTRACT_SUBVECTOR: {
+ Register DstReg = MI.getOperand(0).getReg();
+ LLT DstTy = MRI.getType(DstReg);
+ Register SrcReg = MI.getOperand(1).getReg();
+ LLT SrcTy = MRI.getType(SrcReg);
+ uint64_t InsertionPointImm = MI.getOperand(2).getImm();
+
+ // If Dst > 128 bits, then cannot legalize (yet)
+ if (DstTy.getSizeInBits() > 128)
+ return UnableToLegalize;
+ // If the extract is into a vector half its size, then convert to a copy
+ if (2 * DstTy.getNumElements() != SrcTy.getNumElements())
+ return UnableToLegalize;
+
+ // extract_subvector(large_vector) -> copy(high/low half of
+ // unmerge_values(large_vector, 2))
+ auto Unmerge = MIRBuilder.buildUnmerge(DstTy, SrcReg);
+ if (InsertionPointImm == 0)
+ MIRBuilder.buildCopy(DstReg, Unmerge.getReg(0));
+ else
+ MIRBuilder.buildCopy(DstReg, Unmerge.getReg(0));
+
+ MI.eraseFromParent();
+ return Legalized;
+ }
case G_EXTRACT_VECTOR_ELT:
case G_INSERT_VECTOR_ELT:
return fewerElementsVectorExtractInsertVectorElt(MI, TypeIdx, NarrowTy);
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
index 9750b5c61fb50..efcb12b4fa603 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
@@ -1344,6 +1344,19 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST)
getActionDefinitionsBuilder(G_EXTRACT_SUBVECTOR)
.legalFor({{v8s8, v16s8}, {v4s16, v8s16}, {v2s32, v4s32}})
.widenScalarOrEltToNextPow2(0)
+ .fewerElementsIf(
+ [=](const LegalityQuery &Q) {
+ LLT SrcTy = Q.Types[1];
+ if (SrcTy.isScalar())
+ return false;
+ if (!isPowerOf2_32(SrcTy.getNumElements()))
+ return false;
+ return SrcTy.getSizeInBits() > 128;
+ },
+ [=](const LegalityQuery &Q) {
+ LLT SrcTy = Q.Types[1];
+ return std::make_pair(1, SrcTy.divide(2));
+ })
.lower()
.immIdx(0); // Inform verifier imm idx 0 is handled.
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/insert-subvector.ll b/llvm/test/CodeGen/AArch64/GlobalISel/insert-subvector.ll
index 4bb7bddd2105d..419a574f17b64 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/insert-subvector.ll
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/insert-subvector.ll
@@ -33,12 +33,8 @@ define <8 x i32> @insert_v8i32_v4i32_high(<8 x i32> %a, <4 x i32> %b) {
;
; CHECK-GI-LABEL: insert_v8i32_v4i32_high:
; CHECK-GI: // %bb.0: // %entry
-; CHECK-GI-NEXT: mov s3, v1.s[0]
+; CHECK-GI-NEXT: mov v1.16b, v0.16b
; CHECK-GI-NEXT: mov v0.16b, v2.16b
-; CHECK-GI-NEXT: mov v3.s[1], v1.s[1]
-; CHECK-GI-NEXT: mov v3.s[2], v1.s[2]
-; CHECK-GI-NEXT: mov v3.s[3], v1.s[3]
-; CHECK-GI-NEXT: mov v1.16b, v3.16b
; CHECK-GI-NEXT: ret
entry:
%vector = call <8 x i32> @llvm.vector.insert.v8i32.v4i32(<8 x i32> %a, <4 x i32> %b, i64 0)
@@ -46,20 +42,10 @@ entry:
}
define <8 x i32> @insert_v8i32_v4i32_low(<8 x i32> %a, <4 x i32> %b) {
-; CHECK-SD-LABEL: insert_v8i32_v4i32_low:
-; CHECK-SD: // %bb.0: // %entry
-; CHECK-SD-NEXT: mov v1.16b, v2.16b
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: insert_v8i32_v4i32_low:
-; CHECK-GI: // %bb.0: // %entry
-; CHECK-GI-NEXT: mov s1, v0.s[0]
-; CHECK-GI-NEXT: mov v1.s[1], v0.s[1]
-; CHECK-GI-NEXT: mov v1.s[2], v0.s[2]
-; CHECK-GI-NEXT: mov v1.s[3], v0.s[3]
-; CHECK-GI-NEXT: mov v0.16b, v1.16b
-; CHECK-GI-NEXT: mov v1.16b, v2.16b
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: insert_v8i32_v4i32_low:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: mov v1.16b, v2.16b
+; CHECK-NEXT: ret
entry:
%vector = call <8 x i32> @llvm.vector.insert.v8i32.v4i32(<8 x i32> %a, <4 x i32> %b, i64 4)
ret <8 x i32> %vector
diff --git a/llvm/test/CodeGen/AArch64/complex-deinterleaving-f16-add.ll b/llvm/test/CodeGen/AArch64/complex-deinterleaving-f16-add.ll
index 5bd7ed492d74b..6441effcc55a9 100644
--- a/llvm/test/CodeGen/AArch64/complex-deinterleaving-f16-add.ll
+++ b/llvm/test/CodeGen/AArch64/complex-deinterleaving-f16-add.ll
@@ -86,48 +86,8 @@ define <16 x half> @complex_add_v16f16(<16 x half> %a, <16 x half> %b) {
;
; CHECK-GI-LABEL: complex_add_v16f16:
; CHECK-GI: // %bb.0: // %entry
-; CHECK-GI-NEXT: mov h4, v2.h[0]
-; CHECK-GI-NEXT: mov h5, v0.h[0]
-; CHECK-GI-NEXT: mov h6, v1.h[0]
-; CHECK-GI-NEXT: mov v4.h[1], v2.h[1]
-; CHECK-GI-NEXT: mov v5.h[1], v0.h[1]
-; CHECK-GI-NEXT: mov v6.h[1], v1.h[1]
-; CHECK-GI-NEXT: mov v4.h[2], v2.h[2]
-; CHECK-GI-NEXT: mov v5.h[2], v0.h[2]
-; CHECK-GI-NEXT: mov v6.h[2], v1.h[2]
-; CHECK-GI-NEXT: mov v4.h[3], v2.h[3]
-; CHECK-GI-NEXT: mov v5.h[3], v0.h[3]
-; CHECK-GI-NEXT: mov v6.h[3], v1.h[3]
-; CHECK-GI-NEXT: mov v4.h[4], v2.h[4]
-; CHECK-GI-NEXT: mov v5.h[4], v0.h[4]
-; CHECK-GI-NEXT: mov v6.h[4], v1.h[4]
-; CHECK-GI-NEXT: mov v4.h[5], v2.h[5]
-; CHECK-GI-NEXT: mov v5.h[5], v0.h[5]
-; CHECK-GI-NEXT: mov v6.h[5], v1.h[5]
-; CHECK-GI-NEXT: mov v4.h[6], v2.h[6]
-; CHECK-GI-NEXT: mov v5.h[6], v0.h[6]
-; CHECK-GI-NEXT: mov v6.h[6], v1.h[6]
-; CHECK-GI-NEXT: mov v4.h[7], v2.h[7]
-; CHECK-GI-NEXT: mov v5.h[7], v0.h[7]
-; CHECK-GI-NEXT: mov h2, v3.h[0]
-; CHECK-GI-NEXT: mov v6.h[7], v1.h[7]
-; CHECK-GI-NEXT: fcadd v4.8h, v4.8h, v5.8h, #90
-; CHECK-GI-NEXT: mov v2.h[1], v3.h[1]
-; CHECK-GI-NEXT: mov h0, v4.h[0]
-; CHECK-GI-NEXT: mov v2.h[2], v3.h[2]
-; CHECK-GI-NEXT: mov v0.h[1], v4.h[1]
-; CHECK-GI-NEXT: mov v2.h[3], v3.h[3]
-; CHECK-GI-NEXT: mov v0.h[2], v4.h[2]
-; CHECK-GI-NEXT: mov v2.h[4], v3.h[4]
-; CHECK-GI-NEXT: mov v0.h[3], v4.h[3]
-; CHECK-GI-NEXT: mov v2.h[5], v3.h[5]
-; CHECK-GI-NEXT: mov v0.h[4], v4.h[4]
-; CHECK-GI-NEXT: mov v2.h[6], v3.h[6]
-; CHECK-GI-NEXT: mov v0.h[5], v4.h[5]
-; CHECK-GI-NEXT: mov v2.h[7], v3.h[7]
-; CHECK-GI-NEXT: mov v0.h[6], v4.h[6]
-; CHECK-GI-NEXT: fcadd v1.8h, v2.8h, v6.8h, #90
-; CHECK-GI-NEXT: mov v0.h[7], v4.h[7]
+; CHECK-GI-NEXT: fcadd v0.8h, v2.8h, v0.8h, #90
+; CHECK-GI-NEXT: mov v1.16b, v0.16b
; CHECK-GI-NEXT: ret
entry:
%a.real = shufflevector <16 x half> %a, <16 x half> zeroinitializer, <8 x i32> <i32 0, i32 2, i32 4, i32 6, i32 8, i32 10, i32 12, i32 14>
@@ -142,109 +102,13 @@ entry:
; Expected to transform
define <32 x half> @complex_add_v32f16(<32 x half> %a, <32 x half> %b) {
-; CHECK-SD-LABEL: complex_add_v32f16:
-; CHECK-SD: // %bb.0: // %entry
-; CHECK-SD-NEXT: fcadd v2.8h, v6.8h, v2.8h, #90
-; CHECK-SD-NEXT: fcadd v0.8h, v4.8h, v0.8h, #90
-; CHECK-SD-NEXT: fcadd v1.8h, v5.8h, v1.8h, #90
-; CHECK-SD-NEXT: fcadd v3.8h, v7.8h, v3.8h, #90
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: complex_add_v32f16:
-; CHECK-GI: // %bb.0: // %entry
-; CHECK-GI-NEXT: mov h16, v4.h[0]
-; CHECK-GI-NEXT: mov h18, v0.h[0]
-; CHECK-GI-NEXT: mov h17, v5.h[0]
-; CHECK-GI-NEXT: mov h19, v1.h[0]
-; CHECK-GI-NEXT: mov h20, v6.h[0]
-; CHECK-GI-NEXT: mov h21, v2.h[0]
-; CHECK-GI-NEXT: mov v16.h[1], v4.h[1]
-; CHECK-GI-NEXT: mov v18.h[1], v0.h[1]
-; CHECK-GI-NEXT: mov v17.h[1], v5.h[1]
-; CHECK-GI-NEXT: mov v19.h[1], v1.h[1]
-; CHECK-GI-NEXT: mov v20.h[1], v6.h[1]
-; CHECK-GI-NEXT: mov v21.h[1], v2.h[1]
-; CHECK-GI-NEXT: mov v16.h[2], v4.h[2]
-; CHECK-GI-NEXT: mov v18.h[2], v0.h[2]
-; CHECK-GI-NEXT: mov v17.h[2], v5.h[2]
-; CHECK-GI-NEXT: mov v19.h[2], v1.h[2]
-; CHECK-GI-NEXT: mov v20.h[2], v6.h[2]
-; CHECK-GI-NEXT: mov v21.h[2], v2.h[2]
-; CHECK-GI-NEXT: mov v16.h[3], v4.h[3]
-; CHECK-GI-NEXT: mov v18.h[3], v0.h[3]
-; CHECK-GI-NEXT: mov v17.h[3], v5.h[3]
-; CHECK-GI-NEXT: mov v19.h[3], v1.h[3]
-; CHECK-GI-NEXT: mov v20.h[3], v6.h[3]
-; CHECK-GI-NEXT: mov v21.h[3], v2.h[3]
-; CHECK-GI-NEXT: mov v16.h[4], v4.h[4]
-; CHECK-GI-NEXT: mov v18.h[4], v0.h[4]
-; CHECK-GI-NEXT: mov v17.h[4], v5.h[4]
-; CHECK-GI-NEXT: mov v19.h[4], v1.h[4]
-; CHECK-GI-NEXT: mov v20.h[4], v6.h[4]
-; CHECK-GI-NEXT: mov v21.h[4], v2.h[4]
-; CHECK-GI-NEXT: mov v16.h[5], v4.h[5]
-; CHECK-GI-NEXT: mov v18.h[5], v0.h[5]
-; CHECK-GI-NEXT: mov v17.h[5], v5.h[5]
-; CHECK-GI-NEXT: mov v19.h[5], v1.h[5]
-; CHECK-GI-NEXT: mov v20.h[5], v6.h[5]
-; CHECK-GI-NEXT: mov v21.h[5], v2.h[5]
-; CHECK-GI-NEXT: mov v16.h[6], v4.h[6]
-; CHECK-GI-NEXT: mov v18.h[6], v0.h[6]
-; CHECK-GI-NEXT: mov v17.h[6], v5.h[6]
-; CHECK-GI-NEXT: mov v19.h[6], v1.h[6]
-; CHECK-GI-NEXT: mov v20.h[6], v6.h[6]
-; CHECK-GI-NEXT: mov v21.h[6], v2.h[6]
-; CHECK-GI-NEXT: mov v16.h[7], v4.h[7]
-; CHECK-GI-NEXT: mov v18.h[7], v0.h[7]
-; CHECK-GI-NEXT: mov v17.h[7], v5.h[7]
-; CHECK-GI-NEXT: mov v19.h[7], v1.h[7]
-; CHECK-GI-NEXT: mov v20.h[7], v6.h[7]
-; CHECK-GI-NEXT: mov v21.h[7], v2.h[7]
-; CHECK-GI-NEXT: mov h4, v7.h[0]
-; CHECK-GI-NEXT: fcadd v5.8h, v16.8h, v18.8h, #90
-; CHECK-GI-NEXT: mov h16, v3.h[0]
-; CHECK-GI-NEXT: fcadd v6.8h, v17.8h, v19.8h, #90
-; CHECK-GI-NEXT: fcadd v17.8h, v20.8h, v21.8h, #90
-; CHECK-GI-NEXT: mov v4.h[1], v7.h[1]
-; CHECK-GI-NEXT: mov h0, v5.h[0]
-; CHECK-GI-NEXT: mov v16.h[1], v3.h[1]
-; CHECK-GI-NEXT: mov h2, v17.h[0]
-; CHECK-GI-NEXT: mov h1, v6.h[0]
-; CHECK-GI-NEXT: mov v4.h[2], v7.h[2]
-; CHECK-GI-NEXT: mov v0.h[1], v5.h[1]
-; CHECK-GI-NEXT: mov v16.h[2], v3.h[2]
-; CHECK-GI-NEXT: mov v2.h[1], v17.h[1]
-; CHECK-GI-NEXT: mov v1.h[1], v6.h[1]
-; CHECK-GI-NEXT: mov v4.h[3], v7.h[3]
-; CHECK-GI-NEXT: mov v0.h[2], v5.h[2]
-; CHECK-GI-NEXT: mov v16.h[3], v3.h[3]
-; CHECK-GI-NEXT: mov v2.h[2], v17.h[2]
-; CHECK-GI-NEXT: mov v1.h[2], v6.h[2]
-; CHECK-GI-NEXT: mov v4.h[4], v7.h[4]
-; CHECK-GI-NEXT: mov v0.h[3], v5.h[3]
-; CHECK-GI-NEXT: mov v16.h[4], v3.h[4]
-; CHECK-GI-NEXT: mov v2.h[3], v17.h[3]
-; CHECK-GI-NEXT: mov v1.h[3], v6.h[3]
-; CHECK-GI-NEXT: mov v4.h[5], v7.h[5]
-; CHECK-GI-NEXT: mov v0.h[4], v5.h[4]
-; CHECK-GI-NEXT: mov v16.h[5], v3.h[5]
-; CHECK-GI-NEXT: mov v2.h[4], v17.h[4]
-; CHECK-GI-NEXT: mov v1.h[4], v6.h[4]
-; CHECK-GI-NEXT: mov v4.h[6], v7.h[6]
-; CHECK-GI-NEXT: mov v0.h[5], v5.h[5]
-; CHECK-GI-NEXT: mov v16.h[6], v3.h[6]
-; CHECK-GI-NEXT: mov v2.h[5], v17.h[5]
-; CHECK-GI-NEXT: mov v1.h[5], v6.h[5]
-; CHECK-GI-NEXT: mov v4.h[7], v7.h[7]
-; CHECK-GI-NEXT: mov v0.h[6], v5.h[6]
-; CHECK-GI-NEXT: mov v16.h[7], v3.h[7]
-; CHECK-GI-NEXT: mov v2.h[6], v17.h[6]
-; CHECK-GI-NEXT: mov v1.h[6], v6.h[6]
-; CHECK-GI-NEXT: mov v0.h[7], v5.h[7]
-; CHECK-GI-NEXT: fcadd v3.8h, v4.8h, v16.8h, #90
-; CHECK-GI-NEXT: mov v2.h[7], v17.h[7]
-; CHECK-GI-NEXT: mov v1.h[7], v6.h[7]
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: complex_add_v32f16:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: fcadd v2.8h, v6.8h, v2.8h, #90
+; CHECK-NEXT: fcadd v0.8h, v4.8h, v0.8h, #90
+; CHECK-NEXT: fcadd v1.8h, v5.8h, v1.8h, #90
+; CHECK-NEXT: fcadd v3.8h, v7.8h, v3.8h, #90
+; CHECK-NEXT: ret
entry:
%a.real = shufflevector <32 x half> %a, <32 x half> zeroinitializer, <16 x i32> <i32 0, i32 2, i32 4, i32 6, i32 8, i32 10, i32 12, i32 14, i32 16, i32 18, i32 20, i32 22, i32 24, i32 26, i32 28, i32 30>
%a.imag = shufflevector <32 x half> %a, <32 x half> zeroinitializer, <16 x i32> <i32 1, i32 3, i32 5, i32 7, i32 9, i32 11, i32 13, i32 15, i32 17, i32 19, i32 21, i32 23, i32 25, i32 27, i32 29, i32 31>
@@ -304,48 +168,8 @@ define <16 x half> @complex_add_v16f16_with_intrinsic(<16 x half> %a, <16 x half
;
; CHECK-GI-LABEL: complex_add_v16f16_with_intrinsic:
; CHECK-GI: // %bb.0: // %entry
-; CHECK-GI-NEXT: mov h4, v2.h[0]
-; CHECK-GI-NEXT: mov h5, v0.h[0]
-; CHECK-GI-NEXT: mov h6, v1.h[0]
-; CHECK-GI-NEXT: mov v4.h[1], v2.h[1]
-; CHECK-GI-NEXT: mov v5.h[1], v0.h[1]
-; CHECK-GI-NEXT: mov v6.h[1], v1.h[1]
-; CHECK-GI-NEXT: mov v4.h[2], v2.h[2]
-; CHECK-GI-NEXT: mov v5.h[2], v0.h[2]
-; CHECK-GI-NEXT: mov v6.h[2], v1.h[2]
-; CHECK-GI-NEXT: mov v4.h[3], v2.h[3]
-; CHECK-GI-NEXT: mov v5.h[3], v0.h[3]
-; CHECK-GI-NEXT: mov v6.h[3], v1.h[3]
-; CHECK-GI-NEXT: mov v4.h[4], v2.h[4]
-; CHECK-GI-NEXT: mov v5.h[4], v0.h[4]
-; CHECK-GI-NEXT: mov v6.h[4], v1.h[4]
-; CHECK-GI-NEXT: mov v4.h[5], v2.h[5]
-; CHECK-GI-NEXT: mov v5.h[5], v0.h[5]
-; CHECK-GI-NEXT: mov v6.h[5], v1.h[5]
-; CHECK-GI-NEXT: mov v4.h[6], v2.h[6]
-; CHECK-GI-NEXT: mov v5.h[6], v0.h[6]
-; CHECK-GI-NEXT: mov v6.h[6], v1.h[6]
-; CHECK-GI-NEXT: mov v4.h[7], v2.h[7]
-; CHECK-GI-NEXT: mov v5.h[7], v0.h[7]
-; CHECK-GI-NEXT: mov h2, v3.h[0]
-; CHECK-GI-NEXT: mov v6.h[7], v1.h[7]
-; CHECK-GI-NEXT: fcadd v4.8h, v4.8h, v5.8h, #90
-; CHECK-GI-NEXT: mov v2.h[1], v3.h[1]
-; CHECK-GI-NEXT: mov h0, v4.h[0]
-; CHECK-GI-NEXT: mov v2.h[2], v3.h[2]
-; CHECK-GI-NEXT: mov v0.h[1], v4.h[1]
-; CHECK-GI-NEXT: mov v2.h[3], v3.h[3]
-; CHECK-GI-NEXT: mov v0.h[2], v4.h[2]
-; CHECK-GI-NEXT: mov v2.h[4], v3.h[4]
-; CHECK-GI-NEXT: mov v0.h[3], v4.h[3]
-; CHECK-GI-NEXT: mov v2.h[5], v3.h[5]
-; CHECK-GI-NEXT: mov v0.h[4], v4.h[4]
-; CHECK-GI-NEXT: mov v2.h[6], v3.h[6]
-; CHECK-GI-NEXT: mov v0.h[5], v4.h[5]
-; CHECK-GI-NEXT: mov v2.h[7], v3.h[7]
-; CHECK-GI-NEXT: mov v0.h[6], v4.h[6]
-; CHECK-GI-NEXT: fcadd v1.8h, v2.8h, v6.8h, #90
-; CHECK-GI-NEXT: mov v0.h[7], v4.h[7]
+; CHECK-GI-NEXT: fcadd v0.8h, v2.8h, v0.8h, #90
+; CHECK-GI-NEXT: mov v1.16b, v0.16b
; CHECK-GI-NEXT: ret
entry:
%a.deinterleaved = tail call { <8 x half>, <8 x half> } @llvm.vector.deinterleave2.v16f16(<16 x half> %a)
>From bc0d8fb940ebc43eac7a50a4f3b12077dcf36317 Mon Sep 17 00:00:00 2001
From: Josh Rodriguez <josh.rodriguez at arm.com>
Date: Wed, 15 Jul 2026 15:01:29 +0000
Subject: [PATCH 07/10] [AArch64][GlobalISel] Clamp the AArch6 Src register to
128 bits or fewer
As AArch64 NEON registers can only be 64 or 128 bits long, clamp any larger src types to 128 bits or fewer.
If, after clamping, the src type == dst type, convert the extract_subvector into a copy.
---
.../CodeGen/GlobalISel/LegalizerHelper.cpp | 54 ++++++++++---------
.../AArch64/GISel/AArch64LegalizerInfo.cpp | 16 ++----
.../AArch64/GlobalISel/insert-subvector.ll | 14 ++---
.../AArch64/complex-deinterleaving-f16-add.ll | 4 +-
.../CodeGen/AArch64/extract-vector-elt.ll | 41 +++++++++-----
5 files changed, 65 insertions(+), 64 deletions(-)
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index 87403423dc5cb..009574c7fc0bd 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -4887,13 +4887,13 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
auto InsertionPointImm = MI.getOperand(3).getImm();
LLT VectorTy = MRI.getType(Vector);
- LLT SubvectorTy = MRI.getType(Subvector);
+ LLT DstTy = MRI.getType(Subvector);
// If so, -> concat(subvector, extract(half of vector))
// (Operands can be either way round depending on insertion point
- if (VectorTy.getSizeInBits() == SubvectorTy.getSizeInBits() * 2) {
+ if (VectorTy.getSizeInBits() == DstTy.getSizeInBits() * 2) {
bool InsertInLowHalf = InsertionPointImm == 0;
auto Extract = MIRBuilder.buildExtractSubvector(
- SubvectorTy, Vector,
+ DstTy, Vector,
(uint64_t)(InsertInLowHalf ? VectorTy.getNumElements() / 2 : 0));
auto LowHalf = InsertInLowHalf ? Subvector : Extract.getReg(0);
@@ -4915,7 +4915,7 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
for (int i = 0; i < VectorTy.getNumElements(); i++) {
// If this index is within bounds, put subvector's index into mask
if (i >= InsertionPointImm &&
- i < InsertionPointImm + SubvectorTy.getNumElements())
+ i < InsertionPointImm + DstTy.getNumElements())
Mask.push_back(VectorTy.getNumElements() + i - InsertionPointImm);
else
Mask.push_back(i);
@@ -4929,33 +4929,33 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
}
}
case G_EXTRACT_SUBVECTOR: {
- Register Subvector = MI.getOperand(0).getReg();
- Register Vector = MI.getOperand(1).getReg();
+ Register DstReg = MI.getOperand(0).getReg();
+ Register SrcReg = MI.getOperand(1).getReg();
uint64_t ExtractionPointImm = MI.getOperand(2).getImm();
- LLT VectorTy = MRI.getType(Vector);
- LLT SubvectorTy = MRI.getType(Subvector);
+ LLT SrcTy = MRI.getType(SrcReg);
+ LLT DstTy = MRI.getType(DstReg);
- if (VectorTy.isScalable() || SubvectorTy.isScalable())
+ if (SrcTy.isScalable() || DstTy.isScalable())
return UnableToLegalize;
- if (VectorTy.getScalarType() != SubvectorTy.getScalarType())
+ if (SrcTy.getScalarType() != DstTy.getScalarType())
return UnableToLegalize;
- if (VectorTy.getNumElements() <= SubvectorTy.getNumElements())
+ if (SrcTy.getNumElements() < DstTy.getNumElements())
return UnableToLegalize;
// extract_subvector = build_vector(extract_element, extract_element, ...)
SmallVector<Register> ExtractedElements;
- for (uint64_t i = 0; i < SubvectorTy.getNumElements(); i++) {
+ for (uint64_t i = 0; i < DstTy.getNumElements(); i++) {
ExtractedElements.push_back(
MIRBuilder
- .buildExtractVectorElementConstant(VectorTy.getScalarType(),
- Vector, ExtractionPointImm + i)
+ .buildExtractVectorElementConstant(SrcTy.getScalarType(), SrcReg,
+ ExtractionPointImm + i)
.getReg(0));
}
- MIRBuilder.buildBuildVector(Subvector, ExtractedElements);
+ MIRBuilder.buildBuildVector(DstReg, ExtractedElements);
MI.eraseFromParent();
return Legalized;
}
@@ -5833,20 +5833,24 @@ LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx,
LLT SrcTy = MRI.getType(SrcReg);
uint64_t InsertionPointImm = MI.getOperand(2).getImm();
- // If Dst > 128 bits, then cannot legalize (yet)
- if (DstTy.getSizeInBits() > 128)
+ // If Dst > NarrowTy bits, then cannot legalize
+ if (DstTy.getSizeInBits() > NarrowTy.getSizeInBits())
return UnableToLegalize;
- // If the extract is into a vector half its size, then convert to a copy
- if (2 * DstTy.getNumElements() != SrcTy.getNumElements())
+
+ // If DstTy's size is not a multiple of NarrowTy's, then cannot legalize
+ if (DstTy.getSizeInBits() % NarrowTy.getSizeInBits() != 0)
return UnableToLegalize;
- // extract_subvector(large_vector) -> copy(high/low half of
- // unmerge_values(large_vector, 2))
- auto Unmerge = MIRBuilder.buildUnmerge(DstTy, SrcReg);
- if (InsertionPointImm == 0)
- MIRBuilder.buildCopy(DstReg, Unmerge.getReg(0));
+ auto Unmerge = MIRBuilder.buildUnmerge(NarrowTy, SrcReg);
+ uint64_t RequiredSubvectorIndex =
+ InsertionPointImm / NarrowTy.getNumElements();
+ // If Dst and Narrow are both same size, convert to a copy
+ if (DstTy.getNumElements() == NarrowTy.getNumElements())
+ MIRBuilder.buildCopy(DstReg, Unmerge.getReg(RequiredSubvectorIndex));
else
- MIRBuilder.buildCopy(DstReg, Unmerge.getReg(0));
+ MIRBuilder.buildExtractSubvector(
+ DstTy, Unmerge.getReg(RequiredSubvectorIndex),
+ InsertionPointImm % NarrowTy.getNumElements());
MI.eraseFromParent();
return Legalized;
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
index efcb12b4fa603..90f30de118929 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
@@ -1344,19 +1344,9 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST)
getActionDefinitionsBuilder(G_EXTRACT_SUBVECTOR)
.legalFor({{v8s8, v16s8}, {v4s16, v8s16}, {v2s32, v4s32}})
.widenScalarOrEltToNextPow2(0)
- .fewerElementsIf(
- [=](const LegalityQuery &Q) {
- LLT SrcTy = Q.Types[1];
- if (SrcTy.isScalar())
- return false;
- if (!isPowerOf2_32(SrcTy.getNumElements()))
- return false;
- return SrcTy.getSizeInBits() > 128;
- },
- [=](const LegalityQuery &Q) {
- LLT SrcTy = Q.Types[1];
- return std::make_pair(1, SrcTy.divide(2));
- })
+ .clampNumElements(1, v8s8, v16s8)
+ .clampNumElements(1, v4s16, v8s16)
+ .clampNumElements(1, v2s32, v4s32)
.lower()
.immIdx(0); // Inform verifier imm idx 0 is handled.
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/insert-subvector.ll b/llvm/test/CodeGen/AArch64/GlobalISel/insert-subvector.ll
index 419a574f17b64..d2f9723a6e756 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/insert-subvector.ll
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/insert-subvector.ll
@@ -26,16 +26,10 @@ entry:
}
define <8 x i32> @insert_v8i32_v4i32_high(<8 x i32> %a, <4 x i32> %b) {
-; CHECK-SD-LABEL: insert_v8i32_v4i32_high:
-; CHECK-SD: // %bb.0: // %entry
-; CHECK-SD-NEXT: mov v0.16b, v2.16b
-; CHECK-SD-NEXT: ret
-;
-; CHECK-GI-LABEL: insert_v8i32_v4i32_high:
-; CHECK-GI: // %bb.0: // %entry
-; CHECK-GI-NEXT: mov v1.16b, v0.16b
-; CHECK-GI-NEXT: mov v0.16b, v2.16b
-; CHECK-GI-NEXT: ret
+; CHECK-LABEL: insert_v8i32_v4i32_high:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: mov v0.16b, v2.16b
+; CHECK-NEXT: ret
entry:
%vector = call <8 x i32> @llvm.vector.insert.v8i32.v4i32(<8 x i32> %a, <4 x i32> %b, i64 0)
ret <8 x i32> %vector
diff --git a/llvm/test/CodeGen/AArch64/complex-deinterleaving-f16-add.ll b/llvm/test/CodeGen/AArch64/complex-deinterleaving-f16-add.ll
index 6441effcc55a9..acbe0c4097daa 100644
--- a/llvm/test/CodeGen/AArch64/complex-deinterleaving-f16-add.ll
+++ b/llvm/test/CodeGen/AArch64/complex-deinterleaving-f16-add.ll
@@ -87,7 +87,7 @@ define <16 x half> @complex_add_v16f16(<16 x half> %a, <16 x half> %b) {
; CHECK-GI-LABEL: complex_add_v16f16:
; CHECK-GI: // %bb.0: // %entry
; CHECK-GI-NEXT: fcadd v0.8h, v2.8h, v0.8h, #90
-; CHECK-GI-NEXT: mov v1.16b, v0.16b
+; CHECK-GI-NEXT: fcadd v1.8h, v3.8h, v1.8h, #90
; CHECK-GI-NEXT: ret
entry:
%a.real = shufflevector <16 x half> %a, <16 x half> zeroinitializer, <8 x i32> <i32 0, i32 2, i32 4, i32 6, i32 8, i32 10, i32 12, i32 14>
@@ -169,7 +169,7 @@ define <16 x half> @complex_add_v16f16_with_intrinsic(<16 x half> %a, <16 x half
; CHECK-GI-LABEL: complex_add_v16f16_with_intrinsic:
; CHECK-GI: // %bb.0: // %entry
; CHECK-GI-NEXT: fcadd v0.8h, v2.8h, v0.8h, #90
-; CHECK-GI-NEXT: mov v1.16b, v0.16b
+; CHECK-GI-NEXT: fcadd v1.8h, v3.8h, v1.8h, #90
; CHECK-GI-NEXT: ret
entry:
%a.deinterleaved = tail call { <8 x half>, <8 x half> } @llvm.vector.deinterleave2.v16f16(<16 x half> %a)
diff --git a/llvm/test/CodeGen/AArch64/extract-vector-elt.ll b/llvm/test/CodeGen/AArch64/extract-vector-elt.ll
index bd312737cade8..3ab413b50e17d 100644
--- a/llvm/test/CodeGen/AArch64/extract-vector-elt.ll
+++ b/llvm/test/CodeGen/AArch64/extract-vector-elt.ll
@@ -2,9 +2,6 @@
; RUN: llc -mtriple=aarch64 -verify-machineinstrs %s -o - | FileCheck %s --check-prefixes=CHECK,CHECK-SD
; RUN: llc -mtriple=aarch64 -global-isel -global-isel-abort=2 -verify-machineinstrs %s -o - 2>&1 | FileCheck %s --check-prefixes=CHECK,CHECK-GI
-; CHECK-GI: warning: Instruction selection used fallback path for extract_v4i32_vector_extract
-; CHECK-GI-NEXT: warning: Instruction selection used fallback path for extract_v4i32_vector_extract_const
-
define i64 @extract_v2i64_undef_index(<2 x i64> %a, i32 %c) {
; CHECK-SD-LABEL: extract_v2i64_undef_index:
; CHECK-SD: // %bb.0: // %entry
@@ -816,17 +813,33 @@ entry:
}
define i32 @extract_v4i32_vector_extract(<4 x i32> %a, <2 x i32> %b, i32 %c) {
-; CHECK-LABEL: extract_v4i32_vector_extract:
-; CHECK: // %bb.0: // %entry
-; CHECK-NEXT: sub sp, sp, #16
-; CHECK-NEXT: .cfi_def_cfa_offset 16
-; CHECK-NEXT: mov x8, sp
-; CHECK-NEXT: // kill: def $w0 killed $w0 def $x0
-; CHECK-NEXT: str q0, [sp]
-; CHECK-NEXT: bfi x8, x0, #2, #2
-; CHECK-NEXT: ldr w0, [x8]
-; CHECK-NEXT: add sp, sp, #16
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: extract_v4i32_vector_extract:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: sub sp, sp, #16
+; CHECK-SD-NEXT: .cfi_def_cfa_offset 16
+; CHECK-SD-NEXT: mov x8, sp
+; CHECK-SD-NEXT: // kill: def $w0 killed $w0 def $x0
+; CHECK-SD-NEXT: str q0, [sp]
+; CHECK-SD-NEXT: bfi x8, x0, #2, #2
+; CHECK-SD-NEXT: ldr w0, [x8]
+; CHECK-SD-NEXT: add sp, sp, #16
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: extract_v4i32_vector_extract:
+; CHECK-GI: // %bb.0: // %entry
+; CHECK-GI-NEXT: sub sp, sp, #16
+; CHECK-GI-NEXT: .cfi_def_cfa_offset 16
+; CHECK-GI-NEXT: mov s1, v0.s[0]
+; CHECK-GI-NEXT: mov w9, w0
+; CHECK-GI-NEXT: mov x8, sp
+; CHECK-GI-NEXT: and x9, x9, #0x3
+; CHECK-GI-NEXT: mov v1.s[1], v0.s[1]
+; CHECK-GI-NEXT: mov v1.s[2], v0.s[2]
+; CHECK-GI-NEXT: mov v1.s[3], v0.s[3]
+; CHECK-GI-NEXT: str q1, [sp]
+; CHECK-GI-NEXT: ldr w0, [x8, x9, lsl #2]
+; CHECK-GI-NEXT: add sp, sp, #16
+; CHECK-GI-NEXT: ret
entry:
%vector = call <4 x i32> @llvm.vector.extract.v2i32.v4i32(<4 x i32> %a, i64 0)
%d = extractelement <4 x i32> %vector, i32 %c
>From 0abc65a1a6823bdd98904dee79df241a49f8453f Mon Sep 17 00:00:00 2001
From: Josh Rodriguez <josh.rodriguez at arm.com>
Date: Thu, 16 Jul 2026 09:54:20 +0000
Subject: [PATCH 08/10] [AArch64][GlobalISel] Remove unused variable
---
llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp | 1 -
1 file changed, 1 deletion(-)
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index 009574c7fc0bd..4d031234efe05 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -5830,7 +5830,6 @@ LegalizerHelper::fewerElementsVector(MachineInstr &MI, unsigned TypeIdx,
Register DstReg = MI.getOperand(0).getReg();
LLT DstTy = MRI.getType(DstReg);
Register SrcReg = MI.getOperand(1).getReg();
- LLT SrcTy = MRI.getType(SrcReg);
uint64_t InsertionPointImm = MI.getOperand(2).getImm();
// If Dst > NarrowTy bits, then cannot legalize
>From ad072c90cc895aeab3adf8a583e840600b19dd40 Mon Sep 17 00:00:00 2001
From: Josh Rodriguez <josh.rodriguez at arm.com>
Date: Thu, 16 Jul 2026 13:29:41 +0000
Subject: [PATCH 09/10] [AArch64][GlobalISel] Create extract_subvector test
file
Create file that tests GI/SDAG compilation of extract_subvector. Tests included are every possible extract subvector from/to:
v4i32, v8i32 --> v4i32, v2i32
v8i16, v16i16 --> v8i16, v4i16
---
.../AArch64/GlobalISel/extract-subvector.ll | 197 ++++++++++++++++++
1 file changed, 197 insertions(+)
create mode 100644 llvm/test/CodeGen/AArch64/GlobalISel/extract-subvector.ll
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/extract-subvector.ll b/llvm/test/CodeGen/AArch64/GlobalISel/extract-subvector.ll
new file mode 100644
index 0000000000000..04d994236be8f
--- /dev/null
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/extract-subvector.ll
@@ -0,0 +1,197 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+
+; RUN: llc -mtriple=aarch64 %s -o - | FileCheck --check-prefix=CHECK --check-prefix=CHECK-SD %s
+; RUN: llc -mtriple=aarch64 -global-isel -global-isel-abort=2 %s -o - 2>&1 | FileCheck --check-prefix=CHECK --check-prefix=CHECK-GI %s
+
+define <4 x i32> @extract_v4i32_v8i32_low(<8 x i32> %a) {
+; CHECK-LABEL: extract_v4i32_v8i32_low:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: ret
+entry:
+ %vector = call <4 x i32> @llvm.vector.extract.subvector.v4i32.v8i32(<8 x i32> %a, i64 0)
+ ret <4 x i32> %vector
+}
+
+define <4 x i32> @extract_v4i32_v8i32_high(<8 x i32> %a) {
+; CHECK-LABEL: extract_v4i32_v8i32_high:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: mov v0.16b, v1.16b
+; CHECK-NEXT: ret
+entry:
+ %vector = call <4 x i32> @llvm.vector.extract.subvector.v4i32.v8i32(<8 x i32> %a, i64 4)
+ ret <4 x i32> %vector
+}
+
+define <4 x i32> @extract_v4i32_v4i32(<4 x i32> %a) {
+; CHECK-SD-LABEL: extract_v4i32_v4i32:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: extract_v4i32_v4i32:
+; CHECK-GI: // %bb.0: // %entry
+; CHECK-GI-NEXT: mov s1, v0.s[0]
+; CHECK-GI-NEXT: mov v1.s[1], v0.s[1]
+; CHECK-GI-NEXT: mov v1.s[2], v0.s[2]
+; CHECK-GI-NEXT: mov v1.s[3], v0.s[3]
+; CHECK-GI-NEXT: mov v0.16b, v1.16b
+; CHECK-GI-NEXT: ret
+entry:
+ %vector = call <4 x i32> @llvm.vector.extract.subvector.v4i32.v4i32(<4 x i32> %a, i64 0)
+ ret <4 x i32> %vector
+}
+
+define <2 x i32> @extract_v2i32_v8i32_low(<8 x i32> %a) {
+; CHECK-LABEL: extract_v2i32_v8i32_low:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: // kill: def $d0 killed $d0 killed $q0
+; CHECK-NEXT: ret
+entry:
+ %vector = call <2 x i32> @llvm.vector.extract.subvector.v2i32.v8i32(<8 x i32> %a, i64 0)
+ ret <2 x i32> %vector
+}
+
+define <2 x i32> @extract_v2i32_v8i32_high(<8 x i32> %a) {
+; CHECK-LABEL: extract_v2i32_v8i32_high:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: mov d0, v1.d[1]
+; CHECK-NEXT: ret
+entry:
+ %vector = call <2 x i32> @llvm.vector.extract.subvector.v2i32.v8i32(<8 x i32> %a, i64 6)
+ ret <2 x i32> %vector
+}
+
+define <2 x i32> @extract_v2i32_v4i32_low(<4 x i32> %a) {
+; CHECK-LABEL: extract_v2i32_v4i32_low:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: // kill: def $d0 killed $d0 killed $q0
+; CHECK-NEXT: ret
+entry:
+ %vector = call <2 x i32> @llvm.vector.extract.subvector.v2i32.v4i32(<4 x i32> %a, i64 0)
+ ret <2 x i32> %vector
+}
+
+define <2 x i32> @extract_v2i32_v4i32_high(<4 x i32> %a) {
+; CHECK-LABEL: extract_v2i32_v4i32_high:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: mov d0, v0.d[1]
+; CHECK-NEXT: ret
+entry:
+ %vector = call <2 x i32> @llvm.vector.extract.subvector.v2i32.v4i32(<4 x i32> %a, i64 2)
+ ret <2 x i32> %vector
+}
+define <2 x i32> @extract_v2i32_v2i32(<2 x i32> %a) {
+; CHECK-SD-LABEL: extract_v2i32_v2i32:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: extract_v2i32_v2i32:
+; CHECK-GI: // %bb.0: // %entry
+; CHECK-GI-NEXT: // kill: def $d0 killed $d0 def $q0
+; CHECK-GI-NEXT: mov v1.s[0], v0.s[0]
+; CHECK-GI-NEXT: mov v1.s[1], v0.s[1]
+; CHECK-GI-NEXT: fmov d0, d1
+; CHECK-GI-NEXT: ret
+entry:
+ %vector = call <2 x i32> @llvm.vector.extract.subvector.v2i32.v2i32(<2 x i32> %a, i64 0)
+ ret <2 x i32> %vector
+}
+
+define <8 x i16> @extract_v8i16_v16i16_low(<16 x i16> %a) {
+; CHECK-LABEL: extract_v8i16_v16i16_low:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: ret
+entry:
+ %vector = call <8 x i16> @llvm.vector.extract.subvector.v8i16.v16i16(<16 x i16> %a, i64 0)
+ ret <8 x i16> %vector
+}
+
+define <8 x i16> @extract_v8i16_v16i16_high(<16 x i16> %a) {
+; CHECK-LABEL: extract_v8i16_v16i16_high:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: mov v0.16b, v1.16b
+; CHECK-NEXT: ret
+entry:
+ %vector = call <8 x i16> @llvm.vector.extract.subvector.v8i16.v16i16(<16 x i16> %a, i64 8)
+ ret <8 x i16> %vector
+}
+define <8 x i16> @extract_v8i16_v8i16(<8 x i16> %a) {
+; CHECK-SD-LABEL: extract_v8i16_v8i16:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: extract_v8i16_v8i16:
+; CHECK-GI: // %bb.0: // %entry
+; CHECK-GI-NEXT: mov h1, v0.h[0]
+; CHECK-GI-NEXT: mov v1.h[1], v0.h[1]
+; CHECK-GI-NEXT: mov v1.h[2], v0.h[2]
+; CHECK-GI-NEXT: mov v1.h[3], v0.h[3]
+; CHECK-GI-NEXT: mov v1.h[4], v0.h[4]
+; CHECK-GI-NEXT: mov v1.h[5], v0.h[5]
+; CHECK-GI-NEXT: mov v1.h[6], v0.h[6]
+; CHECK-GI-NEXT: mov v1.h[7], v0.h[7]
+; CHECK-GI-NEXT: mov v0.16b, v1.16b
+; CHECK-GI-NEXT: ret
+entry:
+ %vector = call <8 x i16> @llvm.vector.extract.subvector.v8i16.v8i16(<8 x i16> %a, i64 0)
+ ret <8 x i16> %vector
+}
+
+define <4 x i16> @extract_v4i16_v16i16_low(<16 x i16> %a) {
+; CHECK-LABEL: extract_v4i16_v16i16_low:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: // kill: def $d0 killed $d0 killed $q0
+; CHECK-NEXT: ret
+entry:
+ %vector = call <4 x i16> @llvm.vector.extract.subvector.v4i16.v16i16(<16 x i16> %a, i64 0)
+ ret <4 x i16> %vector
+}
+
+define <4 x i16> @extract_v4i16_v16i16_high(<16 x i16> %a) {
+; CHECK-LABEL: extract_v4i16_v16i16_high:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: mov d0, v1.d[1]
+; CHECK-NEXT: ret
+entry:
+ %vector = call <4 x i16> @llvm.vector.extract.subvector.v4i16.v16i16(<16 x i16> %a, i64 12)
+ ret <4 x i16> %vector
+}
+
+define <4 x i16> @extract_v4i16_v8i16_low(<8 x i16> %a) {
+; CHECK-LABEL: extract_v4i16_v8i16_low:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: // kill: def $d0 killed $d0 killed $q0
+; CHECK-NEXT: ret
+entry:
+ %vector = call <4 x i16> @llvm.vector.extract.subvector.v4i16.v8i16(<8 x i16> %a, i64 0)
+ ret <4 x i16> %vector
+}
+
+define <4 x i16> @extract_v4i16_v8i16_high(<8 x i16> %a) {
+; CHECK-LABEL: extract_v4i16_v8i16_high:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: mov d0, v0.d[1]
+; CHECK-NEXT: ret
+entry:
+ %vector = call <4 x i16> @llvm.vector.extract.subvector.v4i16.v8i16(<8 x i16> %a, i64 4)
+ ret <4 x i16> %vector
+}
+
+define <4 x i16> @extract_v4i16_v4i16(<4 x i16> %a) {
+; CHECK-SD-LABEL: extract_v4i16_v4i16:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: extract_v4i16_v4i16:
+; CHECK-GI: // %bb.0: // %entry
+; CHECK-GI-NEXT: // kill: def $d0 killed $d0 def $q0
+; CHECK-GI-NEXT: mov v1.h[0], v0.h[0]
+; CHECK-GI-NEXT: mov v1.h[1], v0.h[1]
+; CHECK-GI-NEXT: mov v1.h[2], v0.h[2]
+; CHECK-GI-NEXT: mov v1.h[3], v0.h[3]
+; CHECK-GI-NEXT: fmov d0, d1
+; CHECK-GI-NEXT: ret
+entry:
+ %vector = call <4 x i16> @llvm.vector.extract.subvector.v4i16.v4i16(<4 x i16> %a, i64 0)
+ ret <4 x i16> %vector
+}
+
>From c6ce50e9c6de331a03486da627c9340a0e2703e2 Mon Sep 17 00:00:00 2001
From: Josh Rodriguez <josh.rodriguez at arm.com>
Date: Thu, 16 Jul 2026 13:56:41 +0000
Subject: [PATCH 10/10] [AArch64][GlobalISel]Add i8 vectors test checks
Assisted by Codex
---
.../AArch64/GlobalISel/extract-subvector.ll | 111 ++++++++++++++++++
1 file changed, 111 insertions(+)
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/extract-subvector.ll b/llvm/test/CodeGen/AArch64/GlobalISel/extract-subvector.ll
index 04d994236be8f..40bc7458c6968 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/extract-subvector.ll
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/extract-subvector.ll
@@ -195,3 +195,114 @@ entry:
ret <4 x i16> %vector
}
+define <16 x i8> @extract_v16i8_v32i8_low(<32 x i8> %a) {
+; CHECK-LABEL: extract_v16i8_v32i8_low:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: ret
+entry:
+ %vector = call <16 x i8> @llvm.vector.extract.subvector.v16i8.v32i8(<32 x i8> %a, i64 0)
+ ret <16 x i8> %vector
+}
+
+define <16 x i8> @extract_v16i8_v32i8_high(<32 x i8> %a) {
+; CHECK-LABEL: extract_v16i8_v32i8_high:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: mov v0.16b, v1.16b
+; CHECK-NEXT: ret
+entry:
+ %vector = call <16 x i8> @llvm.vector.extract.subvector.v16i8.v32i8(<32 x i8> %a, i64 16)
+ ret <16 x i8> %vector
+}
+
+define <16 x i8> @extract_v16i8_v16i8(<16 x i8> %a) {
+; CHECK-SD-LABEL: extract_v16i8_v16i8:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: extract_v16i8_v16i8:
+; CHECK-GI: // %bb.0: // %entry
+; CHECK-GI-NEXT: mov b1, v0.b[0]
+; CHECK-GI-NEXT: mov v1.b[1], v0.b[1]
+; CHECK-GI-NEXT: mov v1.b[2], v0.b[2]
+; CHECK-GI-NEXT: mov v1.b[3], v0.b[3]
+; CHECK-GI-NEXT: mov v1.b[4], v0.b[4]
+; CHECK-GI-NEXT: mov v1.b[5], v0.b[5]
+; CHECK-GI-NEXT: mov v1.b[6], v0.b[6]
+; CHECK-GI-NEXT: mov v1.b[7], v0.b[7]
+; CHECK-GI-NEXT: mov v1.b[8], v0.b[8]
+; CHECK-GI-NEXT: mov v1.b[9], v0.b[9]
+; CHECK-GI-NEXT: mov v1.b[10], v0.b[10]
+; CHECK-GI-NEXT: mov v1.b[11], v0.b[11]
+; CHECK-GI-NEXT: mov v1.b[12], v0.b[12]
+; CHECK-GI-NEXT: mov v1.b[13], v0.b[13]
+; CHECK-GI-NEXT: mov v1.b[14], v0.b[14]
+; CHECK-GI-NEXT: mov v1.b[15], v0.b[15]
+; CHECK-GI-NEXT: mov v0.16b, v1.16b
+; CHECK-GI-NEXT: ret
+entry:
+ %vector = call <16 x i8> @llvm.vector.extract.subvector.v16i8.v16i8(<16 x i8> %a, i64 0)
+ ret <16 x i8> %vector
+}
+
+define <8 x i8> @extract_v8i8_v32i8_low(<32 x i8> %a) {
+; CHECK-LABEL: extract_v8i8_v32i8_low:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: // kill: def $d0 killed $d0 killed $q0
+; CHECK-NEXT: ret
+entry:
+ %vector = call <8 x i8> @llvm.vector.extract.subvector.v8i8.v32i8(<32 x i8> %a, i64 0)
+ ret <8 x i8> %vector
+}
+
+define <8 x i8> @extract_v8i8_v32i8_high(<32 x i8> %a) {
+; CHECK-LABEL: extract_v8i8_v32i8_high:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: mov d0, v1.d[1]
+; CHECK-NEXT: ret
+entry:
+ %vector = call <8 x i8> @llvm.vector.extract.subvector.v8i8.v32i8(<32 x i8> %a, i64 24)
+ ret <8 x i8> %vector
+}
+
+define <8 x i8> @extract_v8i8_v16i8_low(<16 x i8> %a) {
+; CHECK-LABEL: extract_v8i8_v16i8_low:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: // kill: def $d0 killed $d0 killed $q0
+; CHECK-NEXT: ret
+entry:
+ %vector = call <8 x i8> @llvm.vector.extract.subvector.v8i8.v16i8(<16 x i8> %a, i64 0)
+ ret <8 x i8> %vector
+}
+
+define <8 x i8> @extract_v8i8_v16i8_high(<16 x i8> %a) {
+; CHECK-LABEL: extract_v8i8_v16i8_high:
+; CHECK: // %bb.0: // %entry
+; CHECK-NEXT: mov d0, v0.d[1]
+; CHECK-NEXT: ret
+entry:
+ %vector = call <8 x i8> @llvm.vector.extract.subvector.v8i8.v16i8(<16 x i8> %a, i64 8)
+ ret <8 x i8> %vector
+}
+
+define <8 x i8> @extract_v8i8_v8i8(<8 x i8> %a) {
+; CHECK-SD-LABEL: extract_v8i8_v8i8:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: extract_v8i8_v8i8:
+; CHECK-GI: // %bb.0: // %entry
+; CHECK-GI-NEXT: // kill: def $d0 killed $d0 def $q0
+; CHECK-GI-NEXT: mov v1.b[0], v0.b[0]
+; CHECK-GI-NEXT: mov v1.b[1], v0.b[1]
+; CHECK-GI-NEXT: mov v1.b[2], v0.b[2]
+; CHECK-GI-NEXT: mov v1.b[3], v0.b[3]
+; CHECK-GI-NEXT: mov v1.b[4], v0.b[4]
+; CHECK-GI-NEXT: mov v1.b[5], v0.b[5]
+; CHECK-GI-NEXT: mov v1.b[6], v0.b[6]
+; CHECK-GI-NEXT: mov v1.b[7], v0.b[7]
+; CHECK-GI-NEXT: fmov d0, d1
+; CHECK-GI-NEXT: ret
+entry:
+ %vector = call <8 x i8> @llvm.vector.extract.subvector.v8i8.v8i8(<8 x i8> %a, i64 0)
+ ret <8 x i8> %vector
+}
More information about the llvm-commits
mailing list