[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