Teach tablegen to allow "let" expressions inside multiclasses,

providing more ways to factor out commonality from the records.

llvm-svn: 105776
This commit is contained in:
Bruno Cardoso Lopes 2010-06-10 02:42:59 +00:00
parent 38f6560461
commit 5f2adccc1b
4 changed files with 98 additions and 53 deletions

View File

@ -798,6 +798,32 @@ examples:</p>
need to be added to several records, and the records do not otherwise need to be
opened, as in the case with the <tt>CALL*</tt> instructions above.</p>
<p>It's also possible to use "let" expressions inside multiclasses, providing
more ways to factor out commonality from the records, specially if using
several levels of multiclass instanciations. This also avoids the need of using
"let" expressions within subsequent records inside a multiclass.</p>
<div class="doc_code">
<pre>
<b>multiclass </b>basic_r&lt;bits&lt;4&gt; opc&gt; {
<b>let </b>Predicates = [HasSSE2] in {
<b>def </b>rr : Instruction&lt;opc, "rr"&gt;;
<b>def </b>rm : Instruction&lt;opc, "rm"&gt;;
}
<b>let </b>Predicates = [HasSSE3] in
<b>def </b>rx : Instruction&lt;opc, "rx"&gt;;
}
<b>multiclass </b>basic_ss&lt;bits&lt;4&gt; opc&gt; {
<b>let </b>IsDouble = 0 in
<b>defm </b>SS : basic_r&lt;opc&gt;;
<b>let </b>IsDouble = 1 in
<b>defm </b>SD : basic_r&lt;opc&gt;;
}
<b>defm </b>ADD : basic_ss&lt;0xf&gt;;
</pre>
</div>
<!-- *********************************************************************** -->

View File

@ -0,0 +1,29 @@
// RUN: tblgen %s | grep "bit IsDouble = 1;" | count 3
// XFAIL: vg_leak
class Instruction<bits<4> opc, string Name> {
bits<4> opcode = opc;
string name = Name;
bit IsDouble = 0;
}
multiclass basic_r<bits<4> opc> {
let name = "newname" in {
def rr : Instruction<opc, "rr">;
def rm : Instruction<opc, "rm">;
}
let name = "othername" in
def rx : Instruction<opc, "rx">;
}
multiclass basic_ss<bits<4> opc> {
let IsDouble = 0 in
defm SS : basic_r<opc>;
let IsDouble = 1 in
defm SD : basic_r<opc>;
}
defm ADD : basic_ss<0xf>;

View File

@ -1640,7 +1640,7 @@ bool TGParser::ParseObjectBody(Record *CurRec) {
///
/// DefInst ::= DEF ObjectName ObjectBody
///
llvm::Record *TGParser::ParseDef(MultiClass *CurMultiClass) {
bool TGParser::ParseDef(MultiClass *CurMultiClass) {
SMLoc DefLoc = Lex.getLoc();
assert(Lex.getCode() == tgtok::Def && "Unknown tok");
Lex.Lex(); // Eat the 'def' token.
@ -1654,7 +1654,7 @@ llvm::Record *TGParser::ParseDef(MultiClass *CurMultiClass) {
// Ensure redefinition doesn't happen.
if (Records.getDef(CurRec->getName())) {
Error(DefLoc, "def '" + CurRec->getName() + "' already defined");
return 0;
return true;
}
Records.addDef(CurRec);
} else {
@ -1663,20 +1663,33 @@ llvm::Record *TGParser::ParseDef(MultiClass *CurMultiClass) {
if (CurMultiClass->DefPrototypes[i]->getName() == CurRec->getName()) {
Error(DefLoc, "def '" + CurRec->getName() +
"' already defined in this multiclass!");
return 0;
return true;
}
CurMultiClass->DefPrototypes.push_back(CurRec);
}
if (ParseObjectBody(CurRec))
return 0;
return true;
if (CurMultiClass == 0) // Def's in multiclasses aren't really defs.
CurRec->resolveReferences();
// If ObjectBody has template arguments, it's an error.
assert(CurRec->getTemplateArgs().empty() && "How'd this get template args?");
return CurRec;
if (CurMultiClass) {
// Copy the template arguments for the multiclass into the def.
const std::vector<std::string> &TArgs =
CurMultiClass->Rec.getTemplateArgs();
for (unsigned i = 0, e = TArgs.size(); i != e; ++i) {
const RecordVal *RV = CurMultiClass->Rec.getValue(TArgs[i]);
assert(RV && "Template arg doesn't exist?");
CurRec->addValue(*RV);
}
}
return false;
}
@ -1757,12 +1770,12 @@ std::vector<LetRecord> TGParser::ParseLetList() {
}
/// ParseTopLevelLet - Parse a 'let' at top level. This can be a couple of
/// different related productions.
/// different related productions. This works inside multiclasses too.
///
/// Object ::= LET LetList IN '{' ObjectList '}'
/// Object ::= LET LetList IN Object
///
bool TGParser::ParseTopLevelLet() {
bool TGParser::ParseTopLevelLet(MultiClass *CurMultiClass) {
assert(Lex.getCode() == tgtok::Let && "Unexpected token");
Lex.Lex();
@ -1778,7 +1791,7 @@ bool TGParser::ParseTopLevelLet() {
// If this is a scalar let, just handle it now
if (Lex.getCode() != tgtok::l_brace) {
// LET LetList IN Object
if (ParseObject())
if (ParseObject(CurMultiClass))
return true;
} else { // Object ::= LETCommand '{' ObjectList '}'
SMLoc BraceLoc = Lex.getLoc();
@ -1786,7 +1799,7 @@ bool TGParser::ParseTopLevelLet() {
Lex.Lex(); // eat the '{'.
// Parse the object list.
if (ParseObjectList())
if (ParseObjectList(CurMultiClass))
return true;
if (Lex.getCode() != tgtok::r_brace) {
@ -1801,27 +1814,6 @@ bool TGParser::ParseTopLevelLet() {
return false;
}
/// ParseMultiClassDef - Parse a def in a multiclass context.
///
/// MultiClassDef ::= DefInst
///
bool TGParser::ParseMultiClassDef(MultiClass *CurMC) {
Record *D = ParseDef(CurMC);
if (D == 0) return true;
// Copy the template arguments for the multiclass into the def.
const std::vector<std::string> &TArgs = CurMC->Rec.getTemplateArgs();
for (unsigned i = 0, e = TArgs.size(); i != e; ++i) {
const RecordVal *RV = CurMC->Rec.getValue(TArgs[i]);
assert(RV && "Template arg doesn't exist?");
D->addValue(*RV);
}
return false;
}
/// ParseMultiClass - Parse a multiclass definition.
///
/// MultiClassInst ::= MULTICLASS ID TemplateArgList?
@ -1883,18 +1875,17 @@ bool TGParser::ParseMultiClass() {
return TokError("multiclass must contain at least one def");
while (Lex.getCode() != tgtok::r_brace) {
if (Lex.getCode() != tgtok::Defm && Lex.getCode() != tgtok::Def)
return TokError("expected 'def' or 'defm' in multiclass body");
if (Lex.getCode() == tgtok::Def)
if (ParseMultiClassDef(CurMultiClass))
return true;
if (Lex.getCode() == tgtok::Defm)
if (ParseDefm(CurMultiClass))
return true;
switch (Lex.getCode()) {
default:
return TokError("expected 'let', 'def' or 'defm' in multiclass body");
case tgtok::Let:
case tgtok::Def:
case tgtok::Defm:
if (ParseObject(CurMultiClass))
return true;
break;
}
}
Lex.Lex(); // eat the '}'.
}
@ -2048,12 +2039,12 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) {
/// Object ::= DefMInst
/// Object ::= LETCommand '{' ObjectList '}'
/// Object ::= LETCommand Object
bool TGParser::ParseObject() {
bool TGParser::ParseObject(MultiClass *MC) {
switch (Lex.getCode()) {
default: assert(0 && "This is not an object");
case tgtok::Let: return ParseTopLevelLet();
case tgtok::Def: return ParseDef(0) == 0;
case tgtok::Defm: return ParseDefm();
case tgtok::Let: return ParseTopLevelLet(MC);
case tgtok::Def: return ParseDef(MC);
case tgtok::Defm: return ParseDefm(MC);
case tgtok::Class: return ParseClass();
case tgtok::MultiClass: return ParseMultiClass();
}
@ -2061,9 +2052,9 @@ bool TGParser::ParseObject() {
/// ParseObjectList
/// ObjectList :== Object*
bool TGParser::ParseObjectList() {
bool TGParser::ParseObjectList(MultiClass *MC) {
while (isObjectStart(Lex.getCode())) {
if (ParseObject())
if (ParseObject(MC))
return true;
}
return false;

View File

@ -69,16 +69,15 @@ private: // Semantic analysis methods.
SubMultiClassReference &SubMultiClass);
private: // Parser methods.
bool ParseObjectList();
bool ParseObject();
bool ParseObjectList(MultiClass *MC = 0);
bool ParseObject(MultiClass *MC);
bool ParseClass();
bool ParseMultiClass();
bool ParseMultiClassDef(MultiClass *CurMC);
bool ParseDefm(MultiClass *CurMultiClass = 0);
bool ParseTopLevelLet();
bool ParseDefm(MultiClass *CurMultiClass);
bool ParseDef(MultiClass *CurMultiClass);
bool ParseTopLevelLet(MultiClass *CurMultiClass);
std::vector<LetRecord> ParseLetList();
Record *ParseDef(MultiClass *CurMultiClass);
bool ParseObjectBody(Record *CurRec);
bool ParseBody(Record *CurRec);
bool ParseBodyItem(Record *CurRec);