[llvm] [AArch64][GlobalISel] Select vector element extract into GPR (PR #210030)

via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 16 03:59:43 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-globalisel

Author: Cullen Rhodes (c-rhodes)

<details>
<summary>Changes</summary>

Prototyping a new minimal type-based approach to RegBankSelect (#<!-- -->199040) for compile-time purposes exposed various gaps in instruction selection when not using the existing RegBankSelect pass. These manifested as new fallbacks when compiling the IR dataset from [1].

This patch teaches instruction selection to handle extracts of scalar i8/i16/i32 into GPR directly. This will prevent new fallbacks being introduced when a new type-based RBS pass is added.

The test cases are extracted from [1].

Assisted-by: codex

[1] https://davemgreen.github.io/gisel.html

---
Full diff: https://github.com/llvm/llvm-project/pull/210030.diff


2 Files Affected:

- (modified) llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp (+29-7) 
- (modified) llvm/test/CodeGen/AArch64/GlobalISel/select-extract-vector-elt.mir (+92) 


``````````diff
diff --git a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
index 7fa788ec86cc2..0c2f3f97ec07d 100644
--- a/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
+++ b/llvm/lib/Target/AArch64/GISel/AArch64InstructionSelector.cpp
@@ -4016,7 +4016,6 @@ bool AArch64InstructionSelector::selectExtractElt(
   const LLT NarrowTy = MRI.getType(DstReg);
   const Register SrcReg = I.getOperand(1).getReg();
   const LLT WideTy = MRI.getType(SrcReg);
-  (void)WideTy;
   assert(WideTy.getSizeInBits() >= NarrowTy.getSizeInBits() &&
          "source register size too small!");
   assert(!NarrowTy.isVector() && "cannot extract vector into vector!");
@@ -4025,19 +4024,42 @@ bool AArch64InstructionSelector::selectExtractElt(
   MachineOperand &LaneIdxOp = I.getOperand(2);
   assert(LaneIdxOp.isReg() && "Lane index operand was not a register?");
 
-  if (RBI.getRegBank(DstReg, MRI, TRI)->getID() != AArch64::FPRRegBankID) {
-    LLVM_DEBUG(dbgs() << "Cannot extract into GPR.\n");
-    return false;
-  }
-
   // Find the index to extract from.
   auto VRegAndVal = getIConstantVRegValWithLookThrough(LaneIdxOp.getReg(), MRI);
   if (!VRegAndVal)
     return false;
   unsigned LaneIdx = VRegAndVal->Value.getSExtValue();
 
-
   const RegisterBank &DstRB = *RBI.getRegBank(DstReg, MRI, TRI);
+  if (DstRB.getID() == AArch64::GPRRegBankID) {
+    unsigned Opcode;
+    switch (WideTy.getScalarSizeInBits()) {
+    case 8:
+      Opcode = AArch64::UMOVvi8;
+      break;
+    case 16:
+      Opcode = AArch64::UMOVvi16;
+      break;
+    case 32:
+      Opcode = AArch64::UMOVvi32;
+      break;
+    default:
+      return false;
+    }
+
+    if (WideTy.getSizeInBits() != 128) {
+      MachineInstr *ScalarToVector = emitScalarToVector(
+          WideTy.getSizeInBits(), &AArch64::FPR128RegClass, SrcReg, MIB);
+      assert(ScalarToVector && "Didn't expect emitScalarToVector to fail!");
+      I.getOperand(1).setReg(ScalarToVector->getOperand(0).getReg());
+    }
+
+    I.setDesc(TII.get(Opcode));
+    I.getOperand(2).ChangeToImmediate(LaneIdx);
+    constrainSelectedInstRegOperands(I, TII, TRI, RBI);
+    return true;
+  }
+
   MachineInstr *Extract = emitExtractVectorElt(DstReg, DstRB, NarrowTy, SrcReg,
                                                LaneIdx, MIB);
   if (!Extract)
diff --git a/llvm/test/CodeGen/AArch64/GlobalISel/select-extract-vector-elt.mir b/llvm/test/CodeGen/AArch64/GlobalISel/select-extract-vector-elt.mir
index 0f716ae7ab6e8..62c1bb707f819 100644
--- a/llvm/test/CodeGen/AArch64/GlobalISel/select-extract-vector-elt.mir
+++ b/llvm/test/CodeGen/AArch64/GlobalISel/select-extract-vector-elt.mir
@@ -32,6 +32,36 @@ body:             |
     $s0 = COPY %1(i32)
     RET_ReallyLR implicit $s0
 
+...
+---
+name:            v2s32_gpr
+alignment:       4
+legalized:       true
+regBankSelected: true
+tracksRegLiveness: true
+registers:
+  - { id: 0, class: fpr }
+  - { id: 1, class: gpr }
+  - { id: 2, class: gpr }
+body:             |
+  bb.0:
+    liveins: $d0
+
+    ; CHECK-LABEL: name: v2s32_gpr
+    ; CHECK: liveins: $d0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr64 = COPY $d0
+    ; CHECK-NEXT: [[DEF:%[0-9]+]]:fpr128 = IMPLICIT_DEF
+    ; CHECK-NEXT: [[INSERT_SUBREG:%[0-9]+]]:fpr128 = INSERT_SUBREG [[DEF]], [[COPY]], %subreg.dsub
+    ; CHECK-NEXT: [[UMOVvi32_:%[0-9]+]]:gpr32 = UMOVvi32 [[INSERT_SUBREG]], 0
+    ; CHECK-NEXT: $w0 = COPY [[UMOVvi32_]]
+    ; CHECK-NEXT: RET_ReallyLR implicit $w0
+    %0:fpr(<2 x i32>) = COPY $d0
+    %2:gpr(i64) = G_CONSTANT i64 0
+    %1:gpr(i32) = G_EXTRACT_VECTOR_ELT %0(<2 x i32>), %2(i64)
+    $w0 = COPY %1(i32)
+    RET_ReallyLR implicit $w0
+
 ...
 ---
 name:            v2s32_fpr_idx0
@@ -300,3 +330,65 @@ body:             |
     RET_ReallyLR implicit $d0
 
 ...
+---
+name:            shuffle_extract_i8
+legalized:       true
+regBankSelected: true
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $d0
+
+    ; CHECK-LABEL: name: shuffle_extract_i8
+    ; CHECK: liveins: $d0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr64 = COPY $d0
+    ; CHECK-NEXT: [[DEF:%[0-9]+]]:fpr128 = IMPLICIT_DEF
+    ; CHECK-NEXT: [[INSERT_SUBREG:%[0-9]+]]:fpr128 = INSERT_SUBREG [[DEF]], [[COPY]], %subreg.dsub
+    ; CHECK-NEXT: [[UMOVvi8_:%[0-9]+]]:gpr32 = UMOVvi8 [[INSERT_SUBREG]], 4
+    ; CHECK-NEXT: [[DEF1:%[0-9]+]]:fpr128 = IMPLICIT_DEF
+    ; CHECK-NEXT: [[INSERT_SUBREG1:%[0-9]+]]:fpr128 = INSERT_SUBREG [[DEF1]], [[COPY]], %subreg.dsub
+    ; CHECK-NEXT: [[INSvi8gpr:%[0-9]+]]:fpr128 = INSvi8gpr [[INSERT_SUBREG1]], 1, [[UMOVvi8_]]
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:fpr64 = COPY [[INSvi8gpr]].dsub
+    ; CHECK-NEXT: $d0 = COPY [[COPY1]]
+    ; CHECK-NEXT: RET_ReallyLR implicit $d0
+    %0:fpr(<8 x i8>) = COPY $d0
+    %1:gpr(i64) = G_CONSTANT i64 4
+    %2:gpr(i8) = G_EXTRACT_VECTOR_ELT %0(<8 x i8>), %1(i64)
+    %3:gpr(i64) = G_CONSTANT i64 1
+    %4:fpr(<8 x i8>) = G_INSERT_VECTOR_ELT %0, %2(i8), %3(i64)
+    $d0 = COPY %4(<8 x i8>)
+    RET_ReallyLR implicit $d0
+
+...
+---
+name:            shuffle_extract_i16
+legalized:       true
+regBankSelected: true
+tracksRegLiveness: true
+body:             |
+  bb.0:
+    liveins: $d0
+
+    ; CHECK-LABEL: name: shuffle_extract_i16
+    ; CHECK: liveins: $d0
+    ; CHECK-NEXT: {{  $}}
+    ; CHECK-NEXT: [[COPY:%[0-9]+]]:fpr64 = COPY $d0
+    ; CHECK-NEXT: [[DEF:%[0-9]+]]:fpr128 = IMPLICIT_DEF
+    ; CHECK-NEXT: [[INSERT_SUBREG:%[0-9]+]]:fpr128 = INSERT_SUBREG [[DEF]], [[COPY]], %subreg.dsub
+    ; CHECK-NEXT: [[UMOVvi16_:%[0-9]+]]:gpr32 = UMOVvi16 [[INSERT_SUBREG]], 1
+    ; CHECK-NEXT: [[DEF1:%[0-9]+]]:fpr128 = IMPLICIT_DEF
+    ; CHECK-NEXT: [[INSERT_SUBREG1:%[0-9]+]]:fpr128 = INSERT_SUBREG [[DEF1]], [[COPY]], %subreg.dsub
+    ; CHECK-NEXT: [[INSvi16gpr:%[0-9]+]]:fpr128 = INSvi16gpr [[INSERT_SUBREG1]], 0, [[UMOVvi16_]]
+    ; CHECK-NEXT: [[COPY1:%[0-9]+]]:fpr64 = COPY [[INSvi16gpr]].dsub
+    ; CHECK-NEXT: $d0 = COPY [[COPY1]]
+    ; CHECK-NEXT: RET_ReallyLR implicit $d0
+    %0:fpr(<4 x i16>) = COPY $d0
+    %1:gpr(i64) = G_CONSTANT i64 1
+    %2:gpr(i16) = G_EXTRACT_VECTOR_ELT %0(<4 x i16>), %1(i64)
+    %3:gpr(i64) = G_CONSTANT i64 0
+    %4:fpr(<4 x i16>) = G_INSERT_VECTOR_ELT %0, %2(i16), %3(i64)
+    $d0 = COPY %4(<4 x i16>)
+    RET_ReallyLR implicit $d0
+
+...

``````````

</details>


https://github.com/llvm/llvm-project/pull/210030


More information about the llvm-commits mailing list