Teach tablegen to allow "let" expressions inside multiclasses,

providing more ways to factor out commonality from the records.


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@105776 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Bruno Cardoso Lopes
2010-06-10 02:42:59 +00:00
parent 302ef834e0
commit ee65db3add
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 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> 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> </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 /// DefInst ::= DEF ObjectName ObjectBody
/// ///
llvm::Record *TGParser::ParseDef(MultiClass *CurMultiClass) { bool TGParser::ParseDef(MultiClass *CurMultiClass) {
SMLoc DefLoc = Lex.getLoc(); SMLoc DefLoc = Lex.getLoc();
assert(Lex.getCode() == tgtok::Def && "Unknown tok"); assert(Lex.getCode() == tgtok::Def && "Unknown tok");
Lex.Lex(); // Eat the 'def' token. Lex.Lex(); // Eat the 'def' token.
@ -1654,7 +1654,7 @@ llvm::Record *TGParser::ParseDef(MultiClass *CurMultiClass) {
// Ensure redefinition doesn't happen. // Ensure redefinition doesn't happen.
if (Records.getDef(CurRec->getName())) { if (Records.getDef(CurRec->getName())) {
Error(DefLoc, "def '" + CurRec->getName() + "' already defined"); Error(DefLoc, "def '" + CurRec->getName() + "' already defined");
return 0; return true;
} }
Records.addDef(CurRec); Records.addDef(CurRec);
} else { } else {
@ -1663,20 +1663,33 @@ llvm::Record *TGParser::ParseDef(MultiClass *CurMultiClass) {
if (CurMultiClass->DefPrototypes[i]->getName() == CurRec->getName()) { if (CurMultiClass->DefPrototypes[i]->getName() == CurRec->getName()) {
Error(DefLoc, "def '" + CurRec->getName() + Error(DefLoc, "def '" + CurRec->getName() +
"' already defined in this multiclass!"); "' already defined in this multiclass!");
return 0; return true;
} }
CurMultiClass->DefPrototypes.push_back(CurRec); CurMultiClass->DefPrototypes.push_back(CurRec);
} }
if (ParseObjectBody(CurRec)) if (ParseObjectBody(CurRec))
return 0; return true;
if (CurMultiClass == 0) // Def's in multiclasses aren't really defs. if (CurMultiClass == 0) // Def's in multiclasses aren't really defs.
CurRec->resolveReferences(); CurRec->resolveReferences();
// If ObjectBody has template arguments, it's an error. // If ObjectBody has template arguments, it's an error.
assert(CurRec->getTemplateArgs().empty() && "How'd this get template args?"); 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 /// 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 '{' ObjectList '}'
/// Object ::= LET LetList IN Object /// Object ::= LET LetList IN Object
/// ///
bool TGParser::ParseTopLevelLet() { bool TGParser::ParseTopLevelLet(MultiClass *CurMultiClass) {
assert(Lex.getCode() == tgtok::Let && "Unexpected token"); assert(Lex.getCode() == tgtok::Let && "Unexpected token");
Lex.Lex(); Lex.Lex();
@ -1778,7 +1791,7 @@ bool TGParser::ParseTopLevelLet() {
// If this is a scalar let, just handle it now // If this is a scalar let, just handle it now
if (Lex.getCode() != tgtok::l_brace) { if (Lex.getCode() != tgtok::l_brace) {
// LET LetList IN Object // LET LetList IN Object
if (ParseObject()) if (ParseObject(CurMultiClass))
return true; return true;
} else { // Object ::= LETCommand '{' ObjectList '}' } else { // Object ::= LETCommand '{' ObjectList '}'
SMLoc BraceLoc = Lex.getLoc(); SMLoc BraceLoc = Lex.getLoc();
@ -1786,7 +1799,7 @@ bool TGParser::ParseTopLevelLet() {
Lex.Lex(); // eat the '{'. Lex.Lex(); // eat the '{'.
// Parse the object list. // Parse the object list.
if (ParseObjectList()) if (ParseObjectList(CurMultiClass))
return true; return true;
if (Lex.getCode() != tgtok::r_brace) { if (Lex.getCode() != tgtok::r_brace) {
@ -1801,27 +1814,6 @@ bool TGParser::ParseTopLevelLet() {
return false; 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. /// ParseMultiClass - Parse a multiclass definition.
/// ///
/// MultiClassInst ::= MULTICLASS ID TemplateArgList? /// MultiClassInst ::= MULTICLASS ID TemplateArgList?
@ -1883,18 +1875,17 @@ bool TGParser::ParseMultiClass() {
return TokError("multiclass must contain at least one def"); return TokError("multiclass must contain at least one def");
while (Lex.getCode() != tgtok::r_brace) { while (Lex.getCode() != tgtok::r_brace) {
if (Lex.getCode() != tgtok::Defm && Lex.getCode() != tgtok::Def) switch (Lex.getCode()) {
return TokError("expected 'def' or 'defm' in multiclass body"); default:
return TokError("expected 'let', 'def' or 'defm' in multiclass body");
if (Lex.getCode() == tgtok::Def) case tgtok::Let:
if (ParseMultiClassDef(CurMultiClass)) case tgtok::Def:
return true; case tgtok::Defm:
if (ParseObject(CurMultiClass))
if (Lex.getCode() == tgtok::Defm)
if (ParseDefm(CurMultiClass))
return true; return true;
break;
}
} }
Lex.Lex(); // eat the '}'. Lex.Lex(); // eat the '}'.
} }
@ -2048,12 +2039,12 @@ bool TGParser::ParseDefm(MultiClass *CurMultiClass) {
/// Object ::= DefMInst /// Object ::= DefMInst
/// Object ::= LETCommand '{' ObjectList '}' /// Object ::= LETCommand '{' ObjectList '}'
/// Object ::= LETCommand Object /// Object ::= LETCommand Object
bool TGParser::ParseObject() { bool TGParser::ParseObject(MultiClass *MC) {
switch (Lex.getCode()) { switch (Lex.getCode()) {
default: assert(0 && "This is not an object"); default: assert(0 && "This is not an object");
case tgtok::Let: return ParseTopLevelLet(); case tgtok::Let: return ParseTopLevelLet(MC);
case tgtok::Def: return ParseDef(0) == 0; case tgtok::Def: return ParseDef(MC);
case tgtok::Defm: return ParseDefm(); case tgtok::Defm: return ParseDefm(MC);
case tgtok::Class: return ParseClass(); case tgtok::Class: return ParseClass();
case tgtok::MultiClass: return ParseMultiClass(); case tgtok::MultiClass: return ParseMultiClass();
} }
@ -2061,9 +2052,9 @@ bool TGParser::ParseObject() {
/// ParseObjectList /// ParseObjectList
/// ObjectList :== Object* /// ObjectList :== Object*
bool TGParser::ParseObjectList() { bool TGParser::ParseObjectList(MultiClass *MC) {
while (isObjectStart(Lex.getCode())) { while (isObjectStart(Lex.getCode())) {
if (ParseObject()) if (ParseObject(MC))
return true; return true;
} }
return false; return false;

View File

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