Skip to content

[X86][GlobalISel] Support addr matching in SDAG patterns #130445

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 13 commits into from
Apr 19, 2025

Conversation

e-kud
Copy link
Contributor

@e-kud e-kud commented Mar 8, 2025

addr matching was the only gatekeeper for starting selecting G_LOAD and G_STORE using SDAG patterns.

  • Introduce a complex renderer gi_addr for addr. In this patch only the existing functionality has been implemented. The renderer's name is the same as in SDAG: selectAddr. Apparently the type of GIComplexOperandMatcher doesn't matter as RISCV also uses s32 for both 64 and 32 bit pointers.
  • X86SelectAddress now is used for both: pattern matching and manual selection. As a result it accumulates all the code that previously was distrubuted among different selection functions.
  • Replace getLoadStoreOp with getPtrLoadStoreOp in Load/Store selector as GlobalISel matcher or emitter can't map the pointer type into i32/i64 types used in SDAG patterns for pointers. So the load and store selection of pointers is still manual. getLoadStoreOp is still present because it is used in G_FCONSTANT lowering that requires extra efforts to select it using SDAG patterns.
  • Since truncating stores are not supported, we custom legalize them by matching types of store and MMO.
  • Introduce a constant pool flag in X86AddressMode because otherwise we need to introduce a GlobalISel copy for X86ISelAddressMode.
  • Also please notice in the tests that GlobalISel prefers to fold memory operands immediately comparing to SDAG. The reason is that GlobalISel doesn't have target hooks in GIM_CheckIsSafeToFold. Or maybe another check on profitability is required along with safety check that is currently not present.

addr matching was the only gatekeeper for starting selecting G_LOAD and
G_STORE using SDAG patterns.

* Replace getLoadStoreOp with getPtrLoadStoreOp in Load/Store selector
  as GlobalISel matcher or emitter can't map the pointer type into
  i32/i64 types used in SDAG patterns for pointers. So the load and
  store selection of pointers is still manual.
* X86SelectAddress now is used for both: pattern matching and manual
  selection. As a result it accumulates all the code that previously was
  distrubuted among different selection functions.
* Introduce a complex rederer `gi_addr` for `addr`. In this patch only
  existing functionality has been implemented. The renderer's name is
  the same as in SDAG: `selectAddr`.
* Since truncating stores are not supported, we custom legalize them by
  matching types of store and MMO.
* Introduce a ConstantPool flag to X86AddressMode because otherwise we
  need to introduce a GlobalISel copy for X86ISelAddressMode.
@llvmbot
Copy link
Member

llvmbot commented Mar 8, 2025

@llvm/pr-subscribers-llvm-globalisel

@llvm/pr-subscribers-backend-x86

Author: Evgenii Kudriashov (e-kud)

Changes

addr matching was the only gatekeeper for starting selecting G_LOAD and G_STORE using SDAG patterns.

  • Introduce a complex renderer gi_addr for addr. In this patch only the existing functionality has been implemented. The renderer's name is the same as in SDAG: selectAddr. Apparently the type of GIComplexOperandMatcher doesn't matter as RISCV also uses s32 for both 64 and 32 bit pointers.
  • X86SelectAddress now is used for both: pattern matching and manual selection. As a result it accumulates all the code that previously was distrubuted among different selection functions.
  • Replace getLoadStoreOp with getPtrLoadStoreOp in Load/Store selector as GlobalISel matcher or emitter can't map the pointer type into i32/i64 types used in SDAG patterns for pointers. So the load and store selection of pointers is still manual.
  • Since truncating stores are not supported, we custom legalize them by matching types of store and MMO.
  • Introduce a constant pool flag in X86AddressMode because otherwise we need to introduce a GlobalISel copy for X86ISelAddressMode.
  • Also please notice in the tests that GlobalISel prefers to fold memory operands immediately comparing to SDAG. The reason is that GlobalISel doesn't have target hooks in GIM_CheckIsSafeToFold. Or maybe another check on profitability is required along with safety check that is currently not present.

Patch is 95.94 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/130445.diff

37 Files Affected:

  • (modified) llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h (+3)
  • (modified) llvm/lib/Target/X86/GISel/X86InstructionSelector.cpp (+121-58)
  • (modified) llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp (+37-9)
  • (modified) llvm/lib/Target/X86/GISel/X86LegalizerInfo.h (+3)
  • (modified) llvm/lib/Target/X86/X86InstrBuilder.h (+3-2)
  • (modified) llvm/lib/Target/X86/X86InstrFragments.td (+30-4)
  • (modified) llvm/lib/Target/X86/X86InstrFragmentsSIMD.td (+12-2)
  • (modified) llvm/test/CodeGen/X86/GlobalISel/GV.ll (+4-8)
  • (modified) llvm/test/CodeGen/X86/GlobalISel/add-scalar.ll (+4-4)
  • (modified) llvm/test/CodeGen/X86/GlobalISel/callingconv.ll (+3-4)
  • (modified) llvm/test/CodeGen/X86/GlobalISel/isel-fcmp-i686.mir (+28-28)
  • (modified) llvm/test/CodeGen/X86/GlobalISel/legalize-memop-scalar-32.mir (+1-1)
  • (modified) llvm/test/CodeGen/X86/GlobalISel/legalize-memop-scalar-64.mir (+1-1)
  • (modified) llvm/test/CodeGen/X86/GlobalISel/legalize-mul-scalar.mir (+1-1)
  • (modified) llvm/test/CodeGen/X86/GlobalISel/legalize-trunc.mir (+2-2)
  • (modified) llvm/test/CodeGen/X86/GlobalISel/legalize-undef.mir (+2-2)
  • (modified) llvm/test/CodeGen/X86/GlobalISel/memop-scalar-x32.ll (+3-3)
  • (modified) llvm/test/CodeGen/X86/GlobalISel/mul-scalar.ll (+6-6)
  • (modified) llvm/test/CodeGen/X86/GlobalISel/select-GV-32.mir (+3-5)
  • (modified) llvm/test/CodeGen/X86/GlobalISel/select-GV-64.mir (+3-5)
  • (modified) llvm/test/CodeGen/X86/GlobalISel/select-memop-v128.mir (+10-8)
  • (modified) llvm/test/CodeGen/X86/GlobalISel/select-memop-v256.mir (+12-9)
  • (modified) llvm/test/CodeGen/X86/GlobalISel/sub-scalar.ll (+4-4)
  • (modified) llvm/test/CodeGen/X86/isel-and.ll (+46-34)
  • (modified) llvm/test/CodeGen/X86/isel-buildvector-sse.ll (+16-32)
  • (modified) llvm/test/CodeGen/X86/isel-buildvector-sse2.ll (+7-14)
  • (modified) llvm/test/CodeGen/X86/isel-icmp.ll (+4-4)
  • (modified) llvm/test/CodeGen/X86/isel-or.ll (+46-34)
  • (modified) llvm/test/CodeGen/X86/isel-phi.ll (+3-3)
  • (modified) llvm/test/CodeGen/X86/isel-sdiv.ll (+4-4)
  • (modified) llvm/test/CodeGen/X86/isel-select-cmov.ll (+20-20)
  • (modified) llvm/test/CodeGen/X86/isel-srem.ll (+4-4)
  • (modified) llvm/test/CodeGen/X86/isel-traps.ll (+1-2)
  • (modified) llvm/test/CodeGen/X86/isel-udiv.ll (+4-4)
  • (modified) llvm/test/CodeGen/X86/isel-urem.ll (+4-4)
  • (modified) llvm/test/CodeGen/X86/isel-x87.ll (+2-4)
  • (modified) llvm/test/CodeGen/X86/isel-xor.ll (+46-34)
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h b/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h
index 9e5d4d34f24d2..571ec6dd7e9ba 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/GenericMachineInstrs.h
@@ -66,6 +66,9 @@ class GMemOperation : public GenericMachineInstr {
   /// memory operations can't be reordered.
   bool isUnordered() const { return getMMO().isUnordered(); }
 
+  /// Return the minimum known alignment in bytes of the actual memory
+  /// reference.
+  Align getAlign() const { return getMMO().getAlign(); }
   /// Returns the size in bytes of the memory access.
   LocationSize getMemSize() const { return getMMO().getSize(); }
   /// Returns the size in bits of the memory access.
diff --git a/llvm/lib/Target/X86/GISel/X86InstructionSelector.cpp b/llvm/lib/Target/X86/GISel/X86InstructionSelector.cpp
index d7f315d82b832..828494ae9cfbf 100644
--- a/llvm/lib/Target/X86/GISel/X86InstructionSelector.cpp
+++ b/llvm/lib/Target/X86/GISel/X86InstructionSelector.cpp
@@ -73,6 +73,9 @@ class X86InstructionSelector : public InstructionSelector {
   // TODO: remove after supported by Tablegen-erated instruction selection.
   unsigned getLoadStoreOp(const LLT &Ty, const RegisterBank &RB, unsigned Opc,
                           Align Alignment) const;
+  // TODO: remove once p0<->i32/i64 matching is available
+  unsigned getPtrLoadStoreOp(const LLT &Ty, const RegisterBank &RB,
+                             unsigned Opc) const;
 
   bool selectLoadStoreOp(MachineInstr &I, MachineRegisterInfo &MRI,
                          MachineFunction &MF) const;
@@ -119,6 +122,8 @@ class X86InstructionSelector : public InstructionSelector {
   bool selectSelect(MachineInstr &I, MachineRegisterInfo &MRI,
                     MachineFunction &MF) const;
 
+  ComplexRendererFns selectAddr(MachineOperand &Root) const;
+
   // emit insert subreg instruction and insert it before MachineInstr &I
   bool emitInsertSubreg(unsigned DstReg, unsigned SrcReg, MachineInstr &I,
                         MachineRegisterInfo &MRI, MachineFunction &MF) const;
@@ -445,6 +450,17 @@ bool X86InstructionSelector::select(MachineInstr &I) {
   return false;
 }
 
+unsigned X86InstructionSelector::getPtrLoadStoreOp(const LLT &Ty,
+                                                   const RegisterBank &RB,
+                                                   unsigned Opc) const {
+  bool Isload = (Opc == TargetOpcode::G_LOAD);
+  if (Ty == LLT::pointer(0, 32) && X86::GPRRegBankID == RB.getID())
+    return Isload ? X86::MOV32rm : X86::MOV32mr;
+  if (Ty == LLT::pointer(0, 64) && X86::GPRRegBankID == RB.getID())
+    return Isload ? X86::MOV64rm : X86::MOV64mr;
+  return Opc;
+}
+
 unsigned X86InstructionSelector::getLoadStoreOp(const LLT &Ty,
                                                 const RegisterBank &RB,
                                                 unsigned Opc,
@@ -460,7 +476,7 @@ unsigned X86InstructionSelector::getLoadStoreOp(const LLT &Ty,
   } else if (Ty == LLT::scalar(16)) {
     if (X86::GPRRegBankID == RB.getID())
       return Isload ? X86::MOV16rm : X86::MOV16mr;
-  } else if (Ty == LLT::scalar(32) || Ty == LLT::pointer(0, 32)) {
+  } else if (Ty == LLT::scalar(32)) {
     if (X86::GPRRegBankID == RB.getID())
       return Isload ? X86::MOV32rm : X86::MOV32mr;
     if (X86::VECRRegBankID == RB.getID())
@@ -472,7 +488,7 @@ unsigned X86InstructionSelector::getLoadStoreOp(const LLT &Ty,
                                    X86::MOVSSmr);
     if (X86::PSRRegBankID == RB.getID())
       return Isload ? X86::LD_Fp32m : X86::ST_Fp32m;
-  } else if (Ty == LLT::scalar(64) || Ty == LLT::pointer(0, 64)) {
+  } else if (Ty == LLT::scalar(64)) {
     if (X86::GPRRegBankID == RB.getID())
       return Isload ? X86::MOV64rm : X86::MOV64mr;
     if (X86::VECRRegBankID == RB.getID())
@@ -530,30 +546,75 @@ unsigned X86InstructionSelector::getLoadStoreOp(const LLT &Ty,
 }
 
 // Fill in an address from the given instruction.
-static void X86SelectAddress(const MachineInstr &I,
+static bool X86SelectAddress(MachineInstr &I, const X86TargetMachine &TM,
                              const MachineRegisterInfo &MRI,
-                             X86AddressMode &AM) {
-  assert(I.getOperand(0).isReg() && "unsupported opperand.");
+                             const X86Subtarget &STI, X86AddressMode &AM) {
+  assert(I.getOperand(0).isReg() && "unsupported operand.");
   assert(MRI.getType(I.getOperand(0).getReg()).isPointer() &&
          "unsupported type.");
 
-  if (I.getOpcode() == TargetOpcode::G_PTR_ADD) {
+  switch (I.getOpcode()) {
+  default:
+    break;
+  case TargetOpcode::G_FRAME_INDEX:
+    AM.Base.FrameIndex = I.getOperand(1).getIndex();
+    AM.BaseType = X86AddressMode::FrameIndexBase;
+    return true;
+  case TargetOpcode::G_PTR_ADD: {
     if (auto COff = getIConstantVRegSExtVal(I.getOperand(2).getReg(), MRI)) {
       int64_t Imm = *COff;
       if (isInt<32>(Imm)) { // Check for displacement overflow.
         AM.Disp = static_cast<int32_t>(Imm);
         AM.Base.Reg = I.getOperand(1).getReg();
-        return;
+        return true;
       }
     }
-  } else if (I.getOpcode() == TargetOpcode::G_FRAME_INDEX) {
-    AM.Base.FrameIndex = I.getOperand(1).getIndex();
-    AM.BaseType = X86AddressMode::FrameIndexBase;
-    return;
+    break;
   }
+  case TargetOpcode::G_GLOBAL_VALUE: {
+    auto GV = I.getOperand(1).getGlobal();
+    if (GV->isThreadLocal()) {
+      return false; // TODO: we don't support TLS yet.
+    }
+    // Can't handle alternate code models yet.
+    if (TM.getCodeModel() != CodeModel::Small)
+      return false;
+    AM.GV = GV;
+    AM.GVOpFlags = STI.classifyGlobalReference(GV);
+
+    // TODO: The ABI requires an extra load. not supported yet.
+    if (isGlobalStubReference(AM.GVOpFlags))
+      return false;
 
+    // TODO: This reference is relative to the pic base. not supported yet.
+    if (isGlobalRelativeToPICBase(AM.GVOpFlags))
+      return false;
+
+    if (STI.isPICStyleRIPRel()) {
+      // Use rip-relative addressing.
+      assert(AM.Base.Reg == 0 && AM.IndexReg == 0);
+      AM.Base.Reg = X86::RIP;
+    }
+    return true;
+  }
+  case TargetOpcode::G_CONSTANT_POOL: {
+    // TODO: Need a separate move for Large model
+    if (TM.getCodeModel() == CodeModel::Large)
+      return false;
+
+    AM.GVOpFlags = STI.classifyLocalReference(nullptr);
+    if (AM.GVOpFlags == X86II::MO_GOTOFF)
+      AM.Base.Reg = STI.getInstrInfo()->getGlobalBaseReg(I.getMF());
+    else if (STI.is64Bit())
+      AM.Base.Reg = X86::RIP;
+    AM.CP = true;
+    AM.Disp = I.getOperand(1).getIndex();
+    return true;
+  }
+  }
   // Default behavior.
   AM.Base.Reg = I.getOperand(0).getReg();
+  return true;
 }
 
 bool X86InstructionSelector::selectLoadStoreOp(MachineInstr &I,
@@ -586,36 +647,18 @@ bool X86InstructionSelector::selectLoadStoreOp(MachineInstr &I,
     }
   }
 
-  unsigned NewOpc = getLoadStoreOp(Ty, RB, Opc, MemOp.getAlign());
+  unsigned NewOpc = getPtrLoadStoreOp(Ty, RB, Opc);
   if (NewOpc == Opc)
     return false;
 
   I.setDesc(TII.get(NewOpc));
   MachineInstrBuilder MIB(MF, I);
-  const MachineInstr *Ptr = MRI.getVRegDef(I.getOperand(1).getReg());
-
-  if (Ptr->getOpcode() == TargetOpcode::G_CONSTANT_POOL) {
-    assert(Opc == TargetOpcode::G_LOAD &&
-           "Only G_LOAD from constant pool is expected");
-    // TODO: Need a separate move for Large model
-    if (TM.getCodeModel() == CodeModel::Large)
-      return false;
-
-    unsigned char OpFlag = STI.classifyLocalReference(nullptr);
-    unsigned PICBase = 0;
-    if (OpFlag == X86II::MO_GOTOFF)
-      PICBase = TII.getGlobalBaseReg(&MF);
-    else if (STI.is64Bit())
-      PICBase = X86::RIP;
-
-    I.removeOperand(1);
-    addConstantPoolReference(MIB, Ptr->getOperand(1).getIndex(), PICBase,
-                             OpFlag);
-    return constrainSelectedInstRegOperands(I, TII, TRI, RBI);
-  }
+  MachineInstr *Ptr = MRI.getVRegDef(I.getOperand(1).getReg());
 
   X86AddressMode AM;
-  X86SelectAddress(*Ptr, MRI, AM);
+  if (!X86SelectAddress(*Ptr, TM, MRI, STI, AM))
+    return false;
+
   if (Opc == TargetOpcode::G_LOAD) {
     I.removeOperand(1);
     addFullAddress(MIB, AM);
@@ -673,33 +716,10 @@ bool X86InstructionSelector::selectGlobalValue(MachineInstr &I,
   assert((I.getOpcode() == TargetOpcode::G_GLOBAL_VALUE) &&
          "unexpected instruction");
 
-  auto GV = I.getOperand(1).getGlobal();
-  if (GV->isThreadLocal()) {
-    return false; // TODO: we don't support TLS yet.
-  }
-
-  // Can't handle alternate code models yet.
-  if (TM.getCodeModel() != CodeModel::Small)
-    return false;
-
   X86AddressMode AM;
-  AM.GV = GV;
-  AM.GVOpFlags = STI.classifyGlobalReference(GV);
-
-  // TODO: The ABI requires an extra load. not supported yet.
-  if (isGlobalStubReference(AM.GVOpFlags))
+  if (!X86SelectAddress(I, TM, MRI, STI, AM))
     return false;
 
-  // TODO: This reference is relative to the pic base. not supported yet.
-  if (isGlobalRelativeToPICBase(AM.GVOpFlags))
-    return false;
-
-  if (STI.isPICStyleRIPRel()) {
-    // Use rip-relative addressing.
-    assert(AM.Base.Reg == 0 && AM.IndexReg == 0);
-    AM.Base.Reg = X86::RIP;
-  }
-
   const Register DefReg = I.getOperand(0).getReg();
   LLT Ty = MRI.getType(DefReg);
   unsigned NewOpc = getLeaOP(Ty, STI);
@@ -1880,6 +1900,49 @@ bool X86InstructionSelector::selectSelect(MachineInstr &I,
   return true;
 }
 
+InstructionSelector::ComplexRendererFns
+X86InstructionSelector::selectAddr(MachineOperand &Root) const {
+  MachineInstr *MI = Root.getParent();
+  MachineIRBuilder MIRBuilder(*MI);
+
+  MachineRegisterInfo &MRI = MI->getMF()->getRegInfo();
+  MachineInstr *Ptr = MRI.getVRegDef(Root.getReg());
+  X86AddressMode AM;
+  X86SelectAddress(*Ptr, TM, MRI, STI, AM);
+
+  if (AM.Scale != 1)
+    return std::nullopt;
+
+  if (AM.IndexReg)
+    return std::nullopt;
+
+  return {// Base
+          {[=](MachineInstrBuilder &MIB) {
+             if (AM.BaseType == X86AddressMode::RegBase)
+               MIB.addUse(AM.Base.Reg);
+             else {
+               assert(AM.BaseType == X86AddressMode::FrameIndexBase &&
+                      "Unknown type of address base");
+               MIB.addFrameIndex(AM.Base.FrameIndex);
+             }
+           },
+           // Scale
+           [=](MachineInstrBuilder &MIB) { MIB.addImm(AM.Scale); },
+           // Index
+           [=](MachineInstrBuilder &MIB) { MIB.addUse(0); },
+           // Disp
+           [=](MachineInstrBuilder &MIB) {
+             if (AM.GV)
+               MIB.addGlobalAddress(AM.GV, AM.Disp, AM.GVOpFlags);
+             else if (AM.CP)
+               MIB.addConstantPoolIndex(AM.Disp, 0, AM.GVOpFlags);
+             else
+               MIB.addImm(AM.Disp);
+           },
+           // Segment
+           [=](MachineInstrBuilder &MIB) { MIB.addUse(0); }}};
+}
+
 InstructionSelector *
 llvm::createX86InstructionSelector(const X86TargetMachine &TM,
                                    const X86Subtarget &Subtarget,
diff --git a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
index 24bf0dd378641..83bca5adde3b9 100644
--- a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
+++ b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.cpp
@@ -368,22 +368,16 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
   // load/store: add more corner cases
   for (unsigned Op : {G_LOAD, G_STORE}) {
     auto &Action = getActionDefinitionsBuilder(Op);
-    Action.legalForTypesWithMemDesc({{s8, p0, s1, 1},
-                                     {s8, p0, s8, 1},
-                                     {s16, p0, s8, 1},
+    Action.legalForTypesWithMemDesc({{s8, p0, s8, 1},
                                      {s16, p0, s16, 1},
-                                     {s32, p0, s8, 1},
-                                     {s32, p0, s16, 1},
                                      {s32, p0, s32, 1},
                                      {s80, p0, s80, 1},
                                      {p0, p0, p0, 1},
                                      {v4s8, p0, v4s8, 1}});
     if (Is64Bit)
-      Action.legalForTypesWithMemDesc({{s64, p0, s8, 1},
-                                       {s64, p0, s16, 1},
-                                       {s64, p0, s32, 1},
-                                       {s64, p0, s64, 1},
+      Action.legalForTypesWithMemDesc({{s64, p0, s64, 1},
                                        {v2s32, p0, v2s32, 1}});
+
     if (HasSSE1)
       Action.legalForTypesWithMemDesc({{v4s32, p0, v4s32, 1}});
     if (HasSSE2)
@@ -402,6 +396,22 @@ X86LegalizerInfo::X86LegalizerInfo(const X86Subtarget &STI,
                                        {v32s16, p0, v32s16, 1},
                                        {v16s32, p0, v16s32, 1},
                                        {v8s64, p0, v8s64, 1}});
+
+    // X86 supports extending loads but not stores for GPRs
+    if (Op == G_LOAD) {
+      Action.legalForTypesWithMemDesc({{s8, p0, s1, 1},
+                                       {s16, p0, s8, 1},
+                                       {s32, p0, s8, 1},
+                                       {s32, p0, s16, 1}});
+      if (Is64Bit)
+        Action.legalForTypesWithMemDesc({{s64, p0, s8, 1},
+                                         {s64, p0, s16, 1},
+                                         {s64, p0, s32, 1}});
+    } else {
+      Action.customIf([=](const LegalityQuery &Query) {
+        return Query.Types[0] != Query.MMODescrs[0].MemoryTy;
+      });
+    }
     Action.widenScalarToNextPow2(0, /*Min=*/8)
         .clampScalar(0, s8, sMaxScalar)
         .scalarize(0);
@@ -655,6 +665,8 @@ bool X86LegalizerInfo::legalizeCustom(LegalizerHelper &Helper, MachineInstr &MI,
     return legalizeFPTOUI(MI, MRI, Helper);
   case TargetOpcode::G_UITOFP:
     return legalizeUITOFP(MI, MRI, Helper);
+  case TargetOpcode::G_STORE:
+    return legalizeNarrowingStore(MI, MRI, Helper);
   }
   llvm_unreachable("expected switch to return");
 }
@@ -749,6 +761,22 @@ bool X86LegalizerInfo::legalizeUITOFP(MachineInstr &MI,
   return false;
 }
 
+bool X86LegalizerInfo::legalizeNarrowingStore(MachineInstr &MI,
+                                              MachineRegisterInfo &MRI,
+                                              LegalizerHelper &Helper) const {
+  auto &Store = cast<GStore>(MI);
+  MachineIRBuilder &MIRBuilder = Helper.MIRBuilder;
+  MachineMemOperand &MMO = **Store.memoperands_begin();
+  MachineFunction &MF = MIRBuilder.getMF();
+  LLT ValTy = MRI.getType(Store.getValueReg());
+  auto *NewMMO = MF.getMachineMemOperand(&MMO, MMO.getPointerInfo(), ValTy);
+
+  Helper.Observer.changingInstr(Store);
+  Store.setMemRefs(MF, {NewMMO});
+  Helper.Observer.changedInstr(Store);
+  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 39bd9892e2f16..54f776456397b 100644
--- a/llvm/lib/Target/X86/GISel/X86LegalizerInfo.h
+++ b/llvm/lib/Target/X86/GISel/X86LegalizerInfo.h
@@ -45,6 +45,9 @@ class X86LegalizerInfo : public LegalizerInfo {
 
   bool legalizeUITOFP(MachineInstr &MI, MachineRegisterInfo &MRI,
                       LegalizerHelper &Helper) const;
+
+  bool legalizeNarrowingStore(MachineInstr &MI, MachineRegisterInfo &MRI,
+                              LegalizerHelper &Helper) const;
 };
 } // namespace llvm
 #endif
diff --git a/llvm/lib/Target/X86/X86InstrBuilder.h b/llvm/lib/Target/X86/X86InstrBuilder.h
index 45c5f8aa82e97..4243c831726d6 100644
--- a/llvm/lib/Target/X86/X86InstrBuilder.h
+++ b/llvm/lib/Target/X86/X86InstrBuilder.h
@@ -55,10 +55,11 @@ struct X86AddressMode {
   int Disp;
   const GlobalValue *GV;
   unsigned GVOpFlags;
+  bool CP;
 
   X86AddressMode()
-    : BaseType(RegBase), Scale(1), IndexReg(0), Disp(0), GV(nullptr),
-      GVOpFlags(0) {
+      : BaseType(RegBase), Scale(1), IndexReg(0), Disp(0), GV(nullptr),
+        GVOpFlags(0), CP(false) {
     Base.Reg = 0;
   }
 
diff --git a/llvm/lib/Target/X86/X86InstrFragments.td b/llvm/lib/Target/X86/X86InstrFragments.td
index a7ef72be9316f..f9d70d1bb5d85 100644
--- a/llvm/lib/Target/X86/X86InstrFragments.td
+++ b/llvm/lib/Target/X86/X86InstrFragments.td
@@ -354,6 +354,8 @@ def X86cmpccxadd : SDNode<"X86ISD::CMPCCXADD", SDTX86Cmpccxadd,
 // Define X86-specific addressing mode.
 let WantsParent = true in
 def addr      : ComplexPattern<iPTR, 5, "selectAddr">;
+def gi_addr   : GIComplexOperandMatcher<s32, "selectAddr">,
+                GIComplexPatternEquiv<addr>;
 def lea32addr : ComplexPattern<i32, 5, "selectLEAAddr",
                                [add, sub, mul, X86mul_imm, shl, or, xor, frameindex],
                                []>;
@@ -444,7 +446,11 @@ def i64relocImmSExt32 : PatLeaf<(i64 relocImm), [{
 //
 def imm_su : PatLeaf<(imm), [{
     return !shouldAvoidImmediateInstFormsForSize(N);
-}]>;
+}]> {
+  // TODO : introduce the same check as in SDAG
+  let GISelPredicateCode = [{ return true; }];
+}
+
 def i64immSExt32_su : PatLeaf<(i64immSExt32), [{
     return !shouldAvoidImmediateInstFormsForSize(N);
 }]>;
@@ -500,7 +506,9 @@ def loadi8 : PatFrag<(ops node:$ptr), (i8 (unindexedload node:$ptr)), [{
   ISD::LoadExtType ExtType = LD->getExtensionType();
   return ExtType == ISD::NON_EXTLOAD || ExtType == ISD::EXTLOAD ||
          ExtType == ISD::ZEXTLOAD;
-}]>;
+}]> {
+  let GISelPredicateCode = [{ return isa<GLoad>(MI); }];
+}
 
 // It's always safe to treat a anyext i16 load as a i32 load if the i16 is
 // known to be 32-bit aligned or better. Ditto for i8 to i16.
@@ -512,7 +520,16 @@ def loadi16 : PatFrag<(ops node:$ptr), (i16 (unindexedload node:$ptr)), [{
   if (ExtType == ISD::EXTLOAD && EnablePromoteAnyextLoad)
     return LD->getAlign() >= 2 && LD->isSimple();
   return false;
-}]>;
+}]> {
+  let GISelPredicateCode = [{
+    auto &Load = cast<GLoad>(MI);
+    LLT Ty = MRI.getType(Load.getDstReg());
+    // Non extending load has MMO and destination types of the same size
+    if (Load.getMemSizeInBits() == Ty.getSizeInBits())
+       return true;
+    return Load.getAlign() >= 2 && Load.isSimple();
+  }];
+}
 
 def loadi32 : PatFrag<(ops node:$ptr), (i32 (unindexedload node:$ptr)), [{
   LoadSDNode *LD = cast<LoadSDNode>(N);
@@ -522,7 +539,16 @@ def loadi32 : PatFrag<(ops node:$ptr), (i32 (unindexedload node:$ptr)), [{
   if (ExtType == ISD::EXTLOAD && EnablePromoteAnyextLoad)
     return LD->getAlign() >= 4 && LD->isSimple();
   return false;
-}]>;
+}]> {
+  let GISelPredicateCode = [{
+    auto &Load = cast<GLoad>(MI);
+    LLT Ty = MRI.getType(Load.getDstReg());
+    // Non extending load has MMO and destination types of the same size
+    if (Load.getMemSizeInBits() == Ty.getSizeInBits())
+       return true;
+    return Load.getAlign() >= 4 && Load.isSimple();
+  }];
+}
 
 def loadi64  : PatFrag<(ops node:$ptr), (i64 (load node:$ptr))>;
 def loadf16  : PatFrag<(ops node:$ptr), (f16 (load node:$ptr))>;
diff --git a/llvm/lib/Target/X86/X86InstrFragmentsSIMD.td b/llvm/lib/Target/X86/X86InstrFragmentsSIMD.td
index de70570481fc2..0c20ffed77e77 100644
--- a/llvm/lib/Target/X86/X86InstrFragmentsSIMD.td
+++ b/llvm/lib/Target/X86/X86InstrFragmentsSIMD.td
@@ -1008,13 +1008,23 @@ def alignedstore : PatFrag<(ops node:$val, node:$ptr),
                            (store node:$val, node:$ptr), [{
   auto *St = cast<StoreSDNode>(N);
   return St->getAlign() >= St->getMemoryVT().getStoreSize();
-}]>;
+}]> {
+  let GISelPredicateCode = [{
+    auto &LdSt = cast<GLoadStore>(MI);
+    return LdSt.getAlign() >= LdSt.getMemSize().getValue();
+  }];
+}
 
 // Like 'load', but always requires vector size alignment.
 def alignedload : PatFrag<(ops node:$ptr), (load node:$ptr), [{
   auto *Ld = cast<LoadSDNode>(N);
   return Ld->getAlign() >= Ld->getMemoryVT().getStoreSize();
-}]>;
+}]> {
+  let GISelPredicateCode = [{
+    auto &LdSt = cast<GLoadStore>(MI);
+    return LdSt.getAlign() >= LdSt.getMemSize().getValue();
+  }];
+}
 
 // 128-bit aligned load pattern fragments
 // NOTE: all 128-bit integer vector loads are promoted to v2i64
diff --git a/llvm/test/CodeGen/X86/GlobalISel/GV.ll b/llvm/test/CodeGen/X86/GlobalISel/GV.ll
index 8c14b54864752...
[truncated]

Copy link

github-actions bot commented Mar 8, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@e-kud e-kud requested a review from topperc March 18, 2025 13:09
@e-kud
Copy link
Contributor Author

e-kud commented Mar 18, 2025

Tentative ping.

; GISEL-X86-LABEL: or_imm8_i32:
; GISEL-X86: # %bb.0:
; GISEL-X86-NEXT: movl $-5, %eax
; GISEL-X86-NEXT: orl {{[0-9]+}}(%esp), %eax
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is GISel missing constant to RHS canonicalization or is something else going on?

Copy link
Contributor Author

@e-kud e-kud Mar 18, 2025

Choose a reason for hiding this comment

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

No, GISel matches differently comparing to SDAG due to absence of the target hook in GIM_CheckIsSafeToFold similar to IsProfitableToFold in OPC_CheckFoldableChainNode.

unsigned X86InstructionSelector::getPtrLoadStoreOp(const LLT &Ty,
const RegisterBank &RB,
unsigned Opc) const {
bool Isload = (Opc == TargetOpcode::G_LOAD);
Copy link
Collaborator

Choose a reason for hiding this comment

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

assert((Opc == TargetOpcode::G_LOAD || Opc == TargetOpcode::G_STORE) && "Unknown memory opcode");

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Thanks! I blindly copied existing code however should've reread it.

unsigned X86InstructionSelector::getPtrLoadStoreOp(const LLT &Ty,
const RegisterBank &RB,
unsigned Opc) const {
bool Isload = (Opc == TargetOpcode::G_LOAD);
Copy link
Collaborator

Choose a reason for hiding this comment

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

(style) Isload -> IsLoad


if (STI.isPICStyleRIPRel()) {
// Use rip-relative addressing.
assert(AM.Base.Reg == 0 && AM.IndexReg == 0);
Copy link
Collaborator

Choose a reason for hiding this comment

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

(style) assert message

@e-kud
Copy link
Contributor Author

e-kud commented Mar 25, 2025

I also collected stats: enabling addr pattern reduces amount of skipped patterns by ~9% (24233->22100). Also other patterns started revealing a new skipping reason.

Copy link
Collaborator

@RKSimon RKSimon left a comment

Choose a reason for hiding this comment

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

Fix clang-format warnings?

@e-kud
Copy link
Contributor Author

e-kud commented Apr 1, 2025

Fix clang-format warnings?

Done. I think that column structure is more readable but I don't mind.

@e-kud
Copy link
Contributor Author

e-kud commented Apr 8, 2025

@RKSimon ping

Comment on lines 459 to 461
if (Ty == LLT::pointer(0, 32) && X86::GPRRegBankID == RB.getID())
return IsLoad ? X86::MOV32rm : X86::MOV32mr;
if (Ty == LLT::pointer(0, 64) && X86::GPRRegBankID == RB.getID())
Copy link
Contributor

Choose a reason for hiding this comment

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

Check isPointer and the size? This will fail on non-0 address spaces

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I think we'll start seeing problems at Legalizer because there are a lot of assumptions for p0 for stores and loads in particular. But I've changed it anyway.

Copy link
Contributor

Choose a reason for hiding this comment

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

Is X86 backend known to use non-zero addr spaces?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I can think of two use cases:

  1. FS, GS segment registers
  2. User defined address spaces. IIRC, garbage collection passes assume that managed pointers should be in the address space 1.

But I think this code will be fixed earlier then we start caring about different address spaces.

@e-kud
Copy link
Contributor Author

e-kud commented Apr 15, 2025

Ping

@e-kud e-kud requested review from arsenm and RKSimon April 16, 2025 12:24
Copy link
Collaborator

@RKSimon RKSimon left a comment

Choose a reason for hiding this comment

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

LGTM - cheers (the X32 check prefix tweak isn't required - although it would be nice to clean these up at some point).

@@ -32,7 +32,7 @@ define i64 @test_ret_i64() {
define i8 @test_arg_i8(i8 %a) {
; X32-LABEL: test_arg_i8:
; X32: # %bb.0:
; X32-NEXT: movl {{[0-9]+}}(%esp), %eax
; X32-NEXT: movzbl {{[0-9]+}}(%esp), %eax
Copy link
Collaborator

Choose a reason for hiding this comment

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

(pet peeve) - we should use X86 for i686 checks and use X32 for gnux32 triples (this goes 100x for calling convention tests!)

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm going to introduce fastcall convention support and will address this issue in the corresponding tests.

@e-kud e-kud merged commit e8245d5 into llvm:main Apr 19, 2025
11 checks passed
@llvm-ci
Copy link
Collaborator

llvm-ci commented Apr 19, 2025

LLVM Buildbot has detected a new failure on builder lldb-aarch64-ubuntu running on linaro-lldb-aarch64-ubuntu while building llvm at step 6 "test".

Full details are available at: https://lab.llvm.org/buildbot/#/builders/59/builds/16334

Here is the relevant piece of the build log for the reference
Step 6 (test) failure: build (failure)
...
PASS: lldb-api :: tools/lldb-server/TestGdbRemoteAttach.py (1201 of 2125)
UNSUPPORTED: lldb-api :: tools/lldb-server/TestGdbRemoteFork.py (1202 of 2125)
UNSUPPORTED: lldb-api :: tools/lldb-server/TestGdbRemoteForkNonStop.py (1203 of 2125)
UNSUPPORTED: lldb-api :: tools/lldb-server/TestGdbRemoteForkResume.py (1204 of 2125)
PASS: lldb-api :: tools/lldb-server/TestGdbRemoteCompletion.py (1205 of 2125)
PASS: lldb-api :: tools/lldb-server/TestGdbRemoteExitCode.py (1206 of 2125)
PASS: lldb-api :: tools/lldb-server/TestGdbRemoteHostInfo.py (1207 of 2125)
PASS: lldb-api :: tools/lldb-server/TestGdbRemoteModuleInfo.py (1208 of 2125)
PASS: lldb-api :: tools/lldb-server/TestGdbRemoteAuxvSupport.py (1209 of 2125)
UNRESOLVED: lldb-api :: tools/lldb-dap/variables/TestDAP_variables.py (1210 of 2125)
******************** TEST 'lldb-api :: tools/lldb-dap/variables/TestDAP_variables.py' FAILED ********************
Script:
--
/usr/bin/python3.10 /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/dotest.py -u CXXFLAGS -u CFLAGS --env LLVM_LIBS_DIR=/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./lib --env LLVM_INCLUDE_DIR=/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/include --env LLVM_TOOLS_DIR=/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin --arch aarch64 --build-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex --lldb-module-cache-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex/module-cache-lldb/lldb-api --clang-module-cache-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex/module-cache-clang/lldb-api --executable /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin/lldb --compiler /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin/clang --dsymutil /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin/dsymutil --make /usr/bin/gmake --llvm-tools-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./bin --lldb-obj-root /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/tools/lldb --lldb-libs-dir /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/./lib /home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/llvm-project/lldb/test/API/tools/lldb-dap/variables -p TestDAP_variables.py
--
Exit Code: 1

Command Output (stdout):
--
lldb version 21.0.0git (https://github.com/llvm/llvm-project.git revision e8245d53247f155d234e1de647aac2678c49ac28)
  clang revision e8245d53247f155d234e1de647aac2678c49ac28
  llvm revision e8245d53247f155d234e1de647aac2678c49ac28
Skipping the following test categories: ['libc++', 'dsym', 'gmodules', 'debugserver', 'objc']

--
Command Output (stderr):
--
UNSUPPORTED: LLDB (/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang-aarch64) :: test_darwin_dwarf_missing_obj (TestDAP_variables.TestDAP_variables) (requires one of macosx, darwin, ios, tvos, watchos, bridgeos, iphonesimulator, watchsimulator, appletvsimulator) 
UNSUPPORTED: LLDB (/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/bin/clang-aarch64) :: test_darwin_dwarf_missing_obj_with_symbol_ondemand_enabled (TestDAP_variables.TestDAP_variables) (requires one of macosx, darwin, ios, tvos, watchos, bridgeos, iphonesimulator, watchsimulator, appletvsimulator) 
========= DEBUG ADAPTER PROTOCOL LOGS =========
1745097128.166585207 --> (stdin/stdout) {"command":"initialize","type":"request","arguments":{"adapterID":"lldb-native","clientID":"vscode","columnsStartAt1":true,"linesStartAt1":true,"locale":"en-us","pathFormat":"path","supportsRunInTerminalRequest":true,"supportsVariablePaging":true,"supportsVariableType":true,"supportsStartDebuggingRequest":true,"supportsProgressReporting":true,"$__lldb_sourceInitFile":false},"seq":1}
1745097128.168626070 <-- (stdin/stdout) {"body":{"$__lldb_version":"lldb version 21.0.0git (https://github.com/llvm/llvm-project.git revision e8245d53247f155d234e1de647aac2678c49ac28)\n  clang revision e8245d53247f155d234e1de647aac2678c49ac28\n  llvm revision e8245d53247f155d234e1de647aac2678c49ac28","completionTriggerCharacters":["."," ","\t"],"exceptionBreakpointFilters":[{"default":false,"filter":"cpp_catch","label":"C++ Catch"},{"default":false,"filter":"cpp_throw","label":"C++ Throw"},{"default":false,"filter":"objc_catch","label":"Objective-C Catch"},{"default":false,"filter":"objc_throw","label":"Objective-C Throw"}],"supportTerminateDebuggee":true,"supportsBreakpointLocationsRequest":true,"supportsCancelRequest":true,"supportsCompletionsRequest":true,"supportsConditionalBreakpoints":true,"supportsConfigurationDoneRequest":true,"supportsDataBreakpoints":true,"supportsDelayedStackTraceLoading":true,"supportsDisassembleRequest":true,"supportsEvaluateForHovers":true,"supportsExceptionInfoRequest":true,"supportsExceptionOptions":true,"supportsFunctionBreakpoints":true,"supportsHitConditionalBreakpoints":true,"supportsInstructionBreakpoints":true,"supportsLogPoints":true,"supportsModulesRequest":true,"supportsReadMemoryRequest":true,"supportsRestartRequest":true,"supportsSetVariable":true,"supportsStepInTargetsRequest":true,"supportsSteppingGranularity":true,"supportsValueFormattingOptions":true},"command":"initialize","request_seq":1,"seq":0,"success":true,"type":"response"}
1745097128.168871403 --> (stdin/stdout) {"command":"launch","type":"request","arguments":{"program":"/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex/tools/lldb-dap/variables/TestDAP_variables.test_indexedVariables/a.out","initCommands":["settings clear -all","settings set symbols.enable-external-lookup false","settings set target.inherit-tcc true","settings set target.disable-aslr false","settings set target.detach-on-error false","settings set target.auto-apply-fixits false","settings set plugin.process.gdb-remote.packet-timeout 60","settings set symbols.clang-modules-cache-path \"/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex/module-cache-lldb/lldb-api\"","settings set use-color false","settings set show-statusline false"],"disableASLR":false,"enableAutoVariableSummaries":false,"enableSyntheticChildDebugging":false,"displayExtendedBacktrace":false,"commandEscapePrefix":null},"seq":2}
1745097128.169078827 <-- (stdin/stdout) {"body":{"category":"console","output":"Running initCommands:\n"},"event":"output","seq":0,"type":"event"}
1745097128.169106960 <-- (stdin/stdout) {"body":{"category":"console","output":"(lldb) settings clear -all\n"},"event":"output","seq":0,"type":"event"}
1745097128.169117928 <-- (stdin/stdout) {"body":{"category":"console","output":"(lldb) settings set symbols.enable-external-lookup false\n"},"event":"output","seq":0,"type":"event"}
1745097128.169126987 <-- (stdin/stdout) {"body":{"category":"console","output":"(lldb) settings set target.inherit-tcc true\n"},"event":"output","seq":0,"type":"event"}
1745097128.169135094 <-- (stdin/stdout) {"body":{"category":"console","output":"(lldb) settings set target.disable-aslr false\n"},"event":"output","seq":0,"type":"event"}
1745097128.169143200 <-- (stdin/stdout) {"body":{"category":"console","output":"(lldb) settings set target.detach-on-error false\n"},"event":"output","seq":0,"type":"event"}
1745097128.169151068 <-- (stdin/stdout) {"body":{"category":"console","output":"(lldb) settings set target.auto-apply-fixits false\n"},"event":"output","seq":0,"type":"event"}
1745097128.169159651 <-- (stdin/stdout) {"body":{"category":"console","output":"(lldb) settings set plugin.process.gdb-remote.packet-timeout 60\n"},"event":"output","seq":0,"type":"event"}
1745097128.169180393 <-- (stdin/stdout) {"body":{"category":"console","output":"(lldb) settings set symbols.clang-modules-cache-path \"/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex/module-cache-lldb/lldb-api\"\n"},"event":"output","seq":0,"type":"event"}
1745097128.169188976 <-- (stdin/stdout) {"body":{"category":"console","output":"(lldb) settings set use-color false\n"},"event":"output","seq":0,"type":"event"}
1745097128.169196844 <-- (stdin/stdout) {"body":{"category":"console","output":"(lldb) settings set show-statusline false\n"},"event":"output","seq":0,"type":"event"}
1745097128.246194601 <-- (stdin/stdout) {"command":"launch","request_seq":2,"seq":0,"success":true,"type":"response"}
1745097128.246246576 <-- (stdin/stdout) {"body":{"isLocalProcess":true,"name":"/home/tcwg-buildbot/worker/lldb-aarch64-ubuntu/build/lldb-test-build.noindex/tools/lldb-dap/variables/TestDAP_variables.test_indexedVariables/a.out","startMethod":"launch","systemProcessId":2382214},"event":"process","seq":0,"type":"event"}
1745097128.246256351 <-- (stdin/stdout) {"event":"initialized","seq":0,"type":"event"}
1745097128.246543884 --> (stdin/stdout) {"command":"setBreakpoints","type":"request","arguments":{"source":{"name":"main.cpp","path":"main.cpp"},"sourceModified":false,"lines":[40],"breakpoints":[{"line":40}]},"seq":3}
1745097128.248012066 <-- (stdin/stdout) {"body":{"breakpoints":[{"column":1,"id":1,"instructionReference":"0xAAAAC4090C54","line":41,"source":{"name":"main.cpp","path":"main.cpp"},"verified":true}]},"command":"setBreakpoints","request_seq":3,"seq":0,"success":true,"type":"response"}

@e-kud e-kud deleted the global-load-2 branch April 24, 2025 00:56
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
addr matching was the only gatekeeper for starting selecting G_LOAD
and G_STORE using SDAG patterns.

* Introduce a complex renderer gi_addr for addr. In this patch only
the existing functionality has been implemented. The renderer's name is
the same as in SDAG: selectAddr. Apparently the type of
GIComplexOperandMatcher doesn't matter as RISCV also uses s32 for
both 64 and 32 bit pointers.
* X86SelectAddress now is used for both: pattern matching and manual
selection. As a result it accumulates all the code that previously was
distributed among different selection functions.
* Replace getLoadStoreOp with getPtrLoadStoreOp in Load/Store
selector as GlobalISel matcher or emitter can't map the pointer type
into i32/i64 types used in SDAG patterns for pointers. So the load and
store selection of pointers is still manual. getLoadStoreOp is still
present because it is used in G_FCONSTANT lowering that requires extra
efforts to select it using SDAG patterns.
* Since truncating stores are not supported, we custom legalize them by
matching types of store and MMO.
* Introduce a constant pool flag in X86AddressMode because otherwise
we need to introduce a GlobalISel copy for X86ISelAddressMode.
* Also please notice in the tests that GlobalISel prefers to fold memory
operands immediately comparing to SDAG. The reason is that GlobalISel
doesn't have target hooks in GIM_CheckIsSafeToFold. Or maybe another
check on profitability is required along with safety check that is
currently not present.
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
addr matching was the only gatekeeper for starting selecting G_LOAD
and G_STORE using SDAG patterns.

* Introduce a complex renderer gi_addr for addr. In this patch only
the existing functionality has been implemented. The renderer's name is
the same as in SDAG: selectAddr. Apparently the type of
GIComplexOperandMatcher doesn't matter as RISCV also uses s32 for
both 64 and 32 bit pointers.
* X86SelectAddress now is used for both: pattern matching and manual
selection. As a result it accumulates all the code that previously was
distributed among different selection functions.
* Replace getLoadStoreOp with getPtrLoadStoreOp in Load/Store
selector as GlobalISel matcher or emitter can't map the pointer type
into i32/i64 types used in SDAG patterns for pointers. So the load and
store selection of pointers is still manual. getLoadStoreOp is still
present because it is used in G_FCONSTANT lowering that requires extra
efforts to select it using SDAG patterns.
* Since truncating stores are not supported, we custom legalize them by
matching types of store and MMO.
* Introduce a constant pool flag in X86AddressMode because otherwise
we need to introduce a GlobalISel copy for X86ISelAddressMode.
* Also please notice in the tests that GlobalISel prefers to fold memory
operands immediately comparing to SDAG. The reason is that GlobalISel
doesn't have target hooks in GIM_CheckIsSafeToFold. Or maybe another
check on profitability is required along with safety check that is
currently not present.
IanWood1 pushed a commit to IanWood1/llvm-project that referenced this pull request May 6, 2025
addr matching was the only gatekeeper for starting selecting G_LOAD
and G_STORE using SDAG patterns.

* Introduce a complex renderer gi_addr for addr. In this patch only
the existing functionality has been implemented. The renderer's name is
the same as in SDAG: selectAddr. Apparently the type of
GIComplexOperandMatcher doesn't matter as RISCV also uses s32 for
both 64 and 32 bit pointers.
* X86SelectAddress now is used for both: pattern matching and manual
selection. As a result it accumulates all the code that previously was
distributed among different selection functions.
* Replace getLoadStoreOp with getPtrLoadStoreOp in Load/Store
selector as GlobalISel matcher or emitter can't map the pointer type
into i32/i64 types used in SDAG patterns for pointers. So the load and
store selection of pointers is still manual. getLoadStoreOp is still
present because it is used in G_FCONSTANT lowering that requires extra
efforts to select it using SDAG patterns.
* Since truncating stores are not supported, we custom legalize them by
matching types of store and MMO.
* Introduce a constant pool flag in X86AddressMode because otherwise
we need to introduce a GlobalISel copy for X86ISelAddressMode.
* Also please notice in the tests that GlobalISel prefers to fold memory
operands immediately comparing to SDAG. The reason is that GlobalISel
doesn't have target hooks in GIM_CheckIsSafeToFold. Or maybe another
check on profitability is required along with safety check that is
currently not present.
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.

6 participants