[llvm] [GlobalISel] Add immediates and predicates to `LegalityQuery` (PR #198979)

via llvm-commits llvm-commits at lists.llvm.org
Thu May 21 01:08:57 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-backend-webassembly

@llvm/pr-subscribers-llvm-globalisel

Author: Demetrius Kanios (QuantumSegfault)

<details>
<summary>Changes</summary>

Expands `LegalityQuery` to include instruction immediates, and (comparison) predicate operands in the query.

This allows namely `G_SEXT_INREG` to be legalized conditionally based on sext width, and for `G_ICMP` and `G_FCMP` to do the same based on its predicate.

Also adds new `LegalityPredicates` helpers accordingly.

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


7 Files Affected:

- (modified) llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h (+4-3) 
- (modified) llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h (+27-2) 
- (modified) llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp (+22-9) 
- (modified) llvm/lib/CodeGen/GlobalISel/LegalityPredicates.cpp (+39) 
- (modified) llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp (+28-14) 
- (modified) llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp (+11-17) 
- (modified) llvm/lib/Target/WebAssembly/GISel/WebAssemblyLegalizerInfo.cpp (+12-18) 


``````````diff
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h b/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h
index d8d7ccc0bd7a7..4d94316490d94 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/LegalizationArtifactCombiner.h
@@ -205,11 +205,12 @@ class LegalizationArtifactCombiner {
     Register TruncSrc;
     if (mi_match(SrcReg, MRI, m_GTrunc(m_Reg(TruncSrc)))) {
       LLT DstTy = MRI.getType(DstReg);
-      if (isInstUnsupported({TargetOpcode::G_SEXT_INREG, {DstTy}}))
-        return false;
-      LLVM_DEBUG(dbgs() << ".. Combine MI: " << MI);
       LLT SrcTy = MRI.getType(SrcReg);
       uint64_t SizeInBits = SrcTy.getScalarSizeInBits();
+      if (isInstUnsupported(
+              {TargetOpcode::G_SEXT_INREG, {DstTy}, {}, {(int64_t)SizeInBits}}))
+        return false;
+      LLVM_DEBUG(dbgs() << ".. Combine MI: " << MI);
       if (DstTy != MRI.getType(TruncSrc))
         TruncSrc = Builder.buildAnyExtOrTrunc(DstTy, TruncSrc).getReg(0);
       // Elide G_SEXT_INREG if possible. This is similar to eliding G_AND in
diff --git a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h
index 1d6a6cfb15a50..7fbed6d7398dc 100644
--- a/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h
+++ b/llvm/include/llvm/CodeGen/GlobalISel/LegalizerInfo.h
@@ -132,9 +132,15 @@ struct LegalityQuery {
   /// memory type for each MMO.
   ArrayRef<MemDesc> MMODescrs;
 
+  ArrayRef<int64_t> Immediates;
+  ArrayRef<CmpInst::Predicate> Predicates;
+
   constexpr LegalityQuery(unsigned Opcode, ArrayRef<LLT> Types,
-                          ArrayRef<MemDesc> MMODescrs = {})
-      : Opcode(Opcode), Types(Types), MMODescrs(MMODescrs) {}
+                          ArrayRef<MemDesc> MMODescrs = {},
+                          ArrayRef<int64_t> Immediates = {},
+                          ArrayRef<CmpInst::Predicate> Predicates = {})
+      : Opcode(Opcode), Types(Types), MMODescrs(MMODescrs),
+        Immediates(Immediates), Predicates(Predicates) {}
 
   LLVM_ABI raw_ostream &print(raw_ostream &OS) const;
 };
@@ -370,6 +376,25 @@ LLVM_ABI LegalityPredicate numElementsNotPow2(unsigned TypeIdx);
 /// stronger.
 LLVM_ABI LegalityPredicate
 atomicOrderingAtLeastOrStrongerThan(unsigned MMOIdx, AtomicOrdering Ordering);
+
+/// True iff the immediate at the given index has the specified value.
+LLVM_ABI LegalityPredicate immIs(unsigned ImmIdx, int64_t Imm);
+/// True iff the immediate at the given index has one of the specified values.
+LLVM_ABI LegalityPredicate immInSet(unsigned ImmIdx,
+                                    std::initializer_list<int64_t> ImmsInit);
+/// True iff the immediate at the given index does not have the specified value.
+LLVM_ABI LegalityPredicate immIsNot(unsigned ImmIdx, int64_t Imm);
+
+/// True iff the predicate at the given index is the specfied predicate
+LLVM_ABI LegalityPredicate predicateIs(unsigned PredIdx,
+                                       CmpInst::Predicate Pred);
+/// True iff the predicate at the given index is one of the specified predicates
+LLVM_ABI LegalityPredicate predicateInSet(
+    unsigned PredIdx, std::initializer_list<CmpInst::Predicate> PredsInit);
+/// True iff the predicate at the given index is not the specified predicate
+LLVM_ABI LegalityPredicate predicateIsNot(unsigned PredIdx,
+                                          CmpInst::Predicate Pred);
+
 } // end namespace LegalityPredicates
 
 namespace LegalizeMutations {
diff --git a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
index ddf8085b4e249..f4ef5d949492c 100644
--- a/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/CombinerHelper.cpp
@@ -3395,7 +3395,7 @@ bool CombinerHelper::matchAshrShlToSextInreg(
   if (ShlCst != AshrCst)
     return false;
   if (!isLegalOrBeforeLegalizer(
-          {TargetOpcode::G_SEXT_INREG, {MRI.getType(Src)}}))
+          {TargetOpcode::G_SEXT_INREG, {MRI.getType(Src)}, {}, {Src - ShlCst}}))
     return false;
   MatchInfo = std::make_tuple(Src, ShlCst);
   return true;
@@ -5801,7 +5801,10 @@ bool CombinerHelper::matchUDivOrURemByConst(MachineInstr &MI) const {
     if (!isLegalOrBeforeLegalizer(
             {TargetOpcode::G_ICMP,
              {DstTy.isVector() ? DstTy.changeElementSize(1) : LLT::scalar(1),
-              DstTy}}))
+              DstTy},
+             {},
+             {},
+             {CmpInst::Predicate::ICMP_EQ}}))
       return false;
     if (Opcode == TargetOpcode::G_UREM &&
         !isLegalOrBeforeLegalizer({TargetOpcode::G_SUB, {DstTy, DstTy}}))
@@ -7967,11 +7970,9 @@ bool CombinerHelper::tryFoldLogicOfFCmps(GLogicalBinOp *Logic,
   LLT CmpTy = MRI.getType(Cmp1->getReg(0));
   LLT CmpOperandTy = MRI.getType(Cmp1->getLHSReg());
 
-  // We build one fcmp, want to fold the fcmps, replace the logic op,
+  // We want to fold the fcmps, replace the logic op,
   // and the fcmps must have the same shape.
-  if (!isLegalOrBeforeLegalizer(
-          {TargetOpcode::G_FCMP, {CmpTy, CmpOperandTy}}) ||
-      !MRI.hasOneNonDBGUse(Logic->getReg(0)) ||
+  if (!MRI.hasOneNonDBGUse(Logic->getReg(0)) ||
       !MRI.hasOneNonDBGUse(Cmp1->getReg(0)) ||
       !MRI.hasOneNonDBGUse(Cmp2->getReg(0)) ||
       MRI.getType(Cmp1->getLHSReg()) != MRI.getType(Cmp2->getLHSReg()))
@@ -7994,11 +7995,23 @@ bool CombinerHelper::tryFoldLogicOfFCmps(GLogicalBinOp *Logic,
     // We determine the new predicate.
     unsigned CmpCodeL = getFCmpCode(PredL);
     unsigned CmpCodeR = getFCmpCode(PredR);
-    unsigned NewPred = IsAnd ? CmpCodeL & CmpCodeR : CmpCodeL | CmpCodeR;
+
+    // The fcmp predicates fill the lower part of the enum.
+    FCmpInst::Predicate Pred = static_cast<FCmpInst::Predicate>(
+        IsAnd ? CmpCodeL & CmpCodeR : CmpCodeL | CmpCodeR);
+
+    // Make sure the fcmp will be legal, or otherwise replaced by an appropriate
+    // constant.
+    if (!isLegalOrBeforeLegalizer(
+            {TargetOpcode::G_FCMP, {CmpTy, CmpOperandTy}, {}, {Pred}}) &&
+        !(Pred == FCmpInst::FCMP_FALSE &&
+          isConstantLegalOrBeforeLegalizer(CmpTy)) &&
+        !(Pred == FCmpInst::FCMP_TRUE &&
+          isConstantLegalOrBeforeLegalizer(CmpTy)))
+      return false;
+
     unsigned Flags = Cmp1->getFlags() | Cmp2->getFlags();
     MatchInfo = [=](MachineIRBuilder &B) {
-      // The fcmp predicates fill the lower part of the enum.
-      FCmpInst::Predicate Pred = static_cast<FCmpInst::Predicate>(NewPred);
       if (Pred == FCmpInst::FCMP_FALSE &&
           isConstantLegalOrBeforeLegalizer(CmpTy)) {
         auto False = B.buildConstant(CmpTy, 0);
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalityPredicates.cpp b/llvm/lib/CodeGen/GlobalISel/LegalityPredicates.cpp
index 247489f23e83f..cbe0347e0e5d9 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalityPredicates.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalityPredicates.cpp
@@ -249,3 +249,42 @@ LegalityPredicate LegalityPredicates::atomicOrderingAtLeastOrStrongerThan(
     return isAtLeastOrStrongerThan(Query.MMODescrs[MMOIdx].Ordering, Ordering);
   };
 }
+
+LegalityPredicate LegalityPredicates::immIs(unsigned ImmIdx, int64_t Imm) {
+  return
+      [=](const LegalityQuery &Query) { return Query.Immediates[ImmIdx] == Imm; };
+}
+
+LegalityPredicate
+LegalityPredicates::immInSet(unsigned ImmIdx,
+                              std::initializer_list<int64_t> ImmsInit) {
+  SmallVector<int64_t, 4> Imms = ImmsInit;
+  return [=](const LegalityQuery &Query) {
+    return llvm::is_contained(Imms, Query.Immediates[ImmIdx]);
+  };
+}
+
+LegalityPredicate LegalityPredicates::immIsNot(unsigned ImmIdx, int64_t Imm) {
+  return
+      [=](const LegalityQuery &Query) { return Query.Immediates[ImmIdx] != Imm; };
+}
+
+
+LegalityPredicate LegalityPredicates::predicateIs(unsigned PredIdx, CmpInst::Predicate Pred) {
+  return
+      [=](const LegalityQuery &Query) { return Query.Predicates[PredIdx] == Pred; };
+}
+
+LegalityPredicate
+LegalityPredicates::predicateInSet(unsigned PredIdx,
+                              std::initializer_list<CmpInst::Predicate> PredsInit) {
+  SmallVector<CmpInst::Predicate, 4> Preds = PredsInit;
+  return [=](const LegalityQuery &Query) {
+    return llvm::is_contained(Preds, Query.Predicates[PredIdx]);
+  };
+}
+
+LegalityPredicate LegalityPredicates::predicateIsNot(unsigned PredIdx, CmpInst::Predicate Pred) {
+  return
+      [=](const LegalityQuery &Query) { return Query.Predicates[PredIdx] != Pred; };
+}
diff --git a/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp b/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp
index c2d474fdde696..49e3df5b6ca94 100644
--- a/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp
+++ b/llvm/lib/CodeGen/GlobalISel/LegalizerInfo.cpp
@@ -91,6 +91,14 @@ raw_ostream &LegalityQuery::print(raw_ostream &OS) const {
   for (const auto &MMODescr : MMODescrs) {
     OS << MMODescr.MemoryTy << ", ";
   }
+  OS << "}, Imms={";
+  for (const auto Imm : Immediates) {
+    OS << Imm << ", ";
+  }
+  OS << "}, Predicates={";
+  for (const auto Pred : Predicates) {
+    OS << Pred << ", ";
+  }
   OS << "}";
 
   return OS;
@@ -355,30 +363,36 @@ LegalizeActionStep
 LegalizerInfo::getAction(const MachineInstr &MI,
                          const MachineRegisterInfo &MRI) const {
   SmallVector<LLT, 8> Types;
+  SmallVector<int64_t, 8> Immediates;
+  SmallVector<CmpInst::Predicate, 8> Predicates;
   SmallBitVector SeenTypes(8);
   ArrayRef<MCOperandInfo> OpInfo = MI.getDesc().operands();
   // FIXME: probably we'll need to cache the results here somehow?
   for (unsigned i = 0; i < MI.getDesc().getNumOperands(); ++i) {
-    if (!OpInfo[i].isGenericType())
-      continue;
-
-    // We must only record actions once for each TypeIdx; otherwise we'd
-    // try to legalize operands multiple times down the line.
-    unsigned TypeIdx = OpInfo[i].getGenericTypeIndex();
-    if (SeenTypes[TypeIdx])
-      continue;
-
-    SeenTypes.set(TypeIdx);
-
-    LLT Ty = getTypeFromTypeIdx(MI, MRI, i, TypeIdx);
-    Types.push_back(Ty);
+    if (OpInfo[i].isGenericType()) {
+      // We must only record actions once for each TypeIdx; otherwise we'd
+      // try to legalize operands multiple times down the line.
+      unsigned TypeIdx = OpInfo[i].getGenericTypeIndex();
+      if (SeenTypes[TypeIdx])
+        continue;
+
+      SeenTypes.set(TypeIdx);
+
+      LLT Ty = getTypeFromTypeIdx(MI, MRI, i, TypeIdx);
+      Types.push_back(Ty);
+    } else if (OpInfo[i].isGenericImm()) {
+      Immediates.push_back(MI.getOperand(i).getImm());
+    } else if (MI.getOperand(i).isPredicate()) {
+      Predicates.push_back(
+          static_cast<CmpInst::Predicate>(MI.getOperand(i).getPredicate()));
+    }
   }
 
   SmallVector<LegalityQuery::MemDesc, 2> MemDescrs;
   for (const auto &MMO : MI.memoperands())
     MemDescrs.push_back({*MMO});
 
-  return getAction({MI.getOpcode(), Types, MemDescrs});
+  return getAction({MI.getOpcode(), Types, MemDescrs, Immediates, Predicates});
 }
 
 bool LegalizerInfo::isLegal(const MachineInstr &MI,
diff --git a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
index 6a690402696e6..b04a929f4c49c 100644
--- a/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
+++ b/llvm/lib/Target/RISCV/GISel/RISCVLegalizerInfo.cpp
@@ -176,10 +176,17 @@ RISCVLegalizerInfo::RISCVLegalizerInfo(const RISCVSubtarget &ST)
       .customIf(typeIsLegalBoolVec(1, BoolVecTys, ST))
       .maxScalar(0, sXLen);
 
-  getActionDefinitionsBuilder(G_SEXT_INREG)
-      .customFor({sXLen})
-      .clampScalar(0, sXLen, sXLen)
-      .lower();
+  {
+    LegalityPredicate ValidSextInRegWidth = all(sizeIs(0, 64), immIs(0, 32));
+
+    if (STI.hasStdExtZbb())
+      ValidSextInRegWidth = LegalityPredicates::any(ValidSextInRegWidth, immInSet(0, {8, 16}));
+
+    getActionDefinitionsBuilder(G_SEXT_INREG)
+        .legalIf(all(typeIs(0, sXLen), ValidSextInRegWidth))
+        .clampScalar(0, sXLen, sXLen)
+        .lower();
+  }
 
   // Merge/Unmerge
   for (unsigned Op : {G_MERGE_VALUES, G_UNMERGE_VALUES}) {
@@ -1457,19 +1464,6 @@ bool RISCVLegalizerInfo::legalizeCustom(
     Helper.Observer.changedInstr(MI);
     return true;
   }
-  case TargetOpcode::G_SEXT_INREG: {
-    LLT DstTy = MRI.getType(MI.getOperand(0).getReg());
-    int64_t SizeInBits = MI.getOperand(2).getImm();
-    // Source size of 32 is sext.w.
-    if (DstTy.getSizeInBits() == 64 && SizeInBits == 32)
-      return true;
-
-    if (STI.hasStdExtZbb() && (SizeInBits == 8 || SizeInBits == 16))
-      return true;
-
-    return Helper.lower(MI, 0, /* Unused hint type */ LLT()) ==
-           LegalizerHelper::Legalized;
-  }
   case TargetOpcode::G_ASHR:
   case TargetOpcode::G_LSHR:
   case TargetOpcode::G_SHL: {
diff --git a/llvm/lib/Target/WebAssembly/GISel/WebAssemblyLegalizerInfo.cpp b/llvm/lib/Target/WebAssembly/GISel/WebAssemblyLegalizerInfo.cpp
index fb499d0db1733..76d92243662cf 100644
--- a/llvm/lib/Target/WebAssembly/GISel/WebAssemblyLegalizerInfo.cpp
+++ b/llvm/lib/Target/WebAssembly/GISel/WebAssemblyLegalizerInfo.cpp
@@ -20,6 +20,7 @@
 
 using namespace llvm;
 using namespace LegalizeActions;
+using namespace LegalityPredicates;
 
 WebAssemblyLegalizerInfo::WebAssemblyLegalizerInfo(
     const WebAssemblySubtarget &ST) {
@@ -76,10 +77,17 @@ WebAssemblyLegalizerInfo::WebAssemblyLegalizerInfo(
       .clampScalar(0, s32, s32)
       .clampScalar(1, s64, s64);
 
-  getActionDefinitionsBuilder(G_SEXT_INREG)
-      .customFor(ST.hasSignExt(), {i32, i64})
-      .clampScalar(0, s32, s64)
-      .lower();
+  {
+    LegalizeRuleSet &Builder = getActionDefinitionsBuilder(G_SEXT_INREG);
+
+    if (ST.hasSignExt())
+      Builder.legalIf(
+          all(typeInSet(0, {i32, i64}),
+              LegalityPredicates::any(immInSet(0, {8, 16}),
+                                      all(typeIs(0, i64), immIs(0, 32)))));
+
+    Builder.clampScalar(0, s32, s64).lower();
+  }
 
   getActionDefinitionsBuilder({G_FCONSTANT, G_FABS, G_FNEG, G_FCEIL, G_FFLOOR,
                                G_INTRINSIC_TRUNC, G_FNEARBYINT, G_FRINT,
@@ -110,20 +118,6 @@ bool WebAssemblyLegalizerInfo::legalizeCustom(
     LegalizerHelper &Helper, MachineInstr &MI,
     LostDebugLocObserver &LocObserver) const {
   switch (MI.getOpcode()) {
-  case TargetOpcode::G_SEXT_INREG: {
-    assert(MI.getOperand(2).isImm() && "Expected immediate");
-
-    // Mark only 8/16/32-bit SEXT_INREG as legal
-    auto [DstType, SrcType] = MI.getFirst2LLTs();
-    auto ExtFromWidth = MI.getOperand(2).getImm();
-
-    if (ExtFromWidth == 8 || ExtFromWidth == 16 ||
-        (DstType.getScalarSizeInBits() == 64 && ExtFromWidth == 32)) {
-      return true;
-    }
-
-    return Helper.lower(MI, 0, DstType) != LegalizerHelper::UnableToLegalize;
-  }
   default:
     break;
   }

``````````

</details>


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


More information about the llvm-commits mailing list