[llvm] [AArch64][GlobalISel] Add legalisation for G_INSERT_SUBVECTOR (PR #205349)
Joshua Rodriguez via llvm-commits
llvm-commits at lists.llvm.org
Thu Jun 25 07:25:45 PDT 2026
https://github.com/JoshdRod updated https://github.com/llvm/llvm-project/pull/205349
>From 3f8492ab8df093256f6000789058fcd96c081862 Mon Sep 17 00:00:00 2001
From: Josh Rodriguez <josh.rodriguez at arm.com>
Date: Fri, 12 Jun 2026 10:17:39 +0000
Subject: [PATCH 01/10] [AArch64][GlobalISel] Add basic legalisation rules for
G_INSERT_SUBVECTOR
---
.../AArch64/GISel/AArch64LegalizerInfo.cpp | 18 ++++++++++++++++++
1 file changed, 18 insertions(+)
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
index e6521a211226e..89dfeb97c82cc 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
@@ -400,6 +400,24 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST)
.scalarizeIf(scalarOrEltWiderThan(0, 32), 0)
.scalarSameSizeAs(0, 1);
+ getActionDefinitionsBuilder(G_INSERT_SUBVECTOR)
+ .legalFor({{v16i8, v16i8},
+ {v16i8, v8i8},
+ {v8i16, v8i16},
+ {v8i16, v4i16},
+ {v4i32, v4i32},
+ {v4i32, v2i32}})
+ .immIdx(0); // Inform verifier imm idx 0 is handled.
+ //.widenScalarToNextPow2(1, /*Min=*/32)
+ //.clampScalar(1, s32, s64)
+ //.widenScalarOrEltToNextPow2OrMinSize(1, /*Min=*/8)
+ //.clampNumElements(0, v8s8, v16s8)
+ //.clampNumElements(0, v4s16, v8s16)
+ //.clampNumElements(0, v2s32, v4s32)
+ //.moreElementsToNextPow2(0)
+ //.scalarizeIf(scalarOrEltWiderThan(0, 32), 0)
+ //.scalarSameSizeAs(0, 1);
+
getActionDefinitionsBuilder(G_CTLZ_ZERO_POISON).lower();
getActionDefinitionsBuilder(G_CTTZ)
>From 0d271ab65bf3601e8c0216a8adc976953971c0cc Mon Sep 17 00:00:00 2001
From: Josh Rodriguez <josh.rodriguez at arm.com>
Date: Fri, 12 Jun 2026 15:17:37 +0000
Subject: [PATCH 02/10] [AArch64][GlobalISel]! Add support for half-and-half
subvector inserts
Some subvector inserts involve inserting half of one vector into another.
This can be lowered to concat(subvector, extract(vector)).
---
.../CodeGen/GlobalISel/LegalizerHelper.cpp | 40 ++++++++++++++++++-
llvm/lib/Target/AArch64/AArch64InstrGISel.td | 1 +
.../AArch64/GISel/AArch64LegalizerInfo.cpp | 15 +++----
3 files changed, 48 insertions(+), 8 deletions(-)
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index 8c38d8ce79d59..8ca8b57cf1082 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -4572,7 +4572,6 @@ void LegalizerHelper::changeOpcode(MachineInstr &MI, unsigned NewOpcode) {
LegalizerHelper::LegalizeResult
LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
using namespace TargetOpcode;
-
switch(MI.getOpcode()) {
default:
return UnableToLegalize;
@@ -4877,6 +4876,45 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
return lowerVECTOR_COMPRESS(MI);
case G_DYN_STACKALLOC:
return lowerDynStackAlloc(MI);
+ case G_INSERT_SUBVECTOR: {
+ if (MRI.getType(MI.getOperand(1).getReg()).isScalable()
+ || MRI.getType(MI.getOperand(2).getReg()).isScalable())
+ return UnableToLegalize;
+
+ // Check that subvector is half size of main vector
+ Register Vector = MI.getOperand(1).getReg();
+ Register Subvector = MI.getOperand(2).getReg();
+ auto insertionPointImm = MI.getOperand(3).getImm();
+
+ LLT VectorTy = MRI.getType(Vector);
+ LLT SubvectorTy = 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)
+ {
+ bool insertInLowHalf = insertionPointImm == 0;
+ auto extract = MIRBuilder.buildInstr(TargetOpcode::G_EXTRACT_SUBVECTOR,
+ {SubvectorTy},
+ {Vector, (uint64_t)(insertInLowHalf ? VectorTy.getElementCount().getKnownMinValue() / 2 : 0)});
+
+ auto LowHalf = insertInLowHalf ? Subvector : extract.getReg(0);
+ auto HighHalf = insertInLowHalf ? extract.getReg(0) : Subvector;
+
+ MIRBuilder.buildInstr(TargetOpcode::G_CONCAT_VECTORS,
+ {MI.getOperand(0)},
+ {LowHalf, HighHalf});
+ MI.eraseFromParent();
+ return Legalized;
+ }
+ // Else -> shuffle
+ else
+ {
+ return UnableToLegalize;
+ }
+ // Look up what sdag does**
+ // The g opcodes should all be supported by gi
+ // Make sdag tests works for GI
+ }
case G_STACKSAVE:
return lowerStackSave(MI);
case G_STACKRESTORE:
diff --git a/llvm/lib/Target/AArch64/AArch64InstrGISel.td b/llvm/lib/Target/AArch64/AArch64InstrGISel.td
index ec95448f61043..f56deb14b8a5f 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrGISel.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrGISel.td
@@ -349,6 +349,7 @@ def : GINodeEquiv<G_SLI, AArch64vsli>;
def : GINodeEquiv<G_SRI, AArch64vsri>;
def : GINodeEquiv<G_EXTRACT_VECTOR_ELT, vector_extract>;
+def : GINodeEquiv<G_INSERT_SUBVECTOR, insert_subvector>;
def : GINodeEquiv<G_AARCH64_PREFETCH, AArch64Prefetch>;
def : GINodeEquiv<G_AARCH64_RANGE_PREFETCH, AArch64RangePrefetch>;
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
index 89dfeb97c82cc..4273fae5fa118 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
@@ -401,13 +401,14 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST)
.scalarSameSizeAs(0, 1);
getActionDefinitionsBuilder(G_INSERT_SUBVECTOR)
- .legalFor({{v16i8, v16i8},
- {v16i8, v8i8},
- {v8i16, v8i16},
- {v8i16, v4i16},
- {v4i32, v4i32},
- {v4i32, v2i32}})
- .immIdx(0); // Inform verifier imm idx 0 is handled.
+ .lower(); // go to legalizerhelper.cpp
+ //.legalFor({{v16i8, v16i8},
+ // {v16i8, v8i8},
+ // {v8i16, v8i16},
+ // {v8i16, v4i16},
+ // {v4i32, v4i32},
+ // {v4i32, v2i32}})
+ //.immIdx(0); // Inform verifier imm idx 0 is handled.
//.widenScalarToNextPow2(1, /*Min=*/32)
//.clampScalar(1, s32, s64)
//.widenScalarOrEltToNextPow2OrMinSize(1, /*Min=*/8)
>From 5fba05378f2ac1f98042dd07085d89b721f0e4d4 Mon Sep 17 00:00:00 2001
From: Josh Rodriguez <josh.rodriguez at arm.com>
Date: Fri, 19 Jun 2026 16:03:28 +0000
Subject: [PATCH 03/10] [AArch64][GlobalISel] Add support for irregular-sized
subvector inserts
There are two types of subvector inserts.
1. Half-and-half
Vector V is double the size of subvector W. A subvector insert of W into V can be expressed as concat(W, extract(correct half of V)).
2. Irregular
V is NOT double the size of W. Hence, we must express a subvector insert of W into V as a shuffle(V, W, Mask).
Add logic for this shuffle(V, W, Mask).
Note: Shuffle takes 2 vectors of equal length and returns a vector with some of the elements of its inputs, in an order determined by the mask.
The way it gets to its result can be thought of like this: the V and W are concatenated into one big vector, and the mask's elements map to the indices in the big vector of each element in the resulting vector.
---
.../CodeGen/GlobalISel/LegalizerHelper.cpp | 22 +++++++++++++++++--
1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index 8ca8b57cf1082..ddcaeaa558095 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -4906,10 +4906,28 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
MI.eraseFromParent();
return Legalized;
}
- // Else -> shuffle
+ // Else -> shuffle(vector, extend(subvector, size(vector)), mask)
else
{
- return UnableToLegalize;
+ // Extend subvector to same size as vector
+ Register ExtendedSubvector = MRI.createGenericVirtualRegister(VectorTy);
+ MIRBuilder.buildPadVectorWithUndefElements(ExtendedSubvector, Subvector);
+
+ // Calculate mask required for this shuffle
+ SmallVector<int> Mask;
+ for (int i; i < VectorTy.getElementCount().getKnownMinValue(); i++)
+ {
+ // If this index is within bounds, put subvector's index into mask
+ if (i > insertionPointImm && i < insertionPointImm + SubvectorTy.getElementCount().getKnownMinValue())
+ Mask.push_back(VectorTy.getElementCount().getKnownMinValue() + i - insertionPointImm);
+ else
+ Mask.push_back(i);
+ }
+
+ // Build shuffle
+ MIRBuilder.buildShuffleVector(MI.getOperand(0), Vector, ExtendedSubvector, Mask);
+ MI.eraseFromParent();
+ return Legalized;
}
// Look up what sdag does**
// The g opcodes should all be supported by gi
>From d91f629c0e27feb0e8ad5b6fa34ea03fe4d8c38d Mon Sep 17 00:00:00 2001
From: Josh Rodriguez <josh.rodriguez at arm.com>
Date: Tue, 23 Jun 2026 13:46:09 +0000
Subject: [PATCH 04/10] [AArch64][GlobalISel] Update test checks
---
.../GlobalISel/legalizer-info-validation.mir | 5 +-
.../CodeGen/AArch64/extract-vector-elt.ll | 66 ++++++++++++-------
2 files changed, 47 insertions(+), 24 deletions(-)
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
index 190761c4124e0..8aa1c2679ac3e 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
@@ -1,3 +1,4 @@
+# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
# RUN: llc -mtriple=aarch64-- -run-pass=legalizer %s \
# RUN: -mcpu=cortex-a75 -o - 2>&1 | FileCheck %s --check-prefixes=CHECK
@@ -724,8 +725,8 @@
# DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined
# DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined
# DEBUG-NEXT: G_INSERT_SUBVECTOR (opcode {{[0-9]+}}): 2 type indices, 1 imm index
-# DEBUG-NEXT: .. type index coverage check SKIPPED: no rules defined
-# DEBUG-NEXT: .. imm index coverage check SKIPPED: no rules defined
+# 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
diff --git a/llvm/test/CodeGen/AArch64/extract-vector-elt.ll b/llvm/test/CodeGen/AArch64/extract-vector-elt.ll
index f05b37435f83c..d0ca98ee94299 100644
--- a/llvm/test/CodeGen/AArch64/extract-vector-elt.ll
+++ b/llvm/test/CodeGen/AArch64/extract-vector-elt.ll
@@ -2,9 +2,7 @@
; 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_insert
-; CHECK-GI-NEXT: warning: Instruction selection used fallback path for extract_v4i32_vector_insert_const
-; CHECK-GI-NEXT: warning: Instruction selection used fallback path for extract_v4i32_vector_extract
+; 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) {
@@ -761,20 +759,35 @@ entry:
}
define i32 @extract_v4i32_vector_insert(<4 x i32> %a, <2 x i32> %b, i32 %c) {
-; CHECK-LABEL: extract_v4i32_vector_insert:
-; CHECK: // %bb.0: // %entry
-; CHECK-NEXT: sub sp, sp, #16
-; CHECK-NEXT: .cfi_def_cfa_offset 16
-; CHECK-NEXT: mov d0, v0.d[1]
-; CHECK-NEXT: // kill: def $d1 killed $d1 def $q1
-; CHECK-NEXT: mov x8, sp
-; CHECK-NEXT: // kill: def $w0 killed $w0 def $x0
-; CHECK-NEXT: bfi x8, x0, #2, #2
-; CHECK-NEXT: mov v1.d[1], v0.d[0]
-; CHECK-NEXT: str q1, [sp]
-; CHECK-NEXT: ldr w0, [x8]
-; CHECK-NEXT: add sp, sp, #16
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: extract_v4i32_vector_insert:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: sub sp, sp, #16
+; CHECK-SD-NEXT: .cfi_def_cfa_offset 16
+; CHECK-SD-NEXT: mov d0, v0.d[1]
+; CHECK-SD-NEXT: // kill: def $d1 killed $d1 def $q1
+; CHECK-SD-NEXT: mov x8, sp
+; CHECK-SD-NEXT: // kill: def $w0 killed $w0 def $x0
+; CHECK-SD-NEXT: bfi x8, x0, #2, #2
+; CHECK-SD-NEXT: mov v1.d[1], v0.d[0]
+; CHECK-SD-NEXT: str q1, [sp]
+; CHECK-SD-NEXT: ldr w0, [x8]
+; CHECK-SD-NEXT: add sp, sp, #16
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: extract_v4i32_vector_insert:
+; CHECK-GI: // %bb.0: // %entry
+; CHECK-GI-NEXT: sub sp, sp, #16
+; CHECK-GI-NEXT: .cfi_def_cfa_offset 16
+; CHECK-GI-NEXT: mov d0, v0.d[1]
+; CHECK-GI-NEXT: // kill: def $d1 killed $d1 def $q1
+; CHECK-GI-NEXT: mov w8, w0
+; CHECK-GI-NEXT: mov x9, sp
+; CHECK-GI-NEXT: and x8, x8, #0x3
+; CHECK-GI-NEXT: mov v1.d[1], v0.d[0]
+; CHECK-GI-NEXT: str q1, [sp]
+; CHECK-GI-NEXT: ldr w0, [x9, x8, lsl #2]
+; CHECK-GI-NEXT: add sp, sp, #16
+; CHECK-GI-NEXT: ret
entry:
%vector = call <4 x i32> @llvm.vector.insert.v4i32.v2i32(<4 x i32> %a, <2 x i32> %b, i64 0)
%d = extractelement <4 x i32> %vector, i32 %c
@@ -782,11 +795,20 @@ entry:
}
define i32 @extract_v4i32_vector_insert_const(<4 x i32> %a, <2 x i32> %b, i32 %c) {
-; CHECK-LABEL: extract_v4i32_vector_insert_const:
-; CHECK: // %bb.0: // %entry
-; CHECK-NEXT: // kill: def $d1 killed $d1 def $q1
-; CHECK-NEXT: mov w0, v1.s[1]
-; CHECK-NEXT: ret
+; CHECK-SD-LABEL: extract_v4i32_vector_insert_const:
+; CHECK-SD: // %bb.0: // %entry
+; CHECK-SD-NEXT: // kill: def $d1 killed $d1 def $q1
+; CHECK-SD-NEXT: mov w0, v1.s[1]
+; CHECK-SD-NEXT: ret
+;
+; CHECK-GI-LABEL: extract_v4i32_vector_insert_const:
+; CHECK-GI: // %bb.0: // %entry
+; CHECK-GI-NEXT: mov d0, v0.d[1]
+; CHECK-GI-NEXT: // kill: def $d1 killed $d1 def $q1
+; CHECK-GI-NEXT: mov v1.d[1], v0.d[0]
+; CHECK-GI-NEXT: mov s0, v1.s[1]
+; CHECK-GI-NEXT: fmov w0, s0
+; CHECK-GI-NEXT: ret
entry:
%vector = call <4 x i32> @llvm.vector.insert.v4i32.v2i32(<4 x i32> %a, <2 x i32> %b, i64 0)
%d = extractelement <4 x i32> %vector, i32 1
>From 0f160cb16d406053241d2305a995f893ef244416 Mon Sep 17 00:00:00 2001
From: Josh Rodriguez <josh.rodriguez at arm.com>
Date: Wed, 24 Jun 2026 13:22:13 +0000
Subject: [PATCH 05/10] [AArch64][GlobalISel] Run clang-format
---
.../CodeGen/GlobalISel/LegalizerHelper.cpp | 67 ++++++++++---------
.../AArch64/GISel/AArch64LegalizerInfo.cpp | 32 ++++-----
2 files changed, 51 insertions(+), 48 deletions(-)
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index ddcaeaa558095..be84a518d321e 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -4877,8 +4877,8 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
case G_DYN_STACKALLOC:
return lowerDynStackAlloc(MI);
case G_INSERT_SUBVECTOR: {
- if (MRI.getType(MI.getOperand(1).getReg()).isScalable()
- || MRI.getType(MI.getOperand(2).getReg()).isScalable())
+ if (MRI.getType(MI.getOperand(1).getReg()).isScalable() ||
+ MRI.getType(MI.getOperand(2).getReg()).isScalable())
return UnableToLegalize;
// Check that subvector is half size of main vector
@@ -4890,44 +4890,47 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
LLT SubvectorTy = 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() == SubvectorTy.getSizeInBits() * 2) {
bool insertInLowHalf = insertionPointImm == 0;
- auto extract = MIRBuilder.buildInstr(TargetOpcode::G_EXTRACT_SUBVECTOR,
- {SubvectorTy},
- {Vector, (uint64_t)(insertInLowHalf ? VectorTy.getElementCount().getKnownMinValue() / 2 : 0)});
-
+ auto extract = MIRBuilder.buildInstr(
+ TargetOpcode::G_EXTRACT_SUBVECTOR, {SubvectorTy},
+ {Vector,
+ (uint64_t)(insertInLowHalf
+ ? VectorTy.getElementCount().getKnownMinValue() / 2
+ : 0)});
+
auto LowHalf = insertInLowHalf ? Subvector : extract.getReg(0);
auto HighHalf = insertInLowHalf ? extract.getReg(0) : Subvector;
- MIRBuilder.buildInstr(TargetOpcode::G_CONCAT_VECTORS,
- {MI.getOperand(0)},
- {LowHalf, HighHalf});
+ MIRBuilder.buildInstr(TargetOpcode::G_CONCAT_VECTORS, {MI.getOperand(0)},
+ {LowHalf, HighHalf});
MI.eraseFromParent();
return Legalized;
}
// Else -> shuffle(vector, extend(subvector, size(vector)), mask)
- else
- {
- // Extend subvector to same size as vector
- Register ExtendedSubvector = MRI.createGenericVirtualRegister(VectorTy);
- MIRBuilder.buildPadVectorWithUndefElements(ExtendedSubvector, Subvector);
-
- // Calculate mask required for this shuffle
- SmallVector<int> Mask;
- for (int i; i < VectorTy.getElementCount().getKnownMinValue(); i++)
- {
- // If this index is within bounds, put subvector's index into mask
- if (i > insertionPointImm && i < insertionPointImm + SubvectorTy.getElementCount().getKnownMinValue())
- Mask.push_back(VectorTy.getElementCount().getKnownMinValue() + i - insertionPointImm);
- else
- Mask.push_back(i);
- }
-
- // Build shuffle
- MIRBuilder.buildShuffleVector(MI.getOperand(0), Vector, ExtendedSubvector, Mask);
- MI.eraseFromParent();
- return Legalized;
+ else {
+ // Extend subvector to same size as vector
+ Register ExtendedSubvector = MRI.createGenericVirtualRegister(VectorTy);
+ MIRBuilder.buildPadVectorWithUndefElements(ExtendedSubvector, Subvector);
+
+ // Calculate mask required for this shuffle
+ SmallVector<int> Mask;
+ for (int i; i < VectorTy.getElementCount().getKnownMinValue(); i++) {
+ // If this index is within bounds, put subvector's index into mask
+ if (i > insertionPointImm &&
+ i < insertionPointImm +
+ SubvectorTy.getElementCount().getKnownMinValue())
+ Mask.push_back(VectorTy.getElementCount().getKnownMinValue() + i -
+ insertionPointImm);
+ else
+ Mask.push_back(i);
+ }
+
+ // Build shuffle
+ MIRBuilder.buildShuffleVector(MI.getOperand(0), Vector, ExtendedSubvector,
+ Mask);
+ MI.eraseFromParent();
+ return Legalized;
}
// Look up what sdag does**
// The g opcodes should all be supported by gi
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
index 4273fae5fa118..9074c25950432 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
@@ -402,22 +402,22 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST)
getActionDefinitionsBuilder(G_INSERT_SUBVECTOR)
.lower(); // go to legalizerhelper.cpp
- //.legalFor({{v16i8, v16i8},
- // {v16i8, v8i8},
- // {v8i16, v8i16},
- // {v8i16, v4i16},
- // {v4i32, v4i32},
- // {v4i32, v2i32}})
- //.immIdx(0); // Inform verifier imm idx 0 is handled.
- //.widenScalarToNextPow2(1, /*Min=*/32)
- //.clampScalar(1, s32, s64)
- //.widenScalarOrEltToNextPow2OrMinSize(1, /*Min=*/8)
- //.clampNumElements(0, v8s8, v16s8)
- //.clampNumElements(0, v4s16, v8s16)
- //.clampNumElements(0, v2s32, v4s32)
- //.moreElementsToNextPow2(0)
- //.scalarizeIf(scalarOrEltWiderThan(0, 32), 0)
- //.scalarSameSizeAs(0, 1);
+ //.legalFor({{v16i8, v16i8},
+ // {v16i8, v8i8},
+ // {v8i16, v8i16},
+ // {v8i16, v4i16},
+ // {v4i32, v4i32},
+ // {v4i32, v2i32}})
+ //.immIdx(0); // Inform verifier imm idx 0 is handled.
+ //.widenScalarToNextPow2(1, /*Min=*/32)
+ //.clampScalar(1, s32, s64)
+ //.widenScalarOrEltToNextPow2OrMinSize(1, /*Min=*/8)
+ //.clampNumElements(0, v8s8, v16s8)
+ //.clampNumElements(0, v4s16, v8s16)
+ //.clampNumElements(0, v2s32, v4s32)
+ //.moreElementsToNextPow2(0)
+ //.scalarizeIf(scalarOrEltWiderThan(0, 32), 0)
+ //.scalarSameSizeAs(0, 1);
getActionDefinitionsBuilder(G_CTLZ_ZERO_POISON).lower();
>From e62de04ee54c4127336174a3432448c303b798d3 Mon Sep 17 00:00:00 2001
From: Josh Rodriguez <josh.rodriguez at arm.com>
Date: Wed, 24 Jun 2026 13:40:50 +0000
Subject: [PATCH 06/10] [AArch64][GlobalISel] Remove comments
---
.../CodeGen/GlobalISel/LegalizerHelper.cpp | 3 ---
.../AArch64/GISel/AArch64LegalizerInfo.cpp | 19 +------------------
.../GlobalISel/legalizer-info-validation.mir | 1 -
3 files changed, 1 insertion(+), 22 deletions(-)
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index be84a518d321e..09c5e35b6d4e7 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -4932,9 +4932,6 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
MI.eraseFromParent();
return Legalized;
}
- // Look up what sdag does**
- // The g opcodes should all be supported by gi
- // Make sdag tests works for GI
}
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 9074c25950432..156af2dd310e4 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64LegalizerInfo.cpp
@@ -400,24 +400,7 @@ AArch64LegalizerInfo::AArch64LegalizerInfo(const AArch64Subtarget &ST)
.scalarizeIf(scalarOrEltWiderThan(0, 32), 0)
.scalarSameSizeAs(0, 1);
- getActionDefinitionsBuilder(G_INSERT_SUBVECTOR)
- .lower(); // go to legalizerhelper.cpp
- //.legalFor({{v16i8, v16i8},
- // {v16i8, v8i8},
- // {v8i16, v8i16},
- // {v8i16, v4i16},
- // {v4i32, v4i32},
- // {v4i32, v2i32}})
- //.immIdx(0); // Inform verifier imm idx 0 is handled.
- //.widenScalarToNextPow2(1, /*Min=*/32)
- //.clampScalar(1, s32, s64)
- //.widenScalarOrEltToNextPow2OrMinSize(1, /*Min=*/8)
- //.clampNumElements(0, v8s8, v16s8)
- //.clampNumElements(0, v4s16, v8s16)
- //.clampNumElements(0, v2s32, v4s32)
- //.moreElementsToNextPow2(0)
- //.scalarizeIf(scalarOrEltWiderThan(0, 32), 0)
- //.scalarSameSizeAs(0, 1);
+ getActionDefinitionsBuilder(G_INSERT_SUBVECTOR).lower();
getActionDefinitionsBuilder(G_CTLZ_ZERO_POISON).lower();
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
index 8aa1c2679ac3e..26c0aaa3bb3c9 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/legalizer-info-validation.mir
@@ -1,4 +1,3 @@
-# NOTE: Assertions have been autogenerated by utils/update_mir_test_checks.py UTC_ARGS: --version 6
# RUN: llc -mtriple=aarch64-- -run-pass=legalizer %s \
# RUN: -mcpu=cortex-a75 -o - 2>&1 | FileCheck %s --check-prefixes=CHECK
>From 4c708511e1bdd4a620ea184d8e5747faab37a9a2 Mon Sep 17 00:00:00 2001
From: Josh Rodriguez <josh.rodriguez at arm.com>
Date: Thu, 25 Jun 2026 13:05:29 +0000
Subject: [PATCH 07/10] [AArch64][GlobalISel] Make variable names uppercase
---
.../lib/CodeGen/GlobalISel/LegalizerHelper.cpp | 18 +++++++++---------
1 file changed, 9 insertions(+), 9 deletions(-)
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index 09c5e35b6d4e7..4775bd71d8d6f 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -4884,23 +4884,23 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
// Check that subvector is half size of main vector
Register Vector = MI.getOperand(1).getReg();
Register Subvector = MI.getOperand(2).getReg();
- auto insertionPointImm = MI.getOperand(3).getImm();
+ auto InsertionPointImm = MI.getOperand(3).getImm();
LLT VectorTy = MRI.getType(Vector);
LLT SubvectorTy = 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) {
- bool insertInLowHalf = insertionPointImm == 0;
- auto extract = MIRBuilder.buildInstr(
+ bool InsertInLowHalf = InsertionPointImm == 0;
+ auto Extract = MIRBuilder.buildInstr(
TargetOpcode::G_EXTRACT_SUBVECTOR, {SubvectorTy},
{Vector,
- (uint64_t)(insertInLowHalf
+ (uint64_t)(InsertInLowHalf
? VectorTy.getElementCount().getKnownMinValue() / 2
: 0)});
- auto LowHalf = insertInLowHalf ? Subvector : extract.getReg(0);
- auto HighHalf = insertInLowHalf ? extract.getReg(0) : Subvector;
+ auto LowHalf = InsertInLowHalf ? Subvector : Extract.getReg(0);
+ auto HighHalf = InsertInLowHalf ? Extract.getReg(0) : Subvector;
MIRBuilder.buildInstr(TargetOpcode::G_CONCAT_VECTORS, {MI.getOperand(0)},
{LowHalf, HighHalf});
@@ -4917,11 +4917,11 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
SmallVector<int> Mask;
for (int i; i < VectorTy.getElementCount().getKnownMinValue(); i++) {
// If this index is within bounds, put subvector's index into mask
- if (i > insertionPointImm &&
- i < insertionPointImm +
+ if (i > InsertionPointImm &&
+ i < InsertionPointImm +
SubvectorTy.getElementCount().getKnownMinValue())
Mask.push_back(VectorTy.getElementCount().getKnownMinValue() + i -
- insertionPointImm);
+ InsertionPointImm);
else
Mask.push_back(i);
}
>From 9b405a7f7319fa43f2c53895b4a5f2e8efb43375 Mon Sep 17 00:00:00 2001
From: Josh Rodriguez <josh.rodriguez at arm.com>
Date: Thu, 25 Jun 2026 13:27:03 +0000
Subject: [PATCH 08/10] [AArch64][GlobalISel] Replace buildInstr with
buildExtractSubvector
As funtion name is more explicit and signature is more concise, improving readability.
---
llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp | 11 +++++------
1 file changed, 5 insertions(+), 6 deletions(-)
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index 4775bd71d8d6f..6bb0d758d82a0 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -4892,12 +4892,11 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
// (Operands can be either way round depending on insertion point
if (VectorTy.getSizeInBits() == SubvectorTy.getSizeInBits() * 2) {
bool InsertInLowHalf = InsertionPointImm == 0;
- auto Extract = MIRBuilder.buildInstr(
- TargetOpcode::G_EXTRACT_SUBVECTOR, {SubvectorTy},
- {Vector,
- (uint64_t)(InsertInLowHalf
- ? VectorTy.getElementCount().getKnownMinValue() / 2
- : 0)});
+ auto Extract = MIRBuilder.buildExtractSubvector(
+ SubvectorTy, Vector,
+ (uint64_t)(InsertInLowHalf
+ ? VectorTy.getElementCount().getKnownMinValue() / 2
+ : 0));
auto LowHalf = InsertInLowHalf ? Subvector : Extract.getReg(0);
auto HighHalf = InsertInLowHalf ? Extract.getReg(0) : Subvector;
>From af72cc681ec272410228b0cde762a8c6699c124c Mon Sep 17 00:00:00 2001
From: Josh Rodriguez <josh.rodriguez at arm.com>
Date: Thu, 25 Jun 2026 14:07:15 +0000
Subject: [PATCH 09/10] [AArch64][GlobalISel] Refactor
getElementCount().getKnownMinValue() to getNumElements()
As the start of the block checks if the operands are scalable, we can be sure that at this point the operands are non-scalable. In that case, rewrite the function call to the more concise getNumElements().
---
llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp | 12 ++++--------
1 file changed, 4 insertions(+), 8 deletions(-)
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
index 6bb0d758d82a0..5afd078775848 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerHelper.cpp
@@ -4894,9 +4894,7 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
bool InsertInLowHalf = InsertionPointImm == 0;
auto Extract = MIRBuilder.buildExtractSubvector(
SubvectorTy, Vector,
- (uint64_t)(InsertInLowHalf
- ? VectorTy.getElementCount().getKnownMinValue() / 2
- : 0));
+ (uint64_t)(InsertInLowHalf ? VectorTy.getNumElements() / 2 : 0));
auto LowHalf = InsertInLowHalf ? Subvector : Extract.getReg(0);
auto HighHalf = InsertInLowHalf ? Extract.getReg(0) : Subvector;
@@ -4914,13 +4912,11 @@ LegalizerHelper::lower(MachineInstr &MI, unsigned TypeIdx, LLT LowerHintTy) {
// Calculate mask required for this shuffle
SmallVector<int> Mask;
- for (int i; i < VectorTy.getElementCount().getKnownMinValue(); i++) {
+ for (int i; i < VectorTy.getNumElements(); i++) {
// If this index is within bounds, put subvector's index into mask
if (i > InsertionPointImm &&
- i < InsertionPointImm +
- SubvectorTy.getElementCount().getKnownMinValue())
- Mask.push_back(VectorTy.getElementCount().getKnownMinValue() + i -
- InsertionPointImm);
+ i < InsertionPointImm + SubvectorTy.getNumElements())
+ Mask.push_back(VectorTy.getNumElements() + i - InsertionPointImm);
else
Mask.push_back(i);
}
>From e5b43de8d96feae3aed2744b28aa45286eb73c41 Mon Sep 17 00:00:00 2001
From: Josh Rodriguez <josh.rodriguez at arm.com>
Date: Thu, 25 Jun 2026 14:25:21 +0000
Subject: [PATCH 10/10] [AArch64][GlobalISel] Remove erroneous GINodeEquiv
statement
Statement was added whilst I was testing the possibility of handling G_INSERT_SUBVECTOR in Instruction Selection, and having no legalisation rules for it. The approach didn't work, and I forgot to delete the remains.
Remove this statement.
---
llvm/lib/Target/AArch64/AArch64InstrGISel.td | 1 -
1 file changed, 1 deletion(-)
diff --git a/llvm/lib/Target/AArch64/AArch64InstrGISel.td b/llvm/lib/Target/AArch64/AArch64InstrGISel.td
index f56deb14b8a5f..ec95448f61043 100644
--- a/llvm/lib/Target/AArch64/AArch64InstrGISel.td
+++ b/llvm/lib/Target/AArch64/AArch64InstrGISel.td
@@ -349,7 +349,6 @@ def : GINodeEquiv<G_SLI, AArch64vsli>;
def : GINodeEquiv<G_SRI, AArch64vsri>;
def : GINodeEquiv<G_EXTRACT_VECTOR_ELT, vector_extract>;
-def : GINodeEquiv<G_INSERT_SUBVECTOR, insert_subvector>;
def : GINodeEquiv<G_AARCH64_PREFETCH, AArch64Prefetch>;
def : GINodeEquiv<G_AARCH64_RANGE_PREFETCH, AArch64RangePrefetch>;
More information about the llvm-commits
mailing list