From 3f267bf769f169f26dd98d05246cbe75b632f4be Mon Sep 17 00:00:00 2001 From: Daniel Sanders Date: Sun, 15 Oct 2017 02:06:44 +0000 Subject: [PATCH] [tablegen] Handle common load/store predicates inside tablegen. NFC. Summary: GlobalISel and SelectionDAG require different code for the common load/store predicates due to differences in the representation. For example: SelectionDAG: (load:i32 GPR32:$addr) // The <> denote properties of the SDNode that are not printed in the DAG GlobalISel: (G_SEXT:s32 (G_LOAD:s8 GPR32:$addr)) Even without that, differences in the IR (SDNode vs MachineInstr) require differences in the C++ predicate. This patch moves the implementation of the common load/store predicates into tablegen so that it can handle these differences. It's NFC for SelectionDAG since it emits equivalent code and it's NFC for GlobalISel since the rules involving the relevant predicates are still rejected by the importer. Depends on D36618 Reviewers: ab, qcolombet, t.p.northover, rovka, aditya_nandakumar Subscribers: llvm-commits, igorb Differential Revision: https://reviews.llvm.org/D37443 Includes a partial revert of r315826 since this patch makes it necessary for getPredCode() to return a std::string and getImmCode() should have the same interface as getPredCode(). llvm-svn: 315841 --- .../include/llvm/Target/TargetSelectionDAG.td | 425 +++++++++++------- llvm/utils/TableGen/CodeGenDAGPatterns.cpp | 223 ++++++++- llvm/utils/TableGen/CodeGenDAGPatterns.h | 39 +- llvm/utils/TableGen/GlobalISelEmitter.cpp | 25 ++ 4 files changed, 533 insertions(+), 179 deletions(-) diff --git a/llvm/include/llvm/Target/TargetSelectionDAG.td b/llvm/include/llvm/Target/TargetSelectionDAG.td index 4b178989935f..511b7655e501 100644 --- a/llvm/include/llvm/Target/TargetSelectionDAG.td +++ b/llvm/include/llvm/Target/TargetSelectionDAG.td @@ -649,6 +649,39 @@ class PatFrag(N)->getAddressingMode() == ISD::UNINDEXED; + // cast(N)->getAddressingMode() == ISD::UNINDEXED; + bit IsUnindexed = ?; + + // cast(N)->getExtensionType() != ISD::NON_EXTLOAD + bit IsNonExtLoad = ?; + // cast(N)->getExtensionType() == ISD::EXTLOAD; + bit IsAnyExtLoad = ?; + // cast(N)->getExtensionType() == ISD::SEXTLOAD; + bit IsSignExtLoad = ?; + // cast(N)->getExtensionType() == ISD::ZEXTLOAD; + bit IsZeroExtLoad = ?; + // !cast(N)->isTruncatingStore(); + // cast(N)->isTruncatingStore(); + bit IsTruncStore = ?; + + // cast(N)->getMemoryVT() == MVT::; + // cast(N)->getMemoryVT() == MVT::; + ValueType MemoryVT = ?; + // cast(N)->getMemoryVT().getScalarType() == MVT::; + // cast(N)->getMemoryVT().getScalarType() == MVT::; + ValueType ScalarMemoryVT = ?; } // OutPatFrag is a pattern fragment that is used as part of an output pattern @@ -739,170 +772,215 @@ def ineg : PatFrag<(ops node:$in), (sub 0, node:$in)>; def null_frag : SDPatternOperator; // load fragments. -def unindexedload : PatFrag<(ops node:$ptr), (ld node:$ptr), [{ - return cast(N)->getAddressingMode() == ISD::UNINDEXED; -}]>; -def load : PatFrag<(ops node:$ptr), (unindexedload node:$ptr), [{ - return cast(N)->getExtensionType() == ISD::NON_EXTLOAD; -}]>; +def unindexedload : PatFrag<(ops node:$ptr), (ld node:$ptr)> { + let IsLoad = 1; + let IsUnindexed = 1; +} +def load : PatFrag<(ops node:$ptr), (unindexedload node:$ptr)> { + let IsLoad = 1; + let IsNonExtLoad = 1; +} // extending load fragments. -def extload : PatFrag<(ops node:$ptr), (unindexedload node:$ptr), [{ - return cast(N)->getExtensionType() == ISD::EXTLOAD; -}]>; -def sextload : PatFrag<(ops node:$ptr), (unindexedload node:$ptr), [{ - return cast(N)->getExtensionType() == ISD::SEXTLOAD; -}]>; -def zextload : PatFrag<(ops node:$ptr), (unindexedload node:$ptr), [{ - return cast(N)->getExtensionType() == ISD::ZEXTLOAD; -}]>; +def extload : PatFrag<(ops node:$ptr), (unindexedload node:$ptr)> { + let IsLoad = 1; + let IsAnyExtLoad = 1; +} +def sextload : PatFrag<(ops node:$ptr), (unindexedload node:$ptr)> { + let IsLoad = 1; + let IsSignExtLoad = 1; +} +def zextload : PatFrag<(ops node:$ptr), (unindexedload node:$ptr)> { + let IsLoad = 1; + let IsZeroExtLoad = 1; +} -def extloadi1 : PatFrag<(ops node:$ptr), (extload node:$ptr), [{ - return cast(N)->getMemoryVT() == MVT::i1; -}]>; -def extloadi8 : PatFrag<(ops node:$ptr), (extload node:$ptr), [{ - return cast(N)->getMemoryVT() == MVT::i8; -}]>; -def extloadi16 : PatFrag<(ops node:$ptr), (extload node:$ptr), [{ - return cast(N)->getMemoryVT() == MVT::i16; -}]>; -def extloadi32 : PatFrag<(ops node:$ptr), (extload node:$ptr), [{ - return cast(N)->getMemoryVT() == MVT::i32; -}]>; -def extloadf32 : PatFrag<(ops node:$ptr), (extload node:$ptr), [{ - return cast(N)->getMemoryVT() == MVT::f32; -}]>; -def extloadf64 : PatFrag<(ops node:$ptr), (extload node:$ptr), [{ - return cast(N)->getMemoryVT() == MVT::f64; -}]>; +def extloadi1 : PatFrag<(ops node:$ptr), (extload node:$ptr)> { + let IsLoad = 1; + let MemoryVT = i1; +} +def extloadi8 : PatFrag<(ops node:$ptr), (extload node:$ptr)> { + let IsLoad = 1; + let MemoryVT = i8; +} +def extloadi16 : PatFrag<(ops node:$ptr), (extload node:$ptr)> { + let IsLoad = 1; + let MemoryVT = i16; +} +def extloadi32 : PatFrag<(ops node:$ptr), (extload node:$ptr)> { + let IsLoad = 1; + let MemoryVT = i32; +} +def extloadf32 : PatFrag<(ops node:$ptr), (extload node:$ptr)> { + let IsLoad = 1; + let MemoryVT = f32; +} +def extloadf64 : PatFrag<(ops node:$ptr), (extload node:$ptr)> { + let IsLoad = 1; + let MemoryVT = f64; +} -def sextloadi1 : PatFrag<(ops node:$ptr), (sextload node:$ptr), [{ - return cast(N)->getMemoryVT() == MVT::i1; -}]>; -def sextloadi8 : PatFrag<(ops node:$ptr), (sextload node:$ptr), [{ - return cast(N)->getMemoryVT() == MVT::i8; -}]>; -def sextloadi16 : PatFrag<(ops node:$ptr), (sextload node:$ptr), [{ - return cast(N)->getMemoryVT() == MVT::i16; -}]>; -def sextloadi32 : PatFrag<(ops node:$ptr), (sextload node:$ptr), [{ - return cast(N)->getMemoryVT() == MVT::i32; -}]>; +def sextloadi1 : PatFrag<(ops node:$ptr), (sextload node:$ptr)> { + let IsLoad = 1; + let MemoryVT = i1; +} +def sextloadi8 : PatFrag<(ops node:$ptr), (sextload node:$ptr)> { + let IsLoad = 1; + let MemoryVT = i8; +} +def sextloadi16 : PatFrag<(ops node:$ptr), (sextload node:$ptr)> { + let IsLoad = 1; + let MemoryVT = i16; +} +def sextloadi32 : PatFrag<(ops node:$ptr), (sextload node:$ptr)> { + let IsLoad = 1; + let MemoryVT = i32; +} -def zextloadi1 : PatFrag<(ops node:$ptr), (zextload node:$ptr), [{ - return cast(N)->getMemoryVT() == MVT::i1; -}]>; -def zextloadi8 : PatFrag<(ops node:$ptr), (zextload node:$ptr), [{ - return cast(N)->getMemoryVT() == MVT::i8; -}]>; -def zextloadi16 : PatFrag<(ops node:$ptr), (zextload node:$ptr), [{ - return cast(N)->getMemoryVT() == MVT::i16; -}]>; -def zextloadi32 : PatFrag<(ops node:$ptr), (zextload node:$ptr), [{ - return cast(N)->getMemoryVT() == MVT::i32; -}]>; +def zextloadi1 : PatFrag<(ops node:$ptr), (zextload node:$ptr)> { + let IsLoad = 1; + let MemoryVT = i1; +} +def zextloadi8 : PatFrag<(ops node:$ptr), (zextload node:$ptr)> { + let IsLoad = 1; + let MemoryVT = i8; +} +def zextloadi16 : PatFrag<(ops node:$ptr), (zextload node:$ptr)> { + let IsLoad = 1; + let MemoryVT = i16; +} +def zextloadi32 : PatFrag<(ops node:$ptr), (zextload node:$ptr)> { + let IsLoad = 1; + let MemoryVT = i32; +} -def extloadvi1 : PatFrag<(ops node:$ptr), (extload node:$ptr), [{ - return cast(N)->getMemoryVT().getScalarType() == MVT::i1; -}]>; -def extloadvi8 : PatFrag<(ops node:$ptr), (extload node:$ptr), [{ - return cast(N)->getMemoryVT().getScalarType() == MVT::i8; -}]>; -def extloadvi16 : PatFrag<(ops node:$ptr), (extload node:$ptr), [{ - return cast(N)->getMemoryVT().getScalarType() == MVT::i16; -}]>; -def extloadvi32 : PatFrag<(ops node:$ptr), (extload node:$ptr), [{ - return cast(N)->getMemoryVT().getScalarType() == MVT::i32; -}]>; -def extloadvf32 : PatFrag<(ops node:$ptr), (extload node:$ptr), [{ - return cast(N)->getMemoryVT().getScalarType() == MVT::f32; -}]>; -def extloadvf64 : PatFrag<(ops node:$ptr), (extload node:$ptr), [{ - return cast(N)->getMemoryVT().getScalarType() == MVT::f64; -}]>; +def extloadvi1 : PatFrag<(ops node:$ptr), (extload node:$ptr)> { + let IsLoad = 1; + let ScalarMemoryVT = i1; +} +def extloadvi8 : PatFrag<(ops node:$ptr), (extload node:$ptr)> { + let IsLoad = 1; + let ScalarMemoryVT = i8; +} +def extloadvi16 : PatFrag<(ops node:$ptr), (extload node:$ptr)> { + let IsLoad = 1; + let ScalarMemoryVT = i16; +} +def extloadvi32 : PatFrag<(ops node:$ptr), (extload node:$ptr)> { + let IsLoad = 1; + let ScalarMemoryVT = i32; +} +def extloadvf32 : PatFrag<(ops node:$ptr), (extload node:$ptr)> { + let IsLoad = 1; + let ScalarMemoryVT = f32; +} +def extloadvf64 : PatFrag<(ops node:$ptr), (extload node:$ptr)> { + let IsLoad = 1; + let ScalarMemoryVT = f64; +} -def sextloadvi1 : PatFrag<(ops node:$ptr), (sextload node:$ptr), [{ - return cast(N)->getMemoryVT().getScalarType() == MVT::i1; -}]>; -def sextloadvi8 : PatFrag<(ops node:$ptr), (sextload node:$ptr), [{ - return cast(N)->getMemoryVT().getScalarType() == MVT::i8; -}]>; -def sextloadvi16 : PatFrag<(ops node:$ptr), (sextload node:$ptr), [{ - return cast(N)->getMemoryVT().getScalarType() == MVT::i16; -}]>; -def sextloadvi32 : PatFrag<(ops node:$ptr), (sextload node:$ptr), [{ - return cast(N)->getMemoryVT().getScalarType() == MVT::i32; -}]>; +def sextloadvi1 : PatFrag<(ops node:$ptr), (sextload node:$ptr)> { + let IsLoad = 1; + let ScalarMemoryVT = i1; +} +def sextloadvi8 : PatFrag<(ops node:$ptr), (sextload node:$ptr)> { + let IsLoad = 1; + let ScalarMemoryVT = i8; +} +def sextloadvi16 : PatFrag<(ops node:$ptr), (sextload node:$ptr)> { + let IsLoad = 1; + let ScalarMemoryVT = i16; +} +def sextloadvi32 : PatFrag<(ops node:$ptr), (sextload node:$ptr)> { + let IsLoad = 1; + let ScalarMemoryVT = i32; +} -def zextloadvi1 : PatFrag<(ops node:$ptr), (zextload node:$ptr), [{ - return cast(N)->getMemoryVT().getScalarType() == MVT::i1; -}]>; -def zextloadvi8 : PatFrag<(ops node:$ptr), (zextload node:$ptr), [{ - return cast(N)->getMemoryVT().getScalarType() == MVT::i8; -}]>; -def zextloadvi16 : PatFrag<(ops node:$ptr), (zextload node:$ptr), [{ - return cast(N)->getMemoryVT().getScalarType() == MVT::i16; -}]>; -def zextloadvi32 : PatFrag<(ops node:$ptr), (zextload node:$ptr), [{ - return cast(N)->getMemoryVT().getScalarType() == MVT::i32; -}]>; +def zextloadvi1 : PatFrag<(ops node:$ptr), (zextload node:$ptr)> { + let IsLoad = 1; + let ScalarMemoryVT = i1; +} +def zextloadvi8 : PatFrag<(ops node:$ptr), (zextload node:$ptr)> { + let IsLoad = 1; + let ScalarMemoryVT = i8; +} +def zextloadvi16 : PatFrag<(ops node:$ptr), (zextload node:$ptr)> { + let IsLoad = 1; + let ScalarMemoryVT = i16; +} +def zextloadvi32 : PatFrag<(ops node:$ptr), (zextload node:$ptr)> { + let IsLoad = 1; + let ScalarMemoryVT = i32; +} // store fragments. def unindexedstore : PatFrag<(ops node:$val, node:$ptr), - (st node:$val, node:$ptr), [{ - return cast(N)->getAddressingMode() == ISD::UNINDEXED; -}]>; + (st node:$val, node:$ptr)> { + let IsStore = 1; + let IsUnindexed = 1; +} def store : PatFrag<(ops node:$val, node:$ptr), - (unindexedstore node:$val, node:$ptr), [{ - return !cast(N)->isTruncatingStore(); -}]>; + (unindexedstore node:$val, node:$ptr)> { + let IsStore = 1; + let IsTruncStore = 0; +} // truncstore fragments. def truncstore : PatFrag<(ops node:$val, node:$ptr), - (unindexedstore node:$val, node:$ptr), [{ - return cast(N)->isTruncatingStore(); -}]>; + (unindexedstore node:$val, node:$ptr)> { + let IsStore = 1; + let IsTruncStore = 1; +} def truncstorei8 : PatFrag<(ops node:$val, node:$ptr), - (truncstore node:$val, node:$ptr), [{ - return cast(N)->getMemoryVT() == MVT::i8; -}]>; + (truncstore node:$val, node:$ptr)> { + let IsStore = 1; + let MemoryVT = i8; +} def truncstorei16 : PatFrag<(ops node:$val, node:$ptr), - (truncstore node:$val, node:$ptr), [{ - return cast(N)->getMemoryVT() == MVT::i16; -}]>; + (truncstore node:$val, node:$ptr)> { + let IsStore = 1; + let MemoryVT = i16; +} def truncstorei32 : PatFrag<(ops node:$val, node:$ptr), - (truncstore node:$val, node:$ptr), [{ - return cast(N)->getMemoryVT() == MVT::i32; -}]>; + (truncstore node:$val, node:$ptr)> { + let IsStore = 1; + let MemoryVT = i32; +} def truncstoref32 : PatFrag<(ops node:$val, node:$ptr), - (truncstore node:$val, node:$ptr), [{ - return cast(N)->getMemoryVT() == MVT::f32; -}]>; + (truncstore node:$val, node:$ptr)> { + let IsStore = 1; + let MemoryVT = f32; +} def truncstoref64 : PatFrag<(ops node:$val, node:$ptr), - (truncstore node:$val, node:$ptr), [{ - return cast(N)->getMemoryVT() == MVT::f64; -}]>; + (truncstore node:$val, node:$ptr)> { + let IsStore = 1; + let MemoryVT = f64; +} def truncstorevi8 : PatFrag<(ops node:$val, node:$ptr), - (truncstore node:$val, node:$ptr), [{ - return cast(N)->getMemoryVT().getScalarType() == MVT::i8; -}]>; + (truncstore node:$val, node:$ptr)> { + let IsStore = 1; + let ScalarMemoryVT = i8; +} def truncstorevi16 : PatFrag<(ops node:$val, node:$ptr), - (truncstore node:$val, node:$ptr), [{ - return cast(N)->getMemoryVT().getScalarType() == MVT::i16; -}]>; + (truncstore node:$val, node:$ptr)> { + let IsStore = 1; + let ScalarMemoryVT = i16; +} def truncstorevi32 : PatFrag<(ops node:$val, node:$ptr), - (truncstore node:$val, node:$ptr), [{ - return cast(N)->getMemoryVT().getScalarType() == MVT::i32; -}]>; + (truncstore node:$val, node:$ptr)> { + let IsStore = 1; + let ScalarMemoryVT = i32; +} // indexed store fragments. def istore : PatFrag<(ops node:$val, node:$base, node:$offset), - (ist node:$val, node:$base, node:$offset), [{ - return !cast(N)->isTruncatingStore(); -}]>; + (ist node:$val, node:$base, node:$offset)> { + let IsStore = 1; + let IsTruncStore = 0; +} def pre_store : PatFrag<(ops node:$val, node:$base, node:$offset), (istore node:$val, node:$base, node:$offset), [{ @@ -911,34 +989,40 @@ def pre_store : PatFrag<(ops node:$val, node:$base, node:$offset), }]>; def itruncstore : PatFrag<(ops node:$val, node:$base, node:$offset), - (ist node:$val, node:$base, node:$offset), [{ - return cast(N)->isTruncatingStore(); -}]>; + (ist node:$val, node:$base, node:$offset)> { + let IsStore = 1; + let IsTruncStore = 1; +} def pre_truncst : PatFrag<(ops node:$val, node:$base, node:$offset), (itruncstore node:$val, node:$base, node:$offset), [{ ISD::MemIndexedMode AM = cast(N)->getAddressingMode(); return AM == ISD::PRE_INC || AM == ISD::PRE_DEC; }]>; def pre_truncsti1 : PatFrag<(ops node:$val, node:$base, node:$offset), - (pre_truncst node:$val, node:$base, node:$offset), [{ - return cast(N)->getMemoryVT() == MVT::i1; -}]>; + (pre_truncst node:$val, node:$base, node:$offset)> { + let IsStore = 1; + let MemoryVT = i1; +} def pre_truncsti8 : PatFrag<(ops node:$val, node:$base, node:$offset), - (pre_truncst node:$val, node:$base, node:$offset), [{ - return cast(N)->getMemoryVT() == MVT::i8; -}]>; + (pre_truncst node:$val, node:$base, node:$offset)> { + let IsStore = 1; + let MemoryVT = i8; +} def pre_truncsti16 : PatFrag<(ops node:$val, node:$base, node:$offset), - (pre_truncst node:$val, node:$base, node:$offset), [{ - return cast(N)->getMemoryVT() == MVT::i16; -}]>; + (pre_truncst node:$val, node:$base, node:$offset)> { + let IsStore = 1; + let MemoryVT = i16; +} def pre_truncsti32 : PatFrag<(ops node:$val, node:$base, node:$offset), - (pre_truncst node:$val, node:$base, node:$offset), [{ - return cast(N)->getMemoryVT() == MVT::i32; -}]>; + (pre_truncst node:$val, node:$base, node:$offset)> { + let IsStore = 1; + let MemoryVT = i32; +} def pre_truncstf32 : PatFrag<(ops node:$val, node:$base, node:$offset), - (pre_truncst node:$val, node:$base, node:$offset), [{ - return cast(N)->getMemoryVT() == MVT::f32; -}]>; + (pre_truncst node:$val, node:$base, node:$offset)> { + let IsStore = 1; + let MemoryVT = f32; +} def post_store : PatFrag<(ops node:$val, node:$ptr, node:$offset), (istore node:$val, node:$ptr, node:$offset), [{ @@ -952,25 +1036,30 @@ def post_truncst : PatFrag<(ops node:$val, node:$base, node:$offset), return AM == ISD::POST_INC || AM == ISD::POST_DEC; }]>; def post_truncsti1 : PatFrag<(ops node:$val, node:$base, node:$offset), - (post_truncst node:$val, node:$base, node:$offset), [{ - return cast(N)->getMemoryVT() == MVT::i1; -}]>; + (post_truncst node:$val, node:$base, node:$offset)> { + let IsStore = 1; + let MemoryVT = i1; +} def post_truncsti8 : PatFrag<(ops node:$val, node:$base, node:$offset), - (post_truncst node:$val, node:$base, node:$offset), [{ - return cast(N)->getMemoryVT() == MVT::i8; -}]>; + (post_truncst node:$val, node:$base, node:$offset)> { + let IsStore = 1; + let MemoryVT = i8; +} def post_truncsti16 : PatFrag<(ops node:$val, node:$base, node:$offset), - (post_truncst node:$val, node:$base, node:$offset), [{ - return cast(N)->getMemoryVT() == MVT::i16; -}]>; + (post_truncst node:$val, node:$base, node:$offset)> { + let IsStore = 1; + let MemoryVT = i16; +} def post_truncsti32 : PatFrag<(ops node:$val, node:$base, node:$offset), - (post_truncst node:$val, node:$base, node:$offset), [{ - return cast(N)->getMemoryVT() == MVT::i32; -}]>; + (post_truncst node:$val, node:$base, node:$offset)> { + let IsStore = 1; + let MemoryVT = i32; +} def post_truncstf32 : PatFrag<(ops node:$val, node:$base, node:$offset), - (post_truncst node:$val, node:$base, node:$offset), [{ - return cast(N)->getMemoryVT() == MVT::f32; -}]>; + (post_truncst node:$val, node:$base, node:$offset)> { + let IsStore = 1; + let MemoryVT = f32; +} // nontemporal store fragments. def nontemporalstore : PatFrag<(ops node:$val, node:$ptr), diff --git a/llvm/utils/TableGen/CodeGenDAGPatterns.cpp b/llvm/utils/TableGen/CodeGenDAGPatterns.cpp index 8987091a1624..163977f8e57e 100644 --- a/llvm/utils/TableGen/CodeGenDAGPatterns.cpp +++ b/llvm/utils/TableGen/CodeGenDAGPatterns.cpp @@ -854,11 +854,129 @@ TreePredicateFn::TreePredicateFn(TreePattern *N) : PatFragRec(N) { ".td file corrupt: can't have a node predicate *and* an imm predicate"); } -StringRef TreePredicateFn::getPredCode() const { - return PatFragRec->getRecord()->getValueAsString("PredicateCode"); +std::string TreePredicateFn::getPredCode() const { + std::string Code = ""; + + if (!isLoad() && !isStore()) { + if (isUnindexed()) + PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), + "IsUnindexed requires IsLoad or IsStore"); + + Record *MemoryVT = getMemoryVT(); + Record *ScalarMemoryVT = getScalarMemoryVT(); + + if (MemoryVT) + PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), + "MemoryVT requires IsLoad or IsStore"); + if (ScalarMemoryVT) + PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), + "ScalarMemoryVT requires IsLoad or IsStore"); + } + + if (isLoad() && isStore()) + PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), + "IsLoad and IsStore are mutually exclusive"); + + if (isLoad()) { + if (!isUnindexed() && !isNonExtLoad() && !isAnyExtLoad() && + !isSignExtLoad() && !isZeroExtLoad() && getMemoryVT() == nullptr && + getScalarMemoryVT() == nullptr) + PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), + "IsLoad cannot be used by itself"); + } else { + if (isNonExtLoad()) + PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), + "IsNonExtLoad requires IsLoad"); + if (isAnyExtLoad()) + PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), + "IsAnyExtLoad requires IsLoad"); + if (isSignExtLoad()) + PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), + "IsSignExtLoad requires IsLoad"); + if (isZeroExtLoad()) + PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), + "IsZeroExtLoad requires IsLoad"); + } + + if (isStore()) { + if (!isUnindexed() && !isTruncStore() && !isNonTruncStore() && + getMemoryVT() == nullptr && getScalarMemoryVT() == nullptr) + PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), + "IsStore cannot be used by itself"); + } else { + if (isNonTruncStore()) + PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), + "IsNonTruncStore requires IsStore"); + if (isTruncStore()) + PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), + "IsTruncStore requires IsStore"); + } + + if (isLoad() || isStore()) { + StringRef SDNodeName = isLoad() ? "LoadSDNode" : "StoreSDNode"; + + if (isUnindexed()) + Code += ("if (cast<" + SDNodeName + + ">(N)->getAddressingMode() != ISD::UNINDEXED) " + "return false;\n") + .str(); + + if (isLoad()) { + if ((isNonExtLoad() + isAnyExtLoad() + isSignExtLoad() + + isZeroExtLoad()) > 1) + PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), + "IsNonExtLoad, IsAnyExtLoad, IsSignExtLoad, and " + "IsZeroExtLoad are mutually exclusive"); + if (isNonExtLoad()) + Code += "if (cast(N)->getExtensionType() != " + "ISD::NON_EXTLOAD) return false;\n"; + if (isAnyExtLoad()) + Code += "if (cast(N)->getExtensionType() != ISD::EXTLOAD) " + "return false;\n"; + if (isSignExtLoad()) + Code += "if (cast(N)->getExtensionType() != ISD::SEXTLOAD) " + "return false;\n"; + if (isZeroExtLoad()) + Code += "if (cast(N)->getExtensionType() != ISD::ZEXTLOAD) " + "return false;\n"; + } else { + if ((isNonTruncStore() + isTruncStore()) > 1) + PrintFatalError( + getOrigPatFragRecord()->getRecord()->getLoc(), + "IsNonTruncStore, and IsTruncStore are mutually exclusive"); + if (isNonTruncStore()) + Code += + " if (cast(N)->isTruncatingStore()) return false;\n"; + if (isTruncStore()) + Code += + " if (!cast(N)->isTruncatingStore()) return false;\n"; + } + + Record *MemoryVT = getMemoryVT(); + Record *ScalarMemoryVT = getScalarMemoryVT(); + + if (MemoryVT) + Code += ("if (cast<" + SDNodeName + ">(N)->getMemoryVT() != MVT::" + + MemoryVT->getName() + ") return false;\n") + .str(); + if (ScalarMemoryVT) + Code += ("if (cast<" + SDNodeName + + ">(N)->getMemoryVT().getScalarType() != MVT::" + + ScalarMemoryVT->getName() + ") return false;\n") + .str(); + } + + std::string PredicateCode = PatFragRec->getRecord()->getValueAsString("PredicateCode"); + + Code += PredicateCode; + + if (PredicateCode.empty() && !Code.empty()) + Code += "return true;\n"; + + return Code; } -StringRef TreePredicateFn::getImmCode() const { +std::string TreePredicateFn::getImmCode() const { return PatFragRec->getRecord()->getValueAsString("ImmediateCode"); } @@ -873,6 +991,55 @@ bool TreePredicateFn::immCodeUsesAPFloat() const { Unset); } +bool TreePredicateFn::isPredefinedPredicateEqualTo(StringRef Field, + bool Value) const { + bool Unset; + bool Result = + getOrigPatFragRecord()->getRecord()->getValueAsBitOrUnset(Field, Unset); + if (Unset) + return false; + return Result == Value; +} +bool TreePredicateFn::isLoad() const { + return isPredefinedPredicateEqualTo("IsLoad", true); +} +bool TreePredicateFn::isStore() const { + return isPredefinedPredicateEqualTo("IsStore", true); +} +bool TreePredicateFn::isUnindexed() const { + return isPredefinedPredicateEqualTo("IsUnindexed", true); +} +bool TreePredicateFn::isNonExtLoad() const { + return isPredefinedPredicateEqualTo("IsNonExtLoad", true); +} +bool TreePredicateFn::isAnyExtLoad() const { + return isPredefinedPredicateEqualTo("IsAnyExtLoad", true); +} +bool TreePredicateFn::isSignExtLoad() const { + return isPredefinedPredicateEqualTo("IsSignExtLoad", true); +} +bool TreePredicateFn::isZeroExtLoad() const { + return isPredefinedPredicateEqualTo("IsZeroExtLoad", true); +} +bool TreePredicateFn::isNonTruncStore() const { + return isPredefinedPredicateEqualTo("IsTruncStore", false); +} +bool TreePredicateFn::isTruncStore() const { + return isPredefinedPredicateEqualTo("IsTruncStore", true); +} +Record *TreePredicateFn::getMemoryVT() const { + Record *R = getOrigPatFragRecord()->getRecord(); + if (R->isValueUnset("MemoryVT")) + return nullptr; + return R->getValueAsDef("MemoryVT"); +} +Record *TreePredicateFn::getScalarMemoryVT() const { + Record *R = getOrigPatFragRecord()->getRecord(); + if (R->isValueUnset("ScalarMemoryVT")) + return nullptr; + return R->getValueAsDef("ScalarMemoryVT"); +} + StringRef TreePredicateFn::getImmType() const { if (immCodeUsesAPInt()) return "const APInt &"; @@ -906,16 +1073,58 @@ std::string TreePredicateFn::getFnName() const { /// appropriate. std::string TreePredicateFn::getCodeToRunOnSDNode() const { // Handle immediate predicates first. - StringRef ImmCode = getImmCode(); + std::string ImmCode = getImmCode(); if (!ImmCode.empty()) { - std::string Result = " " + getImmType().str() + " Imm = "; + if (isLoad()) + PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), + "IsLoad cannot be used with ImmLeaf or its subclasses"); + if (isStore()) + PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), + "IsStore cannot be used with ImmLeaf or its subclasses"); + if (isUnindexed()) + PrintFatalError( + getOrigPatFragRecord()->getRecord()->getLoc(), + "IsUnindexed cannot be used with ImmLeaf or its subclasses"); + if (isNonExtLoad()) + PrintFatalError( + getOrigPatFragRecord()->getRecord()->getLoc(), + "IsNonExtLoad cannot be used with ImmLeaf or its subclasses"); + if (isAnyExtLoad()) + PrintFatalError( + getOrigPatFragRecord()->getRecord()->getLoc(), + "IsAnyExtLoad cannot be used with ImmLeaf or its subclasses"); + if (isSignExtLoad()) + PrintFatalError( + getOrigPatFragRecord()->getRecord()->getLoc(), + "IsSignExtLoad cannot be used with ImmLeaf or its subclasses"); + if (isZeroExtLoad()) + PrintFatalError( + getOrigPatFragRecord()->getRecord()->getLoc(), + "IsZeroExtLoad cannot be used with ImmLeaf or its subclasses"); + if (isNonTruncStore()) + PrintFatalError( + getOrigPatFragRecord()->getRecord()->getLoc(), + "IsNonTruncStore cannot be used with ImmLeaf or its subclasses"); + if (isTruncStore()) + PrintFatalError( + getOrigPatFragRecord()->getRecord()->getLoc(), + "IsTruncStore cannot be used with ImmLeaf or its subclasses"); + if (getMemoryVT()) + PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(), + "MemoryVT cannot be used with ImmLeaf or its subclasses"); + if (getScalarMemoryVT()) + PrintFatalError( + getOrigPatFragRecord()->getRecord()->getLoc(), + "ScalarMemoryVT cannot be used with ImmLeaf or its subclasses"); + + std::string Result = (" " + getImmType() + " Imm = ").str(); if (immCodeUsesAPFloat()) Result += "cast(Node)->getValueAPF();\n"; else if (immCodeUsesAPInt()) Result += "cast(Node)->getAPIntValue();\n"; else Result += "cast(Node)->getSExtValue();\n"; - return Result + ImmCode.str(); + return Result + ImmCode; } // Handle arbitrary node predicates. @@ -933,7 +1142,7 @@ std::string TreePredicateFn::getCodeToRunOnSDNode() const { else Result = " auto *N = cast<" + ClassName.str() + ">(Node);\n"; - return Result + getPredCode().str(); + return Result + getPredCode(); } //===----------------------------------------------------------------------===// diff --git a/llvm/utils/TableGen/CodeGenDAGPatterns.h b/llvm/utils/TableGen/CodeGenDAGPatterns.h index 2103e154dad3..5b047bc182d5 100644 --- a/llvm/utils/TableGen/CodeGenDAGPatterns.h +++ b/llvm/utils/TableGen/CodeGenDAGPatterns.h @@ -452,8 +452,8 @@ public: /// getImmediatePredicateCode - Return the code that evaluates this pattern if /// this is an immediate predicate. It is an error to call this on a /// non-immediate pattern. - StringRef getImmediatePredicateCode() const { - StringRef Result = getImmCode(); + std::string getImmediatePredicateCode() const { + std::string Result = getImmCode(); assert(!Result.empty() && "Isn't an immediate pattern!"); return Result; } @@ -481,11 +481,42 @@ public: /// usable as part of an identifier. StringRef getImmTypeIdentifier() const; + // Is the desired predefined predicate for a load? + bool isLoad() const; + // Is the desired predefined predicate for a store? + bool isStore() const; + + /// Is this predicate the predefined unindexed load predicate? + /// Is this predicate the predefined unindexed store predicate? + bool isUnindexed() const; + /// Is this predicate the predefined non-extending load predicate? + bool isNonExtLoad() const; + /// Is this predicate the predefined any-extend load predicate? + bool isAnyExtLoad() const; + /// Is this predicate the predefined sign-extend load predicate? + bool isSignExtLoad() const; + /// Is this predicate the predefined zero-extend load predicate? + bool isZeroExtLoad() const; + /// Is this predicate the predefined non-truncating store predicate? + bool isNonTruncStore() const; + /// Is this predicate the predefined truncating store predicate? + bool isTruncStore() const; + + /// If non-null, indicates that this predicate is a predefined memory VT + /// predicate for a load/store and returns the ValueType record for the memory VT. + Record *getMemoryVT() const; + /// If non-null, indicates that this predicate is a predefined memory VT + /// predicate (checking only the scalar type) for load/store and returns the + /// ValueType record for the memory VT. + Record *getScalarMemoryVT() const; + private: - StringRef getPredCode() const; - StringRef getImmCode() const; + std::string getPredCode() const; + std::string getImmCode() const; bool immCodeUsesAPInt() const; bool immCodeUsesAPFloat() const; + + bool isPredefinedPredicateEqualTo(StringRef Field, bool Value) const; }; diff --git a/llvm/utils/TableGen/GlobalISelEmitter.cpp b/llvm/utils/TableGen/GlobalISelEmitter.cpp index b595143701ac..467ae40e51d4 100644 --- a/llvm/utils/TableGen/GlobalISelEmitter.cpp +++ b/llvm/utils/TableGen/GlobalISelEmitter.cpp @@ -170,6 +170,28 @@ static std::string explainPredicates(const TreePatternNode *N) { Explanation += " always-true"; if (P.isImmediatePattern()) Explanation += " immediate"; + + if (P.isUnindexed()) + Explanation += " unindexed"; + + if (P.isNonExtLoad()) + Explanation += " non-extload"; + if (P.isAnyExtLoad()) + Explanation += " extload"; + if (P.isSignExtLoad()) + Explanation += " sextload"; + if (P.isZeroExtLoad()) + Explanation += " zextload"; + + if (P.isNonTruncStore()) + Explanation += " non-truncstore"; + if (P.isTruncStore()) + Explanation += " truncstore"; + + if (Record *VT = P.getMemoryVT()) + Explanation += (" MemVT=" + VT->getName()).str(); + if (Record *VT = P.getScalarMemoryVT()) + Explanation += (" ScalarVT(MemVT)=" + VT->getName()).str(); } return Explanation; } @@ -204,6 +226,9 @@ static Error isTrivialOperatorNode(const TreePatternNode *N) { HasUnsupportedPredicate = true; Explanation = Separator + "Has a predicate (" + explainPredicates(N) + ")"; Separator = ", "; + Explanation += (Separator + "first-failing:" + + Predicate.getOrigPatFragRecord()->getRecord()->getName()) + .str(); break; }