[llvm] [X86][GlobalISel] Select G_INSERT_VECTOR_ELT using SDAG patterns (PR #230317)

Evgenii Kudriashov via llvm-commits llvm-commits at lists.llvm.org
Sun Oct 11 14:21:03 PDT 2026


https://github.com/e-kud updated https://github.com/llvm/llvm-project/pull/230317

>From e33b480f91643c009aae271344b1d0fa5fddacfb Mon Sep 17 00:00:00 2001
From: Evgenii Kudriashov <evgenii.kudriashov at intel.com>
Date: Fri, 9 Oct 2026 01:16:07 +0200
Subject: [PATCH 1/2] [X86][GlobalISel] Select G_INSERT_VECTOR_ELT using SDAG
 patterns

GlobalISel couldn't import the insertelt patterns of PINSRD/PINSRQ for two
reasons: there was no GINodeEquiv for insertelt, and the index has iPTR type,
which the GlobalISel emitter can't represent.

Introduce X86VecIdxVT, a ValueTypeByHwMode that resolves to the pointer-sized
vector index type (i32 on i386 and x32, i64 on x86-64), i.e. exactly what iPTR
resolves to today, and use it for the index of the PINSRD/PINSRQ patterns. The
immediate operand of these instructions gets the same type via the new
vecidximm operand, because the type of an operand in the result pattern has to
agree with the type of the matched immediate.

SelectionDAG matching is unchanged: the isel table checks the index type by
HwMode instead of iPTR (+7 bytes). Encoding, disassembler, EVEX->VEX
compression and memory folding tables are unchanged.

Legalize G_INSERT_VECTOR_ELT for v4s32 and v2s64 (64-bit only) with SSE4.1.
An insert with a constant index is selected by the imported patterns, one with
a variable index is lowered through the stack.

Assisted-by: Claude Code
---
 .../lib/Target/X86/GISel/X86LegalizerInfo.cpp |  29 +++++
 llvm/lib/Target/X86/GISel/X86LegalizerInfo.h  |   3 +
 llvm/lib/Target/X86/X86InstrAVX512.td         |  16 ++-
 llvm/lib/Target/X86/X86InstrGISel.td          |   3 +
 llvm/lib/Target/X86/X86InstrOperands.td       |   9 ++
 llvm/lib/Target/X86/X86InstrPredicates.td     |   7 ++
 llvm/lib/Target/X86/X86InstrSSE.td            |  20 +--
 llvm/test/CodeGen/X86/isel-insertelt-avx.ll   | 108 ++++++++++++++++
 .../test/CodeGen/X86/isel-insertelt-avx512.ll | 115 ++++++++++++++++++
 llvm/test/CodeGen/X86/isel-insertelt-sse41.ll | 108 ++++++++++++++++
 .../CodeGen/X86/isel-insertelt-var-idx.ll     |  80 ++++++++++++
 llvm/utils/TableGen/X86RecognizableInstr.cpp  |   3 +
 12 files changed, 489 insertions(+), 12 deletions(-)
 create mode 100644 llvm/test/CodeGen/X86/isel-insertelt-avx.ll
 create mode 100644 llvm/test/CodeGen/X86/isel-insertelt-avx512.ll
 create mode 100644 llvm/test/CodeGen/X86/isel-insertelt-sse41.ll
 create mode 100644 llvm/test/CodeGen/X86/isel-insertelt-var-idx.ll

diff --git a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
index b78a3f46d6817..07450064f8ddd 100644
--- a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
+++ b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
@@ -80,6 +80,7 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
   const LLT v16s32 = LLT::fixed_vector(16, 32);
   const LLT v8s64 = LLT::fixed_vector(8, 64);
 
+  const LLT sVecIdx = LLT::scalar(p0.getSizeInBits());
   const LLT s8MaxVector = HasAVX512 ? v64s8 : HasAVX ? v32s8 : v16s8;
   const LLT s16MaxVector = HasAVX512 ? v32s16 : HasAVX ? v16s16 : v8s16;
   const LLT s32MaxVector = HasAVX512 ? v16s32 : HasAVX ? v8s32 : v4s32;
@@ -562,6 +563,14 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
       .clampNumElements(0, v2s64, s64MaxVector)
       .moreElementsToNextPow2(0);
 
+  getActionDefinitionsBuilder(G_INSERT_VECTOR_ELT)
+      .customIf([=](const LegalityQuery &Query) {
+        return (HasSSE41 &&
+                typeTupleInSet(0, 1, 2, {{v4s32, s32, sVecIdx}})(Query)) ||
+               (HasSSE41 && Is64Bit &&
+                typeTupleInSet(0, 1, 2, {{v2s64, s64, sVecIdx}})(Query));
+      });
+
   getActionDefinitionsBuilder({G_EXTRACT, G_INSERT})
       .legalIf([=](const LegalityQuery &Query) {
         unsigned SubIdx = Query.Opcode == G_EXTRACT ? 0 : 1;
@@ -656,6 +665,8 @@ bool X86LegalizerInfo::legalizeCustom(LegalizerHelper &Helper, MachineInstr &MI,
     return legalizeSETROUNDING(MI, MRI, Helper);
   case TargetOpcode::G_GLOBAL_VALUE:
     return legalizeGLOBAL_VALUE(MI, MRI, Helper);
+  case TargetOpcode::G_INSERT_VECTOR_ELT:
+    return legalizeInsertVectorElt(MI, MRI, Helper);
   }
   llvm_unreachable("expected switch to return");
 }
@@ -1053,6 +1064,24 @@ bool X86LegalizerInfo::legalizeGLOBAL_VALUE(MachineInstr &MI,
   return true;
 }
 
+bool X86LegalizerInfo::legalizeInsertVectorElt(MachineInstr &MI,
+                                               MachineRegisterInfo &MRI,
+                                               LegalizerHelper &Helper) const {
+  Register Dst = MI.getOperand(0).getReg();
+  LLT DstTy = MRI.getType(Dst);
+  auto IdxVal =
+      getIConstantVRegValWithLookThrough(MI.getOperand(3).getReg(), MRI);
+  if (!IdxVal)
+    return Helper.lowerExtractInsertVectorElt(MI) ==
+           LegalizerHelper::LegalizeResult::Legalized;
+
+  if (IdxVal->Value.uge(DstTy.getNumElements())) {
+    Helper.MIRBuilder.buildUndef(Dst);
+    MI.eraseFromParent();
+  }
+  return true;
+}
+
 bool X86LegalizerInfo::legalizeIntrinsic(LegalizerHelper &Helper,
                                          MachineInstr &MI) const {
   return true;
diff --git a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.h b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.h
index 58be7bb7d02b8..abcc6e920a104 100644
--- a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.h
+++ b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.h
@@ -63,6 +63,9 @@ class X86LegalizerInfo : public LegalizerInfo {
 
   bool legalizeGLOBAL_VALUE(MachineInstr &MI, MachineRegisterInfo &MRI,
                             LegalizerHelper &Helper) const;
+
+  bool legalizeInsertVectorElt(MachineInstr &MI, MachineRegisterInfo &MRI,
+                               LegalizerHelper &Helper) const;
 };
 } // namespace llvm
 #endif
diff --git a/llvm/lib/Target/X86/X86InstrAVX512.td b/llvm/lib/Target/X86/X86InstrAVX512.td
index e8c8c82a5de14..34889866c2822 100644
--- a/llvm/lib/Target/X86/X86InstrAVX512.td
+++ b/llvm/lib/Target/X86/X86InstrAVX512.td
@@ -11634,14 +11634,22 @@ multiclass avx512_insert_elt_dq<bits<8> opc, string OpcodeStr,
                                          X86VectorVTInfo _, RegisterClass GRC> {
   let Predicates = [HasDQI] in {
     def rri : AVX512Ii8<opc, MRMSrcReg, (outs _.RC:$dst),
-        (ins _.RC:$src1, GRC:$src2, u8imm:$src3),
+        (ins _.RC:$src1, GRC:$src2, vecidximm:$src3),
         OpcodeStr#"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}",
         [(set _.RC:$dst,
-            (_.VT (insertelt _.RC:$src1, GRC:$src2, imm:$src3)))]>,
+            (_.VT (insertelt _.RC:$src1, GRC:$src2,
+                             (X86VecIdxVT imm:$src3))))]>,
         EVEX, VVVV, TA, PD, Sched<[WriteVecInsert]>;
 
-    defm NAME : avx512_insert_elt_m<opc, OpcodeStr, insertelt, _,
-                                    _.ScalarLdFrag, imm>, TA, PD;
+    let mayLoad = 1 in
+    def rmi : AVX512Ii8<opc, MRMSrcMem, (outs _.RC:$dst),
+        (ins _.RC:$src1, _.ScalarMemOp:$src2, vecidximm:$src3),
+        OpcodeStr#"\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}",
+        [(set _.RC:$dst,
+            (_.VT (insertelt _.RC:$src1, (_.ScalarLdFrag addr:$src2),
+                             (X86VecIdxVT imm:$src3))))]>,
+        EVEX, VVVV, EVEX_CD8<_.EltSize, CD8VT1>, TA, PD,
+        Sched<[WriteVecInsert.Folded, WriteVecInsert.ReadAfterFold]>;
   }
 }
 
diff --git a/llvm/lib/Target/X86/X86InstrGISel.td b/llvm/lib/Target/X86/X86InstrGISel.td
index 521923175c444..a78370d7a1296 100644
--- a/llvm/lib/Target/X86/X86InstrGISel.td
+++ b/llvm/lib/Target/X86/X86InstrGISel.td
@@ -54,3 +54,6 @@ def : GINodeEquiv<G_FIST, X86fp_to_mem>;
 def : GINodeEquiv<G_FNSTCW16, X86fp_cwd_get16>;
 def : GINodeEquiv<G_FLDCW16, X86fp_cwd_set16>;
 def : GINodeEquiv<G_WRAPPER_RIP, X86WrapperRIP>;
+
+// X86 patterns use insertelt instead of vector_insert.
+def : GINodeEquiv<G_INSERT_VECTOR_ELT, insertelt>;
diff --git a/llvm/lib/Target/X86/X86InstrOperands.td b/llvm/lib/Target/X86/X86InstrOperands.td
index 4373f39c360a8..0c3b32375fb45 100644
--- a/llvm/lib/Target/X86/X86InstrOperands.td
+++ b/llvm/lib/Target/X86/X86InstrOperands.td
@@ -475,6 +475,15 @@ def u8imm : Operand<i8> {
   let OperandType = "OPERAND_IMMEDIATE";
 }
 
+// Unsigned 8-bit immediate used as a vector element index. Its value type is
+// the pointer-sized vector index type, so patterns on insertelt/extractelt
+// get a concrete index type per HwMode instead of iPTR.
+def vecidximm : Operand<X86VecIdxVT> {
+  let PrintMethod = "printU8Imm";
+  let ParserMatchClass = ImmUnsignedi8AsmOperand;
+  let OperandType = "OPERAND_IMMEDIATE";
+}
+
 // 16-bit immediate but only 8-bits are significant and they are unsigned.
 // Used by BT instructions.
 def i16u8imm : Operand<i16> {
diff --git a/llvm/lib/Target/X86/X86InstrPredicates.td b/llvm/lib/Target/X86/X86InstrPredicates.td
index b4e9e27315032..06a78427cf5c0 100644
--- a/llvm/lib/Target/X86/X86InstrPredicates.td
+++ b/llvm/lib/Target/X86/X86InstrPredicates.td
@@ -271,3 +271,10 @@ def NotUseIndirectThunkCalls : Predicate<"!Subtarget->useIndirectThunkCalls()">;
 defvar X86_32 = DefaultMode;
 def X86_64 : HwMode<[In64BitMode, NotX32Mode]>;
 def X86_64_X32 : HwMode<[IsX32Mode]>;
+
+// Type of the vector element index (ISD::INSERT_VECTOR_ELT/EXTRACT_VECTOR_ELT),
+// which is pointer-sized (see TargetLoweringBase::getVectorIdxWidth). Unlike
+// iPTR, it is a concrete type per HwMode, so GlobalISel can import patterns
+// using it.
+def X86VecIdxVT : ValueTypeByHwMode<[X86_32, X86_64, X86_64_X32],
+                                    [i32,    i64,    i32]>;
diff --git a/llvm/lib/Target/X86/X86InstrSSE.td b/llvm/lib/Target/X86/X86InstrSSE.td
index 27bfdb4aa18f9..6396491af42c4 100644
--- a/llvm/lib/Target/X86/X86InstrSSE.td
+++ b/llvm/lib/Target/X86/X86InstrSSE.td
@@ -5451,22 +5451,24 @@ let Constraints = "$src1 = $dst" in
 
 multiclass SS41I_insert32<bits<8> opc, string asm, bit Is2Addr = 1> {
   def rri : SS4AIi8<opc, MRMSrcReg, (outs VR128:$dst),
-      (ins VR128:$src1, GR32:$src2, u8imm:$src3),
+      (ins VR128:$src1, GR32:$src2, vecidximm:$src3),
       !if(Is2Addr,
         !strconcat(asm, "\t{$src3, $src2, $dst|$dst, $src2, $src3}"),
         !strconcat(asm,
                    "\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}")),
       [(set VR128:$dst,
-        (v4i32 (insertelt VR128:$src1, GR32:$src2, imm:$src3)))]>,
+        (v4i32 (insertelt VR128:$src1, GR32:$src2,
+                          (X86VecIdxVT imm:$src3))))]>,
       Sched<[WriteVecInsert, ReadDefault, ReadInt2Fpu]>;
   def rmi : SS4AIi8<opc, MRMSrcMem, (outs VR128:$dst),
-      (ins VR128:$src1, i32mem:$src2, u8imm:$src3),
+      (ins VR128:$src1, i32mem:$src2, vecidximm:$src3),
       !if(Is2Addr,
         !strconcat(asm, "\t{$src3, $src2, $dst|$dst, $src2, $src3}"),
         !strconcat(asm,
                    "\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}")),
       [(set VR128:$dst,
-        (v4i32 (insertelt VR128:$src1, (loadi32 addr:$src2), imm:$src3)))]>,
+        (v4i32 (insertelt VR128:$src1, (loadi32 addr:$src2),
+                          (X86VecIdxVT imm:$src3))))]>,
                    Sched<[WriteVecInsert.Folded, WriteVecInsert.ReadAfterFold]>;
 }
 
@@ -5477,22 +5479,24 @@ let Constraints = "$src1 = $dst" in
 
 multiclass SS41I_insert64<bits<8> opc, string asm, bit Is2Addr = 1> {
   def rri : SS4AIi8<opc, MRMSrcReg, (outs VR128:$dst),
-      (ins VR128:$src1, GR64:$src2, u8imm:$src3),
+      (ins VR128:$src1, GR64:$src2, vecidximm:$src3),
       !if(Is2Addr,
         !strconcat(asm, "\t{$src3, $src2, $dst|$dst, $src2, $src3}"),
         !strconcat(asm,
                    "\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}")),
       [(set VR128:$dst,
-        (v2i64 (insertelt VR128:$src1, GR64:$src2, imm:$src3)))]>,
+        (v2i64 (insertelt VR128:$src1, GR64:$src2,
+                          (X86VecIdxVT imm:$src3))))]>,
       Sched<[WriteVecInsert, ReadDefault, ReadInt2Fpu]>;
   def rmi : SS4AIi8<opc, MRMSrcMem, (outs VR128:$dst),
-      (ins VR128:$src1, i64mem:$src2, u8imm:$src3),
+      (ins VR128:$src1, i64mem:$src2, vecidximm:$src3),
       !if(Is2Addr,
         !strconcat(asm, "\t{$src3, $src2, $dst|$dst, $src2, $src3}"),
         !strconcat(asm,
                    "\t{$src3, $src2, $src1, $dst|$dst, $src1, $src2, $src3}")),
       [(set VR128:$dst,
-        (v2i64 (insertelt VR128:$src1, (loadi64 addr:$src2), imm:$src3)))]>,
+        (v2i64 (insertelt VR128:$src1, (loadi64 addr:$src2),
+                          (X86VecIdxVT imm:$src3))))]>,
                    Sched<[WriteVecInsert.Folded, WriteVecInsert.ReadAfterFold]>;
 }
 
diff --git a/llvm/test/CodeGen/X86/isel-insertelt-avx.ll b/llvm/test/CodeGen/X86/isel-insertelt-avx.ll
new file mode 100644
index 0000000000000..995a158cf8f3e
--- /dev/null
+++ b/llvm/test/CodeGen/X86/isel-insertelt-avx.ll
@@ -0,0 +1,108 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=x86_64-linux-gnu    -mattr=+avx %s -o - | FileCheck %s --check-prefixes=AVX,AVX-X64
+; RUN: llc -mtriple=x86_64-linux-gnu    -mattr=+avx -fast-isel %s -o - | FileCheck %s --check-prefixes=AVX,AVX-X64
+; RUN: llc -mtriple=x86_64-linux-gnu    -mattr=+avx -global-isel -global-isel-abort=1 %s -o - | FileCheck %s --check-prefixes=AVX,AVX-X64
+; RUN: llc -mtriple=x86_64-linux-gnux32 -mattr=+avx %s -o - | FileCheck %s --check-prefixes=AVX,AVX-X32
+; RUN: llc -mtriple=x86_64-linux-gnux32 -mattr=+avx -fast-isel %s -o - | FileCheck %s --check-prefixes=AVX,AVX-X32
+; RUN: llc -mtriple=x86_64-linux-gnux32 -mattr=+avx -global-isel -global-isel-abort=1 %s -o - | FileCheck %s --check-prefixes=AVX,AVX-X32
+; RUN: llc -mtriple=i686-linux-gnu      -mattr=+avx %s -o - | FileCheck %s --check-prefixes=AVX,AVX-X86
+; RUN: llc -mtriple=i686-linux-gnu      -mattr=+avx -fast-isel %s -o - | FileCheck %s --check-prefixes=AVX,AVX-X86
+; RUN: llc -mtriple=i686-linux-gnu      -mattr=+avx -global-isel -global-isel-abort=2 %s -o - | FileCheck %s --check-prefixes=AVX,AVX-X86
+
+; The vector index is pointer-sized: i64 on x86-64 and i32 on x32 and i686.
+; GlobalISel doesn't support <2 x i64> inserts on i686 yet, hence abort=2.
+
+ at g32 = global i32 0
+ at g64 = global i64 0
+
+define <4 x i32> @insert_v4i32(<4 x i32> %v, i32 %e) {
+; AVX-X64-LABEL: insert_v4i32:
+; AVX-X64:       # %bb.0:
+; AVX-X64-NEXT:    vpinsrd $2, %edi, %xmm0, %xmm0
+; AVX-X64-NEXT:    retq
+;
+; AVX-X32-LABEL: insert_v4i32:
+; AVX-X32:       # %bb.0:
+; AVX-X32-NEXT:    vpinsrd $2, %edi, %xmm0, %xmm0
+; AVX-X32-NEXT:    retq
+;
+; AVX-X86-LABEL: insert_v4i32:
+; AVX-X86:       # %bb.0:
+; AVX-X86-NEXT:    vpinsrd $2, {{[0-9]+}}(%esp), %xmm0, %xmm0
+; AVX-X86-NEXT:    retl
+  %r = insertelement <4 x i32> %v, i32 %e, i32 2
+  ret <4 x i32> %r
+}
+
+define <4 x i32> @insert_v4i32_load(<4 x i32> %v) {
+; AVX-X64-LABEL: insert_v4i32_load:
+; AVX-X64:       # %bb.0:
+; AVX-X64-NEXT:    movq g32 at GOTPCREL(%rip), %rax
+; AVX-X64-NEXT:    vpinsrd $3, (%rax), %xmm0, %xmm0
+; AVX-X64-NEXT:    retq
+;
+; AVX-X32-LABEL: insert_v4i32_load:
+; AVX-X32:       # %bb.0:
+; AVX-X32-NEXT:    movl g32 at GOTPCREL(%rip), %eax
+; AVX-X32-NEXT:    vpinsrd $3, (%eax), %xmm0, %xmm0
+; AVX-X32-NEXT:    retq
+;
+; AVX-X86-LABEL: insert_v4i32_load:
+; AVX-X86:       # %bb.0:
+; AVX-X86-NEXT:    vpinsrd $3, g32, %xmm0, %xmm0
+; AVX-X86-NEXT:    retl
+  %e = load i32, ptr @g32
+  %r = insertelement <4 x i32> %v, i32 %e, i32 3
+  ret <4 x i32> %r
+}
+
+define <2 x i64> @insert_v2i64(<2 x i64> %v, i64 %e) {
+; AVX-X64-LABEL: insert_v2i64:
+; AVX-X64:       # %bb.0:
+; AVX-X64-NEXT:    vpinsrq $1, %rdi, %xmm0, %xmm0
+; AVX-X64-NEXT:    retq
+;
+; AVX-X32-LABEL: insert_v2i64:
+; AVX-X32:       # %bb.0:
+; AVX-X32-NEXT:    vpinsrq $1, %rdi, %xmm0, %xmm0
+; AVX-X32-NEXT:    retq
+;
+; AVX-X86-LABEL: insert_v2i64:
+; AVX-X86:       # %bb.0:
+; AVX-X86-NEXT:    vpinsrd $2, {{[0-9]+}}(%esp), %xmm0, %xmm0
+; AVX-X86-NEXT:    vpinsrd $3, {{[0-9]+}}(%esp), %xmm0, %xmm0
+; AVX-X86-NEXT:    retl
+  %r = insertelement <2 x i64> %v, i64 %e, i32 1
+  ret <2 x i64> %r
+}
+
+define <2 x i64> @insert_v2i64_load(<2 x i64> %v) {
+; AVX-X64-LABEL: insert_v2i64_load:
+; AVX-X64:       # %bb.0:
+; AVX-X64-NEXT:    movq g64 at GOTPCREL(%rip), %rax
+; AVX-X64-NEXT:    vpinsrq $1, (%rax), %xmm0, %xmm0
+; AVX-X64-NEXT:    retq
+;
+; AVX-X32-LABEL: insert_v2i64_load:
+; AVX-X32:       # %bb.0:
+; AVX-X32-NEXT:    movl g64 at GOTPCREL(%rip), %eax
+; AVX-X32-NEXT:    vpinsrq $1, (%eax), %xmm0, %xmm0
+; AVX-X32-NEXT:    retq
+;
+; AVX-X86-LABEL: insert_v2i64_load:
+; AVX-X86:       # %bb.0:
+; AVX-X86-NEXT:    vpinsrd $2, g64, %xmm0, %xmm0
+; AVX-X86-NEXT:    vpinsrd $3, g64+4, %xmm0, %xmm0
+; AVX-X86-NEXT:    retl
+  %e = load i64, ptr @g64
+  %r = insertelement <2 x i64> %v, i64 %e, i32 1
+  ret <2 x i64> %r
+}
+
+define <4 x i32> @insert_v4i32_out_of_bounds(<4 x i32> %v, i32 %e) {
+; AVX-LABEL: insert_v4i32_out_of_bounds:
+; AVX:       # %bb.0:
+; AVX-NEXT:    ret{{[l|q]}}
+  %r = insertelement <4 x i32> %v, i32 %e, i32 4
+  ret <4 x i32> %r
+}
diff --git a/llvm/test/CodeGen/X86/isel-insertelt-avx512.ll b/llvm/test/CodeGen/X86/isel-insertelt-avx512.ll
new file mode 100644
index 0000000000000..d6d91c98b03a2
--- /dev/null
+++ b/llvm/test/CodeGen/X86/isel-insertelt-avx512.ll
@@ -0,0 +1,115 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=x86_64-linux-gnu    -mattr=+avx512dq -show-mc-encoding %s -o - | FileCheck %s --check-prefixes=AVX512,AVX512-X64
+; RUN: llc -mtriple=x86_64-linux-gnu    -mattr=+avx512dq -show-mc-encoding -fast-isel %s -o - | FileCheck %s --check-prefixes=AVX512,AVX512-X64
+; RUN: llc -mtriple=x86_64-linux-gnu    -mattr=+avx512dq -show-mc-encoding -global-isel -global-isel-abort=1 %s -o - | FileCheck %s --check-prefixes=AVX512,AVX512-X64
+; RUN: llc -mtriple=x86_64-linux-gnux32 -mattr=+avx512dq -show-mc-encoding %s -o - | FileCheck %s --check-prefixes=AVX512,AVX512-X32
+; RUN: llc -mtriple=x86_64-linux-gnux32 -mattr=+avx512dq -show-mc-encoding -fast-isel %s -o - | FileCheck %s --check-prefixes=AVX512,AVX512-X32
+; RUN: llc -mtriple=x86_64-linux-gnux32 -mattr=+avx512dq -show-mc-encoding -global-isel -global-isel-abort=1 %s -o - | FileCheck %s --check-prefixes=AVX512,AVX512-X32
+; RUN: llc -mtriple=i686-linux-gnu      -mattr=+avx512dq -show-mc-encoding %s -o - | FileCheck %s --check-prefixes=AVX512,AVX512-X86
+; RUN: llc -mtriple=i686-linux-gnu      -mattr=+avx512dq -show-mc-encoding -fast-isel %s -o - | FileCheck %s --check-prefixes=AVX512,AVX512-X86
+; RUN: llc -mtriple=i686-linux-gnu      -mattr=+avx512dq -show-mc-encoding -global-isel -global-isel-abort=2 %s -o - | FileCheck %s --check-prefixes=AVX512,AVX512-X86
+
+; The vector index is pointer-sized: i64 on x86-64 and i32 on x32 and i686.
+; GlobalISel doesn't support <2 x i64> inserts on i686 yet, hence abort=2.
+
+ at g32 = global i32 0
+ at g64 = global i64 0
+
+define <4 x i32> @insert_v4i32(<4 x i32> %v, i32 %e) {
+; AVX512-X64-LABEL: insert_v4i32:
+; AVX512-X64:       # %bb.0:
+; AVX512-X64-NEXT:    vpinsrd $2, %edi, %xmm0, %xmm0 # EVEX TO VEX Compression encoding: [0xc4,0xe3,0x79,0x22,0xc7,0x02]
+; AVX512-X64-NEXT:    retq # encoding: [0xc3]
+;
+; AVX512-X32-LABEL: insert_v4i32:
+; AVX512-X32:       # %bb.0:
+; AVX512-X32-NEXT:    vpinsrd $2, %edi, %xmm0, %xmm0 # EVEX TO VEX Compression encoding: [0xc4,0xe3,0x79,0x22,0xc7,0x02]
+; AVX512-X32-NEXT:    retq # encoding: [0xc3]
+;
+; AVX512-X86-LABEL: insert_v4i32:
+; AVX512-X86:       # %bb.0:
+; AVX512-X86-NEXT:    vpinsrd $2, {{[0-9]+}}(%esp), %xmm0, %xmm0 # EVEX TO VEX Compression encoding: [0xc4,0xe3,0x79,0x22,0x44,0x24,0x04,0x02]
+; AVX512-X86-NEXT:    retl # encoding: [0xc3]
+  %r = insertelement <4 x i32> %v, i32 %e, i32 2
+  ret <4 x i32> %r
+}
+
+define <4 x i32> @insert_v4i32_load(<4 x i32> %v) {
+; AVX512-X64-LABEL: insert_v4i32_load:
+; AVX512-X64:       # %bb.0:
+; AVX512-X64-NEXT:    movq g32 at GOTPCREL(%rip), %rax # encoding: [0x48,0x8b,0x05,A,A,A,A]
+; AVX512-X64-NEXT:    # fixup A - offset: 3, value: g32 at GOTPCREL, kind: reloc_riprel_4byte_movq_load
+; AVX512-X64-NEXT:    vpinsrd $3, (%rax), %xmm0, %xmm0 # EVEX TO VEX Compression encoding: [0xc4,0xe3,0x79,0x22,0x00,0x03]
+; AVX512-X64-NEXT:    retq # encoding: [0xc3]
+;
+; AVX512-X32-LABEL: insert_v4i32_load:
+; AVX512-X32:       # %bb.0:
+; AVX512-X32-NEXT:    movl g32 at GOTPCREL(%rip), %eax # encoding: [0x8b,0x05,A,A,A,A]
+; AVX512-X32-NEXT:    # fixup A - offset: 2, value: g32 at GOTPCREL, kind: reloc_riprel_4byte_relax
+; AVX512-X32-NEXT:    vpinsrd $3, (%eax), %xmm0, %xmm0 # EVEX TO VEX Compression encoding: [0x67,0xc4,0xe3,0x79,0x22,0x00,0x03]
+; AVX512-X32-NEXT:    retq # encoding: [0xc3]
+;
+; AVX512-X86-LABEL: insert_v4i32_load:
+; AVX512-X86:       # %bb.0:
+; AVX512-X86-NEXT:    vpinsrd $3, g32, %xmm0, %xmm0 # EVEX TO VEX Compression encoding: [0xc4,0xe3,0x79,0x22,0x05,A,A,A,A,0x03]
+; AVX512-X86-NEXT:    # fixup A - offset: 5, value: g32, kind: FK_Data_4
+; AVX512-X86-NEXT:    retl # encoding: [0xc3]
+  %e = load i32, ptr @g32
+  %r = insertelement <4 x i32> %v, i32 %e, i32 3
+  ret <4 x i32> %r
+}
+
+define <2 x i64> @insert_v2i64(<2 x i64> %v, i64 %e) {
+; AVX512-X64-LABEL: insert_v2i64:
+; AVX512-X64:       # %bb.0:
+; AVX512-X64-NEXT:    vpinsrq $1, %rdi, %xmm0, %xmm0 # EVEX TO VEX Compression encoding: [0xc4,0xe3,0xf9,0x22,0xc7,0x01]
+; AVX512-X64-NEXT:    retq # encoding: [0xc3]
+;
+; AVX512-X32-LABEL: insert_v2i64:
+; AVX512-X32:       # %bb.0:
+; AVX512-X32-NEXT:    vpinsrq $1, %rdi, %xmm0, %xmm0 # EVEX TO VEX Compression encoding: [0xc4,0xe3,0xf9,0x22,0xc7,0x01]
+; AVX512-X32-NEXT:    retq # encoding: [0xc3]
+;
+; AVX512-X86-LABEL: insert_v2i64:
+; AVX512-X86:       # %bb.0:
+; AVX512-X86-NEXT:    vpinsrd $2, {{[0-9]+}}(%esp), %xmm0, %xmm0 # EVEX TO VEX Compression encoding: [0xc4,0xe3,0x79,0x22,0x44,0x24,0x04,0x02]
+; AVX512-X86-NEXT:    vpinsrd $3, {{[0-9]+}}(%esp), %xmm0, %xmm0 # EVEX TO VEX Compression encoding: [0xc4,0xe3,0x79,0x22,0x44,0x24,0x08,0x03]
+; AVX512-X86-NEXT:    retl # encoding: [0xc3]
+  %r = insertelement <2 x i64> %v, i64 %e, i32 1
+  ret <2 x i64> %r
+}
+
+define <2 x i64> @insert_v2i64_load(<2 x i64> %v) {
+; AVX512-X64-LABEL: insert_v2i64_load:
+; AVX512-X64:       # %bb.0:
+; AVX512-X64-NEXT:    movq g64 at GOTPCREL(%rip), %rax # encoding: [0x48,0x8b,0x05,A,A,A,A]
+; AVX512-X64-NEXT:    # fixup A - offset: 3, value: g64 at GOTPCREL, kind: reloc_riprel_4byte_movq_load
+; AVX512-X64-NEXT:    vpinsrq $1, (%rax), %xmm0, %xmm0 # EVEX TO VEX Compression encoding: [0xc4,0xe3,0xf9,0x22,0x00,0x01]
+; AVX512-X64-NEXT:    retq # encoding: [0xc3]
+;
+; AVX512-X32-LABEL: insert_v2i64_load:
+; AVX512-X32:       # %bb.0:
+; AVX512-X32-NEXT:    movl g64 at GOTPCREL(%rip), %eax # encoding: [0x8b,0x05,A,A,A,A]
+; AVX512-X32-NEXT:    # fixup A - offset: 2, value: g64 at GOTPCREL, kind: reloc_riprel_4byte_relax
+; AVX512-X32-NEXT:    vpinsrq $1, (%eax), %xmm0, %xmm0 # EVEX TO VEX Compression encoding: [0x67,0xc4,0xe3,0xf9,0x22,0x00,0x01]
+; AVX512-X32-NEXT:    retq # encoding: [0xc3]
+;
+; AVX512-X86-LABEL: insert_v2i64_load:
+; AVX512-X86:       # %bb.0:
+; AVX512-X86-NEXT:    vpinsrd $2, g64, %xmm0, %xmm0 # EVEX TO VEX Compression encoding: [0xc4,0xe3,0x79,0x22,0x05,A,A,A,A,0x02]
+; AVX512-X86-NEXT:    # fixup A - offset: 5, value: g64, kind: FK_Data_4
+; AVX512-X86-NEXT:    vpinsrd $3, g64+4, %xmm0, %xmm0 # EVEX TO VEX Compression encoding: [0xc4,0xe3,0x79,0x22,0x05,A,A,A,A,0x03]
+; AVX512-X86-NEXT:    # fixup A - offset: 5, value: g64+4, kind: FK_Data_4
+; AVX512-X86-NEXT:    retl # encoding: [0xc3]
+  %e = load i64, ptr @g64
+  %r = insertelement <2 x i64> %v, i64 %e, i32 1
+  ret <2 x i64> %r
+}
+
+define <4 x i32> @insert_v4i32_out_of_bounds(<4 x i32> %v, i32 %e) {
+; AVX512-LABEL: insert_v4i32_out_of_bounds:
+; AVX512:       # %bb.0:
+; AVX512-NEXT:    ret{{[l|q]}} # encoding: [0xc3]
+  %r = insertelement <4 x i32> %v, i32 %e, i32 4
+  ret <4 x i32> %r
+}
diff --git a/llvm/test/CodeGen/X86/isel-insertelt-sse41.ll b/llvm/test/CodeGen/X86/isel-insertelt-sse41.ll
new file mode 100644
index 0000000000000..04d4a4075c4a8
--- /dev/null
+++ b/llvm/test/CodeGen/X86/isel-insertelt-sse41.ll
@@ -0,0 +1,108 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=x86_64-linux-gnu    -mattr=+sse4.1 %s -o - | FileCheck %s --check-prefixes=SSE41,SSE41-X64
+; RUN: llc -mtriple=x86_64-linux-gnu    -mattr=+sse4.1 -fast-isel %s -o - | FileCheck %s --check-prefixes=SSE41,SSE41-X64
+; RUN: llc -mtriple=x86_64-linux-gnu    -mattr=+sse4.1 -global-isel -global-isel-abort=1 %s -o - | FileCheck %s --check-prefixes=SSE41,SSE41-X64
+; RUN: llc -mtriple=x86_64-linux-gnux32 -mattr=+sse4.1 %s -o - | FileCheck %s --check-prefixes=SSE41,SSE41-X32
+; RUN: llc -mtriple=x86_64-linux-gnux32 -mattr=+sse4.1 -fast-isel %s -o - | FileCheck %s --check-prefixes=SSE41,SSE41-X32
+; RUN: llc -mtriple=x86_64-linux-gnux32 -mattr=+sse4.1 -global-isel -global-isel-abort=1 %s -o - | FileCheck %s --check-prefixes=SSE41,SSE41-X32
+; RUN: llc -mtriple=i686-linux-gnu      -mattr=+sse4.1 %s -o - | FileCheck %s --check-prefixes=SSE41,SSE41-X86
+; RUN: llc -mtriple=i686-linux-gnu      -mattr=+sse4.1 -fast-isel %s -o - | FileCheck %s --check-prefixes=SSE41,SSE41-X86
+; RUN: llc -mtriple=i686-linux-gnu      -mattr=+sse4.1 -global-isel -global-isel-abort=2 %s -o - | FileCheck %s --check-prefixes=SSE41,SSE41-X86
+
+; The vector index is pointer-sized: i64 on x86-64 and i32 on x32 and i686.
+; GlobalISel doesn't support <2 x i64> inserts on i686 yet, hence abort=2.
+
+ at g32 = global i32 0
+ at g64 = global i64 0
+
+define <4 x i32> @insert_v4i32(<4 x i32> %v, i32 %e) {
+; SSE41-X64-LABEL: insert_v4i32:
+; SSE41-X64:       # %bb.0:
+; SSE41-X64-NEXT:    pinsrd $2, %edi, %xmm0
+; SSE41-X64-NEXT:    retq
+;
+; SSE41-X32-LABEL: insert_v4i32:
+; SSE41-X32:       # %bb.0:
+; SSE41-X32-NEXT:    pinsrd $2, %edi, %xmm0
+; SSE41-X32-NEXT:    retq
+;
+; SSE41-X86-LABEL: insert_v4i32:
+; SSE41-X86:       # %bb.0:
+; SSE41-X86-NEXT:    pinsrd $2, {{[0-9]+}}(%esp), %xmm0
+; SSE41-X86-NEXT:    retl
+  %r = insertelement <4 x i32> %v, i32 %e, i32 2
+  ret <4 x i32> %r
+}
+
+define <4 x i32> @insert_v4i32_load(<4 x i32> %v) {
+; SSE41-X64-LABEL: insert_v4i32_load:
+; SSE41-X64:       # %bb.0:
+; SSE41-X64-NEXT:    movq g32 at GOTPCREL(%rip), %rax
+; SSE41-X64-NEXT:    pinsrd $3, (%rax), %xmm0
+; SSE41-X64-NEXT:    retq
+;
+; SSE41-X32-LABEL: insert_v4i32_load:
+; SSE41-X32:       # %bb.0:
+; SSE41-X32-NEXT:    movl g32 at GOTPCREL(%rip), %eax
+; SSE41-X32-NEXT:    pinsrd $3, (%eax), %xmm0
+; SSE41-X32-NEXT:    retq
+;
+; SSE41-X86-LABEL: insert_v4i32_load:
+; SSE41-X86:       # %bb.0:
+; SSE41-X86-NEXT:    pinsrd $3, g32, %xmm0
+; SSE41-X86-NEXT:    retl
+  %e = load i32, ptr @g32
+  %r = insertelement <4 x i32> %v, i32 %e, i32 3
+  ret <4 x i32> %r
+}
+
+define <2 x i64> @insert_v2i64(<2 x i64> %v, i64 %e) {
+; SSE41-X64-LABEL: insert_v2i64:
+; SSE41-X64:       # %bb.0:
+; SSE41-X64-NEXT:    pinsrq $1, %rdi, %xmm0
+; SSE41-X64-NEXT:    retq
+;
+; SSE41-X32-LABEL: insert_v2i64:
+; SSE41-X32:       # %bb.0:
+; SSE41-X32-NEXT:    pinsrq $1, %rdi, %xmm0
+; SSE41-X32-NEXT:    retq
+;
+; SSE41-X86-LABEL: insert_v2i64:
+; SSE41-X86:       # %bb.0:
+; SSE41-X86-NEXT:    pinsrd $2, {{[0-9]+}}(%esp), %xmm0
+; SSE41-X86-NEXT:    pinsrd $3, {{[0-9]+}}(%esp), %xmm0
+; SSE41-X86-NEXT:    retl
+  %r = insertelement <2 x i64> %v, i64 %e, i32 1
+  ret <2 x i64> %r
+}
+
+define <2 x i64> @insert_v2i64_load(<2 x i64> %v) {
+; SSE41-X64-LABEL: insert_v2i64_load:
+; SSE41-X64:       # %bb.0:
+; SSE41-X64-NEXT:    movq g64 at GOTPCREL(%rip), %rax
+; SSE41-X64-NEXT:    pinsrq $1, (%rax), %xmm0
+; SSE41-X64-NEXT:    retq
+;
+; SSE41-X32-LABEL: insert_v2i64_load:
+; SSE41-X32:       # %bb.0:
+; SSE41-X32-NEXT:    movl g64 at GOTPCREL(%rip), %eax
+; SSE41-X32-NEXT:    pinsrq $1, (%eax), %xmm0
+; SSE41-X32-NEXT:    retq
+;
+; SSE41-X86-LABEL: insert_v2i64_load:
+; SSE41-X86:       # %bb.0:
+; SSE41-X86-NEXT:    pinsrd $2, g64, %xmm0
+; SSE41-X86-NEXT:    pinsrd $3, g64+4, %xmm0
+; SSE41-X86-NEXT:    retl
+  %e = load i64, ptr @g64
+  %r = insertelement <2 x i64> %v, i64 %e, i32 1
+  ret <2 x i64> %r
+}
+
+define <4 x i32> @insert_v4i32_out_of_bounds(<4 x i32> %v, i32 %e) {
+; SSE41-LABEL: insert_v4i32_out_of_bounds:
+; SSE41:       # %bb.0:
+; SSE41-NEXT:    ret{{[l|q]}}
+  %r = insertelement <4 x i32> %v, i32 %e, i32 4
+  ret <4 x i32> %r
+}
diff --git a/llvm/test/CodeGen/X86/isel-insertelt-var-idx.ll b/llvm/test/CodeGen/X86/isel-insertelt-var-idx.ll
new file mode 100644
index 0000000000000..34baf2e6a207e
--- /dev/null
+++ b/llvm/test/CodeGen/X86/isel-insertelt-var-idx.ll
@@ -0,0 +1,80 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 6
+; RUN: llc -mtriple=x86_64-linux-gnu -mattr=+sse4.1 %s -o - | FileCheck %s --check-prefixes=X64-SDAG
+; RUN: llc -mtriple=x86_64-linux-gnu -mattr=+sse4.1 -fast-isel %s -o - | FileCheck %s --check-prefixes=X64-SDAG
+; RUN: llc -mtriple=x86_64-linux-gnu -mattr=+sse4.1 -global-isel -global-isel-abort=1 %s -o - | FileCheck %s --check-prefixes=X64-GISEL
+; RUN: llc -mtriple=i686-linux-gnu   -mattr=+sse4.1 %s -o - | FileCheck %s --check-prefixes=X86-SDAG
+; RUN: llc -mtriple=i686-linux-gnu   -mattr=+sse4.1 -fast-isel %s -o - | FileCheck %s --check-prefixes=X86-FAST
+; RUN: llc -mtriple=i686-linux-gnu   -mattr=+sse4.1 -global-isel -global-isel-abort=1 %s -o - | FileCheck %s --check-prefixes=X86-GISEL
+
+; A variable index can't be encoded in PINSR*, the insert goes through memory.
+; No x32 RUN lines: GlobalISel can't select variable pointer offsets there yet.
+
+define <4 x i32> @insert_v4i32_var_idx(<4 x i32> %v, i32 %e, i32 %i) {
+; X64-SDAG-LABEL: insert_v4i32_var_idx:
+; X64-SDAG:       # %bb.0:
+; X64-SDAG-NEXT:    # kill: def $esi killed $esi def $rsi
+; X64-SDAG-NEXT:    movaps %xmm0, -{{[0-9]+}}(%rsp)
+; X64-SDAG-NEXT:    andl $3, %esi
+; X64-SDAG-NEXT:    movl %edi, -24(%rsp,%rsi,4)
+; X64-SDAG-NEXT:    movaps -{{[0-9]+}}(%rsp), %xmm0
+; X64-SDAG-NEXT:    retq
+;
+; X64-GISEL-LABEL: insert_v4i32_var_idx:
+; X64-GISEL:       # %bb.0:
+; X64-GISEL-NEXT:    movl %esi, %eax
+; X64-GISEL-NEXT:    leaq -{{[0-9]+}}(%rsp), %rcx
+; X64-GISEL-NEXT:    movaps %xmm0, -{{[0-9]+}}(%rsp)
+; X64-GISEL-NEXT:    andq $3, %rax
+; X64-GISEL-NEXT:    imulq $4, %rax, %rax
+; X64-GISEL-NEXT:    addq %rcx, %rax
+; X64-GISEL-NEXT:    movl %edi, (%rax)
+; X64-GISEL-NEXT:    movaps -{{[0-9]+}}(%rsp), %xmm0
+; X64-GISEL-NEXT:    retq
+;
+; X86-SDAG-LABEL: insert_v4i32_var_idx:
+; X86-SDAG:       # %bb.0:
+; X86-SDAG-NEXT:    subl $28, %esp
+; X86-SDAG-NEXT:    .cfi_def_cfa_offset 32
+; X86-SDAG-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-SDAG-NEXT:    andl $3, %eax
+; X86-SDAG-NEXT:    movl {{[0-9]+}}(%esp), %ecx
+; X86-SDAG-NEXT:    movaps %xmm0, (%esp)
+; X86-SDAG-NEXT:    movl %ecx, (%esp,%eax,4)
+; X86-SDAG-NEXT:    movaps (%esp), %xmm0
+; X86-SDAG-NEXT:    addl $28, %esp
+; X86-SDAG-NEXT:    .cfi_def_cfa_offset 4
+; X86-SDAG-NEXT:    retl
+;
+; X86-FAST-LABEL: insert_v4i32_var_idx:
+; X86-FAST:       # %bb.0:
+; X86-FAST-NEXT:    subl $28, %esp
+; X86-FAST-NEXT:    .cfi_def_cfa_offset 32
+; X86-FAST-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-FAST-NEXT:    movl {{[0-9]+}}(%esp), %ecx
+; X86-FAST-NEXT:    movaps %xmm0, (%esp)
+; X86-FAST-NEXT:    andl $3, %eax
+; X86-FAST-NEXT:    movl %ecx, (%esp,%eax,4)
+; X86-FAST-NEXT:    movaps (%esp), %xmm0
+; X86-FAST-NEXT:    addl $28, %esp
+; X86-FAST-NEXT:    .cfi_def_cfa_offset 4
+; X86-FAST-NEXT:    retl
+;
+; X86-GISEL-LABEL: insert_v4i32_var_idx:
+; X86-GISEL:       # %bb.0:
+; X86-GISEL-NEXT:    subl $28, %esp
+; X86-GISEL-NEXT:    .cfi_def_cfa_offset 32
+; X86-GISEL-NEXT:    movl {{[0-9]+}}(%esp), %eax
+; X86-GISEL-NEXT:    movl {{[0-9]+}}(%esp), %ecx
+; X86-GISEL-NEXT:    movl %esp, %edx
+; X86-GISEL-NEXT:    movaps %xmm0, (%esp)
+; X86-GISEL-NEXT:    andl $3, %ecx
+; X86-GISEL-NEXT:    imull $4, %ecx, %ecx
+; X86-GISEL-NEXT:    addl %edx, %ecx
+; X86-GISEL-NEXT:    movl %eax, (%ecx)
+; X86-GISEL-NEXT:    movaps (%esp), %xmm0
+; X86-GISEL-NEXT:    addl $28, %esp
+; X86-GISEL-NEXT:    .cfi_def_cfa_offset 4
+; X86-GISEL-NEXT:    retl
+  %r = insertelement <4 x i32> %v, i32 %e, i32 %i
+  ret <4 x i32> %r
+}
diff --git a/llvm/utils/TableGen/X86RecognizableInstr.cpp b/llvm/utils/TableGen/X86RecognizableInstr.cpp
index 44b76ae7e8487..37d48c9e3b7d3 100644
--- a/llvm/utils/TableGen/X86RecognizableInstr.cpp
+++ b/llvm/utils/TableGen/X86RecognizableInstr.cpp
@@ -1036,6 +1036,7 @@ OperandType RecognizableInstr::typeFromString(StringRef Str, bool hasREX_W,
           .Case("i8imm", TYPE_IMM)
           .Case("u4imm", TYPE_UIMM8)
           .Case("u8imm", TYPE_UIMM8)
+          .Case("vecidximm", TYPE_UIMM8)
           .Case("i16u8imm", TYPE_UIMM8)
           .Case("i32u8imm", TYPE_UIMM8)
           .Case("i64u8imm", TYPE_UIMM8)
@@ -1173,6 +1174,7 @@ OperandEncoding RecognizableInstr::immediateEncodingFromString(StringRef Str,
           .Case("cflags", ENCODING_CF)
           .Case("u4imm", ENCODING_IB)
           .Case("u8imm", ENCODING_IB)
+          .Case("vecidximm", ENCODING_IB)
           .Case("i16u8imm", ENCODING_IB)
           .Case("i32u8imm", ENCODING_IB)
           .Case("i64u8imm", ENCODING_IB)
@@ -1434,6 +1436,7 @@ RecognizableInstr::relocationEncodingFromString(StringRef Str, uint8_t OpSize) {
           .Case("i64i8imm", ENCODING_IB)
           .Case("i8imm", ENCODING_IB)
           .Case("u8imm", ENCODING_IB)
+          .Case("vecidximm", ENCODING_IB)
           .Case("i16u8imm", ENCODING_IB)
           .Case("i32u8imm", ENCODING_IB)
           .Case("i64u8imm", ENCODING_IB)

>From ae49c8e921bed6800829405da558e1da0531f992 Mon Sep 17 00:00:00 2001
From: Evgenii Kudriashov <evgenii.kudriashov at intel.com>
Date: Sun, 11 Oct 2026 23:20:21 +0200
Subject: [PATCH 2/2] Finishing touches 1

---
 .../include/llvm/CodeGen/GlobalISel/LegalizerInfo.h |  6 ++++++
 llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp      | 13 +++++--------
 llvm/lib/Target/X86/X86InstrOperands.td             |  4 +---
 llvm/lib/Target/X86/X86InstrPredicates.td           |  5 +----
 llvm/test/CodeGen/X86/isel-insertelt-var-idx.ll     |  8 +-------
 5 files changed, 14 insertions(+), 22 deletions(-)

diff --git a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h
index cbfe8146a70f8..020e58b503ebf 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h
@@ -932,6 +932,12 @@ class LegalizeRuleSet {
       return *this;
     return actionFor(LegalizeAction::Custom, Types);
   }
+  LegalizeRuleSet &
+  customFor(bool Pred, std::initializer_list<std::tuple<LLT, LLT, LLT>> Types) {
+    if (!Pred)
+      return *this;
+    return actionFor(LegalizeAction::Custom, Types);
+  }
 
   LegalizeRuleSet &customForCartesianProduct(std::initializer_list<LLT> Types) {
     return actionForCartesianProduct(LegalizeAction::Custom, Types);
diff --git a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
index 07450064f8ddd..3e3c0f0da08e4 100644
--- a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
+++ b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
@@ -51,7 +51,7 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
   bool HasLZCNT = Subtarget.hasLZCNT();
   bool HasBMI = Subtarget.hasBMI();
 
-  const LLT p0 = LLT::pointer(0, Subtarget.isTarget64BitLP64() ? 64 : 32);
+  const LLT p0 = LLT::pointer(0, TM.getPointerSizeInBits(0));
   const LLT s1 = LLT::scalar(1);
   const LLT s8 = LLT::scalar(8);
   const LLT s16 = LLT::scalar(16);
@@ -80,7 +80,8 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
   const LLT v16s32 = LLT::fixed_vector(16, 32);
   const LLT v8s64 = LLT::fixed_vector(8, 64);
 
-  const LLT sVecIdx = LLT::scalar(p0.getSizeInBits());
+  const LLT sVecIdx =
+      STI.getTargetLowering()->getVectorIdxLLT(TM.createDataLayout());
   const LLT s8MaxVector = HasAVX512 ? v64s8 : HasAVX ? v32s8 : v16s8;
   const LLT s16MaxVector = HasAVX512 ? v32s16 : HasAVX ? v16s16 : v8s16;
   const LLT s32MaxVector = HasAVX512 ? v16s32 : HasAVX ? v8s32 : v4s32;
@@ -564,12 +565,8 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
       .moreElementsToNextPow2(0);
 
   getActionDefinitionsBuilder(G_INSERT_VECTOR_ELT)
-      .customIf([=](const LegalityQuery &Query) {
-        return (HasSSE41 &&
-                typeTupleInSet(0, 1, 2, {{v4s32, s32, sVecIdx}})(Query)) ||
-               (HasSSE41 && Is64Bit &&
-                typeTupleInSet(0, 1, 2, {{v2s64, s64, sVecIdx}})(Query));
-      });
+      .customFor(HasSSE41, {{v4s32, s32, sVecIdx}})
+      .customFor(HasSSE41 && Is64Bit, {{v2s64, s64, sVecIdx}});
 
   getActionDefinitionsBuilder({G_EXTRACT, G_INSERT})
       .legalIf([=](const LegalityQuery &Query) {
diff --git a/llvm/lib/Target/X86/X86InstrOperands.td b/llvm/lib/Target/X86/X86InstrOperands.td
index 0c3b32375fb45..c55b342cb63c6 100644
--- a/llvm/lib/Target/X86/X86InstrOperands.td
+++ b/llvm/lib/Target/X86/X86InstrOperands.td
@@ -475,9 +475,7 @@ def u8imm : Operand<i8> {
   let OperandType = "OPERAND_IMMEDIATE";
 }
 
-// Unsigned 8-bit immediate used as a vector element index. Its value type is
-// the pointer-sized vector index type, so patterns on insertelt/extractelt
-// get a concrete index type per HwMode instead of iPTR.
+// Unsigned 8-bit immediate used as a vector element index based on HwMode.
 def vecidximm : Operand<X86VecIdxVT> {
   let PrintMethod = "printU8Imm";
   let ParserMatchClass = ImmUnsignedi8AsmOperand;
diff --git a/llvm/lib/Target/X86/X86InstrPredicates.td b/llvm/lib/Target/X86/X86InstrPredicates.td
index 06a78427cf5c0..d010d5f12a504 100644
--- a/llvm/lib/Target/X86/X86InstrPredicates.td
+++ b/llvm/lib/Target/X86/X86InstrPredicates.td
@@ -272,9 +272,6 @@ defvar X86_32 = DefaultMode;
 def X86_64 : HwMode<[In64BitMode, NotX32Mode]>;
 def X86_64_X32 : HwMode<[IsX32Mode]>;
 
-// Type of the vector element index (ISD::INSERT_VECTOR_ELT/EXTRACT_VECTOR_ELT),
-// which is pointer-sized (see TargetLoweringBase::getVectorIdxWidth). Unlike
-// iPTR, it is a concrete type per HwMode, so GlobalISel can import patterns
-// using it.
+// Type of the vector element index matching getVectorIdxWidth.
 def X86VecIdxVT : ValueTypeByHwMode<[X86_32, X86_64, X86_64_X32],
                                     [i32,    i64,    i32]>;
diff --git a/llvm/test/CodeGen/X86/isel-insertelt-var-idx.ll b/llvm/test/CodeGen/X86/isel-insertelt-var-idx.ll
index 34baf2e6a207e..75955d5c307dd 100644
--- a/llvm/test/CodeGen/X86/isel-insertelt-var-idx.ll
+++ b/llvm/test/CodeGen/X86/isel-insertelt-var-idx.ll
@@ -9,7 +9,7 @@
 ; A variable index can't be encoded in PINSR*, the insert goes through memory.
 ; No x32 RUN lines: GlobalISel can't select variable pointer offsets there yet.
 
-define <4 x i32> @insert_v4i32_var_idx(<4 x i32> %v, i32 %e, i32 %i) {
+define <4 x i32> @insert_v4i32_var_idx(<4 x i32> %v, i32 %e, i32 %i) nounwind {
 ; X64-SDAG-LABEL: insert_v4i32_var_idx:
 ; X64-SDAG:       # %bb.0:
 ; X64-SDAG-NEXT:    # kill: def $esi killed $esi def $rsi
@@ -34,7 +34,6 @@ define <4 x i32> @insert_v4i32_var_idx(<4 x i32> %v, i32 %e, i32 %i) {
 ; X86-SDAG-LABEL: insert_v4i32_var_idx:
 ; X86-SDAG:       # %bb.0:
 ; X86-SDAG-NEXT:    subl $28, %esp
-; X86-SDAG-NEXT:    .cfi_def_cfa_offset 32
 ; X86-SDAG-NEXT:    movl {{[0-9]+}}(%esp), %eax
 ; X86-SDAG-NEXT:    andl $3, %eax
 ; X86-SDAG-NEXT:    movl {{[0-9]+}}(%esp), %ecx
@@ -42,13 +41,11 @@ define <4 x i32> @insert_v4i32_var_idx(<4 x i32> %v, i32 %e, i32 %i) {
 ; X86-SDAG-NEXT:    movl %ecx, (%esp,%eax,4)
 ; X86-SDAG-NEXT:    movaps (%esp), %xmm0
 ; X86-SDAG-NEXT:    addl $28, %esp
-; X86-SDAG-NEXT:    .cfi_def_cfa_offset 4
 ; X86-SDAG-NEXT:    retl
 ;
 ; X86-FAST-LABEL: insert_v4i32_var_idx:
 ; X86-FAST:       # %bb.0:
 ; X86-FAST-NEXT:    subl $28, %esp
-; X86-FAST-NEXT:    .cfi_def_cfa_offset 32
 ; X86-FAST-NEXT:    movl {{[0-9]+}}(%esp), %eax
 ; X86-FAST-NEXT:    movl {{[0-9]+}}(%esp), %ecx
 ; X86-FAST-NEXT:    movaps %xmm0, (%esp)
@@ -56,13 +53,11 @@ define <4 x i32> @insert_v4i32_var_idx(<4 x i32> %v, i32 %e, i32 %i) {
 ; X86-FAST-NEXT:    movl %ecx, (%esp,%eax,4)
 ; X86-FAST-NEXT:    movaps (%esp), %xmm0
 ; X86-FAST-NEXT:    addl $28, %esp
-; X86-FAST-NEXT:    .cfi_def_cfa_offset 4
 ; X86-FAST-NEXT:    retl
 ;
 ; X86-GISEL-LABEL: insert_v4i32_var_idx:
 ; X86-GISEL:       # %bb.0:
 ; X86-GISEL-NEXT:    subl $28, %esp
-; X86-GISEL-NEXT:    .cfi_def_cfa_offset 32
 ; X86-GISEL-NEXT:    movl {{[0-9]+}}(%esp), %eax
 ; X86-GISEL-NEXT:    movl {{[0-9]+}}(%esp), %ecx
 ; X86-GISEL-NEXT:    movl %esp, %edx
@@ -73,7 +68,6 @@ define <4 x i32> @insert_v4i32_var_idx(<4 x i32> %v, i32 %e, i32 %i) {
 ; X86-GISEL-NEXT:    movl %eax, (%ecx)
 ; X86-GISEL-NEXT:    movaps (%esp), %xmm0
 ; X86-GISEL-NEXT:    addl $28, %esp
-; X86-GISEL-NEXT:    .cfi_def_cfa_offset 4
 ; X86-GISEL-NEXT:    retl
   %r = insertelement <4 x i32> %v, i32 %e, i32 %i
   ret <4 x i32> %r



More information about the llvm-commits mailing list