Completely rewrite tblgen's type inference mechanism,

changing the primary datastructure from being a 
"std::vector<unsigned char>" to being a new TypeSet class
that actually has (gasp) invariants!

This changes more things than I remember, but one major
innovation here is that it enforces that named input 
values agree in type with their output values.

This also eliminates code that transparently assumes (in 
some cases) that SDNodeXForm input/output types are the
same, because this is wrong in many case.

This also eliminates a bug which caused a lot of ambiguous
patterns to go undetected, where a register class would
sometimes pick the first possible type, causing an
ambiguous pattern to get arbitrary results.

With all the recent target changes, this causes no 
functionality change!

llvm-svn: 98534
This commit is contained in:
Chris Lattner 2010-03-15 06:00:16 +00:00
parent 227aa3595b
commit cabe037b2d
7 changed files with 732 additions and 457 deletions

File diff suppressed because it is too large Load Diff

View File

@ -21,6 +21,8 @@
#include "CodeGenTarget.h"
#include "CodeGenIntrinsics.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringMap.h"
namespace llvm {
class Record;
@ -40,20 +42,99 @@ namespace llvm {
/// value is needed.
namespace EEVT {
enum DAGISelGenValueType {
// FIXME: Remove EEVT::isUnknown!
isUnknown = MVT::LAST_VALUETYPE
};
/// TypeSet - This is either empty if it's completely unknown, or holds a set
/// of types. It is used during type inference because register classes can
/// have multiple possible types and we don't know which one they get until
/// type inference is complete.
///
/// TypeSet can have three states:
/// Vector is empty: The type is completely unknown, it can be any valid
/// target type.
/// Vector has multiple constrained types: (e.g. v4i32 + v4f32) it is one
/// of those types only.
/// Vector has one concrete type: The type is completely known.
///
class TypeSet {
SmallVector<MVT::SimpleValueType, 2> TypeVec;
public:
TypeSet() {}
TypeSet(MVT::SimpleValueType VT, TreePattern &TP);
TypeSet(const std::vector<MVT::SimpleValueType> &VTList);
bool isCompletelyUnknown() const { return TypeVec.empty(); }
bool isConcrete() const {
if (TypeVec.size() != 1) return false;
unsigned char T = TypeVec[0]; (void)T;
assert(T < MVT::LAST_VALUETYPE || T == MVT::iPTR || T == MVT::iPTRAny);
return true;
}
MVT::SimpleValueType getConcrete() const {
assert(isConcrete() && "Type isn't concrete yet");
return (MVT::SimpleValueType)TypeVec[0];
}
bool isDynamicallyResolved() const {
return getConcrete() == MVT::iPTR || getConcrete() == MVT::iPTRAny;
}
const SmallVectorImpl<MVT::SimpleValueType> &getTypeList() const {
assert(!TypeVec.empty() && "Not a type list!");
return TypeVec;
}
/// hasIntegerTypes - Return true if this TypeSet contains any integer value
/// types.
bool hasIntegerTypes() const;
/// hasFloatingPointTypes - Return true if this TypeSet contains an fAny or
/// a floating point value type.
bool hasFloatingPointTypes() const;
/// hasVectorTypes - Return true if this TypeSet contains a vector value
/// type.
bool hasVectorTypes() const;
/// getName() - Return this TypeSet as a string.
std::string getName() const;
/// MergeInTypeInfo - This merges in type information from the specified
/// argument. If 'this' changes, it returns true. If the two types are
/// contradictory (e.g. merge f32 into i32) then this throws an exception.
bool MergeInTypeInfo(const EEVT::TypeSet &InVT, TreePattern &TP);
/// isExtIntegerInVTs - Return true if the specified extended value type
/// vector contains iAny or an integer value type.
bool isExtIntegerInVTs(const std::vector<unsigned char> &EVTs);
bool MergeInTypeInfo(MVT::SimpleValueType InVT, TreePattern &TP) {
return MergeInTypeInfo(EEVT::TypeSet(InVT, TP), TP);
}
/// isExtFloatingPointInVTs - Return true if the specified extended value
/// type vector contains fAny or a FP value type.
bool isExtFloatingPointInVTs(const std::vector<unsigned char> &EVTs);
/// Force this type list to only contain integer types.
bool EnforceInteger(TreePattern &TP);
/// isExtVectorinVTs - Return true if the specified extended value type
/// vector contains vAny or a vector value type.
bool isExtVectorInVTs(const std::vector<unsigned char> &EVTs);
/// Force this type list to only contain floating point types.
bool EnforceFloatingPoint(TreePattern &TP);
/// EnforceScalar - Remove all vector types from this type list.
bool EnforceScalar(TreePattern &TP);
/// EnforceVector - Remove all non-vector types from this type list.
bool EnforceVector(TreePattern &TP);
/// EnforceSmallerThan - 'this' must be a smaller VT than Other. Update
/// this an other based on this information.
bool EnforceSmallerThan(EEVT::TypeSet &Other, TreePattern &TP);
/// EnforceVectorEltTypeIs - 'this' is now constrainted to be a vector type
/// whose element is VT.
bool EnforceVectorEltTypeIs(MVT::SimpleValueType VT, TreePattern &TP);
bool operator!=(const TypeSet &RHS) const { return TypeVec != RHS.TypeVec; }
bool operator==(const TypeSet &RHS) const { return TypeVec == RHS.TypeVec; }
};
}
/// Set type used to track multiply used variables in patterns
@ -72,7 +153,7 @@ struct SDTypeConstraint {
union { // The discriminated union.
struct {
unsigned char VT;
MVT::SimpleValueType VT;
} SDTCisVT_Info;
struct {
unsigned OtherOperandNum;
@ -150,10 +231,10 @@ public:
/// patterns), and as such should be ref counted. We currently just leak all
/// TreePatternNode objects!
class TreePatternNode {
/// The inferred type for this node, or EEVT::isUnknown if it hasn't
/// been determined yet. This is a std::vector because during inference
/// there may be multiple possible types.
std::vector<unsigned char> Types;
/// The type of this node. Before and during type inference, this may be a
/// set of possible types. After (successful) type inference, this is a
/// single type.
EEVT::TypeSet Type;
/// Operator - The Record for the operator if this is an interior node (not
/// a leaf).
@ -178,11 +259,9 @@ class TreePatternNode {
std::vector<TreePatternNode*> Children;
public:
TreePatternNode(Record *Op, const std::vector<TreePatternNode*> &Ch)
: Types(), Operator(Op), Val(0), TransformFn(0),
Children(Ch) { Types.push_back(EEVT::isUnknown); }
: Operator(Op), Val(0), TransformFn(0), Children(Ch) { }
TreePatternNode(Init *val) // leaf ctor
: Types(), Operator(0), Val(val), TransformFn(0) {
Types.push_back(EEVT::isUnknown);
: Operator(0), Val(val), TransformFn(0) {
}
~TreePatternNode();
@ -190,28 +269,16 @@ public:
void setName(const std::string &N) { Name = N; }
bool isLeaf() const { return Val != 0; }
bool hasTypeSet() const {
return (Types[0] < MVT::LAST_VALUETYPE) || (Types[0] == MVT::iPTR) ||
(Types[0] == MVT::iPTRAny);
}
bool isTypeCompletelyUnknown() const {
return Types[0] == EEVT::isUnknown;
}
bool isTypeDynamicallyResolved() const {
return (Types[0] == MVT::iPTR) || (Types[0] == MVT::iPTRAny);
}
MVT::SimpleValueType getTypeNum(unsigned Num) const {
assert(hasTypeSet() && "Doesn't have a type yet!");
assert(Types.size() > Num && "Type num out of range!");
return (MVT::SimpleValueType)Types[Num];
}
unsigned char getExtTypeNum(unsigned Num) const {
assert(Types.size() > Num && "Extended type num out of range!");
return Types[Num];
}
const std::vector<unsigned char> &getExtTypes() const { return Types; }
void setTypes(const std::vector<unsigned char> &T) { Types = T; }
void removeTypes() { Types = std::vector<unsigned char>(1, EEVT::isUnknown); }
// Type accessors.
MVT::SimpleValueType getType() const { return Type.getConcrete(); }
const EEVT::TypeSet &getExtType() const { return Type; }
EEVT::TypeSet &getExtType() { return Type; }
void setType(const EEVT::TypeSet &T) { Type = T; }
bool hasTypeSet() const { return Type.isConcrete(); }
bool isTypeCompletelyUnknown() const { return Type.isCompletelyUnknown(); }
bool isTypeDynamicallyResolved() const { return Type.isDynamicallyResolved();}
Init *getLeafValue() const { assert(isLeaf()); return Val; }
Record *getOperator() const { assert(!isLeaf()); return Operator; }
@ -304,17 +371,18 @@ public: // Higher level manipulation routines.
/// information. If N already contains a conflicting type, then throw an
/// exception. This returns true if any information was updated.
///
bool UpdateNodeType(const std::vector<unsigned char> &ExtVTs,
TreePattern &TP);
bool UpdateNodeType(unsigned char ExtVT, TreePattern &TP) {
std::vector<unsigned char> ExtVTs(1, ExtVT);
return UpdateNodeType(ExtVTs, TP);
bool UpdateNodeType(const EEVT::TypeSet &InTy, TreePattern &TP) {
return Type.MergeInTypeInfo(InTy, TP);
}
bool UpdateNodeType(MVT::SimpleValueType InTy, TreePattern &TP) {
return Type.MergeInTypeInfo(EEVT::TypeSet(InTy, TP), TP);
}
/// ContainsUnresolvedType - Return true if this tree contains any
/// unresolved types.
bool ContainsUnresolvedType() const {
if (!hasTypeSet() && !isTypeDynamicallyResolved()) return true;
if (!hasTypeSet()) return true;
for (unsigned i = 0, e = getNumChildren(); i != e; ++i)
if (getChild(i)->ContainsUnresolvedType()) return true;
return false;
@ -340,6 +408,10 @@ class TreePattern {
///
std::vector<TreePatternNode*> Trees;
/// NamedNodes - This is all of the nodes that have names in the trees in this
/// pattern.
StringMap<SmallVector<TreePatternNode*,1> > NamedNodes;
/// TheRecord - The actual TableGen record corresponding to this pattern.
///
Record *TheRecord;
@ -375,6 +447,12 @@ public:
assert(Trees.size() == 1 && "Doesn't have exactly one pattern!");
return Trees[0];
}
const StringMap<SmallVector<TreePatternNode*,1> > &getNamedNodesMap() {
if (NamedNodes.empty())
ComputeNamedNodes();
return NamedNodes;
}
/// getRecord - Return the actual TableGen record corresponding to this
/// pattern.
@ -401,7 +479,8 @@ public:
/// InferAllTypes - Infer/propagate as many types throughout the expression
/// patterns as possible. Return true if all types are inferred, false
/// otherwise. Throw an exception if a type contradiction is found.
bool InferAllTypes();
bool InferAllTypes(const StringMap<SmallVector<TreePatternNode*,1> >
*NamedTypes=0);
/// error - Throw an exception, prefixing it with information about this
/// pattern.
@ -412,6 +491,8 @@ public:
private:
TreePatternNode *ParseTreePattern(DagInit *DI);
void ComputeNamedNodes();
void ComputeNamedNodes(TreePatternNode *N);
};
/// DAGDefaultOperand - One of these is created for each PredicateOperand

View File

@ -184,16 +184,16 @@ void CodeGenTarget::ReadRegisterClasses() const {
RegisterClasses.assign(RegClasses.begin(), RegClasses.end());
}
std::vector<unsigned char> CodeGenTarget::getRegisterVTs(Record *R) const {
std::vector<unsigned char> Result;
std::vector<MVT::SimpleValueType> CodeGenTarget::
getRegisterVTs(Record *R) const {
std::vector<MVT::SimpleValueType> Result;
const std::vector<CodeGenRegisterClass> &RCs = getRegisterClasses();
for (unsigned i = 0, e = RCs.size(); i != e; ++i) {
const CodeGenRegisterClass &RC = RegisterClasses[i];
for (unsigned ei = 0, ee = RC.Elements.size(); ei != ee; ++ei) {
if (R == RC.Elements[ei]) {
const std::vector<MVT::SimpleValueType> &InVTs = RC.getValueTypes();
for (unsigned i = 0, e = InVTs.size(); i != e; ++i)
Result.push_back(InVTs[i]);
Result.insert(Result.end(), InVTs.begin(), InVTs.end());
}
}
}

View File

@ -167,7 +167,7 @@ public:
/// getRegisterVTs - Find the union of all possible SimpleValueTypes for the
/// specified physical register.
std::vector<unsigned char> getRegisterVTs(Record *R) const;
std::vector<MVT::SimpleValueType> getRegisterVTs(Record *R) const;
const std::vector<MVT::SimpleValueType> &getLegalValueTypes() const {
if (LegalValueTypes.empty()) ReadLegalValueTypes();

View File

@ -25,13 +25,7 @@ using namespace llvm;
/// patterns before small ones. This is used to determine the size of a
/// pattern.
static unsigned getPatternSize(TreePatternNode *P, CodeGenDAGPatterns &CGP) {
assert((EEVT::isExtIntegerInVTs(P->getExtTypes()) ||
EEVT::isExtFloatingPointInVTs(P->getExtTypes()) ||
P->getExtTypeNum(0) == MVT::isVoid ||
P->getExtTypeNum(0) == MVT::Flag ||
P->getExtTypeNum(0) == MVT::iPTR ||
P->getExtTypeNum(0) == MVT::iPTRAny) &&
"Not a valid pattern node to size!");
assert(P->hasTypeSet() && "Not a valid pattern node to size!");
unsigned Size = 3; // The node itself.
// If the root node is a ConstantSDNode, increases its size.
// e.g. (set R32:$dst, 0).
@ -55,7 +49,7 @@ static unsigned getPatternSize(TreePatternNode *P, CodeGenDAGPatterns &CGP) {
// Count children in the count if they are also nodes.
for (unsigned i = 0, e = P->getNumChildren(); i != e; ++i) {
TreePatternNode *Child = P->getChild(i);
if (!Child->isLeaf() && Child->getExtTypeNum(0) != MVT::Other)
if (!Child->isLeaf() && Child->getType() != MVT::Other)
Size += getPatternSize(Child, CGP);
else if (Child->isLeaf()) {
if (dynamic_cast<IntInit*>(Child->getLeafValue()))

View File

@ -408,11 +408,11 @@ void MatcherGen::EmitMatchCode(const TreePatternNode *N,
// If N and NodeNoTypes don't agree on a type, then this is a case where we
// need to do a type check. Emit the check, apply the tyep to NodeNoTypes and
// reinfer any correlated types.
unsigned NodeType = EEVT::isUnknown;
if (NodeNoTypes->getExtTypes() != N->getExtTypes()) {
NodeType = N->getTypeNum(0);
NodeNoTypes->setTypes(N->getExtTypes());
bool DoTypeCheck = false;
if (NodeNoTypes->getExtType() != N->getExtType()) {
NodeNoTypes->setType(N->getExtType());
InferPossibleTypes();
DoTypeCheck = true;
}
// If this node has a name associated with it, capture it in VariableMap. If
@ -442,8 +442,8 @@ void MatcherGen::EmitMatchCode(const TreePatternNode *N,
for (unsigned i = 0, e = N->getPredicateFns().size(); i != e; ++i)
AddMatcher(new CheckPredicateMatcher(N->getPredicateFns()[i]));
if (NodeType != EEVT::isUnknown)
AddMatcher(new CheckTypeMatcher((MVT::SimpleValueType)NodeType));
if (DoTypeCheck)
AddMatcher(new CheckTypeMatcher(N->getType()));
}
/// EmitMatcherCode - Generate the code that matches the predicate of this
@ -567,7 +567,7 @@ void MatcherGen::EmitResultLeafAsOperand(const TreePatternNode *N,
assert(N->isLeaf() && "Must be a leaf");
if (IntInit *II = dynamic_cast<IntInit*>(N->getLeafValue())) {
AddMatcher(new EmitIntegerMatcher(II->getValue(),N->getTypeNum(0)));
AddMatcher(new EmitIntegerMatcher(II->getValue(), N->getType()));
ResultOps.push_back(NextRecordedOperandNo++);
return;
}
@ -575,14 +575,13 @@ void MatcherGen::EmitResultLeafAsOperand(const TreePatternNode *N,
// If this is an explicit register reference, handle it.
if (DefInit *DI = dynamic_cast<DefInit*>(N->getLeafValue())) {
if (DI->getDef()->isSubClassOf("Register")) {
AddMatcher(new EmitRegisterMatcher(DI->getDef(),
N->getTypeNum(0)));
AddMatcher(new EmitRegisterMatcher(DI->getDef(), N->getType()));
ResultOps.push_back(NextRecordedOperandNo++);
return;
}
if (DI->getDef()->getName() == "zero_reg") {
AddMatcher(new EmitRegisterMatcher(0, N->getTypeNum(0)));
AddMatcher(new EmitRegisterMatcher(0, N->getType()));
ResultOps.push_back(NextRecordedOperandNo++);
return;
}
@ -709,10 +708,10 @@ EmitResultInstructionAsOperand(const TreePatternNode *N,
// Determine the result types.
SmallVector<MVT::SimpleValueType, 4> ResultVTs;
if (NumResults != 0 && N->getTypeNum(0) != MVT::isVoid) {
if (NumResults != 0 && N->getType() != MVT::isVoid) {
// FIXME2: If the node has multiple results, we should add them. For now,
// preserve existing behavior?!
ResultVTs.push_back(N->getTypeNum(0));
ResultVTs.push_back(N->getType());
}

View File

@ -73,10 +73,9 @@ struct OperandsSignature {
if (!Op->getPredicateFns().empty())
return false;
// For now, filter out any operand with multiple values.
if (Op->getExtTypes().size() != 1)
return false;
assert(Op->hasTypeSet() && "Type infererence not done?");
// For now, all the operands must have the same type.
if (Op->getTypeNum(0) != VT)
if (Op->getType() != VT)
return false;
if (!Op->isLeaf()) {
if (Op->getOperator()->getName() == "imm") {
@ -296,10 +295,10 @@ void FastISelMap::CollectPatterns(CodeGenDAGPatterns &CGP) {
Record *InstPatOp = InstPatNode->getOperator();
std::string OpcodeName = getOpcodeName(InstPatOp, CGP);
MVT::SimpleValueType RetVT = InstPatNode->getTypeNum(0);
MVT::SimpleValueType RetVT = InstPatNode->getType();
MVT::SimpleValueType VT = RetVT;
if (InstPatNode->getNumChildren())
VT = InstPatNode->getChild(0)->getTypeNum(0);
VT = InstPatNode->getChild(0)->getType();
// For now, filter out instructions which just set a register to
// an Operand or an immediate, like MOV32ri.