2007-11-23 04:49:04 +08:00
|
|
|
//===- TGParser.cpp - Parser for TableGen Files ---------------------------===//
|
|
|
|
//
|
2019-01-19 16:50:56 +08:00
|
|
|
// 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
|
2007-11-23 04:49:04 +08:00
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
//
|
|
|
|
// Implement the Parser for TableGen.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
#include "TGParser.h"
|
2016-08-24 01:14:32 +08:00
|
|
|
#include "llvm/ADT/None.h"
|
2015-03-02 05:28:53 +08:00
|
|
|
#include "llvm/ADT/STLExtras.h"
|
2012-12-04 00:50:05 +08:00
|
|
|
#include "llvm/ADT/SmallVector.h"
|
2007-11-23 04:49:04 +08:00
|
|
|
#include "llvm/ADT/StringExtras.h"
|
2018-04-30 22:59:11 +08:00
|
|
|
#include "llvm/Config/llvm-config.h"
|
2016-08-24 01:14:32 +08:00
|
|
|
#include "llvm/Support/Casting.h"
|
|
|
|
#include "llvm/Support/Compiler.h"
|
|
|
|
#include "llvm/Support/ErrorHandling.h"
|
|
|
|
#include "llvm/Support/raw_ostream.h"
|
2012-12-04 00:50:05 +08:00
|
|
|
#include "llvm/TableGen/Record.h"
|
2009-07-03 08:10:29 +08:00
|
|
|
#include <algorithm>
|
2016-08-24 01:14:32 +08:00
|
|
|
#include <cassert>
|
|
|
|
#include <cstdint>
|
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
using namespace llvm;
|
|
|
|
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Support Code for the Semantic Actions.
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
namespace llvm {
|
2016-08-24 01:14:32 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
struct SubClassReference {
|
2013-01-11 02:50:11 +08:00
|
|
|
SMRange RefRange;
|
2007-11-23 04:49:04 +08:00
|
|
|
Record *Rec;
|
2016-12-05 14:41:54 +08:00
|
|
|
SmallVector<Init*, 4> TemplateArgs;
|
2016-08-24 01:14:32 +08:00
|
|
|
|
2014-04-09 12:50:04 +08:00
|
|
|
SubClassReference() : Rec(nullptr) {}
|
2009-04-25 00:55:41 +08:00
|
|
|
|
2014-04-09 12:50:04 +08:00
|
|
|
bool isInvalid() const { return Rec == nullptr; }
|
2007-11-23 04:49:04 +08:00
|
|
|
};
|
2009-04-23 00:42:54 +08:00
|
|
|
|
|
|
|
struct SubMultiClassReference {
|
2013-01-11 02:50:11 +08:00
|
|
|
SMRange RefRange;
|
2009-04-23 00:42:54 +08:00
|
|
|
MultiClass *MC;
|
2016-12-05 14:41:54 +08:00
|
|
|
SmallVector<Init*, 4> TemplateArgs;
|
2016-08-24 01:14:32 +08:00
|
|
|
|
2014-04-09 12:50:04 +08:00
|
|
|
SubMultiClassReference() : MC(nullptr) {}
|
2009-04-29 03:41:44 +08:00
|
|
|
|
2014-04-09 12:50:04 +08:00
|
|
|
bool isInvalid() const { return MC == nullptr; }
|
2009-04-25 00:55:41 +08:00
|
|
|
void dump() const;
|
2009-04-23 00:42:54 +08:00
|
|
|
};
|
2009-04-25 00:55:41 +08:00
|
|
|
|
2017-10-15 22:32:27 +08:00
|
|
|
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
2016-01-30 04:50:44 +08:00
|
|
|
LLVM_DUMP_METHOD void SubMultiClassReference::dump() const {
|
2009-07-03 08:10:29 +08:00
|
|
|
errs() << "Multiclass:\n";
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2009-04-25 00:55:41 +08:00
|
|
|
MC->dump();
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2009-07-03 08:10:29 +08:00
|
|
|
errs() << "Template args:\n";
|
2015-05-04 09:35:39 +08:00
|
|
|
for (Init *TA : TemplateArgs)
|
2015-04-29 12:43:36 +08:00
|
|
|
TA->dump();
|
2009-04-25 00:55:41 +08:00
|
|
|
}
|
2017-01-28 10:47:46 +08:00
|
|
|
#endif
|
2009-04-25 00:55:41 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
} // end namespace llvm
|
|
|
|
|
2018-03-06 21:48:47 +08:00
|
|
|
static bool checkBitsConcrete(Record &R, const RecordVal &RV) {
|
|
|
|
BitsInit *BV = cast<BitsInit>(RV.getValue());
|
|
|
|
for (unsigned i = 0, e = BV->getNumBits(); i != e; ++i) {
|
|
|
|
Init *Bit = BV->getBit(i);
|
|
|
|
bool IsReference = false;
|
|
|
|
if (auto VBI = dyn_cast<VarBitInit>(Bit)) {
|
|
|
|
if (auto VI = dyn_cast<VarInit>(VBI->getBitVar())) {
|
|
|
|
if (R.getValue(VI->getName()))
|
|
|
|
IsReference = true;
|
|
|
|
}
|
|
|
|
} else if (isa<VarInit>(Bit)) {
|
|
|
|
IsReference = true;
|
|
|
|
}
|
|
|
|
if (!(IsReference || Bit->isConcrete()))
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void checkConcrete(Record &R) {
|
|
|
|
for (const RecordVal &RV : R.getValues()) {
|
|
|
|
// HACK: Disable this check for variables declared with 'field'. This is
|
|
|
|
// done merely because existing targets have legitimate cases of
|
|
|
|
// non-concrete variables in helper defs. Ideally, we'd introduce a
|
|
|
|
// 'maybe' or 'optional' modifier instead of this.
|
|
|
|
if (RV.getPrefix())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (Init *V = RV.getValue()) {
|
|
|
|
bool Ok = isa<BitsInit>(V) ? checkBitsConcrete(R, RV) : V->isConcrete();
|
|
|
|
if (!Ok) {
|
|
|
|
PrintError(R.getLoc(),
|
|
|
|
Twine("Initializer of '") + RV.getNameInitAsString() +
|
|
|
|
"' in '" + R.getNameInitAsString() +
|
|
|
|
"' could not be fully resolved: " +
|
|
|
|
RV.getValue()->getAsString());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-21 21:35:44 +08:00
|
|
|
/// Return an Init with a qualifier prefix referring
|
|
|
|
/// to CurRec's name.
|
|
|
|
static Init *QualifyName(Record &CurRec, MultiClass *CurMultiClass,
|
|
|
|
Init *Name, StringRef Scoper) {
|
|
|
|
Init *NewName =
|
|
|
|
BinOpInit::getStrConcat(CurRec.getNameInit(), StringInit::get(Scoper));
|
|
|
|
NewName = BinOpInit::getStrConcat(NewName, Name);
|
|
|
|
if (CurMultiClass && Scoper != "::") {
|
|
|
|
Init *Prefix = BinOpInit::getStrConcat(CurMultiClass->Rec.getNameInit(),
|
|
|
|
StringInit::get("::"));
|
|
|
|
NewName = BinOpInit::getStrConcat(Prefix, NewName);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (BinOpInit *BinOp = dyn_cast<BinOpInit>(NewName))
|
|
|
|
NewName = BinOp->Fold(&CurRec);
|
|
|
|
return NewName;
|
|
|
|
}
|
|
|
|
|
TableGen: Streamline the semantics of NAME
Summary:
The new rules are straightforward. The main rules to keep in mind
are:
1. NAME is an implicit template argument of class and multiclass,
and will be substituted by the name of the instantiating def/defm.
2. The name of a def/defm in a multiclass must contain a reference
to NAME. If such a reference is not present, it is automatically
prepended.
And for some additional subtleties, consider these:
3. defm with no name generates a unique name but has no special
behavior otherwise.
4. def with no name generates an anonymous record, whose name is
unique but undefined. In particular, the name won't contain a
reference to NAME.
Keeping rules 1&2 in mind should allow a predictable behavior of
name resolution that is simple to follow.
The old "rules" were rather surprising: sometimes (but not always),
NAME would correspond to the name of the toplevel defm. They were
also plain bonkers when you pushed them to their limits, as the old
version of the TableGen test case shows.
Having NAME correspond to the name of the toplevel defm introduces
"spooky action at a distance" and breaks composability:
refactoring the upper layers of a hierarchy of nested multiclass
instantiations can cause unexpected breakage by changing the value
of NAME at a lower level of the hierarchy. The new rules don't
suffer from this problem.
Some existing .td files have to be adjusted because they ended up
depending on the details of the old implementation.
Change-Id: I694095231565b30f563e6fd0417b41ee01a12589
Reviewers: tra, simon_tatham, craig.topper, MartinO, arsenm, javed.absar
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D47430
llvm-svn: 333900
2018-06-04 22:26:05 +08:00
|
|
|
/// Return the qualified version of the implicit 'NAME' template argument.
|
|
|
|
static Init *QualifiedNameOfImplicitName(Record &Rec,
|
|
|
|
MultiClass *MC = nullptr) {
|
|
|
|
return QualifyName(Rec, MC, StringInit::get("NAME"), MC ? "::" : ":");
|
|
|
|
}
|
|
|
|
|
|
|
|
static Init *QualifiedNameOfImplicitName(MultiClass *MC) {
|
|
|
|
return QualifiedNameOfImplicitName(MC->Rec, MC);
|
|
|
|
}
|
|
|
|
|
2009-06-21 11:39:35 +08:00
|
|
|
bool TGParser::AddValue(Record *CurRec, SMLoc Loc, const RecordVal &RV) {
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!CurRec)
|
2007-11-23 04:49:04 +08:00
|
|
|
CurRec = &CurMultiClass->Rec;
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2012-01-13 11:16:35 +08:00
|
|
|
if (RecordVal *ERV = CurRec->getValue(RV.getNameInit())) {
|
2007-11-23 04:49:04 +08:00
|
|
|
// The value already exists in the class, treat this as a set.
|
|
|
|
if (ERV->setValue(RV.getValue()))
|
|
|
|
return Error(Loc, "New definition of '" + RV.getName() + "' of type '" +
|
|
|
|
RV.getType()->getAsString() + "' is incompatible with " +
|
2009-11-22 12:24:42 +08:00
|
|
|
"previous definition of type '" +
|
2007-11-23 04:49:04 +08:00
|
|
|
ERV->getType()->getAsString() + "'");
|
|
|
|
} else {
|
|
|
|
CurRec->addValue(RV);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// SetValue -
|
|
|
|
/// Return true on error, false on success.
|
2011-10-19 21:02:39 +08:00
|
|
|
bool TGParser::SetValue(Record *CurRec, SMLoc Loc, Init *ValName,
|
2016-01-04 11:15:08 +08:00
|
|
|
ArrayRef<unsigned> BitList, Init *V,
|
2016-01-04 11:05:14 +08:00
|
|
|
bool AllowSelfAssignment) {
|
2007-11-23 04:49:04 +08:00
|
|
|
if (!V) return false;
|
|
|
|
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!CurRec) CurRec = &CurMultiClass->Rec;
|
2007-11-23 04:49:04 +08:00
|
|
|
|
|
|
|
RecordVal *RV = CurRec->getValue(ValName);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!RV)
|
2015-04-30 13:54:22 +08:00
|
|
|
return Error(Loc, "Value '" + ValName->getAsUnquotedString() +
|
|
|
|
"' unknown!");
|
2007-11-23 04:49:04 +08:00
|
|
|
|
|
|
|
// Do not allow assignments like 'X = X'. This will just cause infinite loops
|
|
|
|
// in the resolution machinery.
|
|
|
|
if (BitList.empty())
|
2012-10-11 04:24:43 +08:00
|
|
|
if (VarInit *VI = dyn_cast<VarInit>(V))
|
2016-01-04 11:05:14 +08:00
|
|
|
if (VI->getNameInit() == ValName && !AllowSelfAssignment)
|
2018-02-22 23:26:21 +08:00
|
|
|
return Error(Loc, "Recursion / self-assignment forbidden");
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
// If we are assigning to a subset of the bits in the value... then we must be
|
|
|
|
// assigning to a field of BitsRecTy, which must have a BitsInit
|
|
|
|
// initializer.
|
|
|
|
//
|
|
|
|
if (!BitList.empty()) {
|
2012-10-11 04:24:43 +08:00
|
|
|
BitsInit *CurVal = dyn_cast<BitsInit>(RV->getValue());
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!CurVal)
|
2015-04-30 13:54:22 +08:00
|
|
|
return Error(Loc, "Value '" + ValName->getAsUnquotedString() +
|
|
|
|
"' is not a bits type");
|
2007-11-23 04:49:04 +08:00
|
|
|
|
|
|
|
// Convert the incoming value to a bits type of the appropriate size...
|
TableGen: Allow !cast of records, cleanup conversion machinery
Summary:
Distinguish two relationships between types: is-a and convertible-to.
For example, a bit is not an int or vice versa, but they can be
converted into each other (with range checks that you can think of
as "dynamic": unlike other type checks, those range checks do not
happen during parsing, but only once the final values have been
established).
Actually converting initializers between types is subtle: even
when values of type A can be converted to type B (e.g. int into
string), it may not be possible to do so with a concrete initializer
(e.g., a VarInit that refers to a variable of type int cannot
be immediately converted to a string).
For this reason, distinguish between getCastTo and convertInitializerTo:
the latter implements the actual conversion when appropriate, while
the former will first try to do the actual conversion and fall back
to introducing a !cast operation so that the conversion will be
delayed until variable references have been resolved.
To make the approach of adding !cast operations to work, !cast needs
to fallback to convertInitializerTo when the special string <-> record
logic does not apply.
This enables casting records to a subclass, although that new
functionality is only truly useful together with !isa, which will be
added in a later change.
The test is removed because it uses !srl on a bit sequence,
which cannot really be supported consistently, but luckily
isn't used anywhere either.
Change-Id: I98168bf52649176654ed2ec61a29bdb29970cfe7
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D43753
llvm-svn: 326785
2018-03-06 21:48:39 +08:00
|
|
|
Init *BI = V->getCastTo(BitsRecTy::get(BitList.size()));
|
2015-05-04 09:35:39 +08:00
|
|
|
if (!BI)
|
2007-11-23 04:49:04 +08:00
|
|
|
return Error(Loc, "Initializer is not compatible with bit range");
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2011-07-30 06:43:06 +08:00
|
|
|
SmallVector<Init *, 16> NewBits(CurVal->getNumBits());
|
2007-11-23 04:49:04 +08:00
|
|
|
|
|
|
|
// Loop over bits, assigning values as appropriate.
|
|
|
|
for (unsigned i = 0, e = BitList.size(); i != e; ++i) {
|
|
|
|
unsigned Bit = BitList[i];
|
2011-07-30 03:07:00 +08:00
|
|
|
if (NewBits[Bit])
|
2015-05-28 19:24:24 +08:00
|
|
|
return Error(Loc, "Cannot set bit #" + Twine(Bit) + " of value '" +
|
2011-10-19 21:02:39 +08:00
|
|
|
ValName->getAsUnquotedString() + "' more than once");
|
TableGen: Allow !cast of records, cleanup conversion machinery
Summary:
Distinguish two relationships between types: is-a and convertible-to.
For example, a bit is not an int or vice versa, but they can be
converted into each other (with range checks that you can think of
as "dynamic": unlike other type checks, those range checks do not
happen during parsing, but only once the final values have been
established).
Actually converting initializers between types is subtle: even
when values of type A can be converted to type B (e.g. int into
string), it may not be possible to do so with a concrete initializer
(e.g., a VarInit that refers to a variable of type int cannot
be immediately converted to a string).
For this reason, distinguish between getCastTo and convertInitializerTo:
the latter implements the actual conversion when appropriate, while
the former will first try to do the actual conversion and fall back
to introducing a !cast operation so that the conversion will be
delayed until variable references have been resolved.
To make the approach of adding !cast operations to work, !cast needs
to fallback to convertInitializerTo when the special string <-> record
logic does not apply.
This enables casting records to a subclass, although that new
functionality is only truly useful together with !isa, which will be
added in a later change.
The test is removed because it uses !srl on a bit sequence,
which cannot really be supported consistently, but luckily
isn't used anywhere either.
Change-Id: I98168bf52649176654ed2ec61a29bdb29970cfe7
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D43753
llvm-svn: 326785
2018-03-06 21:48:39 +08:00
|
|
|
NewBits[Bit] = BI->getBit(i);
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
for (unsigned i = 0, e = CurVal->getNumBits(); i != e; ++i)
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!NewBits[i])
|
2011-07-30 03:07:00 +08:00
|
|
|
NewBits[i] = CurVal->getBit(i);
|
2007-11-23 04:49:04 +08:00
|
|
|
|
2011-07-30 03:07:07 +08:00
|
|
|
V = BitsInit::get(NewBits);
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
|
2014-07-31 09:43:57 +08:00
|
|
|
if (RV->setValue(V)) {
|
2016-08-24 01:14:32 +08:00
|
|
|
std::string InitType;
|
2015-05-04 09:35:39 +08:00
|
|
|
if (BitsInit *BI = dyn_cast<BitsInit>(V))
|
2014-07-31 09:43:57 +08:00
|
|
|
InitType = (Twine("' of type bit initializer with length ") +
|
|
|
|
Twine(BI->getNumBits())).str();
|
2018-02-22 23:26:21 +08:00
|
|
|
else if (TypedInit *TI = dyn_cast<TypedInit>(V))
|
|
|
|
InitType = (Twine("' of type '") + TI->getType()->getAsString()).str();
|
2015-04-30 13:54:22 +08:00
|
|
|
return Error(Loc, "Value '" + ValName->getAsUnquotedString() +
|
2018-02-22 23:26:21 +08:00
|
|
|
"' of type '" + RV->getType()->getAsString() +
|
|
|
|
"' is incompatible with initializer '" +
|
|
|
|
V->getAsString() + InitType + "'");
|
2014-07-31 09:43:57 +08:00
|
|
|
}
|
2007-11-23 04:49:04 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// AddSubClass - Add SubClass as a subclass to CurRec, resolving its template
|
|
|
|
/// args as SubClass's template arguments.
|
2009-02-15 00:06:42 +08:00
|
|
|
bool TGParser::AddSubClass(Record *CurRec, SubClassReference &SubClass) {
|
2007-11-23 04:49:04 +08:00
|
|
|
Record *SC = SubClass.Rec;
|
|
|
|
// Add all of the values in the subclass into the current class.
|
2015-06-02 14:19:28 +08:00
|
|
|
for (const RecordVal &Val : SC->getValues())
|
|
|
|
if (AddValue(CurRec, SubClass.RefRange.Start, Val))
|
2007-11-23 04:49:04 +08:00
|
|
|
return true;
|
|
|
|
|
2015-10-24 20:46:45 +08:00
|
|
|
ArrayRef<Init *> TArgs = SC->getTemplateArgs();
|
2007-11-23 04:49:04 +08:00
|
|
|
|
|
|
|
// Ensure that an appropriate number of template arguments are specified.
|
|
|
|
if (TArgs.size() < SubClass.TemplateArgs.size())
|
2013-01-11 02:50:11 +08:00
|
|
|
return Error(SubClass.RefRange.Start,
|
|
|
|
"More template args specified than expected");
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
// Loop over all of the template arguments, setting them to the specified
|
|
|
|
// value or leaving them as the default if necessary.
|
2018-03-05 23:21:11 +08:00
|
|
|
MapResolver R(CurRec);
|
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
for (unsigned i = 0, e = TArgs.size(); i != e; ++i) {
|
|
|
|
if (i < SubClass.TemplateArgs.size()) {
|
|
|
|
// If a value is specified for this template arg, set it now.
|
2013-01-11 02:50:11 +08:00
|
|
|
if (SetValue(CurRec, SubClass.RefRange.Start, TArgs[i],
|
2016-01-04 11:15:08 +08:00
|
|
|
None, SubClass.TemplateArgs[i]))
|
2007-11-23 04:49:04 +08:00
|
|
|
return true;
|
|
|
|
} else if (!CurRec->getValue(TArgs[i])->getValue()->isComplete()) {
|
2013-01-11 02:50:11 +08:00
|
|
|
return Error(SubClass.RefRange.Start,
|
2015-04-30 13:54:22 +08:00
|
|
|
"Value not specified for template argument #" +
|
2015-05-28 19:24:24 +08:00
|
|
|
Twine(i) + " (" + TArgs[i]->getAsUnquotedString() +
|
2015-04-30 13:54:22 +08:00
|
|
|
") of subclass '" + SC->getNameInitAsString() + "'!");
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
2018-03-05 23:21:11 +08:00
|
|
|
|
|
|
|
R.set(TArgs[i], CurRec->getValue(TArgs[i])->getValue());
|
|
|
|
|
|
|
|
CurRec->removeValue(TArgs[i]);
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
|
TableGen: Streamline the semantics of NAME
Summary:
The new rules are straightforward. The main rules to keep in mind
are:
1. NAME is an implicit template argument of class and multiclass,
and will be substituted by the name of the instantiating def/defm.
2. The name of a def/defm in a multiclass must contain a reference
to NAME. If such a reference is not present, it is automatically
prepended.
And for some additional subtleties, consider these:
3. defm with no name generates a unique name but has no special
behavior otherwise.
4. def with no name generates an anonymous record, whose name is
unique but undefined. In particular, the name won't contain a
reference to NAME.
Keeping rules 1&2 in mind should allow a predictable behavior of
name resolution that is simple to follow.
The old "rules" were rather surprising: sometimes (but not always),
NAME would correspond to the name of the toplevel defm. They were
also plain bonkers when you pushed them to their limits, as the old
version of the TableGen test case shows.
Having NAME correspond to the name of the toplevel defm introduces
"spooky action at a distance" and breaks composability:
refactoring the upper layers of a hierarchy of nested multiclass
instantiations can cause unexpected breakage by changing the value
of NAME at a lower level of the hierarchy. The new rules don't
suffer from this problem.
Some existing .td files have to be adjusted because they ended up
depending on the details of the old implementation.
Change-Id: I694095231565b30f563e6fd0417b41ee01a12589
Reviewers: tra, simon_tatham, craig.topper, MartinO, arsenm, javed.absar
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D47430
llvm-svn: 333900
2018-06-04 22:26:05 +08:00
|
|
|
Init *Name;
|
|
|
|
if (CurRec->isClass())
|
|
|
|
Name =
|
|
|
|
VarInit::get(QualifiedNameOfImplicitName(*CurRec), StringRecTy::get());
|
|
|
|
else
|
|
|
|
Name = CurRec->getNameInit();
|
|
|
|
R.set(QualifiedNameOfImplicitName(*SC), Name);
|
|
|
|
|
2018-03-05 23:21:11 +08:00
|
|
|
CurRec->resolveReferences(R);
|
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
// Since everything went well, we can now set the "superclass" list for the
|
|
|
|
// current record.
|
2016-01-19 03:52:37 +08:00
|
|
|
ArrayRef<std::pair<Record *, SMRange>> SCs = SC->getSuperClasses();
|
|
|
|
for (const auto &SCPair : SCs) {
|
|
|
|
if (CurRec->isSubClassOf(SCPair.first))
|
2013-01-11 02:50:11 +08:00
|
|
|
return Error(SubClass.RefRange.Start,
|
2016-01-19 03:52:37 +08:00
|
|
|
"Already subclass of '" + SCPair.first->getName() + "'!\n");
|
|
|
|
CurRec->addSuperClass(SCPair.first, SCPair.second);
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
2018-02-23 19:31:49 +08:00
|
|
|
|
|
|
|
if (CurRec->isSubClassOf(SC))
|
|
|
|
return Error(SubClass.RefRange.Start,
|
|
|
|
"Already subclass of '" + SC->getName() + "'!\n");
|
|
|
|
CurRec->addSuperClass(SC, SubClass.RefRange);
|
2007-11-23 04:49:04 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-06-21 21:35:44 +08:00
|
|
|
bool TGParser::AddSubClass(RecordsEntry &Entry, SubClassReference &SubClass) {
|
|
|
|
if (Entry.Rec)
|
|
|
|
return AddSubClass(Entry.Rec.get(), SubClass);
|
|
|
|
|
|
|
|
for (auto &E : Entry.Loop->Entries) {
|
|
|
|
if (AddSubClass(E, SubClass))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2009-04-23 00:42:54 +08:00
|
|
|
/// AddSubMultiClass - Add SubMultiClass as a subclass to
|
2009-05-01 02:26:19 +08:00
|
|
|
/// CurMC, resolving its template args as SubMultiClass's
|
2009-04-23 00:42:54 +08:00
|
|
|
/// template arguments.
|
2009-05-01 02:26:19 +08:00
|
|
|
bool TGParser::AddSubMultiClass(MultiClass *CurMC,
|
2009-05-01 01:46:20 +08:00
|
|
|
SubMultiClassReference &SubMultiClass) {
|
2009-04-23 00:42:54 +08:00
|
|
|
MultiClass *SMC = SubMultiClass.MC;
|
2009-04-29 03:41:44 +08:00
|
|
|
|
2015-10-24 20:46:45 +08:00
|
|
|
ArrayRef<Init *> SMCTArgs = SMC->Rec.getTemplateArgs();
|
2009-04-23 00:42:54 +08:00
|
|
|
if (SMCTArgs.size() < SubMultiClass.TemplateArgs.size())
|
2013-01-11 02:50:11 +08:00
|
|
|
return Error(SubMultiClass.RefRange.Start,
|
2009-04-25 00:55:41 +08:00
|
|
|
"More template args specified than expected");
|
2009-04-29 03:41:44 +08:00
|
|
|
|
TableGen: Streamline the semantics of NAME
Summary:
The new rules are straightforward. The main rules to keep in mind
are:
1. NAME is an implicit template argument of class and multiclass,
and will be substituted by the name of the instantiating def/defm.
2. The name of a def/defm in a multiclass must contain a reference
to NAME. If such a reference is not present, it is automatically
prepended.
And for some additional subtleties, consider these:
3. defm with no name generates a unique name but has no special
behavior otherwise.
4. def with no name generates an anonymous record, whose name is
unique but undefined. In particular, the name won't contain a
reference to NAME.
Keeping rules 1&2 in mind should allow a predictable behavior of
name resolution that is simple to follow.
The old "rules" were rather surprising: sometimes (but not always),
NAME would correspond to the name of the toplevel defm. They were
also plain bonkers when you pushed them to their limits, as the old
version of the TableGen test case shows.
Having NAME correspond to the name of the toplevel defm introduces
"spooky action at a distance" and breaks composability:
refactoring the upper layers of a hierarchy of nested multiclass
instantiations can cause unexpected breakage by changing the value
of NAME at a lower level of the hierarchy. The new rules don't
suffer from this problem.
Some existing .td files have to be adjusted because they ended up
depending on the details of the old implementation.
Change-Id: I694095231565b30f563e6fd0417b41ee01a12589
Reviewers: tra, simon_tatham, craig.topper, MartinO, arsenm, javed.absar
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D47430
llvm-svn: 333900
2018-06-04 22:26:05 +08:00
|
|
|
// Prepare the mapping of template argument name to value, filling in default
|
|
|
|
// values if necessary.
|
2018-06-21 21:35:44 +08:00
|
|
|
SubstStack TemplateArgs;
|
2009-04-23 00:42:54 +08:00
|
|
|
for (unsigned i = 0, e = SMCTArgs.size(); i != e; ++i) {
|
|
|
|
if (i < SubMultiClass.TemplateArgs.size()) {
|
TableGen: Streamline the semantics of NAME
Summary:
The new rules are straightforward. The main rules to keep in mind
are:
1. NAME is an implicit template argument of class and multiclass,
and will be substituted by the name of the instantiating def/defm.
2. The name of a def/defm in a multiclass must contain a reference
to NAME. If such a reference is not present, it is automatically
prepended.
And for some additional subtleties, consider these:
3. defm with no name generates a unique name but has no special
behavior otherwise.
4. def with no name generates an anonymous record, whose name is
unique but undefined. In particular, the name won't contain a
reference to NAME.
Keeping rules 1&2 in mind should allow a predictable behavior of
name resolution that is simple to follow.
The old "rules" were rather surprising: sometimes (but not always),
NAME would correspond to the name of the toplevel defm. They were
also plain bonkers when you pushed them to their limits, as the old
version of the TableGen test case shows.
Having NAME correspond to the name of the toplevel defm introduces
"spooky action at a distance" and breaks composability:
refactoring the upper layers of a hierarchy of nested multiclass
instantiations can cause unexpected breakage by changing the value
of NAME at a lower level of the hierarchy. The new rules don't
suffer from this problem.
Some existing .td files have to be adjusted because they ended up
depending on the details of the old implementation.
Change-Id: I694095231565b30f563e6fd0417b41ee01a12589
Reviewers: tra, simon_tatham, craig.topper, MartinO, arsenm, javed.absar
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D47430
llvm-svn: 333900
2018-06-04 22:26:05 +08:00
|
|
|
TemplateArgs.emplace_back(SMCTArgs[i], SubMultiClass.TemplateArgs[i]);
|
|
|
|
} else {
|
|
|
|
Init *Default = SMC->Rec.getValue(SMCTArgs[i])->getValue();
|
|
|
|
if (!Default->isComplete()) {
|
|
|
|
return Error(SubMultiClass.RefRange.Start,
|
|
|
|
"value not specified for template argument #" + Twine(i) +
|
|
|
|
" (" + SMCTArgs[i]->getAsUnquotedString() +
|
|
|
|
") of multiclass '" + SMC->Rec.getNameInitAsString() +
|
|
|
|
"'");
|
2009-04-23 00:42:54 +08:00
|
|
|
}
|
TableGen: Streamline the semantics of NAME
Summary:
The new rules are straightforward. The main rules to keep in mind
are:
1. NAME is an implicit template argument of class and multiclass,
and will be substituted by the name of the instantiating def/defm.
2. The name of a def/defm in a multiclass must contain a reference
to NAME. If such a reference is not present, it is automatically
prepended.
And for some additional subtleties, consider these:
3. defm with no name generates a unique name but has no special
behavior otherwise.
4. def with no name generates an anonymous record, whose name is
unique but undefined. In particular, the name won't contain a
reference to NAME.
Keeping rules 1&2 in mind should allow a predictable behavior of
name resolution that is simple to follow.
The old "rules" were rather surprising: sometimes (but not always),
NAME would correspond to the name of the toplevel defm. They were
also plain bonkers when you pushed them to their limits, as the old
version of the TableGen test case shows.
Having NAME correspond to the name of the toplevel defm introduces
"spooky action at a distance" and breaks composability:
refactoring the upper layers of a hierarchy of nested multiclass
instantiations can cause unexpected breakage by changing the value
of NAME at a lower level of the hierarchy. The new rules don't
suffer from this problem.
Some existing .td files have to be adjusted because they ended up
depending on the details of the old implementation.
Change-Id: I694095231565b30f563e6fd0417b41ee01a12589
Reviewers: tra, simon_tatham, craig.topper, MartinO, arsenm, javed.absar
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D47430
llvm-svn: 333900
2018-06-04 22:26:05 +08:00
|
|
|
TemplateArgs.emplace_back(SMCTArgs[i], Default);
|
2009-04-23 00:42:54 +08:00
|
|
|
}
|
2018-03-05 23:21:15 +08:00
|
|
|
}
|
|
|
|
|
TableGen: Streamline the semantics of NAME
Summary:
The new rules are straightforward. The main rules to keep in mind
are:
1. NAME is an implicit template argument of class and multiclass,
and will be substituted by the name of the instantiating def/defm.
2. The name of a def/defm in a multiclass must contain a reference
to NAME. If such a reference is not present, it is automatically
prepended.
And for some additional subtleties, consider these:
3. defm with no name generates a unique name but has no special
behavior otherwise.
4. def with no name generates an anonymous record, whose name is
unique but undefined. In particular, the name won't contain a
reference to NAME.
Keeping rules 1&2 in mind should allow a predictable behavior of
name resolution that is simple to follow.
The old "rules" were rather surprising: sometimes (but not always),
NAME would correspond to the name of the toplevel defm. They were
also plain bonkers when you pushed them to their limits, as the old
version of the TableGen test case shows.
Having NAME correspond to the name of the toplevel defm introduces
"spooky action at a distance" and breaks composability:
refactoring the upper layers of a hierarchy of nested multiclass
instantiations can cause unexpected breakage by changing the value
of NAME at a lower level of the hierarchy. The new rules don't
suffer from this problem.
Some existing .td files have to be adjusted because they ended up
depending on the details of the old implementation.
Change-Id: I694095231565b30f563e6fd0417b41ee01a12589
Reviewers: tra, simon_tatham, craig.topper, MartinO, arsenm, javed.absar
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D47430
llvm-svn: 333900
2018-06-04 22:26:05 +08:00
|
|
|
TemplateArgs.emplace_back(
|
|
|
|
QualifiedNameOfImplicitName(SMC),
|
|
|
|
VarInit::get(QualifiedNameOfImplicitName(CurMC), StringRecTy::get()));
|
2018-03-05 23:21:15 +08:00
|
|
|
|
TableGen: Streamline the semantics of NAME
Summary:
The new rules are straightforward. The main rules to keep in mind
are:
1. NAME is an implicit template argument of class and multiclass,
and will be substituted by the name of the instantiating def/defm.
2. The name of a def/defm in a multiclass must contain a reference
to NAME. If such a reference is not present, it is automatically
prepended.
And for some additional subtleties, consider these:
3. defm with no name generates a unique name but has no special
behavior otherwise.
4. def with no name generates an anonymous record, whose name is
unique but undefined. In particular, the name won't contain a
reference to NAME.
Keeping rules 1&2 in mind should allow a predictable behavior of
name resolution that is simple to follow.
The old "rules" were rather surprising: sometimes (but not always),
NAME would correspond to the name of the toplevel defm. They were
also plain bonkers when you pushed them to their limits, as the old
version of the TableGen test case shows.
Having NAME correspond to the name of the toplevel defm introduces
"spooky action at a distance" and breaks composability:
refactoring the upper layers of a hierarchy of nested multiclass
instantiations can cause unexpected breakage by changing the value
of NAME at a lower level of the hierarchy. The new rules don't
suffer from this problem.
Some existing .td files have to be adjusted because they ended up
depending on the details of the old implementation.
Change-Id: I694095231565b30f563e6fd0417b41ee01a12589
Reviewers: tra, simon_tatham, craig.topper, MartinO, arsenm, javed.absar
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D47430
llvm-svn: 333900
2018-06-04 22:26:05 +08:00
|
|
|
// Add all of the defs in the subclass into the current multiclass.
|
2018-06-21 21:35:44 +08:00
|
|
|
return resolve(SMC->Entries, TemplateArgs, false, &CurMC->Entries);
|
|
|
|
}
|
2018-03-05 23:21:15 +08:00
|
|
|
|
2018-06-21 21:35:44 +08:00
|
|
|
/// Add a record or foreach loop to the current context (global record keeper,
|
|
|
|
/// current inner-most foreach loop, or multiclass).
|
|
|
|
bool TGParser::addEntry(RecordsEntry E) {
|
|
|
|
assert(!E.Rec || !E.Loop);
|
2018-03-05 23:21:15 +08:00
|
|
|
|
2018-06-21 21:35:44 +08:00
|
|
|
if (!Loops.empty()) {
|
|
|
|
Loops.back()->Entries.push_back(std::move(E));
|
|
|
|
return false;
|
2009-04-23 00:42:54 +08:00
|
|
|
}
|
|
|
|
|
2018-06-21 21:35:44 +08:00
|
|
|
if (E.Loop) {
|
|
|
|
SubstStack Stack;
|
|
|
|
return resolve(*E.Loop, Stack, CurMultiClass == nullptr,
|
|
|
|
CurMultiClass ? &CurMultiClass->Entries : nullptr);
|
|
|
|
}
|
TableGen: Streamline how defs are instantiated
Summary:
Instantiating def's and defm's needs to perform the following steps:
- for defm's, clone multiclass def prototypes and subsitute template args
- for def's and defm's, add subclass definitions, substituting template
args
- clone the record based on foreach loops and substitute loop iteration
variables
- override record variables based on the global 'let' stack
- resolve the record name (this should be simple, but unfortunately it's
not due to existing .td files relying on rather silly implementation
details)
- for def(m)s in multiclasses, add the unresolved record as a multiclass
prototype
- for top-level def(m)s, resolve all internal variable references and add
them to the record keeper and any active defsets
This change streamlines how we go through these steps, by having both
def's and defm's feed into a single addDef() method that handles foreach,
final resolve, and routing the record to the right place.
This happens to make foreach inside of multiclasses work, as the new
test case demonstrates. Previously, foreach inside multiclasses was not
forbidden by the parser, but it was de facto broken.
Another side effect is that the order of "instantiated from" notes in error
messages is reversed, as the modified test case shows. This is arguably
clearer, since the initial error message ends up pointing directly to
whatever triggered the error, and subsequent notes will point to increasingly
outer layers of multiclasses. This is consistent with how C++ compilers
report nested #includes and nested template instantiations.
Change-Id: Ica146d0db2bc133dd7ed88054371becf24320447
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D44478
llvm-svn: 328117
2018-03-22 01:12:53 +08:00
|
|
|
|
2018-06-21 21:35:44 +08:00
|
|
|
if (CurMultiClass) {
|
|
|
|
CurMultiClass->Entries.push_back(std::move(E));
|
|
|
|
return false;
|
|
|
|
}
|
2012-05-25 06:17:33 +08:00
|
|
|
|
2018-06-21 21:35:44 +08:00
|
|
|
return addDefOne(std::move(E.Rec));
|
2012-02-23 00:09:41 +08:00
|
|
|
}
|
|
|
|
|
2018-06-21 21:35:44 +08:00
|
|
|
/// Resolve the entries in \p Loop, going over inner loops recursively
|
|
|
|
/// and making the given subsitutions of (name, value) pairs.
|
|
|
|
///
|
|
|
|
/// The resulting records are stored in \p Dest if non-null. Otherwise, they
|
|
|
|
/// are added to the global record keeper.
|
|
|
|
bool TGParser::resolve(const ForeachLoop &Loop, SubstStack &Substs,
|
|
|
|
bool Final, std::vector<RecordsEntry> *Dest,
|
|
|
|
SMLoc *Loc) {
|
|
|
|
MapResolver R;
|
|
|
|
for (const auto &S : Substs)
|
|
|
|
R.set(S.first, S.second);
|
|
|
|
Init *List = Loop.ListValue->resolveReferences(R);
|
|
|
|
auto LI = dyn_cast<ListInit>(List);
|
|
|
|
if (!LI) {
|
|
|
|
if (!Final) {
|
2019-08-15 23:54:37 +08:00
|
|
|
Dest->emplace_back(std::make_unique<ForeachLoop>(Loop.Loc, Loop.IterVar,
|
2018-06-21 21:35:44 +08:00
|
|
|
List));
|
|
|
|
return resolve(Loop.Entries, Substs, Final, &Dest->back().Loop->Entries,
|
|
|
|
Loc);
|
|
|
|
}
|
|
|
|
|
|
|
|
PrintError(Loop.Loc, Twine("attempting to loop over '") +
|
|
|
|
List->getAsString() + "', expected a list");
|
|
|
|
return true;
|
2012-05-25 06:17:33 +08:00
|
|
|
}
|
2012-02-23 00:09:41 +08:00
|
|
|
|
2018-06-21 21:35:44 +08:00
|
|
|
bool Error = false;
|
|
|
|
for (auto Elt : *LI) {
|
|
|
|
Substs.emplace_back(Loop.IterVar->getNameInit(), Elt);
|
|
|
|
Error = resolve(Loop.Entries, Substs, Final, Dest);
|
|
|
|
Substs.pop_back();
|
|
|
|
if (Error)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return Error;
|
TableGen: Streamline how defs are instantiated
Summary:
Instantiating def's and defm's needs to perform the following steps:
- for defm's, clone multiclass def prototypes and subsitute template args
- for def's and defm's, add subclass definitions, substituting template
args
- clone the record based on foreach loops and substitute loop iteration
variables
- override record variables based on the global 'let' stack
- resolve the record name (this should be simple, but unfortunately it's
not due to existing .td files relying on rather silly implementation
details)
- for def(m)s in multiclasses, add the unresolved record as a multiclass
prototype
- for top-level def(m)s, resolve all internal variable references and add
them to the record keeper and any active defsets
This change streamlines how we go through these steps, by having both
def's and defm's feed into a single addDef() method that handles foreach,
final resolve, and routing the record to the right place.
This happens to make foreach inside of multiclasses work, as the new
test case demonstrates. Previously, foreach inside multiclasses was not
forbidden by the parser, but it was de facto broken.
Another side effect is that the order of "instantiated from" notes in error
messages is reversed, as the modified test case shows. This is arguably
clearer, since the initial error message ends up pointing directly to
whatever triggered the error, and subsequent notes will point to increasingly
outer layers of multiclasses. This is consistent with how C++ compilers
report nested #includes and nested template instantiations.
Change-Id: Ica146d0db2bc133dd7ed88054371becf24320447
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D44478
llvm-svn: 328117
2018-03-22 01:12:53 +08:00
|
|
|
}
|
2012-02-23 00:09:41 +08:00
|
|
|
|
2018-06-21 21:35:44 +08:00
|
|
|
/// Resolve the entries in \p Source, going over loops recursively and
|
|
|
|
/// making the given substitutions of (name, value) pairs.
|
|
|
|
///
|
|
|
|
/// The resulting records are stored in \p Dest if non-null. Otherwise, they
|
|
|
|
/// are added to the global record keeper.
|
|
|
|
bool TGParser::resolve(const std::vector<RecordsEntry> &Source,
|
|
|
|
SubstStack &Substs, bool Final,
|
|
|
|
std::vector<RecordsEntry> *Dest, SMLoc *Loc) {
|
|
|
|
bool Error = false;
|
|
|
|
for (auto &E : Source) {
|
|
|
|
if (E.Loop) {
|
|
|
|
Error = resolve(*E.Loop, Substs, Final, Dest);
|
|
|
|
} else {
|
2019-08-15 23:54:37 +08:00
|
|
|
auto Rec = std::make_unique<Record>(*E.Rec);
|
2018-06-21 21:35:44 +08:00
|
|
|
if (Loc)
|
|
|
|
Rec->appendLoc(*Loc);
|
2012-02-23 00:09:41 +08:00
|
|
|
|
2018-06-21 21:35:44 +08:00
|
|
|
MapResolver R(Rec.get());
|
|
|
|
for (const auto &S : Substs)
|
|
|
|
R.set(S.first, S.second);
|
|
|
|
Rec->resolveReferences(R);
|
2012-02-23 00:09:41 +08:00
|
|
|
|
2018-06-21 21:35:44 +08:00
|
|
|
if (Dest)
|
|
|
|
Dest->push_back(std::move(Rec));
|
|
|
|
else
|
|
|
|
Error = addDefOne(std::move(Rec));
|
TableGen: Streamline how defs are instantiated
Summary:
Instantiating def's and defm's needs to perform the following steps:
- for defm's, clone multiclass def prototypes and subsitute template args
- for def's and defm's, add subclass definitions, substituting template
args
- clone the record based on foreach loops and substitute loop iteration
variables
- override record variables based on the global 'let' stack
- resolve the record name (this should be simple, but unfortunately it's
not due to existing .td files relying on rather silly implementation
details)
- for def(m)s in multiclasses, add the unresolved record as a multiclass
prototype
- for top-level def(m)s, resolve all internal variable references and add
them to the record keeper and any active defsets
This change streamlines how we go through these steps, by having both
def's and defm's feed into a single addDef() method that handles foreach,
final resolve, and routing the record to the right place.
This happens to make foreach inside of multiclasses work, as the new
test case demonstrates. Previously, foreach inside multiclasses was not
forbidden by the parser, but it was de facto broken.
Another side effect is that the order of "instantiated from" notes in error
messages is reversed, as the modified test case shows. This is arguably
clearer, since the initial error message ends up pointing directly to
whatever triggered the error, and subsequent notes will point to increasingly
outer layers of multiclasses. This is consistent with how C++ compilers
report nested #includes and nested template instantiations.
Change-Id: Ica146d0db2bc133dd7ed88054371becf24320447
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D44478
llvm-svn: 328117
2018-03-22 01:12:53 +08:00
|
|
|
}
|
2018-06-21 21:35:44 +08:00
|
|
|
if (Error)
|
|
|
|
break;
|
TableGen: Streamline how defs are instantiated
Summary:
Instantiating def's and defm's needs to perform the following steps:
- for defm's, clone multiclass def prototypes and subsitute template args
- for def's and defm's, add subclass definitions, substituting template
args
- clone the record based on foreach loops and substitute loop iteration
variables
- override record variables based on the global 'let' stack
- resolve the record name (this should be simple, but unfortunately it's
not due to existing .td files relying on rather silly implementation
details)
- for def(m)s in multiclasses, add the unresolved record as a multiclass
prototype
- for top-level def(m)s, resolve all internal variable references and add
them to the record keeper and any active defsets
This change streamlines how we go through these steps, by having both
def's and defm's feed into a single addDef() method that handles foreach,
final resolve, and routing the record to the right place.
This happens to make foreach inside of multiclasses work, as the new
test case demonstrates. Previously, foreach inside multiclasses was not
forbidden by the parser, but it was de facto broken.
Another side effect is that the order of "instantiated from" notes in error
messages is reversed, as the modified test case shows. This is arguably
clearer, since the initial error message ends up pointing directly to
whatever triggered the error, and subsequent notes will point to increasingly
outer layers of multiclasses. This is consistent with how C++ compilers
report nested #includes and nested template instantiations.
Change-Id: Ica146d0db2bc133dd7ed88054371becf24320447
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D44478
llvm-svn: 328117
2018-03-22 01:12:53 +08:00
|
|
|
}
|
2018-06-21 21:35:44 +08:00
|
|
|
return Error;
|
|
|
|
}
|
2012-02-23 00:09:41 +08:00
|
|
|
|
2018-06-21 21:35:44 +08:00
|
|
|
/// Resolve the record fully and add it to the record keeper.
|
|
|
|
bool TGParser::addDefOne(std::unique_ptr<Record> Rec) {
|
TableGen: Streamline how defs are instantiated
Summary:
Instantiating def's and defm's needs to perform the following steps:
- for defm's, clone multiclass def prototypes and subsitute template args
- for def's and defm's, add subclass definitions, substituting template
args
- clone the record based on foreach loops and substitute loop iteration
variables
- override record variables based on the global 'let' stack
- resolve the record name (this should be simple, but unfortunately it's
not due to existing .td files relying on rather silly implementation
details)
- for def(m)s in multiclasses, add the unresolved record as a multiclass
prototype
- for top-level def(m)s, resolve all internal variable references and add
them to the record keeper and any active defsets
This change streamlines how we go through these steps, by having both
def's and defm's feed into a single addDef() method that handles foreach,
final resolve, and routing the record to the right place.
This happens to make foreach inside of multiclasses work, as the new
test case demonstrates. Previously, foreach inside multiclasses was not
forbidden by the parser, but it was de facto broken.
Another side effect is that the order of "instantiated from" notes in error
messages is reversed, as the modified test case shows. This is arguably
clearer, since the initial error message ends up pointing directly to
whatever triggered the error, and subsequent notes will point to increasingly
outer layers of multiclasses. This is consistent with how C++ compilers
report nested #includes and nested template instantiations.
Change-Id: Ica146d0db2bc133dd7ed88054371becf24320447
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D44478
llvm-svn: 328117
2018-03-22 01:12:53 +08:00
|
|
|
if (Record *Prev = Records.getDef(Rec->getNameInitAsString())) {
|
|
|
|
if (!Rec->isAnonymous()) {
|
|
|
|
PrintError(Rec->getLoc(),
|
|
|
|
"def already exists: " + Rec->getNameInitAsString());
|
|
|
|
PrintNote(Prev->getLoc(), "location of previous definition");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
Rec->setName(Records.getNewAnonymousName());
|
|
|
|
}
|
|
|
|
|
|
|
|
Rec->resolveReferences();
|
|
|
|
checkConcrete(*Rec);
|
2014-11-29 13:31:10 +08:00
|
|
|
|
2018-05-30 01:12:20 +08:00
|
|
|
if (!isa<StringInit>(Rec->getNameInit())) {
|
|
|
|
PrintError(Rec->getLoc(), Twine("record name '") +
|
|
|
|
Rec->getNameInit()->getAsString() +
|
|
|
|
"' could not be fully resolved");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
TableGen: Streamline how defs are instantiated
Summary:
Instantiating def's and defm's needs to perform the following steps:
- for defm's, clone multiclass def prototypes and subsitute template args
- for def's and defm's, add subclass definitions, substituting template
args
- clone the record based on foreach loops and substitute loop iteration
variables
- override record variables based on the global 'let' stack
- resolve the record name (this should be simple, but unfortunately it's
not due to existing .td files relying on rather silly implementation
details)
- for def(m)s in multiclasses, add the unresolved record as a multiclass
prototype
- for top-level def(m)s, resolve all internal variable references and add
them to the record keeper and any active defsets
This change streamlines how we go through these steps, by having both
def's and defm's feed into a single addDef() method that handles foreach,
final resolve, and routing the record to the right place.
This happens to make foreach inside of multiclasses work, as the new
test case demonstrates. Previously, foreach inside multiclasses was not
forbidden by the parser, but it was de facto broken.
Another side effect is that the order of "instantiated from" notes in error
messages is reversed, as the modified test case shows. This is arguably
clearer, since the initial error message ends up pointing directly to
whatever triggered the error, and subsequent notes will point to increasingly
outer layers of multiclasses. This is consistent with how C++ compilers
report nested #includes and nested template instantiations.
Change-Id: Ica146d0db2bc133dd7ed88054371becf24320447
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D44478
llvm-svn: 328117
2018-03-22 01:12:53 +08:00
|
|
|
// If ObjectBody has template arguments, it's an error.
|
|
|
|
assert(Rec->getTemplateArgs().empty() && "How'd this get template args?");
|
|
|
|
|
|
|
|
for (DefsetRecord *Defset : Defsets) {
|
|
|
|
DefInit *I = Rec->getDefInit();
|
|
|
|
if (!I->getType()->typeIsA(Defset->EltTy)) {
|
|
|
|
PrintError(Rec->getLoc(), Twine("adding record of incompatible type '") +
|
|
|
|
I->getType()->getAsString() +
|
|
|
|
"' to defset");
|
|
|
|
PrintNote(Defset->Loc, "location of defset declaration");
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
Defset->Elements.push_back(I);
|
2012-05-25 06:17:33 +08:00
|
|
|
}
|
|
|
|
|
TableGen: Streamline how defs are instantiated
Summary:
Instantiating def's and defm's needs to perform the following steps:
- for defm's, clone multiclass def prototypes and subsitute template args
- for def's and defm's, add subclass definitions, substituting template
args
- clone the record based on foreach loops and substitute loop iteration
variables
- override record variables based on the global 'let' stack
- resolve the record name (this should be simple, but unfortunately it's
not due to existing .td files relying on rather silly implementation
details)
- for def(m)s in multiclasses, add the unresolved record as a multiclass
prototype
- for top-level def(m)s, resolve all internal variable references and add
them to the record keeper and any active defsets
This change streamlines how we go through these steps, by having both
def's and defm's feed into a single addDef() method that handles foreach,
final resolve, and routing the record to the right place.
This happens to make foreach inside of multiclasses work, as the new
test case demonstrates. Previously, foreach inside multiclasses was not
forbidden by the parser, but it was de facto broken.
Another side effect is that the order of "instantiated from" notes in error
messages is reversed, as the modified test case shows. This is arguably
clearer, since the initial error message ends up pointing directly to
whatever triggered the error, and subsequent notes will point to increasingly
outer layers of multiclasses. This is consistent with how C++ compilers
report nested #includes and nested template instantiations.
Change-Id: Ica146d0db2bc133dd7ed88054371becf24320447
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D44478
llvm-svn: 328117
2018-03-22 01:12:53 +08:00
|
|
|
Records.addDef(std::move(Rec));
|
2012-02-23 00:09:41 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
// Parser Code
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
|
|
|
/// isObjectStart - Return true if this is a valid first token for an Object.
|
|
|
|
static bool isObjectStart(tgtok::TokKind K) {
|
2018-03-09 20:24:42 +08:00
|
|
|
return K == tgtok::Class || K == tgtok::Def || K == tgtok::Defm ||
|
|
|
|
K == tgtok::Let || K == tgtok::MultiClass || K == tgtok::Foreach ||
|
|
|
|
K == tgtok::Defset;
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
|
TableGen: Streamline how defs are instantiated
Summary:
Instantiating def's and defm's needs to perform the following steps:
- for defm's, clone multiclass def prototypes and subsitute template args
- for def's and defm's, add subclass definitions, substituting template
args
- clone the record based on foreach loops and substitute loop iteration
variables
- override record variables based on the global 'let' stack
- resolve the record name (this should be simple, but unfortunately it's
not due to existing .td files relying on rather silly implementation
details)
- for def(m)s in multiclasses, add the unresolved record as a multiclass
prototype
- for top-level def(m)s, resolve all internal variable references and add
them to the record keeper and any active defsets
This change streamlines how we go through these steps, by having both
def's and defm's feed into a single addDef() method that handles foreach,
final resolve, and routing the record to the right place.
This happens to make foreach inside of multiclasses work, as the new
test case demonstrates. Previously, foreach inside multiclasses was not
forbidden by the parser, but it was de facto broken.
Another side effect is that the order of "instantiated from" notes in error
messages is reversed, as the modified test case shows. This is arguably
clearer, since the initial error message ends up pointing directly to
whatever triggered the error, and subsequent notes will point to increasingly
outer layers of multiclasses. This is consistent with how C++ compilers
report nested #includes and nested template instantiations.
Change-Id: Ica146d0db2bc133dd7ed88054371becf24320447
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D44478
llvm-svn: 328117
2018-03-22 01:12:53 +08:00
|
|
|
/// ParseObjectName - If a valid object name is specified, return it. If no
|
|
|
|
/// name is specified, return the unset initializer. Return nullptr on parse
|
|
|
|
/// error.
|
2011-10-19 21:04:29 +08:00
|
|
|
/// ObjectName ::= Value [ '#' Value ]*
|
2007-11-23 04:49:04 +08:00
|
|
|
/// ObjectName ::= /*empty*/
|
|
|
|
///
|
2011-10-19 21:04:29 +08:00
|
|
|
Init *TGParser::ParseObjectName(MultiClass *CurMultiClass) {
|
|
|
|
switch (Lex.getCode()) {
|
|
|
|
case tgtok::colon:
|
|
|
|
case tgtok::semi:
|
|
|
|
case tgtok::l_brace:
|
|
|
|
// These are all of the tokens that can begin an object body.
|
|
|
|
// Some of these can also begin values but we disallow those cases
|
|
|
|
// because they are unlikely to be useful.
|
TableGen: Streamline how defs are instantiated
Summary:
Instantiating def's and defm's needs to perform the following steps:
- for defm's, clone multiclass def prototypes and subsitute template args
- for def's and defm's, add subclass definitions, substituting template
args
- clone the record based on foreach loops and substitute loop iteration
variables
- override record variables based on the global 'let' stack
- resolve the record name (this should be simple, but unfortunately it's
not due to existing .td files relying on rather silly implementation
details)
- for def(m)s in multiclasses, add the unresolved record as a multiclass
prototype
- for top-level def(m)s, resolve all internal variable references and add
them to the record keeper and any active defsets
This change streamlines how we go through these steps, by having both
def's and defm's feed into a single addDef() method that handles foreach,
final resolve, and routing the record to the right place.
This happens to make foreach inside of multiclasses work, as the new
test case demonstrates. Previously, foreach inside multiclasses was not
forbidden by the parser, but it was de facto broken.
Another side effect is that the order of "instantiated from" notes in error
messages is reversed, as the modified test case shows. This is arguably
clearer, since the initial error message ends up pointing directly to
whatever triggered the error, and subsequent notes will point to increasingly
outer layers of multiclasses. This is consistent with how C++ compilers
report nested #includes and nested template instantiations.
Change-Id: Ica146d0db2bc133dd7ed88054371becf24320447
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D44478
llvm-svn: 328117
2018-03-22 01:12:53 +08:00
|
|
|
return UnsetInit::get();
|
2011-10-19 21:04:29 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
2010-10-23 15:32:37 +08:00
|
|
|
|
2014-04-09 12:50:04 +08:00
|
|
|
Record *CurRec = nullptr;
|
2011-10-19 21:04:29 +08:00
|
|
|
if (CurMultiClass)
|
|
|
|
CurRec = &CurMultiClass->Rec;
|
2007-11-23 04:49:04 +08:00
|
|
|
|
TableGen: Streamline the semantics of NAME
Summary:
The new rules are straightforward. The main rules to keep in mind
are:
1. NAME is an implicit template argument of class and multiclass,
and will be substituted by the name of the instantiating def/defm.
2. The name of a def/defm in a multiclass must contain a reference
to NAME. If such a reference is not present, it is automatically
prepended.
And for some additional subtleties, consider these:
3. defm with no name generates a unique name but has no special
behavior otherwise.
4. def with no name generates an anonymous record, whose name is
unique but undefined. In particular, the name won't contain a
reference to NAME.
Keeping rules 1&2 in mind should allow a predictable behavior of
name resolution that is simple to follow.
The old "rules" were rather surprising: sometimes (but not always),
NAME would correspond to the name of the toplevel defm. They were
also plain bonkers when you pushed them to their limits, as the old
version of the TableGen test case shows.
Having NAME correspond to the name of the toplevel defm introduces
"spooky action at a distance" and breaks composability:
refactoring the upper layers of a hierarchy of nested multiclass
instantiations can cause unexpected breakage by changing the value
of NAME at a lower level of the hierarchy. The new rules don't
suffer from this problem.
Some existing .td files have to be adjusted because they ended up
depending on the details of the old implementation.
Change-Id: I694095231565b30f563e6fd0417b41ee01a12589
Reviewers: tra, simon_tatham, craig.topper, MartinO, arsenm, javed.absar
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D47430
llvm-svn: 333900
2018-06-04 22:26:05 +08:00
|
|
|
Init *Name = ParseValue(CurRec, StringRecTy::get(), ParseNameMode);
|
|
|
|
if (!Name)
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
if (CurMultiClass) {
|
|
|
|
Init *NameStr = QualifiedNameOfImplicitName(CurMultiClass);
|
|
|
|
HasReferenceResolver R(NameStr);
|
|
|
|
Name->resolveReferences(R);
|
|
|
|
if (!R.found())
|
|
|
|
Name = BinOpInit::getStrConcat(VarInit::get(NameStr, StringRecTy::get()),
|
|
|
|
Name);
|
|
|
|
}
|
|
|
|
|
|
|
|
return Name;
|
2011-10-19 21:04:29 +08:00
|
|
|
}
|
2007-11-23 04:49:04 +08:00
|
|
|
|
|
|
|
/// ParseClassID - Parse and resolve a reference to a class name. This returns
|
|
|
|
/// null on error.
|
|
|
|
///
|
|
|
|
/// ClassID ::= ID
|
|
|
|
///
|
|
|
|
Record *TGParser::ParseClassID() {
|
|
|
|
if (Lex.getCode() != tgtok::Id) {
|
|
|
|
TokError("expected name for ClassID");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
Record *Result = Records.getClass(Lex.getCurStrVal());
|
2019-03-26 18:49:09 +08:00
|
|
|
if (!Result) {
|
|
|
|
std::string Msg("Couldn't find class '" + Lex.getCurStrVal() + "'");
|
|
|
|
if (MultiClasses[Lex.getCurStrVal()].get())
|
|
|
|
TokError(Msg + ". Use 'defm' if you meant to use multiclass '" +
|
|
|
|
Lex.getCurStrVal() + "'");
|
|
|
|
else
|
|
|
|
TokError(Msg);
|
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
Lex.Lex();
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2009-04-29 03:41:44 +08:00
|
|
|
/// ParseMultiClassID - Parse and resolve a reference to a multiclass name.
|
|
|
|
/// This returns null on error.
|
2009-04-23 00:42:54 +08:00
|
|
|
///
|
|
|
|
/// MultiClassID ::= ID
|
|
|
|
///
|
|
|
|
MultiClass *TGParser::ParseMultiClassID() {
|
|
|
|
if (Lex.getCode() != tgtok::Id) {
|
2013-01-09 10:11:57 +08:00
|
|
|
TokError("expected name for MultiClassID");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-04-23 00:42:54 +08:00
|
|
|
}
|
2009-04-29 03:41:44 +08:00
|
|
|
|
2014-12-11 13:25:30 +08:00
|
|
|
MultiClass *Result = MultiClasses[Lex.getCurStrVal()].get();
|
2014-11-30 09:20:17 +08:00
|
|
|
if (!Result)
|
2013-01-09 10:11:57 +08:00
|
|
|
TokError("Couldn't find multiclass '" + Lex.getCurStrVal() + "'");
|
2009-04-29 03:41:44 +08:00
|
|
|
|
2009-04-23 00:42:54 +08:00
|
|
|
Lex.Lex();
|
2014-11-30 09:20:17 +08:00
|
|
|
return Result;
|
2009-04-23 00:42:54 +08:00
|
|
|
}
|
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
/// ParseSubClassReference - Parse a reference to a subclass or to a templated
|
|
|
|
/// subclass. This returns a SubClassRefTy with a null Record* on error.
|
|
|
|
///
|
|
|
|
/// SubClassRef ::= ClassID
|
|
|
|
/// SubClassRef ::= ClassID '<' ValueList '>'
|
|
|
|
///
|
|
|
|
SubClassReference TGParser::
|
|
|
|
ParseSubClassReference(Record *CurRec, bool isDefm) {
|
|
|
|
SubClassReference Result;
|
2013-01-11 02:50:11 +08:00
|
|
|
Result.RefRange.Start = Lex.getLoc();
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2013-01-09 10:17:14 +08:00
|
|
|
if (isDefm) {
|
|
|
|
if (MultiClass *MC = ParseMultiClassID())
|
|
|
|
Result.Rec = &MC->Rec;
|
|
|
|
} else {
|
2007-11-23 04:49:04 +08:00
|
|
|
Result.Rec = ParseClassID();
|
2013-01-09 10:17:14 +08:00
|
|
|
}
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!Result.Rec) return Result;
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
// If there is no template arg list, we're done.
|
2013-01-11 02:50:11 +08:00
|
|
|
if (Lex.getCode() != tgtok::less) {
|
|
|
|
Result.RefRange.End = Lex.getLoc();
|
2007-11-23 04:49:04 +08:00
|
|
|
return Result;
|
2013-01-11 02:50:11 +08:00
|
|
|
}
|
2007-11-23 04:49:04 +08:00
|
|
|
Lex.Lex(); // Eat the '<'
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Lex.getCode() == tgtok::greater) {
|
|
|
|
TokError("subclass reference requires a non-empty list of template values");
|
2014-04-09 12:50:04 +08:00
|
|
|
Result.Rec = nullptr;
|
2007-11-23 04:49:04 +08:00
|
|
|
return Result;
|
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2016-12-05 14:41:54 +08:00
|
|
|
ParseValueList(Result.TemplateArgs, CurRec, Result.Rec);
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Result.TemplateArgs.empty()) {
|
2014-04-09 12:50:04 +08:00
|
|
|
Result.Rec = nullptr; // Error parsing value list.
|
2007-11-23 04:49:04 +08:00
|
|
|
return Result;
|
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Lex.getCode() != tgtok::greater) {
|
|
|
|
TokError("expected '>' in template value list");
|
2014-04-09 12:50:04 +08:00
|
|
|
Result.Rec = nullptr;
|
2007-11-23 04:49:04 +08:00
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
Lex.Lex();
|
2013-01-11 02:50:11 +08:00
|
|
|
Result.RefRange.End = Lex.getLoc();
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2009-04-29 03:41:44 +08:00
|
|
|
/// ParseSubMultiClassReference - Parse a reference to a subclass or to a
|
|
|
|
/// templated submulticlass. This returns a SubMultiClassRefTy with a null
|
|
|
|
/// Record* on error.
|
2009-04-23 00:42:54 +08:00
|
|
|
///
|
|
|
|
/// SubMultiClassRef ::= MultiClassID
|
|
|
|
/// SubMultiClassRef ::= MultiClassID '<' ValueList '>'
|
|
|
|
///
|
|
|
|
SubMultiClassReference TGParser::
|
|
|
|
ParseSubMultiClassReference(MultiClass *CurMC) {
|
|
|
|
SubMultiClassReference Result;
|
2013-01-11 02:50:11 +08:00
|
|
|
Result.RefRange.Start = Lex.getLoc();
|
2009-04-29 03:41:44 +08:00
|
|
|
|
2009-04-23 00:42:54 +08:00
|
|
|
Result.MC = ParseMultiClassID();
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!Result.MC) return Result;
|
2009-04-29 03:41:44 +08:00
|
|
|
|
2009-04-23 00:42:54 +08:00
|
|
|
// If there is no template arg list, we're done.
|
2013-01-11 02:50:11 +08:00
|
|
|
if (Lex.getCode() != tgtok::less) {
|
|
|
|
Result.RefRange.End = Lex.getLoc();
|
2009-04-23 00:42:54 +08:00
|
|
|
return Result;
|
2013-01-11 02:50:11 +08:00
|
|
|
}
|
2009-04-23 00:42:54 +08:00
|
|
|
Lex.Lex(); // Eat the '<'
|
2009-04-29 03:41:44 +08:00
|
|
|
|
2009-04-23 00:42:54 +08:00
|
|
|
if (Lex.getCode() == tgtok::greater) {
|
|
|
|
TokError("subclass reference requires a non-empty list of template values");
|
2014-04-09 12:50:04 +08:00
|
|
|
Result.MC = nullptr;
|
2009-04-23 00:42:54 +08:00
|
|
|
return Result;
|
|
|
|
}
|
2009-04-29 03:41:44 +08:00
|
|
|
|
2016-12-05 14:41:54 +08:00
|
|
|
ParseValueList(Result.TemplateArgs, &CurMC->Rec, &Result.MC->Rec);
|
2009-04-23 00:42:54 +08:00
|
|
|
if (Result.TemplateArgs.empty()) {
|
2014-04-09 12:50:04 +08:00
|
|
|
Result.MC = nullptr; // Error parsing value list.
|
2009-04-23 00:42:54 +08:00
|
|
|
return Result;
|
|
|
|
}
|
2009-04-29 03:41:44 +08:00
|
|
|
|
2009-04-23 00:42:54 +08:00
|
|
|
if (Lex.getCode() != tgtok::greater) {
|
|
|
|
TokError("expected '>' in template value list");
|
2014-04-09 12:50:04 +08:00
|
|
|
Result.MC = nullptr;
|
2009-04-23 00:42:54 +08:00
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
Lex.Lex();
|
2013-01-11 02:50:11 +08:00
|
|
|
Result.RefRange.End = Lex.getLoc();
|
2009-04-23 00:42:54 +08:00
|
|
|
|
|
|
|
return Result;
|
|
|
|
}
|
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
/// ParseRangePiece - Parse a bit/value range.
|
|
|
|
/// RangePiece ::= INTVAL
|
|
|
|
/// RangePiece ::= INTVAL '-' INTVAL
|
|
|
|
/// RangePiece ::= INTVAL INTVAL
|
2019-05-23 05:28:20 +08:00
|
|
|
bool TGParser::ParseRangePiece(SmallVectorImpl<unsigned> &Ranges,
|
|
|
|
TypedInit *FirstItem) {
|
|
|
|
Init *CurVal = FirstItem;
|
|
|
|
if (!CurVal)
|
|
|
|
CurVal = ParseValue(nullptr);
|
|
|
|
|
|
|
|
IntInit *II = dyn_cast_or_null<IntInit>(CurVal);
|
|
|
|
if (!II)
|
|
|
|
return TokError("expected integer or bitrange");
|
|
|
|
|
|
|
|
int64_t Start = II->getValue();
|
2008-10-17 09:33:43 +08:00
|
|
|
int64_t End;
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Start < 0)
|
|
|
|
return TokError("invalid range, cannot be negative");
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2019-05-23 05:28:20 +08:00
|
|
|
switch (Lex.getCode()) {
|
2009-11-22 12:24:42 +08:00
|
|
|
default:
|
2007-11-23 04:49:04 +08:00
|
|
|
Ranges.push_back(Start);
|
|
|
|
return false;
|
2019-05-23 05:28:20 +08:00
|
|
|
case tgtok::minus: {
|
|
|
|
Lex.Lex(); // eat
|
|
|
|
|
|
|
|
Init *I_End = ParseValue(nullptr);
|
|
|
|
IntInit *II_End = dyn_cast_or_null<IntInit>(I_End);
|
|
|
|
if (!II_End) {
|
2007-11-23 04:49:04 +08:00
|
|
|
TokError("expected integer value as end of range");
|
|
|
|
return true;
|
|
|
|
}
|
2019-05-23 05:28:20 +08:00
|
|
|
|
|
|
|
End = II_End->getValue();
|
2007-11-23 04:49:04 +08:00
|
|
|
break;
|
2019-05-23 05:28:20 +08:00
|
|
|
}
|
|
|
|
case tgtok::IntVal: {
|
2007-11-23 04:49:04 +08:00
|
|
|
End = -Lex.getCurIntVal();
|
2019-05-23 05:28:20 +08:00
|
|
|
Lex.Lex();
|
2007-11-23 04:49:04 +08:00
|
|
|
break;
|
|
|
|
}
|
2019-05-23 05:28:20 +08:00
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
if (End < 0)
|
2007-11-23 04:49:04 +08:00
|
|
|
return TokError("invalid range, cannot be negative");
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
// Add to the range.
|
2015-05-04 09:35:39 +08:00
|
|
|
if (Start < End)
|
2007-11-23 04:49:04 +08:00
|
|
|
for (; Start <= End; ++Start)
|
|
|
|
Ranges.push_back(Start);
|
2015-05-04 09:35:39 +08:00
|
|
|
else
|
2007-11-23 04:49:04 +08:00
|
|
|
for (; Start >= End; --Start)
|
|
|
|
Ranges.push_back(Start);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseRangeList - Parse a list of scalars and ranges into scalar values.
|
|
|
|
///
|
|
|
|
/// RangeList ::= RangePiece (',' RangePiece)*
|
|
|
|
///
|
2016-12-05 14:41:54 +08:00
|
|
|
void TGParser::ParseRangeList(SmallVectorImpl<unsigned> &Result) {
|
2007-11-23 04:49:04 +08:00
|
|
|
// Parse the first piece.
|
2016-12-05 14:41:54 +08:00
|
|
|
if (ParseRangePiece(Result)) {
|
|
|
|
Result.clear();
|
|
|
|
return;
|
|
|
|
}
|
2007-11-23 04:49:04 +08:00
|
|
|
while (Lex.getCode() == tgtok::comma) {
|
|
|
|
Lex.Lex(); // Eat the comma.
|
|
|
|
|
|
|
|
// Parse the next range piece.
|
2016-12-05 14:41:54 +08:00
|
|
|
if (ParseRangePiece(Result)) {
|
|
|
|
Result.clear();
|
|
|
|
return;
|
|
|
|
}
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseOptionalRangeList - Parse either a range list in <>'s or nothing.
|
|
|
|
/// OptionalRangeList ::= '<' RangeList '>'
|
|
|
|
/// OptionalRangeList ::= /*empty*/
|
2016-12-05 14:41:54 +08:00
|
|
|
bool TGParser::ParseOptionalRangeList(SmallVectorImpl<unsigned> &Ranges) {
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Lex.getCode() != tgtok::less)
|
|
|
|
return false;
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2009-06-21 11:39:35 +08:00
|
|
|
SMLoc StartLoc = Lex.getLoc();
|
2007-11-23 04:49:04 +08:00
|
|
|
Lex.Lex(); // eat the '<'
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
// Parse the range list.
|
2016-12-05 14:41:54 +08:00
|
|
|
ParseRangeList(Ranges);
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Ranges.empty()) return true;
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Lex.getCode() != tgtok::greater) {
|
|
|
|
TokError("expected '>' at end of range list");
|
|
|
|
return Error(StartLoc, "to match this '<'");
|
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the '>'.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseOptionalBitList - Parse either a bit list in {}'s or nothing.
|
|
|
|
/// OptionalBitList ::= '{' RangeList '}'
|
|
|
|
/// OptionalBitList ::= /*empty*/
|
2016-12-05 14:41:54 +08:00
|
|
|
bool TGParser::ParseOptionalBitList(SmallVectorImpl<unsigned> &Ranges) {
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Lex.getCode() != tgtok::l_brace)
|
|
|
|
return false;
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2009-06-21 11:39:35 +08:00
|
|
|
SMLoc StartLoc = Lex.getLoc();
|
2007-11-23 04:49:04 +08:00
|
|
|
Lex.Lex(); // eat the '{'
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
// Parse the range list.
|
2016-12-05 14:41:54 +08:00
|
|
|
ParseRangeList(Ranges);
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Ranges.empty()) return true;
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Lex.getCode() != tgtok::r_brace) {
|
|
|
|
TokError("expected '}' at end of bit list");
|
|
|
|
return Error(StartLoc, "to match this '{'");
|
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the '}'.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseType - Parse and return a tblgen type. This returns null on error.
|
|
|
|
///
|
|
|
|
/// Type ::= STRING // string type
|
2012-01-13 11:38:34 +08:00
|
|
|
/// Type ::= CODE // code type
|
2007-11-23 04:49:04 +08:00
|
|
|
/// Type ::= BIT // bit type
|
|
|
|
/// Type ::= BITS '<' INTVAL '>' // bits<x> type
|
|
|
|
/// Type ::= INT // int type
|
|
|
|
/// Type ::= LIST '<' Type '>' // list<x> type
|
|
|
|
/// Type ::= DAG // dag type
|
|
|
|
/// Type ::= ClassID // Record Type
|
|
|
|
///
|
|
|
|
RecTy *TGParser::ParseType() {
|
|
|
|
switch (Lex.getCode()) {
|
2014-04-09 12:50:04 +08:00
|
|
|
default: TokError("Unknown token when expecting a type"); return nullptr;
|
2011-07-19 01:02:57 +08:00
|
|
|
case tgtok::String: Lex.Lex(); return StringRecTy::get();
|
2016-07-06 05:22:55 +08:00
|
|
|
case tgtok::Code: Lex.Lex(); return CodeRecTy::get();
|
2011-07-19 01:02:57 +08:00
|
|
|
case tgtok::Bit: Lex.Lex(); return BitRecTy::get();
|
|
|
|
case tgtok::Int: Lex.Lex(); return IntRecTy::get();
|
|
|
|
case tgtok::Dag: Lex.Lex(); return DagRecTy::get();
|
2007-11-23 04:49:04 +08:00
|
|
|
case tgtok::Id:
|
2011-07-19 01:02:57 +08:00
|
|
|
if (Record *R = ParseClassID()) return RecordRecTy::get(R);
|
2018-03-09 20:24:42 +08:00
|
|
|
TokError("unknown class name");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2007-11-23 04:49:04 +08:00
|
|
|
case tgtok::Bits: {
|
|
|
|
if (Lex.Lex() != tgtok::less) { // Eat 'bits'
|
|
|
|
TokError("expected '<' after bits type");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
if (Lex.Lex() != tgtok::IntVal) { // Eat '<'
|
|
|
|
TokError("expected integer in bits<n> type");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
2008-10-17 09:33:43 +08:00
|
|
|
uint64_t Val = Lex.getCurIntVal();
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Lex.Lex() != tgtok::greater) { // Eat count.
|
|
|
|
TokError("expected '>' at end of bits<n> type");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
Lex.Lex(); // Eat '>'
|
2011-07-19 01:02:57 +08:00
|
|
|
return BitsRecTy::get(Val);
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
case tgtok::List: {
|
|
|
|
if (Lex.Lex() != tgtok::less) { // Eat 'bits'
|
|
|
|
TokError("expected '<' after list type");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
Lex.Lex(); // Eat '<'
|
|
|
|
RecTy *SubType = ParseType();
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!SubType) return nullptr;
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Lex.getCode() != tgtok::greater) {
|
|
|
|
TokError("expected '>' at end of list<ty> type");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
Lex.Lex(); // Eat '>'
|
2011-07-19 01:02:57 +08:00
|
|
|
return ListRecTy::get(SubType);
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
}
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseIDValue - This is just like ParseIDValue above, but it assumes the ID
|
|
|
|
/// has already been read.
|
2016-12-05 15:35:13 +08:00
|
|
|
Init *TGParser::ParseIDValue(Record *CurRec, StringInit *Name, SMLoc NameLoc,
|
2011-10-19 21:04:20 +08:00
|
|
|
IDParseMode Mode) {
|
2007-11-23 04:49:04 +08:00
|
|
|
if (CurRec) {
|
|
|
|
if (const RecordVal *RV = CurRec->getValue(Name))
|
2011-07-30 03:07:07 +08:00
|
|
|
return VarInit::get(Name, RV->getType());
|
2016-12-05 15:35:13 +08:00
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
TableGen: Streamline the semantics of NAME
Summary:
The new rules are straightforward. The main rules to keep in mind
are:
1. NAME is an implicit template argument of class and multiclass,
and will be substituted by the name of the instantiating def/defm.
2. The name of a def/defm in a multiclass must contain a reference
to NAME. If such a reference is not present, it is automatically
prepended.
And for some additional subtleties, consider these:
3. defm with no name generates a unique name but has no special
behavior otherwise.
4. def with no name generates an anonymous record, whose name is
unique but undefined. In particular, the name won't contain a
reference to NAME.
Keeping rules 1&2 in mind should allow a predictable behavior of
name resolution that is simple to follow.
The old "rules" were rather surprising: sometimes (but not always),
NAME would correspond to the name of the toplevel defm. They were
also plain bonkers when you pushed them to their limits, as the old
version of the TableGen test case shows.
Having NAME correspond to the name of the toplevel defm introduces
"spooky action at a distance" and breaks composability:
refactoring the upper layers of a hierarchy of nested multiclass
instantiations can cause unexpected breakage by changing the value
of NAME at a lower level of the hierarchy. The new rules don't
suffer from this problem.
Some existing .td files have to be adjusted because they ended up
depending on the details of the old implementation.
Change-Id: I694095231565b30f563e6fd0417b41ee01a12589
Reviewers: tra, simon_tatham, craig.topper, MartinO, arsenm, javed.absar
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D47430
llvm-svn: 333900
2018-06-04 22:26:05 +08:00
|
|
|
if ((CurRec && CurRec->isClass()) || CurMultiClass) {
|
|
|
|
Init *TemplateArgName;
|
|
|
|
if (CurMultiClass) {
|
|
|
|
TemplateArgName =
|
|
|
|
QualifyName(CurMultiClass->Rec, CurMultiClass, Name, "::");
|
|
|
|
} else
|
|
|
|
TemplateArgName = QualifyName(*CurRec, CurMultiClass, Name, ":");
|
2011-10-19 21:02:42 +08:00
|
|
|
|
TableGen: Streamline the semantics of NAME
Summary:
The new rules are straightforward. The main rules to keep in mind
are:
1. NAME is an implicit template argument of class and multiclass,
and will be substituted by the name of the instantiating def/defm.
2. The name of a def/defm in a multiclass must contain a reference
to NAME. If such a reference is not present, it is automatically
prepended.
And for some additional subtleties, consider these:
3. defm with no name generates a unique name but has no special
behavior otherwise.
4. def with no name generates an anonymous record, whose name is
unique but undefined. In particular, the name won't contain a
reference to NAME.
Keeping rules 1&2 in mind should allow a predictable behavior of
name resolution that is simple to follow.
The old "rules" were rather surprising: sometimes (but not always),
NAME would correspond to the name of the toplevel defm. They were
also plain bonkers when you pushed them to their limits, as the old
version of the TableGen test case shows.
Having NAME correspond to the name of the toplevel defm introduces
"spooky action at a distance" and breaks composability:
refactoring the upper layers of a hierarchy of nested multiclass
instantiations can cause unexpected breakage by changing the value
of NAME at a lower level of the hierarchy. The new rules don't
suffer from this problem.
Some existing .td files have to be adjusted because they ended up
depending on the details of the old implementation.
Change-Id: I694095231565b30f563e6fd0417b41ee01a12589
Reviewers: tra, simon_tatham, craig.topper, MartinO, arsenm, javed.absar
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D47430
llvm-svn: 333900
2018-06-04 22:26:05 +08:00
|
|
|
Record *TemplateRec = CurMultiClass ? &CurMultiClass->Rec : CurRec;
|
|
|
|
if (TemplateRec->isTemplateArg(TemplateArgName)) {
|
|
|
|
const RecordVal *RV = TemplateRec->getValue(TemplateArgName);
|
2007-11-23 04:49:04 +08:00
|
|
|
assert(RV && "Template arg doesn't exist??");
|
TableGen: Streamline the semantics of NAME
Summary:
The new rules are straightforward. The main rules to keep in mind
are:
1. NAME is an implicit template argument of class and multiclass,
and will be substituted by the name of the instantiating def/defm.
2. The name of a def/defm in a multiclass must contain a reference
to NAME. If such a reference is not present, it is automatically
prepended.
And for some additional subtleties, consider these:
3. defm with no name generates a unique name but has no special
behavior otherwise.
4. def with no name generates an anonymous record, whose name is
unique but undefined. In particular, the name won't contain a
reference to NAME.
Keeping rules 1&2 in mind should allow a predictable behavior of
name resolution that is simple to follow.
The old "rules" were rather surprising: sometimes (but not always),
NAME would correspond to the name of the toplevel defm. They were
also plain bonkers when you pushed them to their limits, as the old
version of the TableGen test case shows.
Having NAME correspond to the name of the toplevel defm introduces
"spooky action at a distance" and breaks composability:
refactoring the upper layers of a hierarchy of nested multiclass
instantiations can cause unexpected breakage by changing the value
of NAME at a lower level of the hierarchy. The new rules don't
suffer from this problem.
Some existing .td files have to be adjusted because they ended up
depending on the details of the old implementation.
Change-Id: I694095231565b30f563e6fd0417b41ee01a12589
Reviewers: tra, simon_tatham, craig.topper, MartinO, arsenm, javed.absar
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D47430
llvm-svn: 333900
2018-06-04 22:26:05 +08:00
|
|
|
return VarInit::get(TemplateArgName, RV->getType());
|
|
|
|
} else if (Name->getValue() == "NAME") {
|
|
|
|
return VarInit::get(TemplateArgName, StringRecTy::get());
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2012-02-23 00:09:41 +08:00
|
|
|
// If this is in a foreach loop, make sure it's not a loop iterator
|
2015-04-29 12:43:36 +08:00
|
|
|
for (const auto &L : Loops) {
|
2018-06-21 21:35:44 +08:00
|
|
|
VarInit *IterVar = dyn_cast<VarInit>(L->IterVar);
|
2016-12-05 15:35:13 +08:00
|
|
|
if (IterVar && IterVar->getNameInit() == Name)
|
2012-02-23 00:09:41 +08:00
|
|
|
return IterVar;
|
|
|
|
}
|
|
|
|
|
2011-10-19 21:04:21 +08:00
|
|
|
if (Mode == ParseNameMode)
|
2016-12-05 15:35:13 +08:00
|
|
|
return Name;
|
2011-10-19 21:04:21 +08:00
|
|
|
|
2018-03-09 20:24:42 +08:00
|
|
|
if (Init *I = Records.getGlobal(Name->getValue()))
|
|
|
|
return I;
|
2007-11-23 04:49:04 +08:00
|
|
|
|
TableGen: Streamline how defs are instantiated
Summary:
Instantiating def's and defm's needs to perform the following steps:
- for defm's, clone multiclass def prototypes and subsitute template args
- for def's and defm's, add subclass definitions, substituting template
args
- clone the record based on foreach loops and substitute loop iteration
variables
- override record variables based on the global 'let' stack
- resolve the record name (this should be simple, but unfortunately it's
not due to existing .td files relying on rather silly implementation
details)
- for def(m)s in multiclasses, add the unresolved record as a multiclass
prototype
- for top-level def(m)s, resolve all internal variable references and add
them to the record keeper and any active defsets
This change streamlines how we go through these steps, by having both
def's and defm's feed into a single addDef() method that handles foreach,
final resolve, and routing the record to the right place.
This happens to make foreach inside of multiclasses work, as the new
test case demonstrates. Previously, foreach inside multiclasses was not
forbidden by the parser, but it was de facto broken.
Another side effect is that the order of "instantiated from" notes in error
messages is reversed, as the modified test case shows. This is arguably
clearer, since the initial error message ends up pointing directly to
whatever triggered the error, and subsequent notes will point to increasingly
outer layers of multiclasses. This is consistent with how C++ compilers
report nested #includes and nested template instantiations.
Change-Id: Ica146d0db2bc133dd7ed88054371becf24320447
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D44478
llvm-svn: 328117
2018-03-22 01:12:53 +08:00
|
|
|
// Allow self-references of concrete defs, but delay the lookup so that we
|
|
|
|
// get the correct type.
|
TableGen: Streamline the semantics of NAME
Summary:
The new rules are straightforward. The main rules to keep in mind
are:
1. NAME is an implicit template argument of class and multiclass,
and will be substituted by the name of the instantiating def/defm.
2. The name of a def/defm in a multiclass must contain a reference
to NAME. If such a reference is not present, it is automatically
prepended.
And for some additional subtleties, consider these:
3. defm with no name generates a unique name but has no special
behavior otherwise.
4. def with no name generates an anonymous record, whose name is
unique but undefined. In particular, the name won't contain a
reference to NAME.
Keeping rules 1&2 in mind should allow a predictable behavior of
name resolution that is simple to follow.
The old "rules" were rather surprising: sometimes (but not always),
NAME would correspond to the name of the toplevel defm. They were
also plain bonkers when you pushed them to their limits, as the old
version of the TableGen test case shows.
Having NAME correspond to the name of the toplevel defm introduces
"spooky action at a distance" and breaks composability:
refactoring the upper layers of a hierarchy of nested multiclass
instantiations can cause unexpected breakage by changing the value
of NAME at a lower level of the hierarchy. The new rules don't
suffer from this problem.
Some existing .td files have to be adjusted because they ended up
depending on the details of the old implementation.
Change-Id: I694095231565b30f563e6fd0417b41ee01a12589
Reviewers: tra, simon_tatham, craig.topper, MartinO, arsenm, javed.absar
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D47430
llvm-svn: 333900
2018-06-04 22:26:05 +08:00
|
|
|
if (CurRec && !CurRec->isClass() && !CurMultiClass &&
|
|
|
|
CurRec->getNameInit() == Name)
|
TableGen: Streamline how defs are instantiated
Summary:
Instantiating def's and defm's needs to perform the following steps:
- for defm's, clone multiclass def prototypes and subsitute template args
- for def's and defm's, add subclass definitions, substituting template
args
- clone the record based on foreach loops and substitute loop iteration
variables
- override record variables based on the global 'let' stack
- resolve the record name (this should be simple, but unfortunately it's
not due to existing .td files relying on rather silly implementation
details)
- for def(m)s in multiclasses, add the unresolved record as a multiclass
prototype
- for top-level def(m)s, resolve all internal variable references and add
them to the record keeper and any active defsets
This change streamlines how we go through these steps, by having both
def's and defm's feed into a single addDef() method that handles foreach,
final resolve, and routing the record to the right place.
This happens to make foreach inside of multiclasses work, as the new
test case demonstrates. Previously, foreach inside multiclasses was not
forbidden by the parser, but it was de facto broken.
Another side effect is that the order of "instantiated from" notes in error
messages is reversed, as the modified test case shows. This is arguably
clearer, since the initial error message ends up pointing directly to
whatever triggered the error, and subsequent notes will point to increasingly
outer layers of multiclasses. This is consistent with how C++ compilers
report nested #includes and nested template instantiations.
Change-Id: Ica146d0db2bc133dd7ed88054371becf24320447
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D44478
llvm-svn: 328117
2018-03-22 01:12:53 +08:00
|
|
|
return UnOpInit::get(UnOpInit::CAST, Name, CurRec->getType());
|
|
|
|
|
TableGen: Streamline the semantics of NAME
Summary:
The new rules are straightforward. The main rules to keep in mind
are:
1. NAME is an implicit template argument of class and multiclass,
and will be substituted by the name of the instantiating def/defm.
2. The name of a def/defm in a multiclass must contain a reference
to NAME. If such a reference is not present, it is automatically
prepended.
And for some additional subtleties, consider these:
3. defm with no name generates a unique name but has no special
behavior otherwise.
4. def with no name generates an anonymous record, whose name is
unique but undefined. In particular, the name won't contain a
reference to NAME.
Keeping rules 1&2 in mind should allow a predictable behavior of
name resolution that is simple to follow.
The old "rules" were rather surprising: sometimes (but not always),
NAME would correspond to the name of the toplevel defm. They were
also plain bonkers when you pushed them to their limits, as the old
version of the TableGen test case shows.
Having NAME correspond to the name of the toplevel defm introduces
"spooky action at a distance" and breaks composability:
refactoring the upper layers of a hierarchy of nested multiclass
instantiations can cause unexpected breakage by changing the value
of NAME at a lower level of the hierarchy. The new rules don't
suffer from this problem.
Some existing .td files have to be adjusted because they ended up
depending on the details of the old implementation.
Change-Id: I694095231565b30f563e6fd0417b41ee01a12589
Reviewers: tra, simon_tatham, craig.topper, MartinO, arsenm, javed.absar
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D47430
llvm-svn: 333900
2018-06-04 22:26:05 +08:00
|
|
|
Error(NameLoc, "Variable not defined: '" + Name->getValue() + "'");
|
|
|
|
return nullptr;
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
|
2009-05-15 04:54:48 +08:00
|
|
|
/// ParseOperation - Parse an operator. This returns null on error.
|
|
|
|
///
|
|
|
|
/// Operation ::= XOperator ['<' Type '>'] '(' Args ')'
|
|
|
|
///
|
2014-06-11 04:10:08 +08:00
|
|
|
Init *TGParser::ParseOperation(Record *CurRec, RecTy *ItemType) {
|
2009-05-15 04:54:48 +08:00
|
|
|
switch (Lex.getCode()) {
|
|
|
|
default:
|
|
|
|
TokError("unknown operation");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2011-01-08 01:05:37 +08:00
|
|
|
case tgtok::XHead:
|
|
|
|
case tgtok::XTail:
|
2018-02-23 18:46:07 +08:00
|
|
|
case tgtok::XSize:
|
2011-01-08 01:05:37 +08:00
|
|
|
case tgtok::XEmpty:
|
2019-12-11 20:02:15 +08:00
|
|
|
case tgtok::XCast:
|
|
|
|
case tgtok::XGetOp: { // Value ::= !unop '(' Value ')'
|
2009-05-15 05:22:49 +08:00
|
|
|
UnOpInit::UnaryOp Code;
|
2014-04-09 12:50:04 +08:00
|
|
|
RecTy *Type = nullptr;
|
2009-05-15 04:54:48 +08:00
|
|
|
|
2009-05-15 05:22:49 +08:00
|
|
|
switch (Lex.getCode()) {
|
2012-02-07 13:05:23 +08:00
|
|
|
default: llvm_unreachable("Unhandled code!");
|
2009-05-15 05:22:49 +08:00
|
|
|
case tgtok::XCast:
|
|
|
|
Lex.Lex(); // eat the operation
|
|
|
|
Code = UnOpInit::CAST;
|
2009-05-15 04:54:48 +08:00
|
|
|
|
2009-05-15 05:22:49 +08:00
|
|
|
Type = ParseOperatorType();
|
2009-05-15 04:54:48 +08:00
|
|
|
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!Type) {
|
2009-05-15 06:38:31 +08:00
|
|
|
TokError("did not get type for unary operator");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-05-15 05:22:49 +08:00
|
|
|
}
|
2009-05-15 04:54:48 +08:00
|
|
|
|
2009-05-15 06:38:31 +08:00
|
|
|
break;
|
2011-01-08 01:05:37 +08:00
|
|
|
case tgtok::XHead:
|
2009-05-15 06:38:31 +08:00
|
|
|
Lex.Lex(); // eat the operation
|
2011-01-08 01:05:37 +08:00
|
|
|
Code = UnOpInit::HEAD;
|
2009-05-15 06:38:31 +08:00
|
|
|
break;
|
2011-01-08 01:05:37 +08:00
|
|
|
case tgtok::XTail:
|
2009-05-15 06:38:31 +08:00
|
|
|
Lex.Lex(); // eat the operation
|
2011-01-08 01:05:37 +08:00
|
|
|
Code = UnOpInit::TAIL;
|
2009-05-15 06:38:31 +08:00
|
|
|
break;
|
2018-02-23 18:46:07 +08:00
|
|
|
case tgtok::XSize:
|
|
|
|
Lex.Lex();
|
|
|
|
Code = UnOpInit::SIZE;
|
|
|
|
Type = IntRecTy::get();
|
|
|
|
break;
|
2011-01-08 01:05:37 +08:00
|
|
|
case tgtok::XEmpty:
|
2009-05-15 06:38:31 +08:00
|
|
|
Lex.Lex(); // eat the operation
|
2011-01-08 01:05:37 +08:00
|
|
|
Code = UnOpInit::EMPTY;
|
2011-07-19 01:02:57 +08:00
|
|
|
Type = IntRecTy::get();
|
2009-05-15 05:22:49 +08:00
|
|
|
break;
|
2019-12-11 20:02:15 +08:00
|
|
|
case tgtok::XGetOp:
|
|
|
|
Lex.Lex(); // eat the operation
|
|
|
|
if (Lex.getCode() == tgtok::less) {
|
|
|
|
// Parse an optional type suffix, so that you can say
|
|
|
|
// !getop<BaseClass>(someDag) as a shorthand for
|
|
|
|
// !cast<BaseClass>(!getop(someDag)).
|
|
|
|
Type = ParseOperatorType();
|
|
|
|
|
|
|
|
if (!Type) {
|
|
|
|
TokError("did not get type for unary operator");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!isa<RecordRecTy>(Type)) {
|
|
|
|
TokError("type for !getop must be a record type");
|
|
|
|
// but keep parsing, to consume the operand
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
Type = RecordRecTy::get({});
|
|
|
|
}
|
|
|
|
Code = UnOpInit::GETOP;
|
|
|
|
break;
|
2009-05-15 05:22:49 +08:00
|
|
|
}
|
|
|
|
if (Lex.getCode() != tgtok::l_paren) {
|
|
|
|
TokError("expected '(' after unary operator");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-05-15 05:22:49 +08:00
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the '('
|
2009-05-15 04:54:48 +08:00
|
|
|
|
2011-07-30 06:43:06 +08:00
|
|
|
Init *LHS = ParseValue(CurRec);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!LHS) return nullptr;
|
2009-05-15 04:54:48 +08:00
|
|
|
|
2015-04-30 13:54:22 +08:00
|
|
|
if (Code == UnOpInit::HEAD ||
|
|
|
|
Code == UnOpInit::TAIL ||
|
|
|
|
Code == UnOpInit::EMPTY) {
|
2012-10-11 04:24:43 +08:00
|
|
|
ListInit *LHSl = dyn_cast<ListInit>(LHS);
|
|
|
|
StringInit *LHSs = dyn_cast<StringInit>(LHS);
|
|
|
|
TypedInit *LHSt = dyn_cast<TypedInit>(LHS);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!LHSl && !LHSs && !LHSt) {
|
2009-06-09 04:23:18 +08:00
|
|
|
TokError("expected list or string type argument in unary operator");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-05-15 06:38:31 +08:00
|
|
|
}
|
|
|
|
if (LHSt) {
|
2012-10-05 11:31:58 +08:00
|
|
|
ListRecTy *LType = dyn_cast<ListRecTy>(LHSt->getType());
|
|
|
|
StringRecTy *SType = dyn_cast<StringRecTy>(LHSt->getType());
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!LType && !SType) {
|
2014-05-31 13:18:52 +08:00
|
|
|
TokError("expected list or string type argument in unary operator");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-05-15 06:38:31 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-23 18:46:07 +08:00
|
|
|
if (Code == UnOpInit::HEAD || Code == UnOpInit::TAIL ||
|
|
|
|
Code == UnOpInit::SIZE) {
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!LHSl && !LHSt) {
|
2014-05-31 13:18:52 +08:00
|
|
|
TokError("expected list type argument in unary operator");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-06-09 04:23:18 +08:00
|
|
|
}
|
2018-02-23 18:46:07 +08:00
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2018-02-23 18:46:07 +08:00
|
|
|
if (Code == UnOpInit::HEAD || Code == UnOpInit::TAIL) {
|
2015-05-14 13:53:53 +08:00
|
|
|
if (LHSl && LHSl->empty()) {
|
2009-05-15 06:38:31 +08:00
|
|
|
TokError("empty list argument in unary operator");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-05-15 06:38:31 +08:00
|
|
|
}
|
|
|
|
if (LHSl) {
|
2011-07-30 06:43:06 +08:00
|
|
|
Init *Item = LHSl->getElement(0);
|
2012-10-11 04:24:43 +08:00
|
|
|
TypedInit *Itemt = dyn_cast<TypedInit>(Item);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!Itemt) {
|
2009-05-15 06:38:31 +08:00
|
|
|
TokError("untyped list element in unary operator");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-05-15 06:38:31 +08:00
|
|
|
}
|
2015-05-04 09:35:39 +08:00
|
|
|
Type = (Code == UnOpInit::HEAD) ? Itemt->getType()
|
|
|
|
: ListRecTy::get(Itemt->getType());
|
2009-11-22 12:24:42 +08:00
|
|
|
} else {
|
2009-05-15 06:38:31 +08:00
|
|
|
assert(LHSt && "expected list type argument in unary operator");
|
2012-10-05 11:31:58 +08:00
|
|
|
ListRecTy *LType = dyn_cast<ListRecTy>(LHSt->getType());
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!LType) {
|
2014-05-31 13:18:52 +08:00
|
|
|
TokError("expected list type argument in unary operator");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-05-15 06:38:31 +08:00
|
|
|
}
|
2015-05-04 09:35:39 +08:00
|
|
|
Type = (Code == UnOpInit::HEAD) ? LType->getElementType() : LType;
|
2009-05-15 06:38:31 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-15 05:22:49 +08:00
|
|
|
if (Lex.getCode() != tgtok::r_paren) {
|
|
|
|
TokError("expected ')' in unary operator");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-05-15 05:22:49 +08:00
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the ')'
|
2018-03-19 22:13:37 +08:00
|
|
|
return (UnOpInit::get(Code, LHS, Type))->Fold(CurRec);
|
2009-05-15 05:22:49 +08:00
|
|
|
}
|
2009-05-15 04:54:48 +08:00
|
|
|
|
2018-03-09 20:24:06 +08:00
|
|
|
case tgtok::XIsA: {
|
|
|
|
// Value ::= !isa '<' Type '>' '(' Value ')'
|
|
|
|
Lex.Lex(); // eat the operation
|
|
|
|
|
|
|
|
RecTy *Type = ParseOperatorType();
|
|
|
|
if (!Type)
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
if (Lex.getCode() != tgtok::l_paren) {
|
|
|
|
TokError("expected '(' after type of !isa");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the '('
|
|
|
|
|
|
|
|
Init *LHS = ParseValue(CurRec);
|
|
|
|
if (!LHS)
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
if (Lex.getCode() != tgtok::r_paren) {
|
|
|
|
TokError("expected ')' in !isa");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the ')'
|
|
|
|
|
|
|
|
return (IsAOpInit::get(Type, LHS))->Fold();
|
|
|
|
}
|
|
|
|
|
2009-05-15 04:54:48 +08:00
|
|
|
case tgtok::XConcat:
|
2013-01-25 22:49:08 +08:00
|
|
|
case tgtok::XADD:
|
2019-03-01 17:46:29 +08:00
|
|
|
case tgtok::XMUL:
|
2014-08-05 17:43:25 +08:00
|
|
|
case tgtok::XAND:
|
2016-11-15 14:49:28 +08:00
|
|
|
case tgtok::XOR:
|
2009-11-22 12:24:42 +08:00
|
|
|
case tgtok::XSRA:
|
2009-05-15 04:54:48 +08:00
|
|
|
case tgtok::XSRL:
|
|
|
|
case tgtok::XSHL:
|
2010-01-06 03:11:42 +08:00
|
|
|
case tgtok::XEq:
|
2018-03-14 19:00:57 +08:00
|
|
|
case tgtok::XNe:
|
|
|
|
case tgtok::XLe:
|
|
|
|
case tgtok::XLt:
|
|
|
|
case tgtok::XGe:
|
|
|
|
case tgtok::XGt:
|
2014-05-07 18:13:19 +08:00
|
|
|
case tgtok::XListConcat:
|
2019-04-11 02:26:36 +08:00
|
|
|
case tgtok::XListSplat:
|
2019-12-11 20:02:15 +08:00
|
|
|
case tgtok::XStrConcat:
|
|
|
|
case tgtok::XSetOp: { // Value ::= !binop '(' Value ',' Value ')'
|
2010-10-06 07:58:18 +08:00
|
|
|
tgtok::TokKind OpTok = Lex.getCode();
|
|
|
|
SMLoc OpLoc = Lex.getLoc();
|
|
|
|
Lex.Lex(); // eat the operation
|
|
|
|
|
2009-05-15 04:54:48 +08:00
|
|
|
BinOpInit::BinaryOp Code;
|
2010-10-06 07:58:18 +08:00
|
|
|
switch (OpTok) {
|
2012-02-07 13:05:23 +08:00
|
|
|
default: llvm_unreachable("Unhandled code!");
|
2018-03-14 19:00:43 +08:00
|
|
|
case tgtok::XConcat: Code = BinOpInit::CONCAT; break;
|
|
|
|
case tgtok::XADD: Code = BinOpInit::ADD; break;
|
2019-03-01 17:46:29 +08:00
|
|
|
case tgtok::XMUL: Code = BinOpInit::MUL; break;
|
2018-03-14 19:00:43 +08:00
|
|
|
case tgtok::XAND: Code = BinOpInit::AND; break;
|
|
|
|
case tgtok::XOR: Code = BinOpInit::OR; break;
|
|
|
|
case tgtok::XSRA: Code = BinOpInit::SRA; break;
|
|
|
|
case tgtok::XSRL: Code = BinOpInit::SRL; break;
|
|
|
|
case tgtok::XSHL: Code = BinOpInit::SHL; break;
|
|
|
|
case tgtok::XEq: Code = BinOpInit::EQ; break;
|
2018-03-14 19:00:57 +08:00
|
|
|
case tgtok::XNe: Code = BinOpInit::NE; break;
|
|
|
|
case tgtok::XLe: Code = BinOpInit::LE; break;
|
|
|
|
case tgtok::XLt: Code = BinOpInit::LT; break;
|
|
|
|
case tgtok::XGe: Code = BinOpInit::GE; break;
|
|
|
|
case tgtok::XGt: Code = BinOpInit::GT; break;
|
2018-03-14 19:00:43 +08:00
|
|
|
case tgtok::XListConcat: Code = BinOpInit::LISTCONCAT; break;
|
2019-04-11 02:26:36 +08:00
|
|
|
case tgtok::XListSplat: Code = BinOpInit::LISTSPLAT; break;
|
2018-03-14 19:00:43 +08:00
|
|
|
case tgtok::XStrConcat: Code = BinOpInit::STRCONCAT; break;
|
2019-12-11 20:02:15 +08:00
|
|
|
case tgtok::XSetOp: Code = BinOpInit::SETOP; break;
|
2018-03-14 19:00:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
RecTy *Type = nullptr;
|
|
|
|
RecTy *ArgType = nullptr;
|
|
|
|
switch (OpTok) {
|
|
|
|
default:
|
|
|
|
llvm_unreachable("Unhandled code!");
|
|
|
|
case tgtok::XConcat:
|
2019-12-11 20:02:15 +08:00
|
|
|
case tgtok::XSetOp:
|
2018-03-14 19:00:43 +08:00
|
|
|
Type = DagRecTy::get();
|
|
|
|
ArgType = DagRecTy::get();
|
|
|
|
break;
|
|
|
|
case tgtok::XAND:
|
|
|
|
case tgtok::XOR:
|
|
|
|
case tgtok::XSRA:
|
|
|
|
case tgtok::XSRL:
|
|
|
|
case tgtok::XSHL:
|
|
|
|
case tgtok::XADD:
|
2019-03-01 17:46:29 +08:00
|
|
|
case tgtok::XMUL:
|
2018-03-14 19:00:43 +08:00
|
|
|
Type = IntRecTy::get();
|
|
|
|
ArgType = IntRecTy::get();
|
|
|
|
break;
|
|
|
|
case tgtok::XEq:
|
2018-03-14 19:00:57 +08:00
|
|
|
case tgtok::XNe:
|
2018-03-14 19:00:43 +08:00
|
|
|
Type = BitRecTy::get();
|
2018-03-14 19:00:57 +08:00
|
|
|
// ArgType for Eq / Ne is not known at this point
|
|
|
|
break;
|
|
|
|
case tgtok::XLe:
|
|
|
|
case tgtok::XLt:
|
|
|
|
case tgtok::XGe:
|
|
|
|
case tgtok::XGt:
|
|
|
|
Type = BitRecTy::get();
|
|
|
|
ArgType = IntRecTy::get();
|
2018-03-14 19:00:43 +08:00
|
|
|
break;
|
2014-05-07 18:13:19 +08:00
|
|
|
case tgtok::XListConcat:
|
|
|
|
// We don't know the list type until we parse the first argument
|
2018-03-14 19:00:43 +08:00
|
|
|
ArgType = ItemType;
|
2014-05-07 18:13:19 +08:00
|
|
|
break;
|
2019-04-11 02:26:36 +08:00
|
|
|
case tgtok::XListSplat:
|
|
|
|
// Can't do any typechecking until we parse the first argument.
|
|
|
|
break;
|
2009-11-22 12:24:42 +08:00
|
|
|
case tgtok::XStrConcat:
|
2011-07-19 01:02:57 +08:00
|
|
|
Type = StringRecTy::get();
|
2018-03-14 19:00:43 +08:00
|
|
|
ArgType = StringRecTy::get();
|
2009-05-15 04:54:48 +08:00
|
|
|
break;
|
|
|
|
}
|
2010-10-23 15:32:37 +08:00
|
|
|
|
2018-03-14 19:00:43 +08:00
|
|
|
if (Type && ItemType && !Type->typeIsConvertibleTo(ItemType)) {
|
|
|
|
Error(OpLoc, Twine("expected value of type '") +
|
|
|
|
ItemType->getAsString() + "', got '" +
|
|
|
|
Type->getAsString() + "'");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2009-05-15 04:54:48 +08:00
|
|
|
if (Lex.getCode() != tgtok::l_paren) {
|
|
|
|
TokError("expected '(' after binary operator");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-05-15 04:54:48 +08:00
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the '('
|
|
|
|
|
2011-07-30 06:43:06 +08:00
|
|
|
SmallVector<Init*, 2> InitList;
|
2010-10-23 15:32:37 +08:00
|
|
|
|
2018-03-14 19:00:43 +08:00
|
|
|
for (;;) {
|
|
|
|
SMLoc InitLoc = Lex.getLoc();
|
|
|
|
InitList.push_back(ParseValue(CurRec, ArgType));
|
|
|
|
if (!InitList.back()) return nullptr;
|
2009-05-15 04:54:48 +08:00
|
|
|
|
2019-09-27 01:11:02 +08:00
|
|
|
RecTy *ListType = cast<TypedInit>(InitList.back())->getType();
|
2018-03-14 19:00:43 +08:00
|
|
|
if (!ArgType) {
|
2019-09-27 01:11:02 +08:00
|
|
|
ArgType = ListType;
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2018-03-14 19:00:43 +08:00
|
|
|
switch (Code) {
|
|
|
|
case BinOpInit::LISTCONCAT:
|
|
|
|
if (!isa<ListRecTy>(ArgType)) {
|
|
|
|
Error(InitLoc, Twine("expected a list, got value of type '") +
|
|
|
|
ArgType->getAsString() + "'");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
break;
|
2019-04-11 02:26:36 +08:00
|
|
|
case BinOpInit::LISTSPLAT:
|
|
|
|
if (ItemType && InitList.size() == 1) {
|
|
|
|
if (!isa<ListRecTy>(ItemType)) {
|
|
|
|
Error(OpLoc,
|
|
|
|
Twine("expected output type to be a list, got type '") +
|
|
|
|
ItemType->getAsString() + "'");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
if (!ArgType->getListTy()->typeIsConvertibleTo(ItemType)) {
|
|
|
|
Error(OpLoc, Twine("expected first arg type to be '") +
|
|
|
|
ArgType->getAsString() +
|
|
|
|
"', got value of type '" +
|
|
|
|
cast<ListRecTy>(ItemType)
|
|
|
|
->getElementType()
|
|
|
|
->getAsString() +
|
|
|
|
"'");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (InitList.size() == 2 && !isa<IntRecTy>(ArgType)) {
|
|
|
|
Error(InitLoc, Twine("expected second parameter to be an int, got "
|
|
|
|
"value of type '") +
|
|
|
|
ArgType->getAsString() + "'");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
ArgType = nullptr; // Broken invariant: types not identical.
|
|
|
|
break;
|
2018-03-14 19:00:43 +08:00
|
|
|
case BinOpInit::EQ:
|
2018-03-14 19:00:57 +08:00
|
|
|
case BinOpInit::NE:
|
2018-03-14 19:00:43 +08:00
|
|
|
if (!ArgType->typeIsConvertibleTo(IntRecTy::get()) &&
|
|
|
|
!ArgType->typeIsConvertibleTo(StringRecTy::get())) {
|
|
|
|
Error(InitLoc, Twine("expected int, bits, or string; got value of "
|
|
|
|
"type '") + ArgType->getAsString() + "'");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
default: llvm_unreachable("other ops have fixed argument types");
|
|
|
|
}
|
|
|
|
} else {
|
2019-09-27 01:11:02 +08:00
|
|
|
RecTy *Resolved = resolveTypes(ArgType, ListType);
|
2018-03-14 19:00:43 +08:00
|
|
|
if (!Resolved) {
|
|
|
|
Error(InitLoc, Twine("expected value of type '") +
|
2019-09-27 01:11:02 +08:00
|
|
|
ArgType->getAsString() + "', got '" +
|
|
|
|
ListType->getAsString() + "'");
|
2018-03-14 19:00:43 +08:00
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
if (Code != BinOpInit::ADD && Code != BinOpInit::AND &&
|
|
|
|
Code != BinOpInit::OR && Code != BinOpInit::SRA &&
|
2019-03-01 17:46:29 +08:00
|
|
|
Code != BinOpInit::SRL && Code != BinOpInit::SHL &&
|
|
|
|
Code != BinOpInit::MUL)
|
2018-03-14 19:00:43 +08:00
|
|
|
ArgType = Resolved;
|
|
|
|
}
|
|
|
|
|
2019-12-11 20:02:15 +08:00
|
|
|
// Deal with BinOps whose arguments have different types, by
|
|
|
|
// rewriting ArgType in between them.
|
|
|
|
switch (Code) {
|
|
|
|
case BinOpInit::SETOP:
|
|
|
|
// After parsing the first dag argument, switch to expecting
|
|
|
|
// a record, with no restriction on its superclasses.
|
|
|
|
ArgType = RecordRecTy::get({});
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-03-14 19:00:43 +08:00
|
|
|
if (Lex.getCode() != tgtok::comma)
|
|
|
|
break;
|
|
|
|
Lex.Lex(); // eat the ','
|
2010-10-06 07:58:18 +08:00
|
|
|
}
|
2009-05-15 04:54:48 +08:00
|
|
|
|
|
|
|
if (Lex.getCode() != tgtok::r_paren) {
|
2010-10-06 07:58:18 +08:00
|
|
|
TokError("expected ')' in operator");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-05-15 04:54:48 +08:00
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the ')'
|
2010-10-06 07:58:18 +08:00
|
|
|
|
2019-04-11 02:26:36 +08:00
|
|
|
// listconcat returns a list with type of the argument.
|
2018-03-14 19:00:43 +08:00
|
|
|
if (Code == BinOpInit::LISTCONCAT)
|
|
|
|
Type = ArgType;
|
2019-04-11 02:26:36 +08:00
|
|
|
// listsplat returns a list of type of the *first* argument.
|
|
|
|
if (Code == BinOpInit::LISTSPLAT)
|
|
|
|
Type = cast<TypedInit>(InitList.front())->getType()->getListTy();
|
2014-05-07 18:13:19 +08:00
|
|
|
|
2010-10-06 07:58:18 +08:00
|
|
|
// We allow multiple operands to associative operators like !strconcat as
|
|
|
|
// shorthand for nesting them.
|
2018-03-14 19:00:43 +08:00
|
|
|
if (Code == BinOpInit::STRCONCAT || Code == BinOpInit::LISTCONCAT ||
|
|
|
|
Code == BinOpInit::CONCAT || Code == BinOpInit::ADD ||
|
2019-03-01 17:46:29 +08:00
|
|
|
Code == BinOpInit::AND || Code == BinOpInit::OR ||
|
|
|
|
Code == BinOpInit::MUL) {
|
2010-10-06 07:58:18 +08:00
|
|
|
while (InitList.size() > 2) {
|
2011-07-30 06:43:06 +08:00
|
|
|
Init *RHS = InitList.pop_back_val();
|
2018-03-19 22:13:37 +08:00
|
|
|
RHS = (BinOpInit::get(Code, InitList.back(), RHS, Type))->Fold(CurRec);
|
2010-10-06 07:58:18 +08:00
|
|
|
InitList.back() = RHS;
|
|
|
|
}
|
|
|
|
}
|
2010-10-23 15:32:37 +08:00
|
|
|
|
2010-10-06 07:58:18 +08:00
|
|
|
if (InitList.size() == 2)
|
2011-07-30 03:07:07 +08:00
|
|
|
return (BinOpInit::get(Code, InitList[0], InitList[1], Type))
|
2018-03-19 22:13:37 +08:00
|
|
|
->Fold(CurRec);
|
2010-10-23 15:32:37 +08:00
|
|
|
|
2010-10-06 07:58:18 +08:00
|
|
|
Error(OpLoc, "expected two operands to operator");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-05-15 04:54:48 +08:00
|
|
|
}
|
|
|
|
|
TableGen: Reimplement !foreach using the resolving mechanism
Summary:
This changes the syntax of !foreach so that the first "parameter" is
a new syntactic variable: !foreach(x, lst, expr) will define the
variable x within the scope of expr, and evaluation of the !foreach
will substitute elements of the given list (or dag) for x in expr.
Aside from leading to a nicer syntax, this allows more complex
expressions where x is deeply nested, or even constant expressions
in which x does not occur at all.
!foreach is currently not actually used anywhere in trunk, but I
plan to use it in the AMDGPU backend. If out-of-tree targets are
using it, they can adjust to the new syntax very easily.
Change-Id: Ib966694d8ab6542279d6bc358b6f4d767945a805
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits, tpr
Differential Revision: https://reviews.llvm.org/D43651
llvm-svn: 326705
2018-03-05 23:21:04 +08:00
|
|
|
case tgtok::XForEach: { // Value ::= !foreach '(' Id ',' Value ',' Value ')'
|
|
|
|
SMLoc OpLoc = Lex.getLoc();
|
|
|
|
Lex.Lex(); // eat the operation
|
|
|
|
if (Lex.getCode() != tgtok::l_paren) {
|
|
|
|
TokError("expected '(' after !foreach");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Lex.Lex() != tgtok::Id) { // eat the '('
|
|
|
|
TokError("first argument of !foreach must be an identifier");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
Init *LHS = StringInit::get(Lex.getCurStrVal());
|
|
|
|
|
2018-06-21 21:35:44 +08:00
|
|
|
if (CurRec && CurRec->getValue(LHS)) {
|
TableGen: Reimplement !foreach using the resolving mechanism
Summary:
This changes the syntax of !foreach so that the first "parameter" is
a new syntactic variable: !foreach(x, lst, expr) will define the
variable x within the scope of expr, and evaluation of the !foreach
will substitute elements of the given list (or dag) for x in expr.
Aside from leading to a nicer syntax, this allows more complex
expressions where x is deeply nested, or even constant expressions
in which x does not occur at all.
!foreach is currently not actually used anywhere in trunk, but I
plan to use it in the AMDGPU backend. If out-of-tree targets are
using it, they can adjust to the new syntax very easily.
Change-Id: Ib966694d8ab6542279d6bc358b6f4d767945a805
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits, tpr
Differential Revision: https://reviews.llvm.org/D43651
llvm-svn: 326705
2018-03-05 23:21:04 +08:00
|
|
|
TokError((Twine("iteration variable '") + LHS->getAsString() +
|
|
|
|
"' already defined")
|
|
|
|
.str());
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Lex.Lex() != tgtok::comma) { // eat the id
|
|
|
|
TokError("expected ',' in ternary operator");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the ','
|
|
|
|
|
|
|
|
Init *MHS = ParseValue(CurRec);
|
|
|
|
if (!MHS)
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
if (Lex.getCode() != tgtok::comma) {
|
|
|
|
TokError("expected ',' in ternary operator");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the ','
|
|
|
|
|
|
|
|
TypedInit *MHSt = dyn_cast<TypedInit>(MHS);
|
|
|
|
if (!MHSt) {
|
|
|
|
TokError("could not get type of !foreach input");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
RecTy *InEltType = nullptr;
|
|
|
|
RecTy *OutEltType = nullptr;
|
|
|
|
bool IsDAG = false;
|
|
|
|
|
|
|
|
if (ListRecTy *InListTy = dyn_cast<ListRecTy>(MHSt->getType())) {
|
|
|
|
InEltType = InListTy->getElementType();
|
|
|
|
if (ItemType) {
|
|
|
|
if (ListRecTy *OutListTy = dyn_cast<ListRecTy>(ItemType)) {
|
|
|
|
OutEltType = OutListTy->getElementType();
|
|
|
|
} else {
|
|
|
|
Error(OpLoc,
|
|
|
|
"expected value of type '" + Twine(ItemType->getAsString()) +
|
|
|
|
"', but got !foreach of list type");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (DagRecTy *InDagTy = dyn_cast<DagRecTy>(MHSt->getType())) {
|
|
|
|
InEltType = InDagTy;
|
|
|
|
if (ItemType && !isa<DagRecTy>(ItemType)) {
|
|
|
|
Error(OpLoc,
|
|
|
|
"expected value of type '" + Twine(ItemType->getAsString()) +
|
|
|
|
"', but got !foreach of dag type");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
IsDAG = true;
|
|
|
|
} else {
|
|
|
|
TokError("!foreach must have list or dag input");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2018-06-21 21:35:44 +08:00
|
|
|
// We need to create a temporary record to provide a scope for the iteration
|
|
|
|
// variable while parsing top-level foreach's.
|
|
|
|
std::unique_ptr<Record> ParseRecTmp;
|
|
|
|
Record *ParseRec = CurRec;
|
|
|
|
if (!ParseRec) {
|
2019-08-15 23:54:37 +08:00
|
|
|
ParseRecTmp = std::make_unique<Record>(".parse", ArrayRef<SMLoc>{}, Records);
|
2018-06-21 21:35:44 +08:00
|
|
|
ParseRec = ParseRecTmp.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
ParseRec->addValue(RecordVal(LHS, InEltType, false));
|
|
|
|
Init *RHS = ParseValue(ParseRec, OutEltType);
|
|
|
|
ParseRec->removeValue(LHS);
|
TableGen: Reimplement !foreach using the resolving mechanism
Summary:
This changes the syntax of !foreach so that the first "parameter" is
a new syntactic variable: !foreach(x, lst, expr) will define the
variable x within the scope of expr, and evaluation of the !foreach
will substitute elements of the given list (or dag) for x in expr.
Aside from leading to a nicer syntax, this allows more complex
expressions where x is deeply nested, or even constant expressions
in which x does not occur at all.
!foreach is currently not actually used anywhere in trunk, but I
plan to use it in the AMDGPU backend. If out-of-tree targets are
using it, they can adjust to the new syntax very easily.
Change-Id: Ib966694d8ab6542279d6bc358b6f4d767945a805
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits, tpr
Differential Revision: https://reviews.llvm.org/D43651
llvm-svn: 326705
2018-03-05 23:21:04 +08:00
|
|
|
if (!RHS)
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
if (Lex.getCode() != tgtok::r_paren) {
|
|
|
|
TokError("expected ')' in binary operator");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the ')'
|
|
|
|
|
|
|
|
RecTy *OutType;
|
|
|
|
if (IsDAG) {
|
|
|
|
OutType = InEltType;
|
|
|
|
} else {
|
|
|
|
TypedInit *RHSt = dyn_cast<TypedInit>(RHS);
|
|
|
|
if (!RHSt) {
|
|
|
|
TokError("could not get type of !foreach result");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
OutType = RHSt->getType()->getListTy();
|
|
|
|
}
|
|
|
|
|
|
|
|
return (TernOpInit::get(TernOpInit::FOREACH, LHS, MHS, RHS, OutType))
|
2018-03-19 22:13:37 +08:00
|
|
|
->Fold(CurRec);
|
TableGen: Reimplement !foreach using the resolving mechanism
Summary:
This changes the syntax of !foreach so that the first "parameter" is
a new syntactic variable: !foreach(x, lst, expr) will define the
variable x within the scope of expr, and evaluation of the !foreach
will substitute elements of the given list (or dag) for x in expr.
Aside from leading to a nicer syntax, this allows more complex
expressions where x is deeply nested, or even constant expressions
in which x does not occur at all.
!foreach is currently not actually used anywhere in trunk, but I
plan to use it in the AMDGPU backend. If out-of-tree targets are
using it, they can adjust to the new syntax very easily.
Change-Id: Ib966694d8ab6542279d6bc358b6f4d767945a805
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits, tpr
Differential Revision: https://reviews.llvm.org/D43651
llvm-svn: 326705
2018-03-05 23:21:04 +08:00
|
|
|
}
|
|
|
|
|
2018-03-14 19:00:26 +08:00
|
|
|
case tgtok::XDag:
|
2009-05-15 07:26:46 +08:00
|
|
|
case tgtok::XIf:
|
2009-05-15 05:54:42 +08:00
|
|
|
case tgtok::XSubst: { // Value ::= !ternop '(' Value ',' Value ',' Value ')'
|
|
|
|
TernOpInit::TernaryOp Code;
|
2014-04-09 12:50:04 +08:00
|
|
|
RecTy *Type = nullptr;
|
2009-05-15 05:54:42 +08:00
|
|
|
|
|
|
|
tgtok::TokKind LexCode = Lex.getCode();
|
|
|
|
Lex.Lex(); // eat the operation
|
|
|
|
switch (LexCode) {
|
2012-02-07 13:05:23 +08:00
|
|
|
default: llvm_unreachable("Unhandled code!");
|
2018-03-14 19:00:26 +08:00
|
|
|
case tgtok::XDag:
|
|
|
|
Code = TernOpInit::DAG;
|
|
|
|
Type = DagRecTy::get();
|
|
|
|
ItemType = nullptr;
|
|
|
|
break;
|
2009-05-15 07:26:46 +08:00
|
|
|
case tgtok::XIf:
|
|
|
|
Code = TernOpInit::IF;
|
|
|
|
break;
|
2009-05-15 05:54:42 +08:00
|
|
|
case tgtok::XSubst:
|
|
|
|
Code = TernOpInit::SUBST;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (Lex.getCode() != tgtok::l_paren) {
|
|
|
|
TokError("expected '(' after ternary operator");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-05-15 05:54:42 +08:00
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the '('
|
|
|
|
|
2011-07-30 06:43:06 +08:00
|
|
|
Init *LHS = ParseValue(CurRec);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!LHS) return nullptr;
|
2009-05-15 05:54:42 +08:00
|
|
|
|
|
|
|
if (Lex.getCode() != tgtok::comma) {
|
|
|
|
TokError("expected ',' in ternary operator");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-05-15 05:54:42 +08:00
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the ','
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2018-03-14 19:00:26 +08:00
|
|
|
SMLoc MHSLoc = Lex.getLoc();
|
2014-06-11 04:10:08 +08:00
|
|
|
Init *MHS = ParseValue(CurRec, ItemType);
|
|
|
|
if (!MHS)
|
|
|
|
return nullptr;
|
2009-05-15 05:54:42 +08:00
|
|
|
|
|
|
|
if (Lex.getCode() != tgtok::comma) {
|
|
|
|
TokError("expected ',' in ternary operator");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-05-15 05:54:42 +08:00
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the ','
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2018-03-14 19:00:26 +08:00
|
|
|
SMLoc RHSLoc = Lex.getLoc();
|
2014-06-11 04:10:08 +08:00
|
|
|
Init *RHS = ParseValue(CurRec, ItemType);
|
|
|
|
if (!RHS)
|
|
|
|
return nullptr;
|
2009-05-15 05:54:42 +08:00
|
|
|
|
|
|
|
if (Lex.getCode() != tgtok::r_paren) {
|
|
|
|
TokError("expected ')' in binary operator");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-05-15 05:54:42 +08:00
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the ')'
|
|
|
|
|
|
|
|
switch (LexCode) {
|
2012-02-07 13:05:23 +08:00
|
|
|
default: llvm_unreachable("Unhandled code!");
|
2018-03-14 19:00:26 +08:00
|
|
|
case tgtok::XDag: {
|
|
|
|
TypedInit *MHSt = dyn_cast<TypedInit>(MHS);
|
|
|
|
if (!MHSt && !isa<UnsetInit>(MHS)) {
|
|
|
|
Error(MHSLoc, "could not determine type of the child list in !dag");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
if (MHSt && !isa<ListRecTy>(MHSt->getType())) {
|
|
|
|
Error(MHSLoc, Twine("expected list of children, got type '") +
|
|
|
|
MHSt->getType()->getAsString() + "'");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
TypedInit *RHSt = dyn_cast<TypedInit>(RHS);
|
|
|
|
if (!RHSt && !isa<UnsetInit>(RHS)) {
|
|
|
|
Error(RHSLoc, "could not determine type of the name list in !dag");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
if (RHSt && StringRecTy::get()->getListTy() != RHSt->getType()) {
|
|
|
|
Error(RHSLoc, Twine("expected list<string>, got type '") +
|
|
|
|
RHSt->getType()->getAsString() + "'");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!MHSt && !RHSt) {
|
|
|
|
Error(MHSLoc,
|
|
|
|
"cannot have both unset children and unset names in !dag");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2009-05-15 07:26:46 +08:00
|
|
|
case tgtok::XIf: {
|
2014-04-09 12:50:04 +08:00
|
|
|
RecTy *MHSTy = nullptr;
|
|
|
|
RecTy *RHSTy = nullptr;
|
2010-12-13 09:46:19 +08:00
|
|
|
|
2012-10-11 04:24:43 +08:00
|
|
|
if (TypedInit *MHSt = dyn_cast<TypedInit>(MHS))
|
2010-12-13 09:46:19 +08:00
|
|
|
MHSTy = MHSt->getType();
|
2012-10-11 04:24:43 +08:00
|
|
|
if (BitsInit *MHSbits = dyn_cast<BitsInit>(MHS))
|
Re-work bit/bits value resolving in tblgen
- This patch is inspired by the failure of the following code snippet
which is used to convert enumerable values into encoding bits to
improve the readability of td files.
class S<int s> {
bits<2> V = !if(!eq(s, 8), {0, 0},
!if(!eq(s, 16), {0, 1},
!if(!eq(s, 32), {1, 0},
!if(!eq(s, 64), {1, 1}, {?, ?}))));
}
Later, PR8330 is found to report not exactly the same bug relevant
issue to bit/bits values.
- Instead of resolving bit/bits values separately through
resolveBitReference(), this patch adds getBit() for all Inits and
resolves bit value by resolving plus getting the specified bit. This
unifies the resolving of bit with other values and removes redundant
logic for resolving bit only. In addition,
BitsInit::resolveReferences() is optimized to take advantage of this
origanization by resolving VarBitInit's variable reference first and
then getting bits from it.
- The type interference in '!if' operator is revised to support possible
combinations of int and bits/bit in MHS and RHS.
- As there may be illegal assignments from integer value to bit, says
assign 2 to a bit, but we only check this during instantiation in some
cases, e.g.
bit V = !if(!eq(x, 17), 0, 2);
Verbose diagnostic message is generated when invalid value is
resolveed to help locating the error.
- PR8330 is fixed as well.
llvm-svn: 163360
2012-09-07 07:32:48 +08:00
|
|
|
MHSTy = BitsRecTy::get(MHSbits->getNumBits());
|
2012-10-11 04:24:47 +08:00
|
|
|
if (isa<BitInit>(MHS))
|
Re-work bit/bits value resolving in tblgen
- This patch is inspired by the failure of the following code snippet
which is used to convert enumerable values into encoding bits to
improve the readability of td files.
class S<int s> {
bits<2> V = !if(!eq(s, 8), {0, 0},
!if(!eq(s, 16), {0, 1},
!if(!eq(s, 32), {1, 0},
!if(!eq(s, 64), {1, 1}, {?, ?}))));
}
Later, PR8330 is found to report not exactly the same bug relevant
issue to bit/bits values.
- Instead of resolving bit/bits values separately through
resolveBitReference(), this patch adds getBit() for all Inits and
resolves bit value by resolving plus getting the specified bit. This
unifies the resolving of bit with other values and removes redundant
logic for resolving bit only. In addition,
BitsInit::resolveReferences() is optimized to take advantage of this
origanization by resolving VarBitInit's variable reference first and
then getting bits from it.
- The type interference in '!if' operator is revised to support possible
combinations of int and bits/bit in MHS and RHS.
- As there may be illegal assignments from integer value to bit, says
assign 2 to a bit, but we only check this during instantiation in some
cases, e.g.
bit V = !if(!eq(x, 17), 0, 2);
Verbose diagnostic message is generated when invalid value is
resolveed to help locating the error.
- PR8330 is fixed as well.
llvm-svn: 163360
2012-09-07 07:32:48 +08:00
|
|
|
MHSTy = BitRecTy::get();
|
|
|
|
|
2012-10-11 04:24:43 +08:00
|
|
|
if (TypedInit *RHSt = dyn_cast<TypedInit>(RHS))
|
2010-12-13 09:46:19 +08:00
|
|
|
RHSTy = RHSt->getType();
|
2012-10-11 04:24:43 +08:00
|
|
|
if (BitsInit *RHSbits = dyn_cast<BitsInit>(RHS))
|
Re-work bit/bits value resolving in tblgen
- This patch is inspired by the failure of the following code snippet
which is used to convert enumerable values into encoding bits to
improve the readability of td files.
class S<int s> {
bits<2> V = !if(!eq(s, 8), {0, 0},
!if(!eq(s, 16), {0, 1},
!if(!eq(s, 32), {1, 0},
!if(!eq(s, 64), {1, 1}, {?, ?}))));
}
Later, PR8330 is found to report not exactly the same bug relevant
issue to bit/bits values.
- Instead of resolving bit/bits values separately through
resolveBitReference(), this patch adds getBit() for all Inits and
resolves bit value by resolving plus getting the specified bit. This
unifies the resolving of bit with other values and removes redundant
logic for resolving bit only. In addition,
BitsInit::resolveReferences() is optimized to take advantage of this
origanization by resolving VarBitInit's variable reference first and
then getting bits from it.
- The type interference in '!if' operator is revised to support possible
combinations of int and bits/bit in MHS and RHS.
- As there may be illegal assignments from integer value to bit, says
assign 2 to a bit, but we only check this during instantiation in some
cases, e.g.
bit V = !if(!eq(x, 17), 0, 2);
Verbose diagnostic message is generated when invalid value is
resolveed to help locating the error.
- PR8330 is fixed as well.
llvm-svn: 163360
2012-09-07 07:32:48 +08:00
|
|
|
RHSTy = BitsRecTy::get(RHSbits->getNumBits());
|
2012-10-11 04:24:47 +08:00
|
|
|
if (isa<BitInit>(RHS))
|
Re-work bit/bits value resolving in tblgen
- This patch is inspired by the failure of the following code snippet
which is used to convert enumerable values into encoding bits to
improve the readability of td files.
class S<int s> {
bits<2> V = !if(!eq(s, 8), {0, 0},
!if(!eq(s, 16), {0, 1},
!if(!eq(s, 32), {1, 0},
!if(!eq(s, 64), {1, 1}, {?, ?}))));
}
Later, PR8330 is found to report not exactly the same bug relevant
issue to bit/bits values.
- Instead of resolving bit/bits values separately through
resolveBitReference(), this patch adds getBit() for all Inits and
resolves bit value by resolving plus getting the specified bit. This
unifies the resolving of bit with other values and removes redundant
logic for resolving bit only. In addition,
BitsInit::resolveReferences() is optimized to take advantage of this
origanization by resolving VarBitInit's variable reference first and
then getting bits from it.
- The type interference in '!if' operator is revised to support possible
combinations of int and bits/bit in MHS and RHS.
- As there may be illegal assignments from integer value to bit, says
assign 2 to a bit, but we only check this during instantiation in some
cases, e.g.
bit V = !if(!eq(x, 17), 0, 2);
Verbose diagnostic message is generated when invalid value is
resolveed to help locating the error.
- PR8330 is fixed as well.
llvm-svn: 163360
2012-09-07 07:32:48 +08:00
|
|
|
RHSTy = BitRecTy::get();
|
|
|
|
|
|
|
|
// For UnsetInit, it's typed from the other hand.
|
2012-10-11 04:24:47 +08:00
|
|
|
if (isa<UnsetInit>(MHS))
|
Re-work bit/bits value resolving in tblgen
- This patch is inspired by the failure of the following code snippet
which is used to convert enumerable values into encoding bits to
improve the readability of td files.
class S<int s> {
bits<2> V = !if(!eq(s, 8), {0, 0},
!if(!eq(s, 16), {0, 1},
!if(!eq(s, 32), {1, 0},
!if(!eq(s, 64), {1, 1}, {?, ?}))));
}
Later, PR8330 is found to report not exactly the same bug relevant
issue to bit/bits values.
- Instead of resolving bit/bits values separately through
resolveBitReference(), this patch adds getBit() for all Inits and
resolves bit value by resolving plus getting the specified bit. This
unifies the resolving of bit with other values and removes redundant
logic for resolving bit only. In addition,
BitsInit::resolveReferences() is optimized to take advantage of this
origanization by resolving VarBitInit's variable reference first and
then getting bits from it.
- The type interference in '!if' operator is revised to support possible
combinations of int and bits/bit in MHS and RHS.
- As there may be illegal assignments from integer value to bit, says
assign 2 to a bit, but we only check this during instantiation in some
cases, e.g.
bit V = !if(!eq(x, 17), 0, 2);
Verbose diagnostic message is generated when invalid value is
resolveed to help locating the error.
- PR8330 is fixed as well.
llvm-svn: 163360
2012-09-07 07:32:48 +08:00
|
|
|
MHSTy = RHSTy;
|
2012-10-11 04:24:47 +08:00
|
|
|
if (isa<UnsetInit>(RHS))
|
Re-work bit/bits value resolving in tblgen
- This patch is inspired by the failure of the following code snippet
which is used to convert enumerable values into encoding bits to
improve the readability of td files.
class S<int s> {
bits<2> V = !if(!eq(s, 8), {0, 0},
!if(!eq(s, 16), {0, 1},
!if(!eq(s, 32), {1, 0},
!if(!eq(s, 64), {1, 1}, {?, ?}))));
}
Later, PR8330 is found to report not exactly the same bug relevant
issue to bit/bits values.
- Instead of resolving bit/bits values separately through
resolveBitReference(), this patch adds getBit() for all Inits and
resolves bit value by resolving plus getting the specified bit. This
unifies the resolving of bit with other values and removes redundant
logic for resolving bit only. In addition,
BitsInit::resolveReferences() is optimized to take advantage of this
origanization by resolving VarBitInit's variable reference first and
then getting bits from it.
- The type interference in '!if' operator is revised to support possible
combinations of int and bits/bit in MHS and RHS.
- As there may be illegal assignments from integer value to bit, says
assign 2 to a bit, but we only check this during instantiation in some
cases, e.g.
bit V = !if(!eq(x, 17), 0, 2);
Verbose diagnostic message is generated when invalid value is
resolveed to help locating the error.
- PR8330 is fixed as well.
llvm-svn: 163360
2012-09-07 07:32:48 +08:00
|
|
|
RHSTy = MHSTy;
|
2010-12-13 09:46:19 +08:00
|
|
|
|
|
|
|
if (!MHSTy || !RHSTy) {
|
2009-05-15 07:26:46 +08:00
|
|
|
TokError("could not get type for !if");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-05-15 07:26:46 +08:00
|
|
|
}
|
2010-12-13 09:46:19 +08:00
|
|
|
|
2018-03-06 21:48:20 +08:00
|
|
|
Type = resolveTypes(MHSTy, RHSTy);
|
|
|
|
if (!Type) {
|
|
|
|
TokError(Twine("inconsistent types '") + MHSTy->getAsString() +
|
|
|
|
"' and '" + RHSTy->getAsString() + "' for !if");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-05-15 07:26:46 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2009-05-15 05:54:42 +08:00
|
|
|
case tgtok::XSubst: {
|
2012-10-11 04:24:43 +08:00
|
|
|
TypedInit *RHSt = dyn_cast<TypedInit>(RHS);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!RHSt) {
|
2009-05-15 05:54:42 +08:00
|
|
|
TokError("could not get type for !subst");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-05-15 05:54:42 +08:00
|
|
|
}
|
|
|
|
Type = RHSt->getType();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2018-03-19 22:13:37 +08:00
|
|
|
return (TernOpInit::get(Code, LHS, MHS, RHS, Type))->Fold(CurRec);
|
2009-05-15 05:54:42 +08:00
|
|
|
}
|
2018-03-06 21:49:16 +08:00
|
|
|
|
2019-01-25 18:25:25 +08:00
|
|
|
case tgtok::XCond:
|
|
|
|
return ParseOperationCond(CurRec, ItemType);
|
|
|
|
|
2018-03-06 21:49:16 +08:00
|
|
|
case tgtok::XFoldl: {
|
|
|
|
// Value ::= !foldl '(' Id ',' Id ',' Value ',' Value ',' Value ')'
|
|
|
|
Lex.Lex(); // eat the operation
|
|
|
|
if (Lex.getCode() != tgtok::l_paren) {
|
|
|
|
TokError("expected '(' after !foldl");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the '('
|
|
|
|
|
|
|
|
Init *StartUntyped = ParseValue(CurRec);
|
|
|
|
if (!StartUntyped)
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
TypedInit *Start = dyn_cast<TypedInit>(StartUntyped);
|
|
|
|
if (!Start) {
|
|
|
|
TokError(Twine("could not get type of !foldl start: '") +
|
|
|
|
StartUntyped->getAsString() + "'");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Lex.getCode() != tgtok::comma) {
|
|
|
|
TokError("expected ',' in !foldl");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the ','
|
|
|
|
|
|
|
|
Init *ListUntyped = ParseValue(CurRec);
|
|
|
|
if (!ListUntyped)
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
TypedInit *List = dyn_cast<TypedInit>(ListUntyped);
|
|
|
|
if (!List) {
|
|
|
|
TokError(Twine("could not get type of !foldl list: '") +
|
|
|
|
ListUntyped->getAsString() + "'");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
ListRecTy *ListType = dyn_cast<ListRecTy>(List->getType());
|
|
|
|
if (!ListType) {
|
|
|
|
TokError(Twine("!foldl list must be a list, but is of type '") +
|
|
|
|
List->getType()->getAsString());
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Lex.getCode() != tgtok::comma) {
|
|
|
|
TokError("expected ',' in !foldl");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Lex.Lex() != tgtok::Id) { // eat the ','
|
|
|
|
TokError("third argument of !foldl must be an identifier");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
Init *A = StringInit::get(Lex.getCurStrVal());
|
2018-06-21 21:35:44 +08:00
|
|
|
if (CurRec && CurRec->getValue(A)) {
|
2018-03-06 21:49:16 +08:00
|
|
|
TokError((Twine("left !foldl variable '") + A->getAsString() +
|
|
|
|
"' already defined")
|
|
|
|
.str());
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Lex.Lex() != tgtok::comma) { // eat the id
|
|
|
|
TokError("expected ',' in !foldl");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Lex.Lex() != tgtok::Id) { // eat the ','
|
|
|
|
TokError("fourth argument of !foldl must be an identifier");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
Init *B = StringInit::get(Lex.getCurStrVal());
|
2018-06-21 21:35:44 +08:00
|
|
|
if (CurRec && CurRec->getValue(B)) {
|
2018-03-06 21:49:16 +08:00
|
|
|
TokError((Twine("right !foldl variable '") + B->getAsString() +
|
|
|
|
"' already defined")
|
|
|
|
.str());
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Lex.Lex() != tgtok::comma) { // eat the id
|
|
|
|
TokError("expected ',' in !foldl");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the ','
|
|
|
|
|
2018-06-21 21:35:44 +08:00
|
|
|
// We need to create a temporary record to provide a scope for the iteration
|
|
|
|
// variable while parsing top-level foreach's.
|
|
|
|
std::unique_ptr<Record> ParseRecTmp;
|
|
|
|
Record *ParseRec = CurRec;
|
|
|
|
if (!ParseRec) {
|
2019-08-15 23:54:37 +08:00
|
|
|
ParseRecTmp = std::make_unique<Record>(".parse", ArrayRef<SMLoc>{}, Records);
|
2018-06-21 21:35:44 +08:00
|
|
|
ParseRec = ParseRecTmp.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
ParseRec->addValue(RecordVal(A, Start->getType(), false));
|
|
|
|
ParseRec->addValue(RecordVal(B, ListType->getElementType(), false));
|
|
|
|
Init *ExprUntyped = ParseValue(ParseRec);
|
|
|
|
ParseRec->removeValue(A);
|
|
|
|
ParseRec->removeValue(B);
|
2018-03-06 21:49:16 +08:00
|
|
|
if (!ExprUntyped)
|
|
|
|
return nullptr;
|
|
|
|
|
|
|
|
TypedInit *Expr = dyn_cast<TypedInit>(ExprUntyped);
|
|
|
|
if (!Expr) {
|
|
|
|
TokError("could not get type of !foldl expression");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Expr->getType() != Start->getType()) {
|
|
|
|
TokError(Twine("!foldl expression must be of same type as start (") +
|
|
|
|
Start->getType()->getAsString() + "), but is of type " +
|
|
|
|
Expr->getType()->getAsString());
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Lex.getCode() != tgtok::r_paren) {
|
|
|
|
TokError("expected ')' in fold operator");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the ')'
|
|
|
|
|
|
|
|
return FoldOpInit::get(Start, List, A, B, Expr, Start->getType())
|
|
|
|
->Fold(CurRec);
|
|
|
|
}
|
2009-05-15 04:54:48 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseOperatorType - Parse a type for an operator. This returns
|
|
|
|
/// null on error.
|
|
|
|
///
|
|
|
|
/// OperatorType ::= '<' Type '>'
|
|
|
|
///
|
2009-08-13 06:10:57 +08:00
|
|
|
RecTy *TGParser::ParseOperatorType() {
|
2014-04-09 12:50:04 +08:00
|
|
|
RecTy *Type = nullptr;
|
2009-05-15 04:54:48 +08:00
|
|
|
|
|
|
|
if (Lex.getCode() != tgtok::less) {
|
|
|
|
TokError("expected type name for operator");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-05-15 04:54:48 +08:00
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the <
|
|
|
|
|
|
|
|
Type = ParseType();
|
|
|
|
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!Type) {
|
2009-05-15 04:54:48 +08:00
|
|
|
TokError("expected type name for operator");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-05-15 04:54:48 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Lex.getCode() != tgtok::greater) {
|
|
|
|
TokError("expected type name for operator");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-05-15 04:54:48 +08:00
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the >
|
|
|
|
|
|
|
|
return Type;
|
|
|
|
}
|
|
|
|
|
2019-01-25 18:25:25 +08:00
|
|
|
Init *TGParser::ParseOperationCond(Record *CurRec, RecTy *ItemType) {
|
|
|
|
Lex.Lex(); // eat the operation 'cond'
|
|
|
|
|
|
|
|
if (Lex.getCode() != tgtok::l_paren) {
|
|
|
|
TokError("expected '(' after !cond operator");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the '('
|
|
|
|
|
|
|
|
// Parse through '[Case: Val,]+'
|
|
|
|
SmallVector<Init *, 4> Case;
|
|
|
|
SmallVector<Init *, 4> Val;
|
|
|
|
while (true) {
|
|
|
|
if (Lex.getCode() == tgtok::r_paren) {
|
|
|
|
Lex.Lex(); // eat the ')'
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
Init *V = ParseValue(CurRec);
|
|
|
|
if (!V)
|
|
|
|
return nullptr;
|
|
|
|
Case.push_back(V);
|
|
|
|
|
|
|
|
if (Lex.getCode() != tgtok::colon) {
|
|
|
|
TokError("expected ':' following a condition in !cond operator");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the ':'
|
|
|
|
|
|
|
|
V = ParseValue(CurRec, ItemType);
|
|
|
|
if (!V)
|
|
|
|
return nullptr;
|
|
|
|
Val.push_back(V);
|
|
|
|
|
|
|
|
if (Lex.getCode() == tgtok::r_paren) {
|
|
|
|
Lex.Lex(); // eat the ')'
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Lex.getCode() != tgtok::comma) {
|
|
|
|
TokError("expected ',' or ')' following a value in !cond operator");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the ','
|
|
|
|
}
|
|
|
|
|
|
|
|
if (Case.size() < 1) {
|
|
|
|
TokError("there should be at least 1 'condition : value' in the !cond operator");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
|
|
|
// resolve type
|
|
|
|
RecTy *Type = nullptr;
|
|
|
|
for (Init *V : Val) {
|
|
|
|
RecTy *VTy = nullptr;
|
|
|
|
if (TypedInit *Vt = dyn_cast<TypedInit>(V))
|
|
|
|
VTy = Vt->getType();
|
|
|
|
if (BitsInit *Vbits = dyn_cast<BitsInit>(V))
|
|
|
|
VTy = BitsRecTy::get(Vbits->getNumBits());
|
|
|
|
if (isa<BitInit>(V))
|
|
|
|
VTy = BitRecTy::get();
|
|
|
|
|
|
|
|
if (Type == nullptr) {
|
|
|
|
if (!isa<UnsetInit>(V))
|
|
|
|
Type = VTy;
|
|
|
|
} else {
|
|
|
|
if (!isa<UnsetInit>(V)) {
|
|
|
|
RecTy *RType = resolveTypes(Type, VTy);
|
|
|
|
if (!RType) {
|
|
|
|
TokError(Twine("inconsistent types '") + Type->getAsString() +
|
|
|
|
"' and '" + VTy->getAsString() + "' for !cond");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
Type = RType;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!Type) {
|
|
|
|
TokError("could not determine type for !cond from its arguments");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
return CondOpInit::get(Case, Val, Type)->Fold(CurRec);
|
|
|
|
}
|
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
/// ParseSimpleValue - Parse a tblgen value. This returns null on error.
|
|
|
|
///
|
|
|
|
/// SimpleValue ::= IDValue
|
|
|
|
/// SimpleValue ::= INTVAL
|
2009-03-12 01:08:13 +08:00
|
|
|
/// SimpleValue ::= STRVAL+
|
2007-11-23 04:49:04 +08:00
|
|
|
/// SimpleValue ::= CODEFRAGMENT
|
|
|
|
/// SimpleValue ::= '?'
|
|
|
|
/// SimpleValue ::= '{' ValueList '}'
|
|
|
|
/// SimpleValue ::= ID '<' ValueListNE '>'
|
|
|
|
/// SimpleValue ::= '[' ValueList ']'
|
|
|
|
/// SimpleValue ::= '(' IDValue DagArgList ')'
|
|
|
|
/// SimpleValue ::= CONCATTOK '(' Value ',' Value ')'
|
2013-01-25 22:49:08 +08:00
|
|
|
/// SimpleValue ::= ADDTOK '(' Value ',' Value ')'
|
2007-11-23 04:49:04 +08:00
|
|
|
/// SimpleValue ::= SHLTOK '(' Value ',' Value ')'
|
|
|
|
/// SimpleValue ::= SRATOK '(' Value ',' Value ')'
|
|
|
|
/// SimpleValue ::= SRLTOK '(' Value ',' Value ')'
|
2014-05-07 18:13:19 +08:00
|
|
|
/// SimpleValue ::= LISTCONCATTOK '(' Value ',' Value ')'
|
2019-04-11 02:26:36 +08:00
|
|
|
/// SimpleValue ::= LISTSPLATTOK '(' Value ',' Value ')'
|
2007-11-23 04:49:04 +08:00
|
|
|
/// SimpleValue ::= STRCONCATTOK '(' Value ',' Value ')'
|
2019-01-25 18:25:25 +08:00
|
|
|
/// SimpleValue ::= COND '(' [Value ':' Value,]+ ')'
|
2007-11-23 04:49:04 +08:00
|
|
|
///
|
2011-10-19 21:04:20 +08:00
|
|
|
Init *TGParser::ParseSimpleValue(Record *CurRec, RecTy *ItemType,
|
|
|
|
IDParseMode Mode) {
|
2014-04-09 12:50:04 +08:00
|
|
|
Init *R = nullptr;
|
2007-11-23 04:49:04 +08:00
|
|
|
switch (Lex.getCode()) {
|
|
|
|
default: TokError("Unknown token when parsing a value"); break;
|
2011-10-19 21:04:43 +08:00
|
|
|
case tgtok::paste:
|
|
|
|
// This is a leading paste operation. This is deprecated but
|
|
|
|
// still exists in some .td files. Ignore it.
|
|
|
|
Lex.Lex(); // Skip '#'.
|
|
|
|
return ParseSimpleValue(CurRec, ItemType, Mode);
|
2011-07-30 03:07:07 +08:00
|
|
|
case tgtok::IntVal: R = IntInit::get(Lex.getCurIntVal()); Lex.Lex(); break;
|
2014-08-07 13:47:00 +08:00
|
|
|
case tgtok::BinaryIntVal: {
|
|
|
|
auto BinaryVal = Lex.getCurBinaryIntVal();
|
|
|
|
SmallVector<Init*, 16> Bits(BinaryVal.second);
|
|
|
|
for (unsigned i = 0, e = BinaryVal.second; i != e; ++i)
|
2014-08-07 20:07:33 +08:00
|
|
|
Bits[i] = BitInit::get(BinaryVal.first & (1LL << i));
|
2014-08-07 13:47:00 +08:00
|
|
|
R = BitsInit::get(Bits);
|
|
|
|
Lex.Lex();
|
|
|
|
break;
|
|
|
|
}
|
2009-03-12 01:08:13 +08:00
|
|
|
case tgtok::StrVal: {
|
|
|
|
std::string Val = Lex.getCurStrVal();
|
|
|
|
Lex.Lex();
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2009-03-27 00:17:51 +08:00
|
|
|
// Handle multiple consecutive concatenated strings.
|
2009-03-12 01:08:13 +08:00
|
|
|
while (Lex.getCode() == tgtok::StrVal) {
|
|
|
|
Val += Lex.getCurStrVal();
|
|
|
|
Lex.Lex();
|
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2011-07-30 03:07:07 +08:00
|
|
|
R = StringInit::get(Val);
|
2009-03-12 01:08:13 +08:00
|
|
|
break;
|
|
|
|
}
|
2007-11-23 04:49:04 +08:00
|
|
|
case tgtok::CodeFragment:
|
[tblgen] Track CodeInit origins when possible
Summary:
Add an SMLoc to CodeInit that records the source line it originated from.
This allows tablegen to point precisely at portions of code when reporting
errors within the CodeInit. For example, in the upcoming GlobalISel
combiner, it can report undefined expansions and point at the instance of
the expansion. This is achieved using something like:
SMLoc::getFromPointer(SMLoc::getPointer() +
(StringRef - CodeInit::getValue()))
The location is lost when producing a CodeInit by string concatenation so
a fallback SMLoc is required (e.g. the Record::getLoc()) but that's pretty
rare for CodeInits.
There's a reasonable case for extending tracking of a couple other Init
objects, for example StringInit's are often parsed and it would be good to
point inside the string when reporting errors about that. However, location
tracking also harms de-duplication. This is fine for CodeInit where there's
only a few hundred of them (~160 for X86) and it may be worth it for
StringInit (~86k up to ~1.9M for roughly 15MB increase for X86).
However the origin tracking would be a _terrible_ idea for IntInit, BitInit,
and UnsetInit. I haven't measured either of those three but BitInit would
most likely be on the order of increasing the current 2 BitInit values up
to billions.
Reviewers: volkan, aditya_nandakumar, bogner, paquette, aemerson
Reviewed By: paquette
Subscribers: javed.absar, kristof.beyls, dexonsmith, llvm-commits, kristina
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D58141
llvm-svn: 355245
2019-03-02 08:12:57 +08:00
|
|
|
R = CodeInit::get(Lex.getCurStrVal(), Lex.getLoc());
|
2010-10-06 12:31:40 +08:00
|
|
|
Lex.Lex();
|
|
|
|
break;
|
|
|
|
case tgtok::question:
|
2011-07-30 03:07:07 +08:00
|
|
|
R = UnsetInit::get();
|
2010-10-06 12:31:40 +08:00
|
|
|
Lex.Lex();
|
|
|
|
break;
|
2007-11-23 04:49:04 +08:00
|
|
|
case tgtok::Id: {
|
2009-06-21 11:39:35 +08:00
|
|
|
SMLoc NameLoc = Lex.getLoc();
|
2016-12-05 15:35:13 +08:00
|
|
|
StringInit *Name = StringInit::get(Lex.getCurStrVal());
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Lex.Lex() != tgtok::less) // consume the Id.
|
2011-10-19 21:04:20 +08:00
|
|
|
return ParseIDValue(CurRec, Name, NameLoc, Mode); // Value ::= IDValue
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
// Value ::= ID '<' ValueListNE '>'
|
|
|
|
if (Lex.Lex() == tgtok::greater) {
|
|
|
|
TokError("expected non-empty value list");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
2009-06-09 04:23:18 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
// This is a CLASS<initvalslist> expression. This is supposed to synthesize
|
|
|
|
// a new anonymous definition, deriving from CLASS<initvalslist> with no
|
|
|
|
// body.
|
2016-12-05 15:35:13 +08:00
|
|
|
Record *Class = Records.getClass(Name->getValue());
|
2007-11-23 04:49:04 +08:00
|
|
|
if (!Class) {
|
2016-12-05 15:35:13 +08:00
|
|
|
Error(NameLoc, "Expected a class name, got '" + Name->getValue() + "'");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
2009-06-09 04:23:18 +08:00
|
|
|
|
TableGen: Delay instantiating inline anonymous records
Summary:
Only instantiate anonymous records once all variable references in template
arguments have been resolved. This allows patterns like the new test case,
which in practice can appear in expressions like:
class IntrinsicTypeProfile<list<LLVMType> ty, int shift> {
list<LLVMType> types =
!listconcat(ty, [llvm_any_ty, LLVMMatchType<shift>]);
}
class FooIntrinsic<IntrinsicTypeProfile P, ...>
: Intrinsic<..., P.types, ...>;
Without this change, the anonymous LLVMMatchType instantiation would
never get resolved.
Another consequence of this change is that anonymous inline
instantiations are uniqued via the folding set of the newly introduced
VarDefInit.
Change-Id: I7a7041a20e297cf98c9109b28d85e64e176c932a
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D43756
llvm-svn: 326788
2018-03-06 21:49:01 +08:00
|
|
|
SmallVector<Init *, 8> Args;
|
|
|
|
ParseValueList(Args, CurRec, Class);
|
|
|
|
if (Args.empty()) return nullptr;
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2009-06-09 04:23:18 +08:00
|
|
|
if (Lex.getCode() != tgtok::greater) {
|
|
|
|
TokError("expected '>' at end of value list");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-06-09 04:23:18 +08:00
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the '>'
|
TableGen: Delay instantiating inline anonymous records
Summary:
Only instantiate anonymous records once all variable references in template
arguments have been resolved. This allows patterns like the new test case,
which in practice can appear in expressions like:
class IntrinsicTypeProfile<list<LLVMType> ty, int shift> {
list<LLVMType> types =
!listconcat(ty, [llvm_any_ty, LLVMMatchType<shift>]);
}
class FooIntrinsic<IntrinsicTypeProfile P, ...>
: Intrinsic<..., P.types, ...>;
Without this change, the anonymous LLVMMatchType instantiation would
never get resolved.
Another consequence of this change is that anonymous inline
instantiations are uniqued via the folding set of the newly introduced
VarDefInit.
Change-Id: I7a7041a20e297cf98c9109b28d85e64e176c932a
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D43756
llvm-svn: 326788
2018-03-06 21:49:01 +08:00
|
|
|
|
|
|
|
// Typecheck the template arguments list
|
|
|
|
ArrayRef<Init *> ExpectedArgs = Class->getTemplateArgs();
|
|
|
|
if (ExpectedArgs.size() < Args.size()) {
|
|
|
|
Error(NameLoc,
|
|
|
|
"More template args specified than expected");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
TableGen: Delay instantiating inline anonymous records
Summary:
Only instantiate anonymous records once all variable references in template
arguments have been resolved. This allows patterns like the new test case,
which in practice can appear in expressions like:
class IntrinsicTypeProfile<list<LLVMType> ty, int shift> {
list<LLVMType> types =
!listconcat(ty, [llvm_any_ty, LLVMMatchType<shift>]);
}
class FooIntrinsic<IntrinsicTypeProfile P, ...>
: Intrinsic<..., P.types, ...>;
Without this change, the anonymous LLVMMatchType instantiation would
never get resolved.
Another consequence of this change is that anonymous inline
instantiations are uniqued via the folding set of the newly introduced
VarDefInit.
Change-Id: I7a7041a20e297cf98c9109b28d85e64e176c932a
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D43756
llvm-svn: 326788
2018-03-06 21:49:01 +08:00
|
|
|
}
|
2014-11-29 13:31:10 +08:00
|
|
|
|
TableGen: Delay instantiating inline anonymous records
Summary:
Only instantiate anonymous records once all variable references in template
arguments have been resolved. This allows patterns like the new test case,
which in practice can appear in expressions like:
class IntrinsicTypeProfile<list<LLVMType> ty, int shift> {
list<LLVMType> types =
!listconcat(ty, [llvm_any_ty, LLVMMatchType<shift>]);
}
class FooIntrinsic<IntrinsicTypeProfile P, ...>
: Intrinsic<..., P.types, ...>;
Without this change, the anonymous LLVMMatchType instantiation would
never get resolved.
Another consequence of this change is that anonymous inline
instantiations are uniqued via the folding set of the newly introduced
VarDefInit.
Change-Id: I7a7041a20e297cf98c9109b28d85e64e176c932a
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D43756
llvm-svn: 326788
2018-03-06 21:49:01 +08:00
|
|
|
for (unsigned i = 0, e = ExpectedArgs.size(); i != e; ++i) {
|
|
|
|
RecordVal *ExpectedArg = Class->getValue(ExpectedArgs[i]);
|
|
|
|
if (i < Args.size()) {
|
|
|
|
if (TypedInit *TI = dyn_cast<TypedInit>(Args[i])) {
|
|
|
|
RecTy *ExpectedType = ExpectedArg->getType();
|
|
|
|
if (!TI->getType()->typeIsConvertibleTo(ExpectedType)) {
|
|
|
|
Error(NameLoc,
|
|
|
|
"Value specified for template argument #" + Twine(i) + " (" +
|
|
|
|
ExpectedArg->getNameInitAsString() + ") is of type '" +
|
|
|
|
TI->getType()->getAsString() + "', expected '" +
|
|
|
|
ExpectedType->getAsString() + "': " + TI->getAsString());
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
} else if (ExpectedArg->getValue()->isComplete())
|
|
|
|
continue;
|
[TableGen] Correctly generate implicit anonymous prototype defs in multiclasses
Even within a multiclass, we had been generating concrete implicit anonymous
defs when parsing values (generally in value lists). This behavior was
incorrect, and led to errors when multiclass parameters were used in the
parameter list of the implicit anonymous def.
If we had some multiclass:
multiclass mc<string n> {
... : SomeClass<SomeOtherClass<n> >
The capture of the multiclass parameter 'n' would not work correctly, and
depending on how the implicit SomeOtherClass was used, either TableGen would
ignore something it shouldn't, or would crash.
To fix this problem, when inside a multiclass, we generate prototype anonymous
defs for implicit anonymous defs (just as we do for explicit anonymous defs).
Within the multiclass, the current record prototype is populated with a node
that is essentially: !cast<SomeOtherClass>(!strconcat(NAME, anon_value_name)).
This is then resolved to the correct concrete anonymous def, in the usual way,
when NAME is resolved during multiclass instantiation.
llvm-svn: 198348
2014-01-03 04:47:09 +08:00
|
|
|
|
TableGen: Delay instantiating inline anonymous records
Summary:
Only instantiate anonymous records once all variable references in template
arguments have been resolved. This allows patterns like the new test case,
which in practice can appear in expressions like:
class IntrinsicTypeProfile<list<LLVMType> ty, int shift> {
list<LLVMType> types =
!listconcat(ty, [llvm_any_ty, LLVMMatchType<shift>]);
}
class FooIntrinsic<IntrinsicTypeProfile P, ...>
: Intrinsic<..., P.types, ...>;
Without this change, the anonymous LLVMMatchType instantiation would
never get resolved.
Another consequence of this change is that anonymous inline
instantiations are uniqued via the folding set of the newly introduced
VarDefInit.
Change-Id: I7a7041a20e297cf98c9109b28d85e64e176c932a
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D43756
llvm-svn: 326788
2018-03-06 21:49:01 +08:00
|
|
|
Error(NameLoc,
|
|
|
|
"Value not specified for template argument #" + Twine(i) + " (" +
|
|
|
|
ExpectedArgs[i]->getAsUnquotedString() + ")");
|
|
|
|
return nullptr;
|
[TableGen] Correctly generate implicit anonymous prototype defs in multiclasses
Even within a multiclass, we had been generating concrete implicit anonymous
defs when parsing values (generally in value lists). This behavior was
incorrect, and led to errors when multiclass parameters were used in the
parameter list of the implicit anonymous def.
If we had some multiclass:
multiclass mc<string n> {
... : SomeClass<SomeOtherClass<n> >
The capture of the multiclass parameter 'n' would not work correctly, and
depending on how the implicit SomeOtherClass was used, either TableGen would
ignore something it shouldn't, or would crash.
To fix this problem, when inside a multiclass, we generate prototype anonymous
defs for implicit anonymous defs (just as we do for explicit anonymous defs).
Within the multiclass, the current record prototype is populated with a node
that is essentially: !cast<SomeOtherClass>(!strconcat(NAME, anon_value_name)).
This is then resolved to the correct concrete anonymous def, in the usual way,
when NAME is resolved during multiclass instantiation.
llvm-svn: 198348
2014-01-03 04:47:09 +08:00
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
TableGen: Delay instantiating inline anonymous records
Summary:
Only instantiate anonymous records once all variable references in template
arguments have been resolved. This allows patterns like the new test case,
which in practice can appear in expressions like:
class IntrinsicTypeProfile<list<LLVMType> ty, int shift> {
list<LLVMType> types =
!listconcat(ty, [llvm_any_ty, LLVMMatchType<shift>]);
}
class FooIntrinsic<IntrinsicTypeProfile P, ...>
: Intrinsic<..., P.types, ...>;
Without this change, the anonymous LLVMMatchType instantiation would
never get resolved.
Another consequence of this change is that anonymous inline
instantiations are uniqued via the folding set of the newly introduced
VarDefInit.
Change-Id: I7a7041a20e297cf98c9109b28d85e64e176c932a
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D43756
llvm-svn: 326788
2018-03-06 21:49:01 +08:00
|
|
|
return VarDefInit::get(Class, Args)->Fold();
|
2009-11-22 12:24:42 +08:00
|
|
|
}
|
2007-11-23 04:49:04 +08:00
|
|
|
case tgtok::l_brace: { // Value ::= '{' ValueList '}'
|
2009-06-21 11:39:35 +08:00
|
|
|
SMLoc BraceLoc = Lex.getLoc();
|
2007-11-23 04:49:04 +08:00
|
|
|
Lex.Lex(); // eat the '{'
|
2016-12-05 14:41:54 +08:00
|
|
|
SmallVector<Init*, 16> Vals;
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Lex.getCode() != tgtok::r_brace) {
|
2016-12-05 14:41:54 +08:00
|
|
|
ParseValueList(Vals, CurRec);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (Vals.empty()) return nullptr;
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
if (Lex.getCode() != tgtok::r_brace) {
|
|
|
|
TokError("expected '}' at end of bit list value");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the '}'
|
2009-11-22 12:24:42 +08:00
|
|
|
|
Change the { } expression in tablegen to accept sized binary literals which are not just 0 and 1.
It also allows nested { } expressions, as now that they are sized, we can merge pull bits from the nested value.
In the current behaviour, everything in { } must have been convertible to a single bit.
However, now that binary literals are sized, its useful to be able to initialize a range of bits.
So, for example, its now possible to do
bits<8> x = { 0, 1, { 0b1001 }, 0, 0b0 }
llvm-svn: 215086
2014-08-07 13:47:07 +08:00
|
|
|
SmallVector<Init *, 16> NewBits;
|
2011-07-30 03:07:00 +08:00
|
|
|
|
Change the { } expression in tablegen to accept sized binary literals which are not just 0 and 1.
It also allows nested { } expressions, as now that they are sized, we can merge pull bits from the nested value.
In the current behaviour, everything in { } must have been convertible to a single bit.
However, now that binary literals are sized, its useful to be able to initialize a range of bits.
So, for example, its now possible to do
bits<8> x = { 0, 1, { 0b1001 }, 0, 0b0 }
llvm-svn: 215086
2014-08-07 13:47:07 +08:00
|
|
|
// As we parse { a, b, ... }, 'a' is the highest bit, but we parse it
|
|
|
|
// first. We'll first read everything in to a vector, then we can reverse
|
|
|
|
// it to get the bits in the correct order for the BitsInit value.
|
2007-11-23 04:49:04 +08:00
|
|
|
for (unsigned i = 0, e = Vals.size(); i != e; ++i) {
|
2014-08-30 06:43:30 +08:00
|
|
|
// FIXME: The following two loops would not be duplicated
|
|
|
|
// if the API was a little more orthogonal.
|
|
|
|
|
Change the { } expression in tablegen to accept sized binary literals which are not just 0 and 1.
It also allows nested { } expressions, as now that they are sized, we can merge pull bits from the nested value.
In the current behaviour, everything in { } must have been convertible to a single bit.
However, now that binary literals are sized, its useful to be able to initialize a range of bits.
So, for example, its now possible to do
bits<8> x = { 0, 1, { 0b1001 }, 0, 0b0 }
llvm-svn: 215086
2014-08-07 13:47:07 +08:00
|
|
|
// bits<n> values are allowed to initialize n bits.
|
|
|
|
if (BitsInit *BI = dyn_cast<BitsInit>(Vals[i])) {
|
|
|
|
for (unsigned i = 0, e = BI->getNumBits(); i != e; ++i)
|
|
|
|
NewBits.push_back(BI->getBit((e - i) - 1));
|
|
|
|
continue;
|
|
|
|
}
|
2014-08-30 03:41:04 +08:00
|
|
|
// bits<n> can also come from variable initializers.
|
|
|
|
if (VarInit *VI = dyn_cast<VarInit>(Vals[i])) {
|
|
|
|
if (BitsRecTy *BitsRec = dyn_cast<BitsRecTy>(VI->getType())) {
|
|
|
|
for (unsigned i = 0, e = BitsRec->getNumBits(); i != e; ++i)
|
|
|
|
NewBits.push_back(VI->getBit((e - i) - 1));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// Fallthrough to try convert this to a bit.
|
|
|
|
}
|
Change the { } expression in tablegen to accept sized binary literals which are not just 0 and 1.
It also allows nested { } expressions, as now that they are sized, we can merge pull bits from the nested value.
In the current behaviour, everything in { } must have been convertible to a single bit.
However, now that binary literals are sized, its useful to be able to initialize a range of bits.
So, for example, its now possible to do
bits<8> x = { 0, 1, { 0b1001 }, 0, 0b0 }
llvm-svn: 215086
2014-08-07 13:47:07 +08:00
|
|
|
// All other values must be convertible to just a single bit.
|
TableGen: Allow !cast of records, cleanup conversion machinery
Summary:
Distinguish two relationships between types: is-a and convertible-to.
For example, a bit is not an int or vice versa, but they can be
converted into each other (with range checks that you can think of
as "dynamic": unlike other type checks, those range checks do not
happen during parsing, but only once the final values have been
established).
Actually converting initializers between types is subtle: even
when values of type A can be converted to type B (e.g. int into
string), it may not be possible to do so with a concrete initializer
(e.g., a VarInit that refers to a variable of type int cannot
be immediately converted to a string).
For this reason, distinguish between getCastTo and convertInitializerTo:
the latter implements the actual conversion when appropriate, while
the former will first try to do the actual conversion and fall back
to introducing a !cast operation so that the conversion will be
delayed until variable references have been resolved.
To make the approach of adding !cast operations to work, !cast needs
to fallback to convertInitializerTo when the special string <-> record
logic does not apply.
This enables casting records to a subclass, although that new
functionality is only truly useful together with !isa, which will be
added in a later change.
The test is removed because it uses !srl on a bit sequence,
which cannot really be supported consistently, but luckily
isn't used anywhere either.
Change-Id: I98168bf52649176654ed2ec61a29bdb29970cfe7
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D43753
llvm-svn: 326785
2018-03-06 21:48:39 +08:00
|
|
|
Init *Bit = Vals[i]->getCastTo(BitRecTy::get());
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!Bit) {
|
2015-05-28 19:24:24 +08:00
|
|
|
Error(BraceLoc, "Element #" + Twine(i) + " (" + Vals[i]->getAsString() +
|
2007-11-23 05:06:59 +08:00
|
|
|
") is not convertable to a bit");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
Change the { } expression in tablegen to accept sized binary literals which are not just 0 and 1.
It also allows nested { } expressions, as now that they are sized, we can merge pull bits from the nested value.
In the current behaviour, everything in { } must have been convertible to a single bit.
However, now that binary literals are sized, its useful to be able to initialize a range of bits.
So, for example, its now possible to do
bits<8> x = { 0, 1, { 0b1001 }, 0, 0b0 }
llvm-svn: 215086
2014-08-07 13:47:07 +08:00
|
|
|
NewBits.push_back(Bit);
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
Change the { } expression in tablegen to accept sized binary literals which are not just 0 and 1.
It also allows nested { } expressions, as now that they are sized, we can merge pull bits from the nested value.
In the current behaviour, everything in { } must have been convertible to a single bit.
However, now that binary literals are sized, its useful to be able to initialize a range of bits.
So, for example, its now possible to do
bits<8> x = { 0, 1, { 0b1001 }, 0, 0b0 }
llvm-svn: 215086
2014-08-07 13:47:07 +08:00
|
|
|
std::reverse(NewBits.begin(), NewBits.end());
|
2011-07-30 03:07:07 +08:00
|
|
|
return BitsInit::get(NewBits);
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
case tgtok::l_square: { // Value ::= '[' ValueList ']'
|
|
|
|
Lex.Lex(); // eat the '['
|
2016-12-05 14:41:54 +08:00
|
|
|
SmallVector<Init*, 16> Vals;
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2014-04-09 12:50:04 +08:00
|
|
|
RecTy *DeducedEltTy = nullptr;
|
|
|
|
ListRecTy *GivenListTy = nullptr;
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2014-04-09 12:50:04 +08:00
|
|
|
if (ItemType) {
|
2012-10-05 11:31:58 +08:00
|
|
|
ListRecTy *ListType = dyn_cast<ListRecTy>(ItemType);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!ListType) {
|
2015-05-28 19:24:24 +08:00
|
|
|
TokError(Twine("Type mismatch for list, expected list type, got ") +
|
|
|
|
ItemType->getAsString());
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-06-09 04:23:18 +08:00
|
|
|
}
|
|
|
|
GivenListTy = ListType;
|
2009-11-22 12:24:42 +08:00
|
|
|
}
|
2009-06-09 04:23:18 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Lex.getCode() != tgtok::r_square) {
|
2016-12-05 14:41:54 +08:00
|
|
|
ParseValueList(Vals, CurRec, nullptr,
|
|
|
|
GivenListTy ? GivenListTy->getElementType() : nullptr);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (Vals.empty()) return nullptr;
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
if (Lex.getCode() != tgtok::r_square) {
|
|
|
|
TokError("expected ']' at end of list value");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the ']'
|
2009-06-09 04:23:18 +08:00
|
|
|
|
2014-04-09 12:50:04 +08:00
|
|
|
RecTy *GivenEltTy = nullptr;
|
2009-06-09 04:23:18 +08:00
|
|
|
if (Lex.getCode() == tgtok::less) {
|
|
|
|
// Optional list element type
|
|
|
|
Lex.Lex(); // eat the '<'
|
|
|
|
|
|
|
|
GivenEltTy = ParseType();
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!GivenEltTy) {
|
2009-06-09 04:23:18 +08:00
|
|
|
// Couldn't parse element type
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-06-09 04:23:18 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Lex.getCode() != tgtok::greater) {
|
|
|
|
TokError("expected '>' at end of list element type");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-06-09 04:23:18 +08:00
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the '>'
|
|
|
|
}
|
|
|
|
|
|
|
|
// Check elements
|
2014-04-09 12:50:04 +08:00
|
|
|
RecTy *EltTy = nullptr;
|
2015-04-29 12:43:36 +08:00
|
|
|
for (Init *V : Vals) {
|
|
|
|
TypedInit *TArg = dyn_cast<TypedInit>(V);
|
2018-03-14 19:00:33 +08:00
|
|
|
if (TArg) {
|
|
|
|
if (EltTy) {
|
|
|
|
EltTy = resolveTypes(EltTy, TArg->getType());
|
|
|
|
if (!EltTy) {
|
|
|
|
TokError("Incompatible types in list elements");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
EltTy = TArg->getType();
|
2009-06-09 04:23:18 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-04-09 12:50:04 +08:00
|
|
|
if (GivenEltTy) {
|
|
|
|
if (EltTy) {
|
2009-06-09 04:23:18 +08:00
|
|
|
// Verify consistency
|
|
|
|
if (!EltTy->typeIsConvertibleTo(GivenEltTy)) {
|
|
|
|
TokError("Incompatible types in list elements");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-06-09 04:23:18 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
EltTy = GivenEltTy;
|
|
|
|
}
|
|
|
|
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!EltTy) {
|
|
|
|
if (!ItemType) {
|
2009-06-09 04:23:18 +08:00
|
|
|
TokError("No type for list");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-06-09 04:23:18 +08:00
|
|
|
}
|
|
|
|
DeducedEltTy = GivenListTy->getElementType();
|
2009-11-22 12:24:42 +08:00
|
|
|
} else {
|
2009-06-09 04:23:18 +08:00
|
|
|
// Make sure the deduced type is compatible with the given type
|
|
|
|
if (GivenListTy) {
|
|
|
|
if (!EltTy->typeIsConvertibleTo(GivenListTy->getElementType())) {
|
2018-02-22 23:26:21 +08:00
|
|
|
TokError(Twine("Element type mismatch for list: element type '") +
|
|
|
|
EltTy->getAsString() + "' not convertible to '" +
|
|
|
|
GivenListTy->getElementType()->getAsString());
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-06-09 04:23:18 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
DeducedEltTy = EltTy;
|
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2011-07-30 03:07:07 +08:00
|
|
|
return ListInit::get(Vals, DeducedEltTy);
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
case tgtok::l_paren: { // Value ::= '(' IDValue DagArgList ')'
|
|
|
|
Lex.Lex(); // eat the '('
|
[TableGen] Permit dag operators to be unset.
This is not a new semantic feature. The syntax `(? 1, 2, 3)` was
disallowed by the parser in a dag //expression//, but there were
already ways to sneak a `?` into the operator field of a dag
//value//, e.g. by initializing it from a class template parameter
which is then set to `?` by the instantiating `def`.
This patch makes `?` in the operator slot syntactically legal, so it's
now easy to construct dags with an unset operator. Also, the semantics
of `!con` are relaxed so that it will allow a combination of set and
unset operator fields in the dag nodes it's concatenating, with the
restriction that all the operators that are //not// unset still have
to agree with each other.
Reviewers: hfinkel, nhaehnle
Reviewed By: hfinkel, nhaehnle
Subscribers: hiraditya, llvm-commits
Tags: #llvm
Differential Revision: https://reviews.llvm.org/D71195
2019-12-10 18:34:40 +08:00
|
|
|
if (Lex.getCode() != tgtok::Id && Lex.getCode() != tgtok::XCast &&
|
2019-12-11 20:02:15 +08:00
|
|
|
Lex.getCode() != tgtok::question && Lex.getCode() != tgtok::XGetOp) {
|
2008-04-10 12:48:34 +08:00
|
|
|
TokError("expected identifier in dag init");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2008-04-10 12:48:34 +08:00
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2011-07-30 06:43:06 +08:00
|
|
|
Init *Operator = ParseValue(CurRec);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!Operator) return nullptr;
|
2009-04-23 04:18:10 +08:00
|
|
|
|
2009-03-19 13:21:56 +08:00
|
|
|
// If the operator name is present, parse it.
|
2016-12-05 14:00:41 +08:00
|
|
|
StringInit *OperatorName = nullptr;
|
2009-03-19 13:21:56 +08:00
|
|
|
if (Lex.getCode() == tgtok::colon) {
|
|
|
|
if (Lex.Lex() != tgtok::VarName) { // eat the ':'
|
|
|
|
TokError("expected variable name in dag operator");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-03-19 13:21:56 +08:00
|
|
|
}
|
2016-12-05 14:00:41 +08:00
|
|
|
OperatorName = StringInit::get(Lex.getCurStrVal());
|
2009-03-19 13:21:56 +08:00
|
|
|
Lex.Lex(); // eat the VarName.
|
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2016-12-05 14:41:51 +08:00
|
|
|
SmallVector<std::pair<llvm::Init*, StringInit*>, 8> DagArgs;
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Lex.getCode() != tgtok::r_paren) {
|
2016-12-05 14:41:51 +08:00
|
|
|
ParseDagArgList(DagArgs, CurRec);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (DagArgs.empty()) return nullptr;
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Lex.getCode() != tgtok::r_paren) {
|
|
|
|
TokError("expected ')' in dag init");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the ')'
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2011-07-30 03:07:07 +08:00
|
|
|
return DagInit::get(Operator, OperatorName, DagArgs);
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2011-01-08 01:05:37 +08:00
|
|
|
case tgtok::XHead:
|
|
|
|
case tgtok::XTail:
|
2018-02-23 18:46:07 +08:00
|
|
|
case tgtok::XSize:
|
2011-01-08 01:05:37 +08:00
|
|
|
case tgtok::XEmpty:
|
2019-12-11 20:02:15 +08:00
|
|
|
case tgtok::XCast:
|
|
|
|
case tgtok::XGetOp: // Value ::= !unop '(' Value ')'
|
2018-03-09 20:24:06 +08:00
|
|
|
case tgtok::XIsA:
|
2007-11-23 04:49:04 +08:00
|
|
|
case tgtok::XConcat:
|
2018-03-14 19:00:26 +08:00
|
|
|
case tgtok::XDag:
|
2013-01-25 22:49:08 +08:00
|
|
|
case tgtok::XADD:
|
2019-03-01 17:46:29 +08:00
|
|
|
case tgtok::XMUL:
|
2014-08-05 17:43:25 +08:00
|
|
|
case tgtok::XAND:
|
2016-11-15 14:49:28 +08:00
|
|
|
case tgtok::XOR:
|
2009-11-22 12:24:42 +08:00
|
|
|
case tgtok::XSRA:
|
2007-11-23 04:49:04 +08:00
|
|
|
case tgtok::XSRL:
|
|
|
|
case tgtok::XSHL:
|
2010-01-06 03:11:42 +08:00
|
|
|
case tgtok::XEq:
|
2018-03-14 19:00:57 +08:00
|
|
|
case tgtok::XNe:
|
|
|
|
case tgtok::XLe:
|
|
|
|
case tgtok::XLt:
|
|
|
|
case tgtok::XGe:
|
|
|
|
case tgtok::XGt:
|
2014-05-07 18:13:19 +08:00
|
|
|
case tgtok::XListConcat:
|
2019-04-11 02:26:36 +08:00
|
|
|
case tgtok::XListSplat:
|
2019-12-11 20:02:15 +08:00
|
|
|
case tgtok::XStrConcat:
|
|
|
|
case tgtok::XSetOp: // Value ::= !binop '(' Value ',' Value ')'
|
2009-05-15 07:26:46 +08:00
|
|
|
case tgtok::XIf:
|
2019-01-25 18:25:25 +08:00
|
|
|
case tgtok::XCond:
|
2018-03-06 21:49:16 +08:00
|
|
|
case tgtok::XFoldl:
|
2009-05-15 06:23:47 +08:00
|
|
|
case tgtok::XForEach:
|
2009-05-15 05:54:42 +08:00
|
|
|
case tgtok::XSubst: { // Value ::= !ternop '(' Value ',' Value ',' Value ')'
|
2014-06-11 04:10:08 +08:00
|
|
|
return ParseOperation(CurRec, ItemType);
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
return R;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseValue - Parse a tblgen value. This returns null on error.
|
|
|
|
///
|
|
|
|
/// Value ::= SimpleValue ValueSuffix*
|
|
|
|
/// ValueSuffix ::= '{' BitList '}'
|
|
|
|
/// ValueSuffix ::= '[' BitList ']'
|
|
|
|
/// ValueSuffix ::= '.' ID
|
|
|
|
///
|
2011-10-19 21:04:20 +08:00
|
|
|
Init *TGParser::ParseValue(Record *CurRec, RecTy *ItemType, IDParseMode Mode) {
|
|
|
|
Init *Result = ParseSimpleValue(CurRec, ItemType, Mode);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!Result) return nullptr;
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
// Parse the suffixes now if present.
|
2016-08-24 01:14:32 +08:00
|
|
|
while (true) {
|
2007-11-23 04:49:04 +08:00
|
|
|
switch (Lex.getCode()) {
|
|
|
|
default: return Result;
|
|
|
|
case tgtok::l_brace: {
|
2018-03-09 20:24:20 +08:00
|
|
|
if (Mode == ParseNameMode)
|
2011-10-19 21:04:26 +08:00
|
|
|
// This is the beginning of the object body.
|
|
|
|
return Result;
|
|
|
|
|
2009-06-21 11:39:35 +08:00
|
|
|
SMLoc CurlyLoc = Lex.getLoc();
|
2007-11-23 04:49:04 +08:00
|
|
|
Lex.Lex(); // eat the '{'
|
2016-12-05 14:41:54 +08:00
|
|
|
SmallVector<unsigned, 16> Ranges;
|
|
|
|
ParseRangeList(Ranges);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (Ranges.empty()) return nullptr;
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
// Reverse the bitlist.
|
|
|
|
std::reverse(Ranges.begin(), Ranges.end());
|
|
|
|
Result = Result->convertInitializerBitRange(Ranges);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!Result) {
|
2007-11-23 04:49:04 +08:00
|
|
|
Error(CurlyLoc, "Invalid bit range for value");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
// Eat the '}'.
|
|
|
|
if (Lex.getCode() != tgtok::r_brace) {
|
|
|
|
TokError("expected '}' at end of bit range list");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
Lex.Lex();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case tgtok::l_square: {
|
2009-06-21 11:39:35 +08:00
|
|
|
SMLoc SquareLoc = Lex.getLoc();
|
2007-11-23 04:49:04 +08:00
|
|
|
Lex.Lex(); // eat the '['
|
2016-12-05 14:41:54 +08:00
|
|
|
SmallVector<unsigned, 16> Ranges;
|
|
|
|
ParseRangeList(Ranges);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (Ranges.empty()) return nullptr;
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
Result = Result->convertInitListSlice(Ranges);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!Result) {
|
2007-11-23 04:49:04 +08:00
|
|
|
Error(SquareLoc, "Invalid range for list slice");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
// Eat the ']'.
|
|
|
|
if (Lex.getCode() != tgtok::r_square) {
|
|
|
|
TokError("expected ']' at end of list slice");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
Lex.Lex();
|
|
|
|
break;
|
|
|
|
}
|
2016-12-05 14:00:36 +08:00
|
|
|
case tgtok::period: {
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Lex.Lex() != tgtok::Id) { // eat the .
|
|
|
|
TokError("expected field identifier after '.'");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
2016-12-05 14:00:36 +08:00
|
|
|
StringInit *FieldName = StringInit::get(Lex.getCurStrVal());
|
|
|
|
if (!Result->getFieldType(FieldName)) {
|
2007-11-23 04:49:04 +08:00
|
|
|
TokError("Cannot access field '" + Lex.getCurStrVal() + "' of value '" +
|
2007-11-23 05:06:59 +08:00
|
|
|
Result->getAsString() + "'");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
2018-03-19 22:14:28 +08:00
|
|
|
Result = FieldInit::get(Result, FieldName)->Fold(CurRec);
|
2007-11-23 04:49:04 +08:00
|
|
|
Lex.Lex(); // eat field name
|
|
|
|
break;
|
2016-12-05 14:00:36 +08:00
|
|
|
}
|
2011-10-19 21:04:43 +08:00
|
|
|
|
|
|
|
case tgtok::paste:
|
|
|
|
SMLoc PasteLoc = Lex.getLoc();
|
2012-10-11 04:24:43 +08:00
|
|
|
TypedInit *LHS = dyn_cast<TypedInit>(Result);
|
2011-10-19 21:04:43 +08:00
|
|
|
if (!LHS) {
|
|
|
|
Error(PasteLoc, "LHS of paste is not typed!");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2011-10-19 21:04:43 +08:00
|
|
|
}
|
2015-05-04 09:35:39 +08:00
|
|
|
|
2019-03-06 01:16:07 +08:00
|
|
|
// Check if it's a 'listA # listB'
|
|
|
|
if (isa<ListRecTy>(LHS->getType())) {
|
|
|
|
Lex.Lex(); // Eat the '#'.
|
|
|
|
|
|
|
|
switch (Lex.getCode()) {
|
|
|
|
case tgtok::colon:
|
|
|
|
case tgtok::semi:
|
|
|
|
case tgtok::l_brace:
|
|
|
|
Result = LHS; // trailing paste, ignore.
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
Init *RHSResult = ParseValue(CurRec, ItemType, ParseNameMode);
|
|
|
|
Result = BinOpInit::getListConcat(LHS, RHSResult);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Create a !strconcat() operation, first casting each operand to
|
|
|
|
// a string if necessary.
|
2011-10-19 21:04:43 +08:00
|
|
|
if (LHS->getType() != StringRecTy::get()) {
|
2019-04-30 21:09:55 +08:00
|
|
|
auto CastLHS = dyn_cast<TypedInit>(
|
2018-03-19 22:14:04 +08:00
|
|
|
UnOpInit::get(UnOpInit::CAST, LHS, StringRecTy::get())
|
|
|
|
->Fold(CurRec));
|
2019-04-30 21:09:55 +08:00
|
|
|
if (!CastLHS) {
|
|
|
|
Error(PasteLoc,
|
|
|
|
Twine("can't cast '") + LHS->getAsString() + "' to string");
|
2018-03-19 22:14:04 +08:00
|
|
|
return nullptr;
|
|
|
|
}
|
2019-04-30 21:09:55 +08:00
|
|
|
LHS = CastLHS;
|
2011-10-19 21:04:43 +08:00
|
|
|
}
|
|
|
|
|
2014-04-09 12:50:04 +08:00
|
|
|
TypedInit *RHS = nullptr;
|
2011-10-19 21:04:43 +08:00
|
|
|
|
|
|
|
Lex.Lex(); // Eat the '#'.
|
2018-03-06 21:49:16 +08:00
|
|
|
switch (Lex.getCode()) {
|
2011-10-19 21:04:43 +08:00
|
|
|
case tgtok::colon:
|
|
|
|
case tgtok::semi:
|
|
|
|
case tgtok::l_brace:
|
|
|
|
// These are all of the tokens that can begin an object body.
|
|
|
|
// Some of these can also begin values but we disallow those cases
|
|
|
|
// because they are unlikely to be useful.
|
2015-05-04 09:35:39 +08:00
|
|
|
|
2011-10-19 21:04:43 +08:00
|
|
|
// Trailing paste, concat with an empty string.
|
|
|
|
RHS = StringInit::get("");
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
2018-03-14 19:00:43 +08:00
|
|
|
Init *RHSResult = ParseValue(CurRec, nullptr, ParseNameMode);
|
2012-10-11 04:24:43 +08:00
|
|
|
RHS = dyn_cast<TypedInit>(RHSResult);
|
2011-10-19 21:04:43 +08:00
|
|
|
if (!RHS) {
|
|
|
|
Error(PasteLoc, "RHS of paste is not typed!");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2011-10-19 21:04:43 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (RHS->getType() != StringRecTy::get()) {
|
2019-04-30 21:09:55 +08:00
|
|
|
auto CastRHS = dyn_cast<TypedInit>(
|
2018-03-19 22:14:04 +08:00
|
|
|
UnOpInit::get(UnOpInit::CAST, RHS, StringRecTy::get())
|
|
|
|
->Fold(CurRec));
|
2019-04-30 21:09:55 +08:00
|
|
|
if (!CastRHS) {
|
|
|
|
Error(PasteLoc,
|
|
|
|
Twine("can't cast '") + RHS->getAsString() + "' to string");
|
2018-03-19 22:14:04 +08:00
|
|
|
return nullptr;
|
|
|
|
}
|
2019-04-30 21:09:55 +08:00
|
|
|
RHS = CastRHS;
|
2011-10-19 21:04:43 +08:00
|
|
|
}
|
2015-05-04 09:35:39 +08:00
|
|
|
|
2011-10-19 21:04:43 +08:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
2018-03-19 22:13:54 +08:00
|
|
|
Result = BinOpInit::getStrConcat(LHS, RHS);
|
2011-10-19 21:04:43 +08:00
|
|
|
break;
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseDagArgList - Parse the argument list for a dag literal expression.
|
|
|
|
///
|
Allow TableGen DAG arguments to be just a name.
DAG arguments can optionally be named:
(dag node, node:$name)
With this change, the node is also optional:
(dag node, node:$name, $name)
The missing node is treated as an UnsetInit, so the above is equivalent
to:
(dag node, node:$name, ?:$name)
This syntax is useful in output patterns where we currently require the
types of variables to be repeated:
def : Pat<(subc i32:$b, i32:$c), (SUBCCrr i32:$b, i32:$c)>;
This is preferable:
def : Pat<(subc i32:$b, i32:$c), (SUBCCrr $b, $c)>;
llvm-svn: 177843
2013-03-25 03:36:51 +08:00
|
|
|
/// DagArg ::= Value (':' VARNAME)?
|
|
|
|
/// DagArg ::= VARNAME
|
|
|
|
/// DagArgList ::= DagArg
|
|
|
|
/// DagArgList ::= DagArgList ',' DagArg
|
2016-12-05 14:41:51 +08:00
|
|
|
void TGParser::ParseDagArgList(
|
|
|
|
SmallVectorImpl<std::pair<llvm::Init*, StringInit*>> &Result,
|
|
|
|
Record *CurRec) {
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2016-08-24 01:14:32 +08:00
|
|
|
while (true) {
|
Allow TableGen DAG arguments to be just a name.
DAG arguments can optionally be named:
(dag node, node:$name)
With this change, the node is also optional:
(dag node, node:$name, $name)
The missing node is treated as an UnsetInit, so the above is equivalent
to:
(dag node, node:$name, ?:$name)
This syntax is useful in output patterns where we currently require the
types of variables to be repeated:
def : Pat<(subc i32:$b, i32:$c), (SUBCCrr i32:$b, i32:$c)>;
This is preferable:
def : Pat<(subc i32:$b, i32:$c), (SUBCCrr $b, $c)>;
llvm-svn: 177843
2013-03-25 03:36:51 +08:00
|
|
|
// DagArg ::= VARNAME
|
|
|
|
if (Lex.getCode() == tgtok::VarName) {
|
|
|
|
// A missing value is treated like '?'.
|
2016-12-05 14:00:46 +08:00
|
|
|
StringInit *VarName = StringInit::get(Lex.getCurStrVal());
|
|
|
|
Result.emplace_back(UnsetInit::get(), VarName);
|
Allow TableGen DAG arguments to be just a name.
DAG arguments can optionally be named:
(dag node, node:$name)
With this change, the node is also optional:
(dag node, node:$name, $name)
The missing node is treated as an UnsetInit, so the above is equivalent
to:
(dag node, node:$name, ?:$name)
This syntax is useful in output patterns where we currently require the
types of variables to be repeated:
def : Pat<(subc i32:$b, i32:$c), (SUBCCrr i32:$b, i32:$c)>;
This is preferable:
def : Pat<(subc i32:$b, i32:$c), (SUBCCrr $b, $c)>;
llvm-svn: 177843
2013-03-25 03:36:51 +08:00
|
|
|
Lex.Lex();
|
|
|
|
} else {
|
|
|
|
// DagArg ::= Value (':' VARNAME)?
|
|
|
|
Init *Val = ParseValue(CurRec);
|
2016-12-05 14:41:51 +08:00
|
|
|
if (!Val) {
|
|
|
|
Result.clear();
|
|
|
|
return;
|
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
Allow TableGen DAG arguments to be just a name.
DAG arguments can optionally be named:
(dag node, node:$name)
With this change, the node is also optional:
(dag node, node:$name, $name)
The missing node is treated as an UnsetInit, so the above is equivalent
to:
(dag node, node:$name, ?:$name)
This syntax is useful in output patterns where we currently require the
types of variables to be repeated:
def : Pat<(subc i32:$b, i32:$c), (SUBCCrr i32:$b, i32:$c)>;
This is preferable:
def : Pat<(subc i32:$b, i32:$c), (SUBCCrr $b, $c)>;
llvm-svn: 177843
2013-03-25 03:36:51 +08:00
|
|
|
// If the variable name is present, add it.
|
2016-12-05 14:00:46 +08:00
|
|
|
StringInit *VarName = nullptr;
|
Allow TableGen DAG arguments to be just a name.
DAG arguments can optionally be named:
(dag node, node:$name)
With this change, the node is also optional:
(dag node, node:$name, $name)
The missing node is treated as an UnsetInit, so the above is equivalent
to:
(dag node, node:$name, ?:$name)
This syntax is useful in output patterns where we currently require the
types of variables to be repeated:
def : Pat<(subc i32:$b, i32:$c), (SUBCCrr i32:$b, i32:$c)>;
This is preferable:
def : Pat<(subc i32:$b, i32:$c), (SUBCCrr $b, $c)>;
llvm-svn: 177843
2013-03-25 03:36:51 +08:00
|
|
|
if (Lex.getCode() == tgtok::colon) {
|
|
|
|
if (Lex.Lex() != tgtok::VarName) { // eat the ':'
|
|
|
|
TokError("expected variable name in dag literal");
|
2016-12-05 14:41:51 +08:00
|
|
|
Result.clear();
|
|
|
|
return;
|
Allow TableGen DAG arguments to be just a name.
DAG arguments can optionally be named:
(dag node, node:$name)
With this change, the node is also optional:
(dag node, node:$name, $name)
The missing node is treated as an UnsetInit, so the above is equivalent
to:
(dag node, node:$name, ?:$name)
This syntax is useful in output patterns where we currently require the
types of variables to be repeated:
def : Pat<(subc i32:$b, i32:$c), (SUBCCrr i32:$b, i32:$c)>;
This is preferable:
def : Pat<(subc i32:$b, i32:$c), (SUBCCrr $b, $c)>;
llvm-svn: 177843
2013-03-25 03:36:51 +08:00
|
|
|
}
|
2016-12-05 14:00:46 +08:00
|
|
|
VarName = StringInit::get(Lex.getCurStrVal());
|
Allow TableGen DAG arguments to be just a name.
DAG arguments can optionally be named:
(dag node, node:$name)
With this change, the node is also optional:
(dag node, node:$name, $name)
The missing node is treated as an UnsetInit, so the above is equivalent
to:
(dag node, node:$name, ?:$name)
This syntax is useful in output patterns where we currently require the
types of variables to be repeated:
def : Pat<(subc i32:$b, i32:$c), (SUBCCrr i32:$b, i32:$c)>;
This is preferable:
def : Pat<(subc i32:$b, i32:$c), (SUBCCrr $b, $c)>;
llvm-svn: 177843
2013-03-25 03:36:51 +08:00
|
|
|
Lex.Lex(); // eat the VarName.
|
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
Allow TableGen DAG arguments to be just a name.
DAG arguments can optionally be named:
(dag node, node:$name)
With this change, the node is also optional:
(dag node, node:$name, $name)
The missing node is treated as an UnsetInit, so the above is equivalent
to:
(dag node, node:$name, ?:$name)
This syntax is useful in output patterns where we currently require the
types of variables to be repeated:
def : Pat<(subc i32:$b, i32:$c), (SUBCCrr i32:$b, i32:$c)>;
This is preferable:
def : Pat<(subc i32:$b, i32:$c), (SUBCCrr $b, $c)>;
llvm-svn: 177843
2013-03-25 03:36:51 +08:00
|
|
|
Result.push_back(std::make_pair(Val, VarName));
|
|
|
|
}
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Lex.getCode() != tgtok::comma) break;
|
2009-11-22 12:24:42 +08:00
|
|
|
Lex.Lex(); // eat the ','
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseValueList - Parse a comma separated list of values, returning them as a
|
|
|
|
/// vector. Note that this always expects to be able to parse at least one
|
|
|
|
/// value. It returns an empty list if this is not possible.
|
|
|
|
///
|
|
|
|
/// ValueList ::= Value (',' Value)
|
|
|
|
///
|
2016-12-05 14:41:54 +08:00
|
|
|
void TGParser::ParseValueList(SmallVectorImpl<Init*> &Result, Record *CurRec,
|
|
|
|
Record *ArgsRec, RecTy *EltTy) {
|
2009-06-09 04:23:18 +08:00
|
|
|
RecTy *ItemType = EltTy;
|
2009-06-30 03:59:52 +08:00
|
|
|
unsigned int ArgN = 0;
|
2014-04-09 12:50:04 +08:00
|
|
|
if (ArgsRec && !EltTy) {
|
2015-10-24 20:46:45 +08:00
|
|
|
ArrayRef<Init *> TArgs = ArgsRec->getTemplateArgs();
|
2015-01-15 19:41:30 +08:00
|
|
|
if (TArgs.empty()) {
|
2012-01-21 04:02:39 +08:00
|
|
|
TokError("template argument provided to non-template class");
|
2016-12-05 14:41:54 +08:00
|
|
|
Result.clear();
|
|
|
|
return;
|
2012-01-21 04:02:39 +08:00
|
|
|
}
|
2009-06-09 04:23:18 +08:00
|
|
|
const RecordVal *RV = ArgsRec->getValue(TArgs[ArgN]);
|
2011-09-20 02:26:07 +08:00
|
|
|
if (!RV) {
|
|
|
|
errs() << "Cannot find template arg " << ArgN << " (" << TArgs[ArgN]
|
|
|
|
<< ")\n";
|
|
|
|
}
|
2009-06-09 04:23:18 +08:00
|
|
|
assert(RV && "Template argument record not found??");
|
|
|
|
ItemType = RV->getType();
|
|
|
|
++ArgN;
|
|
|
|
}
|
|
|
|
Result.push_back(ParseValue(CurRec, ItemType));
|
2016-12-05 14:41:54 +08:00
|
|
|
if (!Result.back()) {
|
|
|
|
Result.clear();
|
|
|
|
return;
|
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
while (Lex.getCode() == tgtok::comma) {
|
|
|
|
Lex.Lex(); // Eat the comma
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2019-03-26 19:16:01 +08:00
|
|
|
// ignore trailing comma for lists
|
|
|
|
if (Lex.getCode() == tgtok::r_square)
|
|
|
|
return;
|
|
|
|
|
2014-04-09 12:50:04 +08:00
|
|
|
if (ArgsRec && !EltTy) {
|
2015-10-24 20:46:45 +08:00
|
|
|
ArrayRef<Init *> TArgs = ArgsRec->getTemplateArgs();
|
2009-06-30 03:59:52 +08:00
|
|
|
if (ArgN >= TArgs.size()) {
|
|
|
|
TokError("too many template arguments");
|
2016-12-05 14:41:54 +08:00
|
|
|
Result.clear();
|
|
|
|
return;
|
2009-11-22 12:24:42 +08:00
|
|
|
}
|
2009-06-09 04:23:18 +08:00
|
|
|
const RecordVal *RV = ArgsRec->getValue(TArgs[ArgN]);
|
|
|
|
assert(RV && "Template argument record not found??");
|
|
|
|
ItemType = RV->getType();
|
|
|
|
++ArgN;
|
|
|
|
}
|
|
|
|
Result.push_back(ParseValue(CurRec, ItemType));
|
2016-12-05 14:41:54 +08:00
|
|
|
if (!Result.back()) {
|
|
|
|
Result.clear();
|
|
|
|
return;
|
|
|
|
}
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseDeclaration - Read a declaration, returning the name of field ID, or an
|
|
|
|
/// empty string on error. This can happen in a number of different context's,
|
|
|
|
/// including within a def or in the template args for a def (which which case
|
|
|
|
/// CurRec will be non-null) and within the template args for a multiclass (in
|
|
|
|
/// which case CurRec will be null, but CurMultiClass will be set). This can
|
|
|
|
/// also happen within a def that is within a multiclass, which will set both
|
|
|
|
/// CurRec and CurMultiClass.
|
|
|
|
///
|
|
|
|
/// Declaration ::= FIELD? Type ID ('=' Value)?
|
|
|
|
///
|
2011-10-19 21:02:42 +08:00
|
|
|
Init *TGParser::ParseDeclaration(Record *CurRec,
|
2007-11-23 04:49:04 +08:00
|
|
|
bool ParsingTemplateArgs) {
|
|
|
|
// Read the field prefix if present.
|
|
|
|
bool HasField = Lex.getCode() == tgtok::Field;
|
|
|
|
if (HasField) Lex.Lex();
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
RecTy *Type = ParseType();
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!Type) return nullptr;
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Lex.getCode() != tgtok::Id) {
|
|
|
|
TokError("Expected identifier in declaration");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
TableGen: Streamline the semantics of NAME
Summary:
The new rules are straightforward. The main rules to keep in mind
are:
1. NAME is an implicit template argument of class and multiclass,
and will be substituted by the name of the instantiating def/defm.
2. The name of a def/defm in a multiclass must contain a reference
to NAME. If such a reference is not present, it is automatically
prepended.
And for some additional subtleties, consider these:
3. defm with no name generates a unique name but has no special
behavior otherwise.
4. def with no name generates an anonymous record, whose name is
unique but undefined. In particular, the name won't contain a
reference to NAME.
Keeping rules 1&2 in mind should allow a predictable behavior of
name resolution that is simple to follow.
The old "rules" were rather surprising: sometimes (but not always),
NAME would correspond to the name of the toplevel defm. They were
also plain bonkers when you pushed them to their limits, as the old
version of the TableGen test case shows.
Having NAME correspond to the name of the toplevel defm introduces
"spooky action at a distance" and breaks composability:
refactoring the upper layers of a hierarchy of nested multiclass
instantiations can cause unexpected breakage by changing the value
of NAME at a lower level of the hierarchy. The new rules don't
suffer from this problem.
Some existing .td files have to be adjusted because they ended up
depending on the details of the old implementation.
Change-Id: I694095231565b30f563e6fd0417b41ee01a12589
Reviewers: tra, simon_tatham, craig.topper, MartinO, arsenm, javed.absar
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D47430
llvm-svn: 333900
2018-06-04 22:26:05 +08:00
|
|
|
std::string Str = Lex.getCurStrVal();
|
|
|
|
if (Str == "NAME") {
|
|
|
|
TokError("'" + Str + "' is a reserved variable name");
|
|
|
|
return nullptr;
|
|
|
|
}
|
|
|
|
|
2009-06-21 11:39:35 +08:00
|
|
|
SMLoc IdLoc = Lex.getLoc();
|
TableGen: Streamline the semantics of NAME
Summary:
The new rules are straightforward. The main rules to keep in mind
are:
1. NAME is an implicit template argument of class and multiclass,
and will be substituted by the name of the instantiating def/defm.
2. The name of a def/defm in a multiclass must contain a reference
to NAME. If such a reference is not present, it is automatically
prepended.
And for some additional subtleties, consider these:
3. defm with no name generates a unique name but has no special
behavior otherwise.
4. def with no name generates an anonymous record, whose name is
unique but undefined. In particular, the name won't contain a
reference to NAME.
Keeping rules 1&2 in mind should allow a predictable behavior of
name resolution that is simple to follow.
The old "rules" were rather surprising: sometimes (but not always),
NAME would correspond to the name of the toplevel defm. They were
also plain bonkers when you pushed them to their limits, as the old
version of the TableGen test case shows.
Having NAME correspond to the name of the toplevel defm introduces
"spooky action at a distance" and breaks composability:
refactoring the upper layers of a hierarchy of nested multiclass
instantiations can cause unexpected breakage by changing the value
of NAME at a lower level of the hierarchy. The new rules don't
suffer from this problem.
Some existing .td files have to be adjusted because they ended up
depending on the details of the old implementation.
Change-Id: I694095231565b30f563e6fd0417b41ee01a12589
Reviewers: tra, simon_tatham, craig.topper, MartinO, arsenm, javed.absar
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D47430
llvm-svn: 333900
2018-06-04 22:26:05 +08:00
|
|
|
Init *DeclName = StringInit::get(Str);
|
2007-11-23 04:49:04 +08:00
|
|
|
Lex.Lex();
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
if (ParsingTemplateArgs) {
|
2015-05-04 09:35:39 +08:00
|
|
|
if (CurRec)
|
2011-10-19 21:02:42 +08:00
|
|
|
DeclName = QualifyName(*CurRec, CurMultiClass, DeclName, ":");
|
2015-05-04 09:35:39 +08:00
|
|
|
else
|
2007-11-23 04:49:04 +08:00
|
|
|
assert(CurMultiClass);
|
|
|
|
if (CurMultiClass)
|
2011-10-19 21:02:42 +08:00
|
|
|
DeclName = QualifyName(CurMultiClass->Rec, CurMultiClass, DeclName,
|
|
|
|
"::");
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
// Add the value.
|
|
|
|
if (AddValue(CurRec, IdLoc, RecordVal(DeclName, Type, HasField)))
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
// If a value is present, parse it.
|
|
|
|
if (Lex.getCode() == tgtok::equal) {
|
|
|
|
Lex.Lex();
|
2009-06-21 11:39:35 +08:00
|
|
|
SMLoc ValLoc = Lex.getLoc();
|
2011-07-30 06:43:06 +08:00
|
|
|
Init *Val = ParseValue(CurRec, Type);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!Val ||
|
2016-01-04 11:15:08 +08:00
|
|
|
SetValue(CurRec, ValLoc, DeclName, None, Val))
|
2014-07-31 09:44:00 +08:00
|
|
|
// Return the name, even if an error is thrown. This is so that we can
|
|
|
|
// continue to make some progress, even without the value having been
|
|
|
|
// initialized.
|
|
|
|
return DeclName;
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
return DeclName;
|
|
|
|
}
|
|
|
|
|
2012-02-23 00:09:41 +08:00
|
|
|
/// ParseForeachDeclaration - Read a foreach declaration, returning
|
|
|
|
/// the name of the declared object or a NULL Init on error. Return
|
|
|
|
/// the name of the parsed initializer list through ForeachListName.
|
|
|
|
///
|
2012-05-25 06:17:39 +08:00
|
|
|
/// ForeachDeclaration ::= ID '=' '{' RangeList '}'
|
|
|
|
/// ForeachDeclaration ::= ID '=' RangePiece
|
2018-03-09 20:24:30 +08:00
|
|
|
/// ForeachDeclaration ::= ID '=' Value
|
2012-02-23 00:09:41 +08:00
|
|
|
///
|
2018-06-21 21:35:44 +08:00
|
|
|
VarInit *TGParser::ParseForeachDeclaration(Init *&ForeachListValue) {
|
2012-02-23 00:09:41 +08:00
|
|
|
if (Lex.getCode() != tgtok::Id) {
|
|
|
|
TokError("Expected identifier in foreach declaration");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2012-02-23 00:09:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
Init *DeclName = StringInit::get(Lex.getCurStrVal());
|
|
|
|
Lex.Lex();
|
|
|
|
|
|
|
|
// If a value is present, parse it.
|
|
|
|
if (Lex.getCode() != tgtok::equal) {
|
|
|
|
TokError("Expected '=' in foreach declaration");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2012-02-23 00:09:41 +08:00
|
|
|
}
|
|
|
|
Lex.Lex(); // Eat the '='
|
|
|
|
|
2014-04-09 12:50:04 +08:00
|
|
|
RecTy *IterType = nullptr;
|
2016-12-05 14:41:54 +08:00
|
|
|
SmallVector<unsigned, 16> Ranges;
|
2012-02-23 00:09:41 +08:00
|
|
|
|
2012-05-25 06:17:39 +08:00
|
|
|
switch (Lex.getCode()) {
|
|
|
|
case tgtok::l_brace: { // '{' RangeList '}'
|
|
|
|
Lex.Lex(); // eat the '{'
|
2016-12-05 14:41:54 +08:00
|
|
|
ParseRangeList(Ranges);
|
2012-05-25 06:17:39 +08:00
|
|
|
if (Lex.getCode() != tgtok::r_brace) {
|
|
|
|
TokError("expected '}' at end of bit range list");
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2012-05-25 06:17:39 +08:00
|
|
|
}
|
|
|
|
Lex.Lex();
|
|
|
|
break;
|
|
|
|
}
|
2018-03-09 20:24:30 +08:00
|
|
|
|
|
|
|
default: {
|
|
|
|
SMLoc ValueLoc = Lex.getLoc();
|
|
|
|
Init *I = ParseValue(nullptr);
|
2019-05-23 05:28:20 +08:00
|
|
|
if (!I)
|
2018-03-09 20:24:30 +08:00
|
|
|
return nullptr;
|
2019-05-23 05:28:20 +08:00
|
|
|
|
|
|
|
TypedInit *TI = dyn_cast<TypedInit>(I);
|
|
|
|
if (TI && isa<ListRecTy>(TI->getType())) {
|
|
|
|
ForeachListValue = I;
|
|
|
|
IterType = cast<ListRecTy>(TI->getType())->getElementType();
|
|
|
|
break;
|
2018-03-09 20:24:30 +08:00
|
|
|
}
|
2019-05-23 05:28:20 +08:00
|
|
|
|
|
|
|
if (TI) {
|
|
|
|
if (ParseRangePiece(Ranges, TI))
|
|
|
|
return nullptr;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
std::string Type;
|
|
|
|
if (TI)
|
|
|
|
Type = (Twine("' of type '") + TI->getType()->getAsString()).str();
|
|
|
|
Error(ValueLoc, "expected a list, got '" + I->getAsString() + Type + "'");
|
|
|
|
if (CurMultiClass) {
|
|
|
|
PrintNote({}, "references to multiclass template arguments cannot be "
|
|
|
|
"resolved at this time");
|
|
|
|
}
|
|
|
|
return nullptr;
|
2018-03-09 20:24:30 +08:00
|
|
|
}
|
2012-02-23 00:09:41 +08:00
|
|
|
}
|
|
|
|
|
2019-05-23 05:28:20 +08:00
|
|
|
|
2012-05-25 06:17:39 +08:00
|
|
|
if (!Ranges.empty()) {
|
|
|
|
assert(!IterType && "Type already initialized?");
|
|
|
|
IterType = IntRecTy::get();
|
|
|
|
std::vector<Init*> Values;
|
2015-06-02 14:19:28 +08:00
|
|
|
for (unsigned R : Ranges)
|
|
|
|
Values.push_back(IntInit::get(R));
|
2012-05-25 06:17:39 +08:00
|
|
|
ForeachListValue = ListInit::get(Values, IterType);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!IterType)
|
2014-04-09 12:50:04 +08:00
|
|
|
return nullptr;
|
2012-02-23 00:09:41 +08:00
|
|
|
|
2012-05-25 06:17:39 +08:00
|
|
|
return VarInit::get(DeclName, IterType);
|
2012-02-23 00:09:41 +08:00
|
|
|
}
|
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
/// ParseTemplateArgList - Read a template argument list, which is a non-empty
|
|
|
|
/// sequence of template-declarations in <>'s. If CurRec is non-null, these are
|
|
|
|
/// template args for a def, which may or may not be in a multiclass. If null,
|
|
|
|
/// these are the template args for a multiclass.
|
|
|
|
///
|
|
|
|
/// TemplateArgList ::= '<' Declaration (',' Declaration)* '>'
|
2009-11-22 12:24:42 +08:00
|
|
|
///
|
2007-11-23 04:49:04 +08:00
|
|
|
bool TGParser::ParseTemplateArgList(Record *CurRec) {
|
|
|
|
assert(Lex.getCode() == tgtok::less && "Not a template arg list!");
|
|
|
|
Lex.Lex(); // eat the '<'
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
Record *TheRecToAddTo = CurRec ? CurRec : &CurMultiClass->Rec;
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
// Read the first declaration.
|
2011-10-19 21:02:42 +08:00
|
|
|
Init *TemplArg = ParseDeclaration(CurRec, true/*templateargs*/);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!TemplArg)
|
2007-11-23 04:49:04 +08:00
|
|
|
return true;
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
TheRecToAddTo->addTemplateArg(TemplArg);
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
while (Lex.getCode() == tgtok::comma) {
|
|
|
|
Lex.Lex(); // eat the ','
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
// Read the following declarations.
|
2018-05-30 01:12:20 +08:00
|
|
|
SMLoc Loc = Lex.getLoc();
|
2007-11-23 04:49:04 +08:00
|
|
|
TemplArg = ParseDeclaration(CurRec, true/*templateargs*/);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!TemplArg)
|
2007-11-23 04:49:04 +08:00
|
|
|
return true;
|
2018-05-30 01:12:20 +08:00
|
|
|
|
|
|
|
if (TheRecToAddTo->isTemplateArg(TemplArg))
|
|
|
|
return Error(Loc, "template argument with the same name has already been "
|
|
|
|
"defined");
|
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
TheRecToAddTo->addTemplateArg(TemplArg);
|
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Lex.getCode() != tgtok::greater)
|
|
|
|
return TokError("expected '>' at end of template argument list");
|
|
|
|
Lex.Lex(); // eat the '>'.
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseBodyItem - Parse a single item at within the body of a def or class.
|
|
|
|
///
|
|
|
|
/// BodyItem ::= Declaration ';'
|
|
|
|
/// BodyItem ::= LET ID OptionalBitList '=' Value ';'
|
|
|
|
bool TGParser::ParseBodyItem(Record *CurRec) {
|
|
|
|
if (Lex.getCode() != tgtok::Let) {
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!ParseDeclaration(CurRec, false))
|
2007-11-23 04:49:04 +08:00
|
|
|
return true;
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Lex.getCode() != tgtok::semi)
|
|
|
|
return TokError("expected ';' after declaration");
|
|
|
|
Lex.Lex();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// LET ID OptionalRangeList '=' Value ';'
|
|
|
|
if (Lex.Lex() != tgtok::Id)
|
|
|
|
return TokError("expected field identifier after let");
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2009-06-21 11:39:35 +08:00
|
|
|
SMLoc IdLoc = Lex.getLoc();
|
2016-12-05 15:35:13 +08:00
|
|
|
StringInit *FieldName = StringInit::get(Lex.getCurStrVal());
|
2007-11-23 04:49:04 +08:00
|
|
|
Lex.Lex(); // eat the field name.
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2016-12-05 14:41:54 +08:00
|
|
|
SmallVector<unsigned, 16> BitList;
|
2009-11-22 12:24:42 +08:00
|
|
|
if (ParseOptionalBitList(BitList))
|
2007-11-23 04:49:04 +08:00
|
|
|
return true;
|
|
|
|
std::reverse(BitList.begin(), BitList.end());
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Lex.getCode() != tgtok::equal)
|
|
|
|
return TokError("expected '=' in let expression");
|
|
|
|
Lex.Lex(); // eat the '='.
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2009-06-09 04:23:18 +08:00
|
|
|
RecordVal *Field = CurRec->getValue(FieldName);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!Field)
|
2016-12-05 15:35:13 +08:00
|
|
|
return TokError("Value '" + FieldName->getValue() + "' unknown!");
|
2009-06-09 04:23:18 +08:00
|
|
|
|
|
|
|
RecTy *Type = Field->getType();
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2011-07-30 06:43:06 +08:00
|
|
|
Init *Val = ParseValue(CurRec, Type);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!Val) return true;
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Lex.getCode() != tgtok::semi)
|
|
|
|
return TokError("expected ';' after let expression");
|
|
|
|
Lex.Lex();
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
return SetValue(CurRec, IdLoc, FieldName, BitList, Val);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseBody - Read the body of a class or def. Return true on error, false on
|
|
|
|
/// success.
|
|
|
|
///
|
|
|
|
/// Body ::= ';'
|
|
|
|
/// Body ::= '{' BodyList '}'
|
|
|
|
/// BodyList BodyItem*
|
|
|
|
///
|
|
|
|
bool TGParser::ParseBody(Record *CurRec) {
|
|
|
|
// If this is a null definition, just eat the semi and return.
|
|
|
|
if (Lex.getCode() == tgtok::semi) {
|
|
|
|
Lex.Lex();
|
|
|
|
return false;
|
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Lex.getCode() != tgtok::l_brace)
|
|
|
|
return TokError("Expected ';' or '{' to start body");
|
|
|
|
// Eat the '{'.
|
|
|
|
Lex.Lex();
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
while (Lex.getCode() != tgtok::r_brace)
|
|
|
|
if (ParseBodyItem(CurRec))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
// Eat the '}'.
|
|
|
|
Lex.Lex();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-05-01 23:54:18 +08:00
|
|
|
/// Apply the current let bindings to \a CurRec.
|
2013-01-09 12:49:14 +08:00
|
|
|
/// \returns true on error, false otherwise.
|
|
|
|
bool TGParser::ApplyLetStack(Record *CurRec) {
|
2016-12-05 14:41:54 +08:00
|
|
|
for (SmallVectorImpl<LetRecord> &LetInfo : LetStack)
|
2015-06-02 14:19:28 +08:00
|
|
|
for (LetRecord &LR : LetInfo)
|
|
|
|
if (SetValue(CurRec, LR.Loc, LR.Name, LR.Bits, LR.Value))
|
2013-01-09 12:49:14 +08:00
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2018-06-21 21:35:44 +08:00
|
|
|
bool TGParser::ApplyLetStack(RecordsEntry &Entry) {
|
|
|
|
if (Entry.Rec)
|
|
|
|
return ApplyLetStack(Entry.Rec.get());
|
|
|
|
|
|
|
|
for (auto &E : Entry.Loop->Entries) {
|
|
|
|
if (ApplyLetStack(E))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
/// ParseObjectBody - Parse the body of a def or class. This consists of an
|
|
|
|
/// optional ClassList followed by a Body. CurRec is the current def or class
|
|
|
|
/// that is being parsed.
|
|
|
|
///
|
|
|
|
/// ObjectBody ::= BaseClassList Body
|
|
|
|
/// BaseClassList ::= /*empty*/
|
|
|
|
/// BaseClassList ::= ':' BaseClassListNE
|
|
|
|
/// BaseClassListNE ::= SubClassRef (',' SubClassRef)*
|
|
|
|
///
|
|
|
|
bool TGParser::ParseObjectBody(Record *CurRec) {
|
|
|
|
// If there is a baseclass list, read it.
|
|
|
|
if (Lex.getCode() == tgtok::colon) {
|
|
|
|
Lex.Lex();
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
// Read all of the subclasses.
|
|
|
|
SubClassReference SubClass = ParseSubClassReference(CurRec, false);
|
2016-08-24 01:14:32 +08:00
|
|
|
while (true) {
|
2007-11-23 04:49:04 +08:00
|
|
|
// Check for error.
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!SubClass.Rec) return true;
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
// Add it.
|
|
|
|
if (AddSubClass(CurRec, SubClass))
|
|
|
|
return true;
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Lex.getCode() != tgtok::comma) break;
|
|
|
|
Lex.Lex(); // eat ','.
|
|
|
|
SubClass = ParseSubClassReference(CurRec, false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-01-09 12:49:14 +08:00
|
|
|
if (ApplyLetStack(CurRec))
|
|
|
|
return true;
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
return ParseBody(CurRec);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseDef - Parse and return a top level or multiclass def, return the record
|
|
|
|
/// corresponding to it. This returns null on error.
|
|
|
|
///
|
|
|
|
/// DefInst ::= DEF ObjectName ObjectBody
|
|
|
|
///
|
2010-06-10 10:42:59 +08:00
|
|
|
bool TGParser::ParseDef(MultiClass *CurMultiClass) {
|
2009-06-21 11:39:35 +08:00
|
|
|
SMLoc DefLoc = Lex.getLoc();
|
2007-11-23 04:49:04 +08:00
|
|
|
assert(Lex.getCode() == tgtok::Def && "Unknown tok");
|
2009-11-22 12:24:42 +08:00
|
|
|
Lex.Lex(); // Eat the 'def' token.
|
2007-11-23 04:49:04 +08:00
|
|
|
|
|
|
|
// Parse ObjectName and make a record for it.
|
TableGen: Streamline how defs are instantiated
Summary:
Instantiating def's and defm's needs to perform the following steps:
- for defm's, clone multiclass def prototypes and subsitute template args
- for def's and defm's, add subclass definitions, substituting template
args
- clone the record based on foreach loops and substitute loop iteration
variables
- override record variables based on the global 'let' stack
- resolve the record name (this should be simple, but unfortunately it's
not due to existing .td files relying on rather silly implementation
details)
- for def(m)s in multiclasses, add the unresolved record as a multiclass
prototype
- for top-level def(m)s, resolve all internal variable references and add
them to the record keeper and any active defsets
This change streamlines how we go through these steps, by having both
def's and defm's feed into a single addDef() method that handles foreach,
final resolve, and routing the record to the right place.
This happens to make foreach inside of multiclasses work, as the new
test case demonstrates. Previously, foreach inside multiclasses was not
forbidden by the parser, but it was de facto broken.
Another side effect is that the order of "instantiated from" notes in error
messages is reversed, as the modified test case shows. This is arguably
clearer, since the initial error message ends up pointing directly to
whatever triggered the error, and subsequent notes will point to increasingly
outer layers of multiclasses. This is consistent with how C++ compilers
report nested #includes and nested template instantiations.
Change-Id: Ica146d0db2bc133dd7ed88054371becf24320447
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D44478
llvm-svn: 328117
2018-03-22 01:12:53 +08:00
|
|
|
std::unique_ptr<Record> CurRec;
|
2013-01-11 02:50:05 +08:00
|
|
|
Init *Name = ParseObjectName(CurMultiClass);
|
TableGen: Streamline how defs are instantiated
Summary:
Instantiating def's and defm's needs to perform the following steps:
- for defm's, clone multiclass def prototypes and subsitute template args
- for def's and defm's, add subclass definitions, substituting template
args
- clone the record based on foreach loops and substitute loop iteration
variables
- override record variables based on the global 'let' stack
- resolve the record name (this should be simple, but unfortunately it's
not due to existing .td files relying on rather silly implementation
details)
- for def(m)s in multiclasses, add the unresolved record as a multiclass
prototype
- for top-level def(m)s, resolve all internal variable references and add
them to the record keeper and any active defsets
This change streamlines how we go through these steps, by having both
def's and defm's feed into a single addDef() method that handles foreach,
final resolve, and routing the record to the right place.
This happens to make foreach inside of multiclasses work, as the new
test case demonstrates. Previously, foreach inside multiclasses was not
forbidden by the parser, but it was de facto broken.
Another side effect is that the order of "instantiated from" notes in error
messages is reversed, as the modified test case shows. This is arguably
clearer, since the initial error message ends up pointing directly to
whatever triggered the error, and subsequent notes will point to increasingly
outer layers of multiclasses. This is consistent with how C++ compilers
report nested #includes and nested template instantiations.
Change-Id: Ica146d0db2bc133dd7ed88054371becf24320447
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D44478
llvm-svn: 328117
2018-03-22 01:12:53 +08:00
|
|
|
if (!Name)
|
2010-06-10 10:42:59 +08:00
|
|
|
return true;
|
2009-11-22 12:24:42 +08:00
|
|
|
|
TableGen: Streamline how defs are instantiated
Summary:
Instantiating def's and defm's needs to perform the following steps:
- for defm's, clone multiclass def prototypes and subsitute template args
- for def's and defm's, add subclass definitions, substituting template
args
- clone the record based on foreach loops and substitute loop iteration
variables
- override record variables based on the global 'let' stack
- resolve the record name (this should be simple, but unfortunately it's
not due to existing .td files relying on rather silly implementation
details)
- for def(m)s in multiclasses, add the unresolved record as a multiclass
prototype
- for top-level def(m)s, resolve all internal variable references and add
them to the record keeper and any active defsets
This change streamlines how we go through these steps, by having both
def's and defm's feed into a single addDef() method that handles foreach,
final resolve, and routing the record to the right place.
This happens to make foreach inside of multiclasses work, as the new
test case demonstrates. Previously, foreach inside multiclasses was not
forbidden by the parser, but it was de facto broken.
Another side effect is that the order of "instantiated from" notes in error
messages is reversed, as the modified test case shows. This is arguably
clearer, since the initial error message ends up pointing directly to
whatever triggered the error, and subsequent notes will point to increasingly
outer layers of multiclasses. This is consistent with how C++ compilers
report nested #includes and nested template instantiations.
Change-Id: Ica146d0db2bc133dd7ed88054371becf24320447
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D44478
llvm-svn: 328117
2018-03-22 01:12:53 +08:00
|
|
|
if (isa<UnsetInit>(Name))
|
2019-08-15 23:54:37 +08:00
|
|
|
CurRec = std::make_unique<Record>(Records.getNewAnonymousName(), DefLoc, Records,
|
TableGen: Streamline how defs are instantiated
Summary:
Instantiating def's and defm's needs to perform the following steps:
- for defm's, clone multiclass def prototypes and subsitute template args
- for def's and defm's, add subclass definitions, substituting template
args
- clone the record based on foreach loops and substitute loop iteration
variables
- override record variables based on the global 'let' stack
- resolve the record name (this should be simple, but unfortunately it's
not due to existing .td files relying on rather silly implementation
details)
- for def(m)s in multiclasses, add the unresolved record as a multiclass
prototype
- for top-level def(m)s, resolve all internal variable references and add
them to the record keeper and any active defsets
This change streamlines how we go through these steps, by having both
def's and defm's feed into a single addDef() method that handles foreach,
final resolve, and routing the record to the right place.
This happens to make foreach inside of multiclasses work, as the new
test case demonstrates. Previously, foreach inside multiclasses was not
forbidden by the parser, but it was de facto broken.
Another side effect is that the order of "instantiated from" notes in error
messages is reversed, as the modified test case shows. This is arguably
clearer, since the initial error message ends up pointing directly to
whatever triggered the error, and subsequent notes will point to increasingly
outer layers of multiclasses. This is consistent with how C++ compilers
report nested #includes and nested template instantiations.
Change-Id: Ica146d0db2bc133dd7ed88054371becf24320447
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D44478
llvm-svn: 328117
2018-03-22 01:12:53 +08:00
|
|
|
/*Anonymous=*/true);
|
|
|
|
else
|
2019-08-15 23:54:37 +08:00
|
|
|
CurRec = std::make_unique<Record>(Name, DefLoc, Records);
|
2010-06-10 10:42:59 +08:00
|
|
|
|
TableGen: Streamline how defs are instantiated
Summary:
Instantiating def's and defm's needs to perform the following steps:
- for defm's, clone multiclass def prototypes and subsitute template args
- for def's and defm's, add subclass definitions, substituting template
args
- clone the record based on foreach loops and substitute loop iteration
variables
- override record variables based on the global 'let' stack
- resolve the record name (this should be simple, but unfortunately it's
not due to existing .td files relying on rather silly implementation
details)
- for def(m)s in multiclasses, add the unresolved record as a multiclass
prototype
- for top-level def(m)s, resolve all internal variable references and add
them to the record keeper and any active defsets
This change streamlines how we go through these steps, by having both
def's and defm's feed into a single addDef() method that handles foreach,
final resolve, and routing the record to the right place.
This happens to make foreach inside of multiclasses work, as the new
test case demonstrates. Previously, foreach inside multiclasses was not
forbidden by the parser, but it was de facto broken.
Another side effect is that the order of "instantiated from" notes in error
messages is reversed, as the modified test case shows. This is arguably
clearer, since the initial error message ends up pointing directly to
whatever triggered the error, and subsequent notes will point to increasingly
outer layers of multiclasses. This is consistent with how C++ compilers
report nested #includes and nested template instantiations.
Change-Id: Ica146d0db2bc133dd7ed88054371becf24320447
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D44478
llvm-svn: 328117
2018-03-22 01:12:53 +08:00
|
|
|
if (ParseObjectBody(CurRec.get()))
|
|
|
|
return true;
|
2012-02-23 00:09:41 +08:00
|
|
|
|
2018-06-21 21:35:44 +08:00
|
|
|
return addEntry(std::move(CurRec));
|
2018-03-09 20:24:42 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseDefset - Parse a defset statement.
|
|
|
|
///
|
|
|
|
/// Defset ::= DEFSET Type Id '=' '{' ObjectList '}'
|
|
|
|
///
|
|
|
|
bool TGParser::ParseDefset() {
|
|
|
|
assert(Lex.getCode() == tgtok::Defset);
|
|
|
|
Lex.Lex(); // Eat the 'defset' token
|
|
|
|
|
|
|
|
DefsetRecord Defset;
|
|
|
|
Defset.Loc = Lex.getLoc();
|
|
|
|
RecTy *Type = ParseType();
|
|
|
|
if (!Type)
|
|
|
|
return true;
|
|
|
|
if (!isa<ListRecTy>(Type))
|
|
|
|
return Error(Defset.Loc, "expected list type");
|
|
|
|
Defset.EltTy = cast<ListRecTy>(Type)->getElementType();
|
|
|
|
|
|
|
|
if (Lex.getCode() != tgtok::Id)
|
|
|
|
return TokError("expected identifier");
|
|
|
|
StringInit *DeclName = StringInit::get(Lex.getCurStrVal());
|
|
|
|
if (Records.getGlobal(DeclName->getValue()))
|
|
|
|
return TokError("def or global variable of this name already exists");
|
|
|
|
|
|
|
|
if (Lex.Lex() != tgtok::equal) // Eat the identifier
|
|
|
|
return TokError("expected '='");
|
|
|
|
if (Lex.Lex() != tgtok::l_brace) // Eat the '='
|
|
|
|
return TokError("expected '{'");
|
|
|
|
SMLoc BraceLoc = Lex.getLoc();
|
|
|
|
Lex.Lex(); // Eat the '{'
|
|
|
|
|
|
|
|
Defsets.push_back(&Defset);
|
|
|
|
bool Err = ParseObjectList(nullptr);
|
|
|
|
Defsets.pop_back();
|
|
|
|
if (Err)
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (Lex.getCode() != tgtok::r_brace) {
|
|
|
|
TokError("expected '}' at end of defset");
|
|
|
|
return Error(BraceLoc, "to match this '{'");
|
|
|
|
}
|
|
|
|
Lex.Lex(); // Eat the '}'
|
|
|
|
|
|
|
|
Records.addExtraGlobal(DeclName->getValue(),
|
|
|
|
ListInit::get(Defset.Elements, Defset.EltTy));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2012-02-23 00:09:41 +08:00
|
|
|
/// ParseForeach - Parse a for statement. Return the record corresponding
|
|
|
|
/// to it. This returns true on error.
|
|
|
|
///
|
|
|
|
/// Foreach ::= FOREACH Declaration IN '{ ObjectList '}'
|
|
|
|
/// Foreach ::= FOREACH Declaration IN Object
|
|
|
|
///
|
|
|
|
bool TGParser::ParseForeach(MultiClass *CurMultiClass) {
|
2018-06-21 21:35:44 +08:00
|
|
|
SMLoc Loc = Lex.getLoc();
|
2012-02-23 00:09:41 +08:00
|
|
|
assert(Lex.getCode() == tgtok::Foreach && "Unknown tok");
|
|
|
|
Lex.Lex(); // Eat the 'for' token.
|
|
|
|
|
|
|
|
// Make a temporary object to record items associated with the for
|
|
|
|
// loop.
|
2018-06-21 21:35:44 +08:00
|
|
|
Init *ListValue = nullptr;
|
2012-05-25 06:17:33 +08:00
|
|
|
VarInit *IterName = ParseForeachDeclaration(ListValue);
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!IterName)
|
2012-02-23 00:09:41 +08:00
|
|
|
return TokError("expected declaration in for");
|
|
|
|
|
|
|
|
if (Lex.getCode() != tgtok::In)
|
|
|
|
return TokError("Unknown tok");
|
|
|
|
Lex.Lex(); // Eat the in
|
|
|
|
|
|
|
|
// Create a loop object and remember it.
|
2019-08-15 23:54:37 +08:00
|
|
|
Loops.push_back(std::make_unique<ForeachLoop>(Loc, IterName, ListValue));
|
2012-02-23 00:09:41 +08:00
|
|
|
|
|
|
|
if (Lex.getCode() != tgtok::l_brace) {
|
|
|
|
// FOREACH Declaration IN Object
|
|
|
|
if (ParseObject(CurMultiClass))
|
|
|
|
return true;
|
2015-05-04 09:35:39 +08:00
|
|
|
} else {
|
2012-02-23 00:09:41 +08:00
|
|
|
SMLoc BraceLoc = Lex.getLoc();
|
|
|
|
// Otherwise, this is a group foreach.
|
|
|
|
Lex.Lex(); // eat the '{'.
|
|
|
|
|
|
|
|
// Parse the object list.
|
|
|
|
if (ParseObjectList(CurMultiClass))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
if (Lex.getCode() != tgtok::r_brace) {
|
|
|
|
TokError("expected '}' at end of foreach command");
|
|
|
|
return Error(BraceLoc, "to match this '{'");
|
|
|
|
}
|
|
|
|
Lex.Lex(); // Eat the }
|
|
|
|
}
|
|
|
|
|
2018-06-21 21:35:44 +08:00
|
|
|
// Resolve the loop or store it for later resolution.
|
|
|
|
std::unique_ptr<ForeachLoop> Loop = std::move(Loops.back());
|
2012-02-23 00:09:41 +08:00
|
|
|
Loops.pop_back();
|
|
|
|
|
2018-06-21 21:35:44 +08:00
|
|
|
return addEntry(std::move(Loop));
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseClass - Parse a tblgen class definition.
|
|
|
|
///
|
|
|
|
/// ClassInst ::= CLASS ID TemplateArgList? ObjectBody
|
|
|
|
///
|
|
|
|
bool TGParser::ParseClass() {
|
|
|
|
assert(Lex.getCode() == tgtok::Class && "Unexpected token!");
|
|
|
|
Lex.Lex();
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Lex.getCode() != tgtok::Id)
|
|
|
|
return TokError("expected class name after 'class' keyword");
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
Record *CurRec = Records.getClass(Lex.getCurStrVal());
|
|
|
|
if (CurRec) {
|
|
|
|
// If the body was previously defined, this is an error.
|
TableGen: Streamline the semantics of NAME
Summary:
The new rules are straightforward. The main rules to keep in mind
are:
1. NAME is an implicit template argument of class and multiclass,
and will be substituted by the name of the instantiating def/defm.
2. The name of a def/defm in a multiclass must contain a reference
to NAME. If such a reference is not present, it is automatically
prepended.
And for some additional subtleties, consider these:
3. defm with no name generates a unique name but has no special
behavior otherwise.
4. def with no name generates an anonymous record, whose name is
unique but undefined. In particular, the name won't contain a
reference to NAME.
Keeping rules 1&2 in mind should allow a predictable behavior of
name resolution that is simple to follow.
The old "rules" were rather surprising: sometimes (but not always),
NAME would correspond to the name of the toplevel defm. They were
also plain bonkers when you pushed them to their limits, as the old
version of the TableGen test case shows.
Having NAME correspond to the name of the toplevel defm introduces
"spooky action at a distance" and breaks composability:
refactoring the upper layers of a hierarchy of nested multiclass
instantiations can cause unexpected breakage by changing the value
of NAME at a lower level of the hierarchy. The new rules don't
suffer from this problem.
Some existing .td files have to be adjusted because they ended up
depending on the details of the old implementation.
Change-Id: I694095231565b30f563e6fd0417b41ee01a12589
Reviewers: tra, simon_tatham, craig.topper, MartinO, arsenm, javed.absar
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D47430
llvm-svn: 333900
2018-06-04 22:26:05 +08:00
|
|
|
if (!CurRec->getValues().empty() ||
|
2007-11-23 04:49:04 +08:00
|
|
|
!CurRec->getSuperClasses().empty() ||
|
|
|
|
!CurRec->getTemplateArgs().empty())
|
2015-04-30 13:54:22 +08:00
|
|
|
return TokError("Class '" + CurRec->getNameInitAsString() +
|
|
|
|
"' already defined");
|
2007-11-23 04:49:04 +08:00
|
|
|
} else {
|
|
|
|
// If this is the first reference to this class, create and add it.
|
2014-11-30 08:31:49 +08:00
|
|
|
auto NewRec =
|
2019-08-15 23:54:37 +08:00
|
|
|
std::make_unique<Record>(Lex.getCurStrVal(), Lex.getLoc(), Records,
|
TableGen: Streamline the semantics of NAME
Summary:
The new rules are straightforward. The main rules to keep in mind
are:
1. NAME is an implicit template argument of class and multiclass,
and will be substituted by the name of the instantiating def/defm.
2. The name of a def/defm in a multiclass must contain a reference
to NAME. If such a reference is not present, it is automatically
prepended.
And for some additional subtleties, consider these:
3. defm with no name generates a unique name but has no special
behavior otherwise.
4. def with no name generates an anonymous record, whose name is
unique but undefined. In particular, the name won't contain a
reference to NAME.
Keeping rules 1&2 in mind should allow a predictable behavior of
name resolution that is simple to follow.
The old "rules" were rather surprising: sometimes (but not always),
NAME would correspond to the name of the toplevel defm. They were
also plain bonkers when you pushed them to their limits, as the old
version of the TableGen test case shows.
Having NAME correspond to the name of the toplevel defm introduces
"spooky action at a distance" and breaks composability:
refactoring the upper layers of a hierarchy of nested multiclass
instantiations can cause unexpected breakage by changing the value
of NAME at a lower level of the hierarchy. The new rules don't
suffer from this problem.
Some existing .td files have to be adjusted because they ended up
depending on the details of the old implementation.
Change-Id: I694095231565b30f563e6fd0417b41ee01a12589
Reviewers: tra, simon_tatham, craig.topper, MartinO, arsenm, javed.absar
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D47430
llvm-svn: 333900
2018-06-04 22:26:05 +08:00
|
|
|
/*Class=*/true);
|
2014-11-29 13:52:51 +08:00
|
|
|
CurRec = NewRec.get();
|
|
|
|
Records.addClass(std::move(NewRec));
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the name.
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
// If there are template args, parse them.
|
|
|
|
if (Lex.getCode() == tgtok::less)
|
|
|
|
if (ParseTemplateArgList(CurRec))
|
|
|
|
return true;
|
|
|
|
|
|
|
|
return ParseObjectBody(CurRec);
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseLetList - Parse a non-empty list of assignment expressions into a list
|
|
|
|
/// of LetRecords.
|
|
|
|
///
|
|
|
|
/// LetList ::= LetItem (',' LetItem)*
|
|
|
|
/// LetItem ::= ID OptionalRangeList '=' Value
|
|
|
|
///
|
2016-12-05 14:41:54 +08:00
|
|
|
void TGParser::ParseLetList(SmallVectorImpl<LetRecord> &Result) {
|
2016-08-24 01:14:32 +08:00
|
|
|
while (true) {
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Lex.getCode() != tgtok::Id) {
|
|
|
|
TokError("expected identifier in let definition");
|
2016-12-05 14:41:54 +08:00
|
|
|
Result.clear();
|
|
|
|
return;
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
2016-12-05 14:41:54 +08:00
|
|
|
|
2016-12-05 15:35:13 +08:00
|
|
|
StringInit *Name = StringInit::get(Lex.getCurStrVal());
|
2009-06-21 11:39:35 +08:00
|
|
|
SMLoc NameLoc = Lex.getLoc();
|
2009-11-22 12:24:42 +08:00
|
|
|
Lex.Lex(); // Eat the identifier.
|
2007-11-23 04:49:04 +08:00
|
|
|
|
|
|
|
// Check for an optional RangeList.
|
2016-12-05 14:41:54 +08:00
|
|
|
SmallVector<unsigned, 16> Bits;
|
|
|
|
if (ParseOptionalRangeList(Bits)) {
|
|
|
|
Result.clear();
|
|
|
|
return;
|
|
|
|
}
|
2007-11-23 04:49:04 +08:00
|
|
|
std::reverse(Bits.begin(), Bits.end());
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Lex.getCode() != tgtok::equal) {
|
|
|
|
TokError("expected '=' in let expression");
|
2016-12-05 14:41:54 +08:00
|
|
|
Result.clear();
|
|
|
|
return;
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
Lex.Lex(); // eat the '='.
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2014-04-09 12:50:04 +08:00
|
|
|
Init *Val = ParseValue(nullptr);
|
2016-12-05 14:41:54 +08:00
|
|
|
if (!Val) {
|
|
|
|
Result.clear();
|
|
|
|
return;
|
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
// Now that we have everything, add the record.
|
2016-12-05 15:35:13 +08:00
|
|
|
Result.emplace_back(Name, Bits, Val, NameLoc);
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Lex.getCode() != tgtok::comma)
|
2016-12-05 14:41:54 +08:00
|
|
|
return;
|
2009-11-22 12:24:42 +08:00
|
|
|
Lex.Lex(); // eat the comma.
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseTopLevelLet - Parse a 'let' at top level. This can be a couple of
|
2010-06-10 10:42:59 +08:00
|
|
|
/// different related productions. This works inside multiclasses too.
|
2007-11-23 04:49:04 +08:00
|
|
|
///
|
|
|
|
/// Object ::= LET LetList IN '{' ObjectList '}'
|
|
|
|
/// Object ::= LET LetList IN Object
|
|
|
|
///
|
2010-06-10 10:42:59 +08:00
|
|
|
bool TGParser::ParseTopLevelLet(MultiClass *CurMultiClass) {
|
2007-11-23 04:49:04 +08:00
|
|
|
assert(Lex.getCode() == tgtok::Let && "Unexpected token");
|
|
|
|
Lex.Lex();
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
// Add this entry to the let stack.
|
2016-12-05 14:41:54 +08:00
|
|
|
SmallVector<LetRecord, 8> LetInfo;
|
|
|
|
ParseLetList(LetInfo);
|
2007-11-23 04:49:04 +08:00
|
|
|
if (LetInfo.empty()) return true;
|
2014-10-04 02:33:16 +08:00
|
|
|
LetStack.push_back(std::move(LetInfo));
|
2007-11-23 04:49:04 +08:00
|
|
|
|
|
|
|
if (Lex.getCode() != tgtok::In)
|
|
|
|
return TokError("expected 'in' at end of top-level 'let'");
|
|
|
|
Lex.Lex();
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
// If this is a scalar let, just handle it now
|
|
|
|
if (Lex.getCode() != tgtok::l_brace) {
|
|
|
|
// LET LetList IN Object
|
2010-06-10 10:42:59 +08:00
|
|
|
if (ParseObject(CurMultiClass))
|
2007-11-23 04:49:04 +08:00
|
|
|
return true;
|
|
|
|
} else { // Object ::= LETCommand '{' ObjectList '}'
|
2009-06-21 11:39:35 +08:00
|
|
|
SMLoc BraceLoc = Lex.getLoc();
|
2007-11-23 04:49:04 +08:00
|
|
|
// Otherwise, this is a group let.
|
|
|
|
Lex.Lex(); // eat the '{'.
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
// Parse the object list.
|
2010-06-10 10:42:59 +08:00
|
|
|
if (ParseObjectList(CurMultiClass))
|
2007-11-23 04:49:04 +08:00
|
|
|
return true;
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
if (Lex.getCode() != tgtok::r_brace) {
|
|
|
|
TokError("expected '}' at end of top level let command");
|
|
|
|
return Error(BraceLoc, "to match this '{'");
|
|
|
|
}
|
|
|
|
Lex.Lex();
|
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
// Outside this let scope, this let block is not active.
|
|
|
|
LetStack.pop_back();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseMultiClass - Parse a multiclass definition.
|
|
|
|
///
|
2009-04-29 03:41:44 +08:00
|
|
|
/// MultiClassInst ::= MULTICLASS ID TemplateArgList?
|
2013-01-09 10:11:55 +08:00
|
|
|
/// ':' BaseMultiClassList '{' MultiClassObject+ '}'
|
|
|
|
/// MultiClassObject ::= DefInst
|
|
|
|
/// MultiClassObject ::= MultiClassInst
|
|
|
|
/// MultiClassObject ::= DefMInst
|
|
|
|
/// MultiClassObject ::= LETCommand '{' ObjectList '}'
|
|
|
|
/// MultiClassObject ::= LETCommand Object
|
2007-11-23 04:49:04 +08:00
|
|
|
///
|
|
|
|
bool TGParser::ParseMultiClass() {
|
|
|
|
assert(Lex.getCode() == tgtok::MultiClass && "Unexpected token");
|
|
|
|
Lex.Lex(); // Eat the multiclass token.
|
|
|
|
|
|
|
|
if (Lex.getCode() != tgtok::Id)
|
|
|
|
return TokError("expected identifier after multiclass for name");
|
|
|
|
std::string Name = Lex.getCurStrVal();
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2014-12-11 13:25:30 +08:00
|
|
|
auto Result =
|
|
|
|
MultiClasses.insert(std::make_pair(Name,
|
2019-08-15 23:54:37 +08:00
|
|
|
std::make_unique<MultiClass>(Name, Lex.getLoc(),Records)));
|
2014-12-11 13:25:30 +08:00
|
|
|
|
|
|
|
if (!Result.second)
|
2007-11-23 04:49:04 +08:00
|
|
|
return TokError("multiclass '" + Name + "' already defined");
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2014-12-11 13:25:30 +08:00
|
|
|
CurMultiClass = Result.first->second.get();
|
2007-11-23 04:49:04 +08:00
|
|
|
Lex.Lex(); // Eat the identifier.
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
// If there are template args, parse them.
|
|
|
|
if (Lex.getCode() == tgtok::less)
|
2014-04-09 12:50:04 +08:00
|
|
|
if (ParseTemplateArgList(nullptr))
|
2007-11-23 04:49:04 +08:00
|
|
|
return true;
|
|
|
|
|
2009-04-25 00:55:41 +08:00
|
|
|
bool inherits = false;
|
|
|
|
|
2009-04-23 00:42:54 +08:00
|
|
|
// If there are submulticlasses, parse them.
|
|
|
|
if (Lex.getCode() == tgtok::colon) {
|
2009-04-25 00:55:41 +08:00
|
|
|
inherits = true;
|
|
|
|
|
2009-04-23 00:42:54 +08:00
|
|
|
Lex.Lex();
|
2009-04-29 03:41:44 +08:00
|
|
|
|
2009-04-23 00:42:54 +08:00
|
|
|
// Read all of the submulticlasses.
|
2009-04-29 03:41:44 +08:00
|
|
|
SubMultiClassReference SubMultiClass =
|
|
|
|
ParseSubMultiClassReference(CurMultiClass);
|
2016-08-24 01:14:32 +08:00
|
|
|
while (true) {
|
2009-04-23 00:42:54 +08:00
|
|
|
// Check for error.
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!SubMultiClass.MC) return true;
|
2009-04-29 03:41:44 +08:00
|
|
|
|
2009-04-23 00:42:54 +08:00
|
|
|
// Add it.
|
|
|
|
if (AddSubMultiClass(CurMultiClass, SubMultiClass))
|
|
|
|
return true;
|
2009-04-29 03:41:44 +08:00
|
|
|
|
2009-04-23 00:42:54 +08:00
|
|
|
if (Lex.getCode() != tgtok::comma) break;
|
|
|
|
Lex.Lex(); // eat ','.
|
|
|
|
SubMultiClass = ParseSubMultiClassReference(CurMultiClass);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-04-25 00:55:41 +08:00
|
|
|
if (Lex.getCode() != tgtok::l_brace) {
|
|
|
|
if (!inherits)
|
|
|
|
return TokError("expected '{' in multiclass definition");
|
2014-11-30 00:05:27 +08:00
|
|
|
if (Lex.getCode() != tgtok::semi)
|
2009-11-22 12:24:42 +08:00
|
|
|
return TokError("expected ';' in multiclass definition");
|
2014-11-30 00:05:27 +08:00
|
|
|
Lex.Lex(); // eat the ';'.
|
2009-11-22 12:24:42 +08:00
|
|
|
} else {
|
2009-04-25 00:55:41 +08:00
|
|
|
if (Lex.Lex() == tgtok::r_brace) // eat the '{'.
|
|
|
|
return TokError("multiclass must contain at least one def");
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2010-06-05 10:11:52 +08:00
|
|
|
while (Lex.getCode() != tgtok::r_brace) {
|
2010-06-10 10:42:59 +08:00
|
|
|
switch (Lex.getCode()) {
|
2014-11-30 00:05:27 +08:00
|
|
|
default:
|
2018-03-09 20:24:42 +08:00
|
|
|
return TokError("expected 'let', 'def', 'defm' or 'foreach' in "
|
|
|
|
"multiclass body");
|
2014-11-30 00:05:27 +08:00
|
|
|
case tgtok::Let:
|
|
|
|
case tgtok::Def:
|
|
|
|
case tgtok::Defm:
|
|
|
|
case tgtok::Foreach:
|
|
|
|
if (ParseObject(CurMultiClass))
|
|
|
|
return true;
|
|
|
|
break;
|
2010-06-10 10:42:59 +08:00
|
|
|
}
|
2010-06-05 10:11:52 +08:00
|
|
|
}
|
2009-04-25 00:55:41 +08:00
|
|
|
Lex.Lex(); // eat the '}'.
|
|
|
|
}
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2014-04-09 12:50:04 +08:00
|
|
|
CurMultiClass = nullptr;
|
2007-11-23 04:49:04 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseDefm - Parse the instantiation of a multiclass.
|
|
|
|
///
|
|
|
|
/// DefMInst ::= DEFM ID ':' DefmSubClassRef ';'
|
|
|
|
///
|
2010-06-05 10:11:52 +08:00
|
|
|
bool TGParser::ParseDefm(MultiClass *CurMultiClass) {
|
2007-11-23 04:49:04 +08:00
|
|
|
assert(Lex.getCode() == tgtok::Defm && "Unexpected token!");
|
TableGen: Streamline how defs are instantiated
Summary:
Instantiating def's and defm's needs to perform the following steps:
- for defm's, clone multiclass def prototypes and subsitute template args
- for def's and defm's, add subclass definitions, substituting template
args
- clone the record based on foreach loops and substitute loop iteration
variables
- override record variables based on the global 'let' stack
- resolve the record name (this should be simple, but unfortunately it's
not due to existing .td files relying on rather silly implementation
details)
- for def(m)s in multiclasses, add the unresolved record as a multiclass
prototype
- for top-level def(m)s, resolve all internal variable references and add
them to the record keeper and any active defsets
This change streamlines how we go through these steps, by having both
def's and defm's feed into a single addDef() method that handles foreach,
final resolve, and routing the record to the right place.
This happens to make foreach inside of multiclasses work, as the new
test case demonstrates. Previously, foreach inside multiclasses was not
forbidden by the parser, but it was de facto broken.
Another side effect is that the order of "instantiated from" notes in error
messages is reversed, as the modified test case shows. This is arguably
clearer, since the initial error message ends up pointing directly to
whatever triggered the error, and subsequent notes will point to increasingly
outer layers of multiclasses. This is consistent with how C++ compilers
report nested #includes and nested template instantiations.
Change-Id: Ica146d0db2bc133dd7ed88054371becf24320447
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D44478
llvm-svn: 328117
2018-03-22 01:12:53 +08:00
|
|
|
Lex.Lex(); // eat the defm
|
2011-10-19 21:04:29 +08:00
|
|
|
|
TableGen: Streamline how defs are instantiated
Summary:
Instantiating def's and defm's needs to perform the following steps:
- for defm's, clone multiclass def prototypes and subsitute template args
- for def's and defm's, add subclass definitions, substituting template
args
- clone the record based on foreach loops and substitute loop iteration
variables
- override record variables based on the global 'let' stack
- resolve the record name (this should be simple, but unfortunately it's
not due to existing .td files relying on rather silly implementation
details)
- for def(m)s in multiclasses, add the unresolved record as a multiclass
prototype
- for top-level def(m)s, resolve all internal variable references and add
them to the record keeper and any active defsets
This change streamlines how we go through these steps, by having both
def's and defm's feed into a single addDef() method that handles foreach,
final resolve, and routing the record to the right place.
This happens to make foreach inside of multiclasses work, as the new
test case demonstrates. Previously, foreach inside multiclasses was not
forbidden by the parser, but it was de facto broken.
Another side effect is that the order of "instantiated from" notes in error
messages is reversed, as the modified test case shows. This is arguably
clearer, since the initial error message ends up pointing directly to
whatever triggered the error, and subsequent notes will point to increasingly
outer layers of multiclasses. This is consistent with how C++ compilers
report nested #includes and nested template instantiations.
Change-Id: Ica146d0db2bc133dd7ed88054371becf24320447
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D44478
llvm-svn: 328117
2018-03-22 01:12:53 +08:00
|
|
|
Init *DefmName = ParseObjectName(CurMultiClass);
|
|
|
|
if (!DefmName)
|
|
|
|
return true;
|
TableGen: Streamline the semantics of NAME
Summary:
The new rules are straightforward. The main rules to keep in mind
are:
1. NAME is an implicit template argument of class and multiclass,
and will be substituted by the name of the instantiating def/defm.
2. The name of a def/defm in a multiclass must contain a reference
to NAME. If such a reference is not present, it is automatically
prepended.
And for some additional subtleties, consider these:
3. defm with no name generates a unique name but has no special
behavior otherwise.
4. def with no name generates an anonymous record, whose name is
unique but undefined. In particular, the name won't contain a
reference to NAME.
Keeping rules 1&2 in mind should allow a predictable behavior of
name resolution that is simple to follow.
The old "rules" were rather surprising: sometimes (but not always),
NAME would correspond to the name of the toplevel defm. They were
also plain bonkers when you pushed them to their limits, as the old
version of the TableGen test case shows.
Having NAME correspond to the name of the toplevel defm introduces
"spooky action at a distance" and breaks composability:
refactoring the upper layers of a hierarchy of nested multiclass
instantiations can cause unexpected breakage by changing the value
of NAME at a lower level of the hierarchy. The new rules don't
suffer from this problem.
Some existing .td files have to be adjusted because they ended up
depending on the details of the old implementation.
Change-Id: I694095231565b30f563e6fd0417b41ee01a12589
Reviewers: tra, simon_tatham, craig.topper, MartinO, arsenm, javed.absar
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D47430
llvm-svn: 333900
2018-06-04 22:26:05 +08:00
|
|
|
if (isa<UnsetInit>(DefmName)) {
|
TableGen: Streamline how defs are instantiated
Summary:
Instantiating def's and defm's needs to perform the following steps:
- for defm's, clone multiclass def prototypes and subsitute template args
- for def's and defm's, add subclass definitions, substituting template
args
- clone the record based on foreach loops and substitute loop iteration
variables
- override record variables based on the global 'let' stack
- resolve the record name (this should be simple, but unfortunately it's
not due to existing .td files relying on rather silly implementation
details)
- for def(m)s in multiclasses, add the unresolved record as a multiclass
prototype
- for top-level def(m)s, resolve all internal variable references and add
them to the record keeper and any active defsets
This change streamlines how we go through these steps, by having both
def's and defm's feed into a single addDef() method that handles foreach,
final resolve, and routing the record to the right place.
This happens to make foreach inside of multiclasses work, as the new
test case demonstrates. Previously, foreach inside multiclasses was not
forbidden by the parser, but it was de facto broken.
Another side effect is that the order of "instantiated from" notes in error
messages is reversed, as the modified test case shows. This is arguably
clearer, since the initial error message ends up pointing directly to
whatever triggered the error, and subsequent notes will point to increasingly
outer layers of multiclasses. This is consistent with how C++ compilers
report nested #includes and nested template instantiations.
Change-Id: Ica146d0db2bc133dd7ed88054371becf24320447
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D44478
llvm-svn: 328117
2018-03-22 01:12:53 +08:00
|
|
|
DefmName = Records.getNewAnonymousName();
|
TableGen: Streamline the semantics of NAME
Summary:
The new rules are straightforward. The main rules to keep in mind
are:
1. NAME is an implicit template argument of class and multiclass,
and will be substituted by the name of the instantiating def/defm.
2. The name of a def/defm in a multiclass must contain a reference
to NAME. If such a reference is not present, it is automatically
prepended.
And for some additional subtleties, consider these:
3. defm with no name generates a unique name but has no special
behavior otherwise.
4. def with no name generates an anonymous record, whose name is
unique but undefined. In particular, the name won't contain a
reference to NAME.
Keeping rules 1&2 in mind should allow a predictable behavior of
name resolution that is simple to follow.
The old "rules" were rather surprising: sometimes (but not always),
NAME would correspond to the name of the toplevel defm. They were
also plain bonkers when you pushed them to their limits, as the old
version of the TableGen test case shows.
Having NAME correspond to the name of the toplevel defm introduces
"spooky action at a distance" and breaks composability:
refactoring the upper layers of a hierarchy of nested multiclass
instantiations can cause unexpected breakage by changing the value
of NAME at a lower level of the hierarchy. The new rules don't
suffer from this problem.
Some existing .td files have to be adjusted because they ended up
depending on the details of the old implementation.
Change-Id: I694095231565b30f563e6fd0417b41ee01a12589
Reviewers: tra, simon_tatham, craig.topper, MartinO, arsenm, javed.absar
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D47430
llvm-svn: 333900
2018-06-04 22:26:05 +08:00
|
|
|
if (CurMultiClass)
|
|
|
|
DefmName = BinOpInit::getStrConcat(
|
|
|
|
VarInit::get(QualifiedNameOfImplicitName(CurMultiClass),
|
|
|
|
StringRecTy::get()),
|
|
|
|
DefmName);
|
|
|
|
}
|
2010-10-23 15:32:37 +08:00
|
|
|
|
2010-10-06 06:51:56 +08:00
|
|
|
if (Lex.getCode() != tgtok::colon)
|
2007-11-23 04:49:04 +08:00
|
|
|
return TokError("expected ':' after defm identifier");
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2010-06-19 03:53:41 +08:00
|
|
|
// Keep track of the new generated record definitions.
|
2018-06-21 21:35:44 +08:00
|
|
|
std::vector<RecordsEntry> NewEntries;
|
2010-06-19 03:53:41 +08:00
|
|
|
|
|
|
|
// This record also inherits from a regular class (non-multiclass)?
|
|
|
|
bool InheritFromClass = false;
|
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
// eat the colon.
|
|
|
|
Lex.Lex();
|
|
|
|
|
2009-06-21 11:39:35 +08:00
|
|
|
SMLoc SubClassLoc = Lex.getLoc();
|
2014-04-09 12:50:04 +08:00
|
|
|
SubClassReference Ref = ParseSubClassReference(nullptr, true);
|
2009-04-23 06:17:51 +08:00
|
|
|
|
2016-08-24 01:14:32 +08:00
|
|
|
while (true) {
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!Ref.Rec) return true;
|
2009-04-23 06:17:51 +08:00
|
|
|
|
|
|
|
// To instantiate a multiclass, we need to first get the multiclass, then
|
|
|
|
// instantiate each def contained in the multiclass with the SubClassRef
|
|
|
|
// template parameters.
|
2014-12-11 13:25:30 +08:00
|
|
|
MultiClass *MC = MultiClasses[Ref.Rec->getName()].get();
|
2014-11-30 09:20:17 +08:00
|
|
|
assert(MC && "Didn't lookup multiclass correctly?");
|
2016-12-05 14:41:54 +08:00
|
|
|
ArrayRef<Init*> TemplateVals = Ref.TemplateArgs;
|
2009-04-23 06:17:51 +08:00
|
|
|
|
|
|
|
// Verify that the correct number of template arguments were specified.
|
2015-10-24 20:46:45 +08:00
|
|
|
ArrayRef<Init *> TArgs = MC->Rec.getTemplateArgs();
|
2009-04-23 06:17:51 +08:00
|
|
|
if (TArgs.size() < TemplateVals.size())
|
|
|
|
return Error(SubClassLoc,
|
|
|
|
"more template args specified than multiclass expects");
|
|
|
|
|
2018-06-21 21:35:44 +08:00
|
|
|
SubstStack Substs;
|
TableGen: Streamline how defs are instantiated
Summary:
Instantiating def's and defm's needs to perform the following steps:
- for defm's, clone multiclass def prototypes and subsitute template args
- for def's and defm's, add subclass definitions, substituting template
args
- clone the record based on foreach loops and substitute loop iteration
variables
- override record variables based on the global 'let' stack
- resolve the record name (this should be simple, but unfortunately it's
not due to existing .td files relying on rather silly implementation
details)
- for def(m)s in multiclasses, add the unresolved record as a multiclass
prototype
- for top-level def(m)s, resolve all internal variable references and add
them to the record keeper and any active defsets
This change streamlines how we go through these steps, by having both
def's and defm's feed into a single addDef() method that handles foreach,
final resolve, and routing the record to the right place.
This happens to make foreach inside of multiclasses work, as the new
test case demonstrates. Previously, foreach inside multiclasses was not
forbidden by the parser, but it was de facto broken.
Another side effect is that the order of "instantiated from" notes in error
messages is reversed, as the modified test case shows. This is arguably
clearer, since the initial error message ends up pointing directly to
whatever triggered the error, and subsequent notes will point to increasingly
outer layers of multiclasses. This is consistent with how C++ compilers
report nested #includes and nested template instantiations.
Change-Id: Ica146d0db2bc133dd7ed88054371becf24320447
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D44478
llvm-svn: 328117
2018-03-22 01:12:53 +08:00
|
|
|
for (unsigned i = 0, e = TArgs.size(); i != e; ++i) {
|
|
|
|
if (i < TemplateVals.size()) {
|
2018-06-21 21:35:44 +08:00
|
|
|
Substs.emplace_back(TArgs[i], TemplateVals[i]);
|
TableGen: Streamline how defs are instantiated
Summary:
Instantiating def's and defm's needs to perform the following steps:
- for defm's, clone multiclass def prototypes and subsitute template args
- for def's and defm's, add subclass definitions, substituting template
args
- clone the record based on foreach loops and substitute loop iteration
variables
- override record variables based on the global 'let' stack
- resolve the record name (this should be simple, but unfortunately it's
not due to existing .td files relying on rather silly implementation
details)
- for def(m)s in multiclasses, add the unresolved record as a multiclass
prototype
- for top-level def(m)s, resolve all internal variable references and add
them to the record keeper and any active defsets
This change streamlines how we go through these steps, by having both
def's and defm's feed into a single addDef() method that handles foreach,
final resolve, and routing the record to the right place.
This happens to make foreach inside of multiclasses work, as the new
test case demonstrates. Previously, foreach inside multiclasses was not
forbidden by the parser, but it was de facto broken.
Another side effect is that the order of "instantiated from" notes in error
messages is reversed, as the modified test case shows. This is arguably
clearer, since the initial error message ends up pointing directly to
whatever triggered the error, and subsequent notes will point to increasingly
outer layers of multiclasses. This is consistent with how C++ compilers
report nested #includes and nested template instantiations.
Change-Id: Ica146d0db2bc133dd7ed88054371becf24320447
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D44478
llvm-svn: 328117
2018-03-22 01:12:53 +08:00
|
|
|
} else {
|
|
|
|
Init *Default = MC->Rec.getValue(TArgs[i])->getValue();
|
|
|
|
if (!Default->isComplete()) {
|
|
|
|
return Error(SubClassLoc,
|
|
|
|
"value not specified for template argument #" +
|
|
|
|
Twine(i) + " (" + TArgs[i]->getAsUnquotedString() +
|
|
|
|
") of multiclass '" + MC->Rec.getNameInitAsString() +
|
|
|
|
"'");
|
|
|
|
}
|
2018-06-21 21:35:44 +08:00
|
|
|
Substs.emplace_back(TArgs[i], Default);
|
TableGen: Streamline how defs are instantiated
Summary:
Instantiating def's and defm's needs to perform the following steps:
- for defm's, clone multiclass def prototypes and subsitute template args
- for def's and defm's, add subclass definitions, substituting template
args
- clone the record based on foreach loops and substitute loop iteration
variables
- override record variables based on the global 'let' stack
- resolve the record name (this should be simple, but unfortunately it's
not due to existing .td files relying on rather silly implementation
details)
- for def(m)s in multiclasses, add the unresolved record as a multiclass
prototype
- for top-level def(m)s, resolve all internal variable references and add
them to the record keeper and any active defsets
This change streamlines how we go through these steps, by having both
def's and defm's feed into a single addDef() method that handles foreach,
final resolve, and routing the record to the right place.
This happens to make foreach inside of multiclasses work, as the new
test case demonstrates. Previously, foreach inside multiclasses was not
forbidden by the parser, but it was de facto broken.
Another side effect is that the order of "instantiated from" notes in error
messages is reversed, as the modified test case shows. This is arguably
clearer, since the initial error message ends up pointing directly to
whatever triggered the error, and subsequent notes will point to increasingly
outer layers of multiclasses. This is consistent with how C++ compilers
report nested #includes and nested template instantiations.
Change-Id: Ica146d0db2bc133dd7ed88054371becf24320447
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D44478
llvm-svn: 328117
2018-03-22 01:12:53 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-21 21:35:44 +08:00
|
|
|
Substs.emplace_back(QualifiedNameOfImplicitName(MC), DefmName);
|
TableGen: Streamline how defs are instantiated
Summary:
Instantiating def's and defm's needs to perform the following steps:
- for defm's, clone multiclass def prototypes and subsitute template args
- for def's and defm's, add subclass definitions, substituting template
args
- clone the record based on foreach loops and substitute loop iteration
variables
- override record variables based on the global 'let' stack
- resolve the record name (this should be simple, but unfortunately it's
not due to existing .td files relying on rather silly implementation
details)
- for def(m)s in multiclasses, add the unresolved record as a multiclass
prototype
- for top-level def(m)s, resolve all internal variable references and add
them to the record keeper and any active defsets
This change streamlines how we go through these steps, by having both
def's and defm's feed into a single addDef() method that handles foreach,
final resolve, and routing the record to the right place.
This happens to make foreach inside of multiclasses work, as the new
test case demonstrates. Previously, foreach inside multiclasses was not
forbidden by the parser, but it was de facto broken.
Another side effect is that the order of "instantiated from" notes in error
messages is reversed, as the modified test case shows. This is arguably
clearer, since the initial error message ends up pointing directly to
whatever triggered the error, and subsequent notes will point to increasingly
outer layers of multiclasses. This is consistent with how C++ compilers
report nested #includes and nested template instantiations.
Change-Id: Ica146d0db2bc133dd7ed88054371becf24320447
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D44478
llvm-svn: 328117
2018-03-22 01:12:53 +08:00
|
|
|
|
2018-06-21 21:35:44 +08:00
|
|
|
if (resolve(MC->Entries, Substs, CurMultiClass == nullptr, &NewEntries,
|
|
|
|
&SubClassLoc))
|
|
|
|
return true;
|
2011-10-06 06:42:07 +08:00
|
|
|
|
2009-04-23 06:17:51 +08:00
|
|
|
if (Lex.getCode() != tgtok::comma) break;
|
|
|
|
Lex.Lex(); // eat ','.
|
|
|
|
|
2013-08-20 12:22:09 +08:00
|
|
|
if (Lex.getCode() != tgtok::Id)
|
|
|
|
return TokError("expected identifier");
|
|
|
|
|
2009-04-23 06:17:51 +08:00
|
|
|
SubClassLoc = Lex.getLoc();
|
2010-06-19 03:53:41 +08:00
|
|
|
|
|
|
|
// A defm can inherit from regular classes (non-multiclass) as
|
|
|
|
// long as they come in the end of the inheritance list.
|
2014-04-09 12:50:04 +08:00
|
|
|
InheritFromClass = (Records.getClass(Lex.getCurStrVal()) != nullptr);
|
2010-06-19 03:53:41 +08:00
|
|
|
|
|
|
|
if (InheritFromClass)
|
|
|
|
break;
|
|
|
|
|
2014-04-09 12:50:04 +08:00
|
|
|
Ref = ParseSubClassReference(nullptr, true);
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
2009-04-23 06:17:51 +08:00
|
|
|
|
2010-06-19 03:53:41 +08:00
|
|
|
if (InheritFromClass) {
|
|
|
|
// Process all the classes to inherit as if they were part of a
|
|
|
|
// regular 'def' and inherit all record values.
|
2014-04-09 12:50:04 +08:00
|
|
|
SubClassReference SubClass = ParseSubClassReference(nullptr, false);
|
2016-08-24 01:14:32 +08:00
|
|
|
while (true) {
|
2010-06-19 03:53:41 +08:00
|
|
|
// Check for error.
|
2014-04-09 12:50:04 +08:00
|
|
|
if (!SubClass.Rec) return true;
|
2010-06-19 03:53:41 +08:00
|
|
|
|
|
|
|
// Get the expanded definition prototypes and teach them about
|
|
|
|
// the record values the current class to inherit has
|
2018-06-21 21:35:44 +08:00
|
|
|
for (auto &E : NewEntries) {
|
2010-06-19 03:53:41 +08:00
|
|
|
// Add it.
|
2018-06-21 21:35:44 +08:00
|
|
|
if (AddSubClass(E, SubClass))
|
2013-01-09 12:49:14 +08:00
|
|
|
return true;
|
2010-06-19 03:53:41 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
if (Lex.getCode() != tgtok::comma) break;
|
|
|
|
Lex.Lex(); // eat ','.
|
2014-04-09 12:50:04 +08:00
|
|
|
SubClass = ParseSubClassReference(nullptr, false);
|
2010-06-19 03:53:41 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-06-21 21:35:44 +08:00
|
|
|
for (auto &E : NewEntries) {
|
|
|
|
if (ApplyLetStack(E))
|
TableGen: Streamline how defs are instantiated
Summary:
Instantiating def's and defm's needs to perform the following steps:
- for defm's, clone multiclass def prototypes and subsitute template args
- for def's and defm's, add subclass definitions, substituting template
args
- clone the record based on foreach loops and substitute loop iteration
variables
- override record variables based on the global 'let' stack
- resolve the record name (this should be simple, but unfortunately it's
not due to existing .td files relying on rather silly implementation
details)
- for def(m)s in multiclasses, add the unresolved record as a multiclass
prototype
- for top-level def(m)s, resolve all internal variable references and add
them to the record keeper and any active defsets
This change streamlines how we go through these steps, by having both
def's and defm's feed into a single addDef() method that handles foreach,
final resolve, and routing the record to the right place.
This happens to make foreach inside of multiclasses work, as the new
test case demonstrates. Previously, foreach inside multiclasses was not
forbidden by the parser, but it was de facto broken.
Another side effect is that the order of "instantiated from" notes in error
messages is reversed, as the modified test case shows. This is arguably
clearer, since the initial error message ends up pointing directly to
whatever triggered the error, and subsequent notes will point to increasingly
outer layers of multiclasses. This is consistent with how C++ compilers
report nested #includes and nested template instantiations.
Change-Id: Ica146d0db2bc133dd7ed88054371becf24320447
Reviewers: arsenm, craig.topper, tra, MartinO
Subscribers: wdng, llvm-commits
Differential Revision: https://reviews.llvm.org/D44478
llvm-svn: 328117
2018-03-22 01:12:53 +08:00
|
|
|
return true;
|
|
|
|
|
2018-06-21 21:35:44 +08:00
|
|
|
addEntry(std::move(E));
|
2018-03-06 21:48:47 +08:00
|
|
|
}
|
2010-06-23 04:30:50 +08:00
|
|
|
|
2009-04-23 06:17:51 +08:00
|
|
|
if (Lex.getCode() != tgtok::semi)
|
|
|
|
return TokError("expected ';' at end of defm");
|
|
|
|
Lex.Lex();
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseObject
|
|
|
|
/// Object ::= ClassInst
|
|
|
|
/// Object ::= DefInst
|
|
|
|
/// Object ::= MultiClassInst
|
|
|
|
/// Object ::= DefMInst
|
|
|
|
/// Object ::= LETCommand '{' ObjectList '}'
|
|
|
|
/// Object ::= LETCommand Object
|
2010-06-10 10:42:59 +08:00
|
|
|
bool TGParser::ParseObject(MultiClass *MC) {
|
2007-11-23 04:49:04 +08:00
|
|
|
switch (Lex.getCode()) {
|
2010-11-01 03:27:15 +08:00
|
|
|
default:
|
2018-03-09 20:24:42 +08:00
|
|
|
return TokError("Expected class, def, defm, defset, multiclass, let or "
|
|
|
|
"foreach");
|
2010-06-10 10:42:59 +08:00
|
|
|
case tgtok::Let: return ParseTopLevelLet(MC);
|
|
|
|
case tgtok::Def: return ParseDef(MC);
|
2012-02-23 00:09:41 +08:00
|
|
|
case tgtok::Foreach: return ParseForeach(MC);
|
2010-06-10 10:42:59 +08:00
|
|
|
case tgtok::Defm: return ParseDefm(MC);
|
2018-03-09 20:24:42 +08:00
|
|
|
case tgtok::Defset:
|
|
|
|
if (MC)
|
|
|
|
return TokError("defset is not allowed inside multiclass");
|
|
|
|
return ParseDefset();
|
2018-03-14 19:01:01 +08:00
|
|
|
case tgtok::Class:
|
|
|
|
if (MC)
|
|
|
|
return TokError("class is not allowed inside multiclass");
|
|
|
|
if (!Loops.empty())
|
|
|
|
return TokError("class is not allowed inside foreach loop");
|
|
|
|
return ParseClass();
|
|
|
|
case tgtok::MultiClass:
|
|
|
|
if (!Loops.empty())
|
|
|
|
return TokError("multiclass is not allowed inside foreach loop");
|
|
|
|
return ParseMultiClass();
|
2007-11-23 04:49:04 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/// ParseObjectList
|
|
|
|
/// ObjectList :== Object*
|
2010-06-10 10:42:59 +08:00
|
|
|
bool TGParser::ParseObjectList(MultiClass *MC) {
|
2007-11-23 04:49:04 +08:00
|
|
|
while (isObjectStart(Lex.getCode())) {
|
2010-06-10 10:42:59 +08:00
|
|
|
if (ParseObject(MC))
|
2007-11-23 04:49:04 +08:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool TGParser::ParseFile() {
|
|
|
|
Lex.Lex(); // Prime the lexer.
|
|
|
|
if (ParseObjectList()) return true;
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
// If we have unread input at the end of the file, report it.
|
|
|
|
if (Lex.getCode() == tgtok::Eof)
|
|
|
|
return false;
|
2009-11-22 12:24:42 +08:00
|
|
|
|
2007-11-23 04:49:04 +08:00
|
|
|
return TokError("Unexpected input at top level");
|
|
|
|
}
|
2018-06-21 21:35:44 +08:00
|
|
|
|
|
|
|
#if !defined(NDEBUG) || defined(LLVM_ENABLE_DUMP)
|
|
|
|
LLVM_DUMP_METHOD void RecordsEntry::dump() const {
|
|
|
|
if (Loop)
|
|
|
|
Loop->dump();
|
|
|
|
if (Rec)
|
|
|
|
Rec->dump();
|
|
|
|
}
|
|
|
|
|
|
|
|
LLVM_DUMP_METHOD void ForeachLoop::dump() const {
|
|
|
|
errs() << "foreach " << IterVar->getAsString() << " = "
|
|
|
|
<< ListValue->getAsString() << " in {\n";
|
|
|
|
|
|
|
|
for (const auto &E : Entries)
|
|
|
|
E.dump();
|
|
|
|
|
|
|
|
errs() << "}\n";
|
|
|
|
}
|
|
|
|
|
|
|
|
LLVM_DUMP_METHOD void MultiClass::dump() const {
|
|
|
|
errs() << "Record:\n";
|
|
|
|
Rec.dump();
|
|
|
|
|
|
|
|
errs() << "Defs:\n";
|
|
|
|
for (const auto &E : Entries)
|
|
|
|
E.dump();
|
|
|
|
}
|
|
|
|
#endif
|