Skip to content

[X86] Added support for 8 and 16bit LEA instructions #122102

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 9 commits into from
Mar 4, 2025

Conversation

JaydeepChauhan14
Copy link
Contributor

No description provided.

@llvmbot
Copy link
Member

llvmbot commented Jan 8, 2025

@llvm/pr-subscribers-backend-x86

Author: None (JaydeepChauhan14)

Changes

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

6 Files Affected:

  • (modified) llvm/lib/Target/X86/X86ISelDAGToDAG.cpp (+37)
  • (modified) llvm/lib/Target/X86/X86InstrArithmetic.td (+6)
  • (modified) llvm/lib/Target/X86/X86InstrFragments.td (+5)
  • (modified) llvm/lib/Target/X86/X86InstrOperands.td (+6)
  • (added) llvm/test/CodeGen/X86/16bit-lea.ll (+14)
  • (modified) llvm/utils/TableGen/X86RecognizableInstr.cpp (+2)
diff --git a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
index 9b340a778b36ad..7f33b40503c2c8 100644
--- a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
@@ -226,6 +226,8 @@ namespace {
     bool selectLEAAddr(SDValue N, SDValue &Base,
                        SDValue &Scale, SDValue &Index, SDValue &Disp,
                        SDValue &Segment);
+    bool selectLEA64_16Addr(SDValue N, SDValue &Base, SDValue &Scale,
+                            SDValue &Index, SDValue &Disp, SDValue &Segment);
     bool selectLEA64_32Addr(SDValue N, SDValue &Base,
                             SDValue &Scale, SDValue &Index, SDValue &Disp,
                             SDValue &Segment);
@@ -3054,6 +3056,41 @@ bool X86DAGToDAGISel::selectMOV64Imm32(SDValue N, SDValue &Imm) {
   return !TM.isLargeGlobalValue(GV);
 }
 
+bool X86DAGToDAGISel::selectLEA64_16Addr(SDValue N, SDValue &Base,
+                                         SDValue &Scale, SDValue &Index,
+                                         SDValue &Disp, SDValue &Segment) {
+  // Save the debug loc before calling selectLEAAddr, in case it invalidates N.
+  SDLoc DL(N);
+
+  if (!selectLEAAddr(N, Base, Scale, Index, Disp, Segment))
+    return false;
+
+  auto *RN = dyn_cast<RegisterSDNode>(Base);
+  if (RN && RN->getReg() == 0)
+    Base = CurDAG->getRegister(0, MVT::i64);
+  else if (Base.getValueType() == MVT::i16 && !isa<FrameIndexSDNode>(Base)) {
+    // Base could already be %rip, particularly in the x32 ABI.
+    SDValue ImplDef =
+        SDValue(CurDAG->getMachineNode(X86::IMPLICIT_DEF, DL, MVT::i64), 0);
+    Base = CurDAG->getTargetInsertSubreg(X86::sub_16bit, DL, MVT::i64, ImplDef,
+                                         Base);
+  }
+
+  RN = dyn_cast<RegisterSDNode>(Index);
+  if (RN && RN->getReg() == 0)
+    Index = CurDAG->getRegister(0, MVT::i64);
+  else {
+    assert(Index.getValueType() == MVT::i16 &&
+           "Expect to be extending 16-bit registers for use in LEA");
+    SDValue ImplDef =
+        SDValue(CurDAG->getMachineNode(X86::IMPLICIT_DEF, DL, MVT::i64), 0);
+    Index = CurDAG->getTargetInsertSubreg(X86::sub_16bit, DL, MVT::i64, ImplDef,
+                                          Index);
+  }
+
+  return true;
+}
+
 bool X86DAGToDAGISel::selectLEA64_32Addr(SDValue N, SDValue &Base,
                                          SDValue &Scale, SDValue &Index,
                                          SDValue &Disp, SDValue &Segment) {
diff --git a/llvm/lib/Target/X86/X86InstrArithmetic.td b/llvm/lib/Target/X86/X86InstrArithmetic.td
index 16ca2882a84daf..a72fc02e1ba523 100644
--- a/llvm/lib/Target/X86/X86InstrArithmetic.td
+++ b/llvm/lib/Target/X86/X86InstrArithmetic.td
@@ -25,6 +25,12 @@ let SchedRW = [WriteLEA] in {
                      [(set GR32:$dst, lea32addr:$src)]>,
                      OpSize32, Requires<[Not64BitMode]>;
 
+  def LEA64_16r : I<0x8D, MRMSrcMem, (outs GR16:$dst), (ins lea64_16mem:$src),
+                    "lea{w}\t{$src|$dst}, {$dst|$src}",
+                    [(set GR16:$dst, lea64_16addr:$src)]>,
+                  OpSize16,
+                  Requires<[In64BitMode]>;
+
   def LEA64_32r : I<0x8D, MRMSrcMem,
                     (outs GR32:$dst), (ins lea64_32mem:$src),
                     "lea{l}\t{$src|$dst}, {$dst|$src}",
diff --git a/llvm/lib/Target/X86/X86InstrFragments.td b/llvm/lib/Target/X86/X86InstrFragments.td
index ea7af893ce103f..ada4c29da4a97f 100644
--- a/llvm/lib/Target/X86/X86InstrFragments.td
+++ b/llvm/lib/Target/X86/X86InstrFragments.td
@@ -357,6 +357,11 @@ def addr      : ComplexPattern<iPTR, 5, "selectAddr">;
 def lea32addr : ComplexPattern<i32, 5, "selectLEAAddr",
                                [add, sub, mul, X86mul_imm, shl, or, xor, frameindex],
                                []>;
+// In 64-bit mode 16-bit LEAs can use RIP-relative addressing.
+def lea64_16addr : ComplexPattern<i16, 5, "selectLEA64_16Addr",
+                                  [add, sub, mul, X86mul_imm, shl, or, xor,
+                                   frameindex, X86WrapperRIP],
+                                  []>;
 // In 64-bit mode 32-bit LEAs can use RIP-relative addressing.
 def lea64_32addr : ComplexPattern<i32, 5, "selectLEA64_32Addr",
                                   [add, sub, mul, X86mul_imm, shl, or, xor,
diff --git a/llvm/lib/Target/X86/X86InstrOperands.td b/llvm/lib/Target/X86/X86InstrOperands.td
index 2102cb4b6b5b73..4bf31c115e635e 100644
--- a/llvm/lib/Target/X86/X86InstrOperands.td
+++ b/llvm/lib/Target/X86/X86InstrOperands.td
@@ -461,6 +461,12 @@ def i64u8imm : Operand<i64> {
   let OperandType = "OPERAND_IMMEDIATE";
 }
 
+def lea64_16mem : Operand<i16> {
+  let PrintMethod = "printMemReference";
+  let MIOperandInfo = (ops GR64, i8imm, GR64_NOSP, i16imm, SEGMENT_REG);
+  let ParserMatchClass = X86MemAsmOperand;
+}
+
 def lea64_32mem : Operand<i32> {
   let PrintMethod = "printMemReference";
   let MIOperandInfo = (ops GR64, i8imm, GR64_NOSP, i32imm, SEGMENT_REG);
diff --git a/llvm/test/CodeGen/X86/16bit-lea.ll b/llvm/test/CodeGen/X86/16bit-lea.ll
new file mode 100644
index 00000000000000..049b216c313fa8
--- /dev/null
+++ b/llvm/test/CodeGen/X86/16bit-lea.ll
@@ -0,0 +1,14 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple=x86_64-linux -mattr=+ndd | FileCheck %s --check-prefixes=CHECK
+
+define dso_local signext range(i16 1, 0) i16 @lea16bit(i16 noundef signext %in) local_unnamed_addr #0 {
+; CHECK-LABEL: lea16bit:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    # kill: def $edi killed $edi def $rdi
+; CHECK-NEXT:    leaw 1(%rdi,%rdi), %ax
+; CHECK-NEXT:    retq
+entry:
+  %shl = shl i16 %in, 1
+  %or = or disjoint i16 %shl, 1
+  ret i16 %or
+}
diff --git a/llvm/utils/TableGen/X86RecognizableInstr.cpp b/llvm/utils/TableGen/X86RecognizableInstr.cpp
index c6cd3da13646a6..af16b3782195b0 100644
--- a/llvm/utils/TableGen/X86RecognizableInstr.cpp
+++ b/llvm/utils/TableGen/X86RecognizableInstr.cpp
@@ -1096,6 +1096,7 @@ OperandType RecognizableInstr::typeFromString(const std::string &s,
   TYPE("brtarget16", TYPE_REL)
   TYPE("brtarget8", TYPE_REL)
   TYPE("f80mem", TYPE_M)
+  TYPE("lea64_16mem", TYPE_M)
   TYPE("lea64_32mem", TYPE_M)
   TYPE("lea64mem", TYPE_M)
   TYPE("VR64", TYPE_MM64)
@@ -1367,6 +1368,7 @@ RecognizableInstr::memoryEncodingFromString(const std::string &s,
   ENCODING("i512mem_GR32", ENCODING_RM)
   ENCODING("i512mem_GR64", ENCODING_RM)
   ENCODING("f80mem", ENCODING_RM)
+  ENCODING("lea64_16mem", ENCODING_RM)
   ENCODING("lea64_32mem", ENCODING_RM)
   ENCODING("lea64mem", ENCODING_RM)
   ENCODING("anymem", ENCODING_RM)

@llvmbot
Copy link
Member

llvmbot commented Jan 8, 2025

@llvm/pr-subscribers-tablegen

Author: None (JaydeepChauhan14)

Changes

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

6 Files Affected:

  • (modified) llvm/lib/Target/X86/X86ISelDAGToDAG.cpp (+37)
  • (modified) llvm/lib/Target/X86/X86InstrArithmetic.td (+6)
  • (modified) llvm/lib/Target/X86/X86InstrFragments.td (+5)
  • (modified) llvm/lib/Target/X86/X86InstrOperands.td (+6)
  • (added) llvm/test/CodeGen/X86/16bit-lea.ll (+14)
  • (modified) llvm/utils/TableGen/X86RecognizableInstr.cpp (+2)
diff --git a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
index 9b340a778b36ad..7f33b40503c2c8 100644
--- a/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
+++ b/llvm/lib/Target/X86/X86ISelDAGToDAG.cpp
@@ -226,6 +226,8 @@ namespace {
     bool selectLEAAddr(SDValue N, SDValue &Base,
                        SDValue &Scale, SDValue &Index, SDValue &Disp,
                        SDValue &Segment);
+    bool selectLEA64_16Addr(SDValue N, SDValue &Base, SDValue &Scale,
+                            SDValue &Index, SDValue &Disp, SDValue &Segment);
     bool selectLEA64_32Addr(SDValue N, SDValue &Base,
                             SDValue &Scale, SDValue &Index, SDValue &Disp,
                             SDValue &Segment);
@@ -3054,6 +3056,41 @@ bool X86DAGToDAGISel::selectMOV64Imm32(SDValue N, SDValue &Imm) {
   return !TM.isLargeGlobalValue(GV);
 }
 
+bool X86DAGToDAGISel::selectLEA64_16Addr(SDValue N, SDValue &Base,
+                                         SDValue &Scale, SDValue &Index,
+                                         SDValue &Disp, SDValue &Segment) {
+  // Save the debug loc before calling selectLEAAddr, in case it invalidates N.
+  SDLoc DL(N);
+
+  if (!selectLEAAddr(N, Base, Scale, Index, Disp, Segment))
+    return false;
+
+  auto *RN = dyn_cast<RegisterSDNode>(Base);
+  if (RN && RN->getReg() == 0)
+    Base = CurDAG->getRegister(0, MVT::i64);
+  else if (Base.getValueType() == MVT::i16 && !isa<FrameIndexSDNode>(Base)) {
+    // Base could already be %rip, particularly in the x32 ABI.
+    SDValue ImplDef =
+        SDValue(CurDAG->getMachineNode(X86::IMPLICIT_DEF, DL, MVT::i64), 0);
+    Base = CurDAG->getTargetInsertSubreg(X86::sub_16bit, DL, MVT::i64, ImplDef,
+                                         Base);
+  }
+
+  RN = dyn_cast<RegisterSDNode>(Index);
+  if (RN && RN->getReg() == 0)
+    Index = CurDAG->getRegister(0, MVT::i64);
+  else {
+    assert(Index.getValueType() == MVT::i16 &&
+           "Expect to be extending 16-bit registers for use in LEA");
+    SDValue ImplDef =
+        SDValue(CurDAG->getMachineNode(X86::IMPLICIT_DEF, DL, MVT::i64), 0);
+    Index = CurDAG->getTargetInsertSubreg(X86::sub_16bit, DL, MVT::i64, ImplDef,
+                                          Index);
+  }
+
+  return true;
+}
+
 bool X86DAGToDAGISel::selectLEA64_32Addr(SDValue N, SDValue &Base,
                                          SDValue &Scale, SDValue &Index,
                                          SDValue &Disp, SDValue &Segment) {
diff --git a/llvm/lib/Target/X86/X86InstrArithmetic.td b/llvm/lib/Target/X86/X86InstrArithmetic.td
index 16ca2882a84daf..a72fc02e1ba523 100644
--- a/llvm/lib/Target/X86/X86InstrArithmetic.td
+++ b/llvm/lib/Target/X86/X86InstrArithmetic.td
@@ -25,6 +25,12 @@ let SchedRW = [WriteLEA] in {
                      [(set GR32:$dst, lea32addr:$src)]>,
                      OpSize32, Requires<[Not64BitMode]>;
 
+  def LEA64_16r : I<0x8D, MRMSrcMem, (outs GR16:$dst), (ins lea64_16mem:$src),
+                    "lea{w}\t{$src|$dst}, {$dst|$src}",
+                    [(set GR16:$dst, lea64_16addr:$src)]>,
+                  OpSize16,
+                  Requires<[In64BitMode]>;
+
   def LEA64_32r : I<0x8D, MRMSrcMem,
                     (outs GR32:$dst), (ins lea64_32mem:$src),
                     "lea{l}\t{$src|$dst}, {$dst|$src}",
diff --git a/llvm/lib/Target/X86/X86InstrFragments.td b/llvm/lib/Target/X86/X86InstrFragments.td
index ea7af893ce103f..ada4c29da4a97f 100644
--- a/llvm/lib/Target/X86/X86InstrFragments.td
+++ b/llvm/lib/Target/X86/X86InstrFragments.td
@@ -357,6 +357,11 @@ def addr      : ComplexPattern<iPTR, 5, "selectAddr">;
 def lea32addr : ComplexPattern<i32, 5, "selectLEAAddr",
                                [add, sub, mul, X86mul_imm, shl, or, xor, frameindex],
                                []>;
+// In 64-bit mode 16-bit LEAs can use RIP-relative addressing.
+def lea64_16addr : ComplexPattern<i16, 5, "selectLEA64_16Addr",
+                                  [add, sub, mul, X86mul_imm, shl, or, xor,
+                                   frameindex, X86WrapperRIP],
+                                  []>;
 // In 64-bit mode 32-bit LEAs can use RIP-relative addressing.
 def lea64_32addr : ComplexPattern<i32, 5, "selectLEA64_32Addr",
                                   [add, sub, mul, X86mul_imm, shl, or, xor,
diff --git a/llvm/lib/Target/X86/X86InstrOperands.td b/llvm/lib/Target/X86/X86InstrOperands.td
index 2102cb4b6b5b73..4bf31c115e635e 100644
--- a/llvm/lib/Target/X86/X86InstrOperands.td
+++ b/llvm/lib/Target/X86/X86InstrOperands.td
@@ -461,6 +461,12 @@ def i64u8imm : Operand<i64> {
   let OperandType = "OPERAND_IMMEDIATE";
 }
 
+def lea64_16mem : Operand<i16> {
+  let PrintMethod = "printMemReference";
+  let MIOperandInfo = (ops GR64, i8imm, GR64_NOSP, i16imm, SEGMENT_REG);
+  let ParserMatchClass = X86MemAsmOperand;
+}
+
 def lea64_32mem : Operand<i32> {
   let PrintMethod = "printMemReference";
   let MIOperandInfo = (ops GR64, i8imm, GR64_NOSP, i32imm, SEGMENT_REG);
diff --git a/llvm/test/CodeGen/X86/16bit-lea.ll b/llvm/test/CodeGen/X86/16bit-lea.ll
new file mode 100644
index 00000000000000..049b216c313fa8
--- /dev/null
+++ b/llvm/test/CodeGen/X86/16bit-lea.ll
@@ -0,0 +1,14 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py UTC_ARGS: --version 5
+; RUN: llc < %s -mtriple=x86_64-linux -mattr=+ndd | FileCheck %s --check-prefixes=CHECK
+
+define dso_local signext range(i16 1, 0) i16 @lea16bit(i16 noundef signext %in) local_unnamed_addr #0 {
+; CHECK-LABEL: lea16bit:
+; CHECK:       # %bb.0: # %entry
+; CHECK-NEXT:    # kill: def $edi killed $edi def $rdi
+; CHECK-NEXT:    leaw 1(%rdi,%rdi), %ax
+; CHECK-NEXT:    retq
+entry:
+  %shl = shl i16 %in, 1
+  %or = or disjoint i16 %shl, 1
+  ret i16 %or
+}
diff --git a/llvm/utils/TableGen/X86RecognizableInstr.cpp b/llvm/utils/TableGen/X86RecognizableInstr.cpp
index c6cd3da13646a6..af16b3782195b0 100644
--- a/llvm/utils/TableGen/X86RecognizableInstr.cpp
+++ b/llvm/utils/TableGen/X86RecognizableInstr.cpp
@@ -1096,6 +1096,7 @@ OperandType RecognizableInstr::typeFromString(const std::string &s,
   TYPE("brtarget16", TYPE_REL)
   TYPE("brtarget8", TYPE_REL)
   TYPE("f80mem", TYPE_M)
+  TYPE("lea64_16mem", TYPE_M)
   TYPE("lea64_32mem", TYPE_M)
   TYPE("lea64mem", TYPE_M)
   TYPE("VR64", TYPE_MM64)
@@ -1367,6 +1368,7 @@ RecognizableInstr::memoryEncodingFromString(const std::string &s,
   ENCODING("i512mem_GR32", ENCODING_RM)
   ENCODING("i512mem_GR64", ENCODING_RM)
   ENCODING("f80mem", ENCODING_RM)
+  ENCODING("lea64_16mem", ENCODING_RM)
   ENCODING("lea64_32mem", ENCODING_RM)
   ENCODING("lea64mem", ENCODING_RM)
   ENCODING("anymem", ENCODING_RM)

@JaydeepChauhan14
Copy link
Contributor Author

@phoebewang, @e-kud please review.

Comment on lines 28 to 32
def LEA64_16r : I<0x8D, MRMSrcMem, (outs GR16:$dst), (ins lea64_16mem:$src),
"lea{w}\t{$src|$dst}, {$dst|$src}",
[(set GR16:$dst, lea64_16addr:$src)]>,
OpSize16,
Requires<[In64BitMode]>;
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it possible not to define a new LEA64_16r, but add a pattern for 16-bit with LEA64_32r? This should address the encoding size concern.

@JaydeepChauhan14 JaydeepChauhan14 changed the title [X86] Added support for 16bit LEA instruction [X86] Added support for 8 and 16bit LEA instructions Feb 22, 2025
Copy link
Contributor

@phoebewang phoebewang left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM.

@phoebewang phoebewang merged commit cf05b6e into llvm:main Mar 4, 2025
9 of 11 checks passed
@JaydeepChauhan14 JaydeepChauhan14 deleted the 16bitLEA branch March 4, 2025 04:35
jph-13 pushed a commit to jph-13/llvm-project that referenced this pull request Mar 21, 2025
fzou1 added a commit to fzou1/llvm-project that referenced this pull request Apr 14, 2025
The 8 and 16 bit LEA instruction support was added by PR llvm#122102, and we
have to update creating index register negations accordingly. The issue
is exposed with APX NDD instructions.
fzou1 added a commit to fzou1/llvm-project that referenced this pull request Apr 15, 2025
The 8 and 16 bit LEA instruction support was added by PR llvm#122102, and we
have to update creating index register negations accordingly. The issue
is exposed with APX NDD instructions.
fzou1 added a commit that referenced this pull request Apr 16, 2025
The 8 and 16 bit LEA instruction support was added by PR #122102, and we
have to update creating index register negations accordingly. The issue
is exposed with APX NDD instructions.
var-const pushed a commit to ldionne/llvm-project that referenced this pull request Apr 17, 2025
The 8 and 16 bit LEA instruction support was added by PR llvm#122102, and we
have to update creating index register negations accordingly. The issue
is exposed with APX NDD instructions.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants