aboutsummaryrefslogtreecommitdiff
path: root/utils/TableGen/CodeGenDAGPatterns.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'utils/TableGen/CodeGenDAGPatterns.cpp')
-rw-r--r--utils/TableGen/CodeGenDAGPatterns.cpp110
1 files changed, 82 insertions, 28 deletions
diff --git a/utils/TableGen/CodeGenDAGPatterns.cpp b/utils/TableGen/CodeGenDAGPatterns.cpp
index 96c90c9cf6bd..c8f710d66a03 100644
--- a/utils/TableGen/CodeGenDAGPatterns.cpp
+++ b/utils/TableGen/CodeGenDAGPatterns.cpp
@@ -1,9 +1,8 @@
//===- CodeGenDAGPatterns.cpp - Read DAG patterns from .td file -----------===//
//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
@@ -68,8 +67,10 @@ static bool berase_if(MachineValueTypeSet &S, Predicate P) {
// inference will apply to each mode separately.
TypeSetByHwMode::TypeSetByHwMode(ArrayRef<ValueTypeByHwMode> VTList) {
- for (const ValueTypeByHwMode &VVT : VTList)
+ for (const ValueTypeByHwMode &VVT : VTList) {
insert(VVT);
+ AddrSpaces.push_back(VVT.PtrAddrSpace);
+ }
}
bool TypeSetByHwMode::isValueTypeByHwMode(bool AllowEmpty) const {
@@ -86,9 +87,13 @@ ValueTypeByHwMode TypeSetByHwMode::getValueTypeByHwMode() const {
assert(isValueTypeByHwMode(true) &&
"The type set has multiple types for at least one HW mode");
ValueTypeByHwMode VVT;
+ auto ASI = AddrSpaces.begin();
+
for (const auto &I : *this) {
MVT T = I.second.empty() ? MVT::Other : *I.second.begin();
VVT.getOrCreateTypeForMode(I.first, T);
+ if (ASI != AddrSpaces.end())
+ VVT.PtrAddrSpace = *ASI++;
}
return VVT;
}
@@ -502,22 +507,14 @@ bool TypeInfer::EnforceSmallerThan(TypeSetByHwMode &Small,
(A.getScalarSizeInBits() == B.getScalarSizeInBits() &&
A.getSizeInBits() < B.getSizeInBits());
};
- auto LE = [](MVT A, MVT B) -> bool {
+ auto LE = [&LT](MVT A, MVT B) -> bool {
// This function is used when removing elements: when a vector is compared
// to a non-vector, it should return false (to avoid removal).
if (A.isVector() != B.isVector())
return false;
- // Note on the < comparison below:
- // X86 has patterns like
- // (set VR128X:$dst, (v16i8 (X86vtrunc (v4i32 VR128X:$src1)))),
- // where the truncated vector is given a type v16i8, while the source
- // vector has type v4i32. They both have the same size in bits.
- // The minimal type in the result is obviously v16i8, and when we remove
- // all types from the source that are smaller-or-equal than v8i16, the
- // only source type would also be removed (since it's equal in size).
- return A.getScalarSizeInBits() <= B.getScalarSizeInBits() ||
- A.getSizeInBits() < B.getSizeInBits();
+ return LT(A, B) || (A.getScalarSizeInBits() == B.getScalarSizeInBits() &&
+ A.getSizeInBits() == B.getSizeInBits());
};
for (unsigned M : Modes) {
@@ -957,13 +954,33 @@ std::string TreePredicateFn::getPredCode() const {
}
if (isLoad() || isStore() || isAtomic()) {
- StringRef SDNodeName =
- isLoad() ? "LoadSDNode" : isStore() ? "StoreSDNode" : "AtomicSDNode";
+ if (ListInit *AddressSpaces = getAddressSpaces()) {
+ Code += "unsigned AddrSpace = cast<MemSDNode>(N)->getAddressSpace();\n"
+ " if (";
+
+ bool First = true;
+ for (Init *Val : AddressSpaces->getValues()) {
+ if (First)
+ First = false;
+ else
+ Code += " && ";
+
+ IntInit *IntVal = dyn_cast<IntInit>(Val);
+ if (!IntVal) {
+ PrintFatalError(getOrigPatFragRecord()->getRecord()->getLoc(),
+ "AddressSpaces element must be integer");
+ }
+
+ Code += "AddrSpace != " + utostr(IntVal->getValue());
+ }
+
+ Code += ")\nreturn false;\n";
+ }
Record *MemoryVT = getMemoryVT();
if (MemoryVT)
- Code += ("if (cast<" + SDNodeName + ">(N)->getMemoryVT() != MVT::" +
+ Code += ("if (cast<MemSDNode>(N)->getMemoryVT() != MVT::" +
MemoryVT->getName() + ") return false;\n")
.str();
}
@@ -1152,6 +1169,14 @@ Record *TreePredicateFn::getMemoryVT() const {
return nullptr;
return R->getValueAsDef("MemoryVT");
}
+
+ListInit *TreePredicateFn::getAddressSpaces() const {
+ Record *R = getOrigPatFragRecord()->getRecord();
+ if (R->isValueUnset("AddressSpaces"))
+ return nullptr;
+ return R->getValueAsListInit("AddressSpaces");
+}
+
Record *TreePredicateFn::getScalarMemoryVT() const {
Record *R = getOrigPatFragRecord()->getRecord();
if (R->isValueUnset("ScalarMemoryVT"))
@@ -1276,6 +1301,17 @@ std::string TreePredicateFn::getCodeToRunOnSDNode() const {
// PatternToMatch implementation
//
+static bool isImmAllOnesAllZerosMatch(const TreePatternNode *P) {
+ if (!P->isLeaf())
+ return false;
+ DefInit *DI = dyn_cast<DefInit>(P->getLeafValue());
+ if (!DI)
+ return false;
+
+ Record *R = DI->getDef();
+ return R->getName() == "immAllOnesV" || R->getName() == "immAllZerosV";
+}
+
/// getPatternSize - Return the 'size' of this pattern. We want to match large
/// patterns before small ones. This is used to determine the size of a
/// pattern.
@@ -1315,6 +1351,8 @@ static unsigned getPatternSize(const TreePatternNode *P,
Size += 5; // Matches a ConstantSDNode (+3) and a specific value (+2).
else if (Child->getComplexPatternInfo(CGP))
Size += getPatternSize(Child, CGP);
+ else if (isImmAllOnesAllZerosMatch(Child))
+ Size += 4; // Matches a build_vector(+3) and a predicate (+1).
else if (!Child->getPredicateCalls().empty())
++Size;
}
@@ -1408,7 +1446,8 @@ SDTypeConstraint::SDTypeConstraint(Record *R, const CodeGenHwModes &CGH) {
x.SDTCisSameSizeAs_Info.OtherOperandNum =
R->getValueAsInt("OtherOperandNum");
} else {
- PrintFatalError("Unrecognized SDTypeConstraint '" + R->getName() + "'!\n");
+ PrintFatalError(R->getLoc(),
+ "Unrecognized SDTypeConstraint '" + R->getName() + "'!\n");
}
}
@@ -2120,7 +2159,8 @@ static TypeSetByHwMode getImplicitType(Record *R, unsigned ResNo,
}
if (R->getName() == "node" || R->getName() == "srcvalue" ||
- R->getName() == "zero_reg") {
+ R->getName() == "zero_reg" || R->getName() == "immAllOnesV" ||
+ R->getName() == "immAllZerosV" || R->getName() == "undef_tied_input") {
// Placeholder.
return TypeSetByHwMode(); // Unknown.
}
@@ -2425,18 +2465,32 @@ bool TreePatternNode::ApplyTypeConstraints(TreePattern &TP, bool NotRegisters) {
}
}
+ // If one or more operands with a default value appear at the end of the
+ // formal operand list for an instruction, we allow them to be overridden
+ // by optional operands provided in the pattern.
+ //
+ // But if an operand B without a default appears at any point after an
+ // operand A with a default, then we don't allow A to be overridden,
+ // because there would be no way to specify whether the next operand in
+ // the pattern was intended to override A or skip it.
+ unsigned NonOverridableOperands = Inst.getNumOperands();
+ while (NonOverridableOperands > 0 &&
+ CDP.operandHasDefault(Inst.getOperand(NonOverridableOperands-1)))
+ --NonOverridableOperands;
+
unsigned ChildNo = 0;
for (unsigned i = 0, e = Inst.getNumOperands(); i != e; ++i) {
Record *OperandNode = Inst.getOperand(i);
- // If the instruction expects a predicate or optional def operand, we
- // codegen this by setting the operand to it's default value if it has a
- // non-empty DefaultOps field.
- if (OperandNode->isSubClassOf("OperandWithDefaultOps") &&
- !CDP.getDefaultOperand(OperandNode).DefaultOps.empty())
+ // If the operand has a default value, do we use it? We must use the
+ // default if we've run out of children of the pattern DAG to consume,
+ // or if the operand is followed by a non-defaulted one.
+ if (CDP.operandHasDefault(OperandNode) &&
+ (i < NonOverridableOperands || ChildNo >= getNumChildren()))
continue;
- // Verify that we didn't run out of provided operands.
+ // If we have run out of child nodes and there _isn't_ a default
+ // value we can use for the next operand, give an error.
if (ChildNo >= getNumChildren()) {
emitTooFewOperandsError(TP, getOperator()->getName(), getNumChildren());
return false;
@@ -2753,7 +2807,7 @@ TreePatternNodePtr TreePattern::ParseTreePattern(Init *TheInit,
// chain.
if (Int.IS.RetVTs.empty())
Operator = getDAGPatterns().get_intrinsic_void_sdnode();
- else if (Int.ModRef != CodeGenIntrinsic::NoMem)
+ else if (Int.ModRef != CodeGenIntrinsic::NoMem || Int.hasSideEffects)
// Has side-effects, requires chain.
Operator = getDAGPatterns().get_intrinsic_w_chain_sdnode();
else // Otherwise, no chain.