19#include "mlir/IR/Attributes.h"
20#include "mlir/IR/Builders.h"
21#include "mlir/IR/BuiltinAttributes.h"
22#include "mlir/IR/BuiltinOps.h"
23#include "mlir/IR/BuiltinTypes.h"
24#include "mlir/IR/Diagnostics.h"
25#include "mlir/IR/Location.h"
26#include "mlir/IR/MLIRContext.h"
27#include "mlir/IR/Value.h"
28#include "mlir/Support/FileUtilities.h"
29#include "mlir/Support/LogicalResult.h"
30#include "mlir/Tools/mlir-translate/Translation.h"
31#include "llvm/ADT/STLExtras.h"
32#include "llvm/ADT/StringRef.h"
33#include "llvm/Support/LogicalResult.h"
34#include "llvm/Support/SourceMgr.h"
36#define DEBUG_TYPE "import-liberty"
46enum class LibertyTokenKind {
66StringRef stringifyTokenKind(LibertyTokenKind kind) {
68 case LibertyTokenKind::Identifier:
70 case LibertyTokenKind::String:
72 case LibertyTokenKind::Number:
74 case LibertyTokenKind::LBrace:
76 case LibertyTokenKind::RBrace:
78 case LibertyTokenKind::LParen:
80 case LibertyTokenKind::RParen:
82 case LibertyTokenKind::Colon:
84 case LibertyTokenKind::Semi:
86 case LibertyTokenKind::Comma:
89 case LibertyTokenKind::EndOfFile:
91 case LibertyTokenKind::Error:
98 LibertyTokenKind kind;
102 LibertyToken(LibertyTokenKind kind, StringRef spelling, SMLoc location)
103 : kind(kind), spelling(spelling), location(location) {}
105 bool is(LibertyTokenKind k)
const {
return kind == k; }
110 LibertyLexer(
const llvm::SourceMgr &sourceMgr, MLIRContext *context)
111 : sourceMgr(sourceMgr), context(context),
113 sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID())->getBuffer()),
114 curPtr(curBuffer.begin()) {}
116 LibertyToken nextToken();
117 LibertyToken peekToken();
119 SMLoc getCurrentLoc()
const {
return SMLoc::getFromPointer(curPtr); }
121 Location translateLocation(llvm::SMLoc loc)
const {
122 unsigned mainFileID = sourceMgr.getMainFileID();
123 auto lineAndColumn = sourceMgr.getLineAndColumn(loc, mainFileID);
124 return FileLineColLoc::get(
127 sourceMgr.getMemoryBuffer(mainFileID)->getBufferIdentifier()),
128 lineAndColumn.first, lineAndColumn.second);
131 bool isAtEnd()
const {
return curPtr >= curBuffer.end(); }
134 const llvm::SourceMgr &sourceMgr;
135 MLIRContext *context;
139 void skipWhitespaceAndComments();
140 LibertyToken lexIdentifier();
141 LibertyToken lexString();
142 LibertyToken lexNumber();
143 LibertyToken makeToken(LibertyTokenKind kind,
const char *start);
160class ExpressionParser {
162 ExpressionParser(LibertyLexer &lexer, OpBuilder &builder, StringRef expr,
163 const llvm::StringMap<Value> &values, SMLoc baseLoc);
165 ParseResult parse(Value &result);
168 enum class TokenKind {
188 const llvm::StringMap<Value> &values;
190 const char *exprStart;
191 SmallVector<Token> tokens;
193 Value trueVal =
nullptr;
195 SMLoc
getLoc(
const char *ptr);
196 void tokenize(StringRef expr);
199 Value createNot(Value val, SMLoc loc);
201 ParseResult parseOrExpr(Value &result);
202 ParseResult parseXorExpr(Value &result);
203 ParseResult parseAndExpr(Value &result);
204 ParseResult parseUnaryExpr(Value &result);
206 InFlightDiagnostic emitError(llvm::SMLoc loc,
const Twine &message)
const;
213ExpressionParser::ExpressionParser(LibertyLexer &lexer, OpBuilder &builder,
215 const llvm::StringMap<Value> &values,
217 : lexer(lexer), builder(builder), values(values), baseLoc(baseLoc),
218 exprStart(expr.begin()) {
222ParseResult ExpressionParser::parse(Value &result) {
223 return parseOrExpr(result);
226SMLoc ExpressionParser::getLoc(
const char *ptr) {
227 size_t offset = ptr - exprStart;
228 return SMLoc::getFromPointer(baseLoc.getPointer() + 1 + offset);
231void ExpressionParser::tokenize(StringRef expr) {
232 const char *ptr = expr.begin();
233 const char *end = expr.end();
245 if (isalnum(*ptr) || *ptr ==
'_') {
246 const char *start = ptr;
247 while (ptr < end && (isalnum(*ptr) || *ptr ==
'_'))
249 tokens.push_back({TokenKind::ID, StringRef(start, ptr - start), loc});
257 tokens.push_back({TokenKind::AND, StringRef(ptr, 1), loc});
261 tokens.push_back({TokenKind::OR, StringRef(ptr, 1), loc});
264 tokens.push_back({TokenKind::XOR, StringRef(ptr, 1), loc});
267 tokens.push_back({TokenKind::PREFIX_NOT, StringRef(ptr, 1), loc});
270 tokens.push_back({TokenKind::POSTFIX_NOT, StringRef(ptr, 1), loc});
273 tokens.push_back({TokenKind::LPAREN, StringRef(ptr, 1), loc});
276 tokens.push_back({TokenKind::RPAREN, StringRef(ptr, 1), loc});
282 tokens.push_back({TokenKind::END,
"",
getLoc(ptr)});
285ExpressionParser::Token ExpressionParser::peek()
const {
return tokens[pos]; }
287ExpressionParser::Token ExpressionParser::consume() {
return tokens[pos++]; }
289Value ExpressionParser::createNot(Value val, SMLoc loc) {
292 builder.getI1Type(), 1);
293 return comb::XorOp::create(builder, lexer.translateLocation(loc), val,
300ParseResult ExpressionParser::parseOrExpr(Value &result) {
302 if (parseXorExpr(lhs))
304 while (peek().kind == TokenKind::OR) {
305 auto loc = consume().loc;
307 if (parseXorExpr(rhs))
309 lhs = comb::OrOp::create(builder, lexer.translateLocation(loc), lhs, rhs);
318ParseResult ExpressionParser::parseXorExpr(Value &result) {
320 if (parseAndExpr(lhs))
322 while (peek().kind == TokenKind::XOR) {
323 auto loc = consume().loc;
325 if (parseAndExpr(rhs))
327 lhs = comb::XorOp::create(builder, lexer.translateLocation(loc), lhs, rhs);
337ParseResult ExpressionParser::parseAndExpr(Value &result) {
339 if (parseUnaryExpr(lhs))
341 while (peek().kind == TokenKind::AND ||
342 (peek().kind == TokenKind::ID || peek().kind == TokenKind::LPAREN ||
343 peek().kind == TokenKind::PREFIX_NOT)) {
344 auto loc = peek().loc;
345 if (peek().kind == TokenKind::AND)
348 if (parseUnaryExpr(rhs))
350 lhs = comb::AndOp::create(builder, lexer.translateLocation(loc), lhs, rhs);
360ParseResult ExpressionParser::parseUnaryExpr(Value &result) {
362 if (peek().kind == TokenKind::PREFIX_NOT) {
363 auto loc = consume().loc;
365 if (parseUnaryExpr(val))
367 result = createNot(val, loc);
372 if (peek().kind == TokenKind::LPAREN) {
375 if (parseOrExpr(val))
377 if (peek().kind != TokenKind::RPAREN)
381 if (peek().kind == TokenKind::POSTFIX_NOT) {
382 auto loc = consume().loc;
383 val = createNot(val, loc);
390 if (peek().kind == TokenKind::ID) {
391 auto tok = consume();
392 StringRef name = tok.spelling;
393 auto it = values.find(name);
394 if (it == values.end())
395 return emitError(tok.loc,
"variable not found");
396 Value val = it->second;
398 if (peek().kind == TokenKind::POSTFIX_NOT) {
399 auto loc = consume().loc;
400 val = createNot(val, loc);
406 return emitError(peek().loc,
"expected expression");
409InFlightDiagnostic ExpressionParser::emitError(llvm::SMLoc loc,
410 const Twine &message)
const {
411 return mlir::emitError(lexer.translateLocation(loc), message);
418 SmallVector<Attribute> args;
423 AttrEntry(StringRef name, Attribute value, SMLoc loc)
424 : name(name), value(value), loc(loc) {}
426 SmallVector<AttrEntry> attrs;
427 SmallVector<std::unique_ptr<LibertyGroup>> subGroups;
430 std::pair<Attribute, SMLoc> getAttribute(StringRef name)
const {
431 for (
const auto &attr : attrs)
432 if (attr.name == name)
433 return {attr.value, attr.loc};
437 void eraseSubGroup(llvm::function_ref<
bool(
const LibertyGroup &)> pred) {
439 std::remove_if(subGroups.begin(), subGroups.end(),
440 [pred](
const auto &group) { return pred(*group); }),
444 LogicalResult checkArgs(
446 llvm::function_ref<LogicalResult(
size_t idx, Attribute)> pred)
const {
447 if (args.size() != n)
449 for (
size_t i = 0; i < n; ++i)
450 if (failed(pred(i, args[i])))
458 LibertyParser(
const llvm::SourceMgr &sourceMgr, MLIRContext *
context,
460 : lexer(sourceMgr,
context), module(module),
461 builder(module.getBodyRegion()) {}
471 ParseResult parseLibrary();
472 ParseResult parseGroupBody(LibertyGroup &group);
473 ParseResult parseStatement(LibertyGroup &parent);
477 lowerCell(
const LibertyGroup &group, StringAttr &cellNameAttr,
478 const llvm::StringMap<const LibertyGroup *> &tableTemplates);
481 parseNLDMTable(
const LibertyGroup &group,
482 const llvm::StringMap<const LibertyGroup *> &tableTemplates,
483 synth::NLDMTableAttr &table);
486 buildTimingArcs(
const LibertyGroup &pinGroup,
487 const llvm::StringMap<const LibertyGroup *> &tableTemplates,
488 SmallVector<Attribute> &timingArcs);
491 collectPorts(
const LibertyGroup &cellGroup,
492 const llvm::StringMap<const LibertyGroup *> &tableTemplates,
493 SmallVector<hw::PortInfo> &ports,
494 SmallVector<const LibertyGroup *> &pinGroups,
495 SmallVector<Attribute> &timingArcs,
496 size_t &numOutputPinMissingFunction);
499 ArrayRef<hw::PortInfo> ports,
500 ArrayRef<const LibertyGroup *> pinGroups);
502 LogicalResult parseLibertyFloatList(StringRef value, SMLoc loc,
503 SmallVectorImpl<double> &result)
const;
509 Attribute convertGroupToAttr(
const LibertyGroup &group);
512 ParseResult parseAttribute(Attribute &result);
515 ParseResult parseExpression(Value &result, StringRef expr,
516 const llvm::StringMap<Value> &values, SMLoc loc);
518 InFlightDiagnostic emitError(llvm::SMLoc loc,
const Twine &message)
const {
519 return mlir::emitError(lexer.translateLocation(loc), message);
522 InFlightDiagnostic emitWarning(llvm::SMLoc loc,
const Twine &message)
const {
523 return mlir::emitWarning(lexer.translateLocation(loc), message);
526 ParseResult consume(LibertyTokenKind kind,
const Twine &msg) {
527 if (lexer.nextToken().is(kind))
529 return emitError(lexer.getCurrentLoc(), msg);
532 ParseResult consumeUntil(LibertyTokenKind kind) {
533 while (!lexer.peekToken().is(kind) &&
534 lexer.peekToken().kind != LibertyTokenKind::EndOfFile)
536 if (lexer.peekToken().is(kind))
538 return emitError(lexer.getCurrentLoc(),
539 " expected " + stringifyTokenKind(kind));
542 ParseResult consume(LibertyTokenKind kind) {
543 if (lexer.nextToken().is(kind))
545 return emitError(lexer.getCurrentLoc(),
546 " expected " + stringifyTokenKind(kind));
549 ParseResult expect(LibertyTokenKind kind) {
550 if (!lexer.peekToken().is(kind))
551 return emitError(lexer.getCurrentLoc(),
552 " expected " + stringifyTokenKind(kind));
557 StringRef getTokenSpelling(
const LibertyToken &token) {
558 StringRef str = token.spelling;
559 if (token.kind == LibertyTokenKind::String)
560 str = str.drop_front().drop_back();
569void LibertyLexer::skipWhitespaceAndComments() {
570 while (curPtr < curBuffer.end()) {
571 if (isspace(*curPtr)) {
577 if (*curPtr ==
'/' && curPtr + 1 < curBuffer.end()) {
578 if (*(curPtr + 1) ==
'*') {
580 while (curPtr + 1 < curBuffer.end() &&
581 (*curPtr !=
'*' || *(curPtr + 1) !=
'/'))
583 if (curPtr + 1 < curBuffer.end())
587 if (*(curPtr + 1) ==
'/') {
588 while (curPtr < curBuffer.end() && *curPtr !=
'\n')
595 if (*curPtr ==
'\\' && curPtr + 1 < curBuffer.end() &&
596 *(curPtr + 1) ==
'\n') {
605LibertyToken LibertyLexer::lexIdentifier() {
606 const char *start = curPtr;
607 while (curPtr < curBuffer.end() &&
608 (isalnum(*curPtr) || *curPtr ==
'_' || *curPtr ==
'.'))
610 return makeToken(LibertyTokenKind::Identifier, start);
613LibertyToken LibertyLexer::lexString() {
614 const char *start = curPtr;
616 while (curPtr < curBuffer.end() && *curPtr !=
'"') {
617 if (*curPtr ==
'\\' && curPtr + 1 < curBuffer.end())
621 if (curPtr < curBuffer.end())
623 return makeToken(LibertyTokenKind::String, start);
626LibertyToken LibertyLexer::lexNumber() {
627 const char *start = curPtr;
628 bool seenDot =
false;
629 while (curPtr < curBuffer.end()) {
632 }
else if (*curPtr ==
'.') {
634 mlir::emitError(translateLocation(SMLoc::getFromPointer(curPtr)),
635 "multiple decimal points in number");
636 return makeToken(LibertyTokenKind::Error, start);
644 return makeToken(LibertyTokenKind::Number, start);
647LibertyToken LibertyLexer::makeToken(LibertyTokenKind kind,
const char *start) {
648 return LibertyToken(kind, StringRef(start, curPtr - start),
649 SMLoc::getFromPointer(start));
652LibertyToken LibertyLexer::nextToken() {
653 skipWhitespaceAndComments();
655 if (curPtr >= curBuffer.end())
656 return makeToken(LibertyTokenKind::EndOfFile, curPtr);
658 const char *start = curPtr;
662 return lexIdentifier();
665 (c ==
'.' && curPtr + 1 < curBuffer.end() &&
isdigit(*(curPtr + 1))))
674 return makeToken(LibertyTokenKind::LBrace, start);
676 return makeToken(LibertyTokenKind::RBrace, start);
678 return makeToken(LibertyTokenKind::LParen, start);
680 return makeToken(LibertyTokenKind::RParen, start);
682 return makeToken(LibertyTokenKind::Colon, start);
684 return makeToken(LibertyTokenKind::Semi, start);
686 return makeToken(LibertyTokenKind::Comma, start);
689 return makeToken(LibertyTokenKind::Error, start);
693LibertyToken LibertyLexer::peekToken() {
694 const char *savedPtr = curPtr;
695 LibertyToken token = nextToken();
704ParseResult LibertyParser::parse() {
705 while (lexer.peekToken().kind != LibertyTokenKind::EndOfFile) {
706 auto token = lexer.peekToken();
708 if (token.kind != LibertyTokenKind::Identifier ||
709 token.spelling !=
"library") {
710 return emitError(token.location,
"expected `library` keyword");
719ParseResult LibertyParser::parseLibrary() {
720 LibertyGroup libertyLib;
721 if (parseGroupBody(libertyLib))
729 llvm::StringMap<const LibertyGroup *> tableTemplates;
730 for (
const auto &stmt : libertyLib.subGroups)
731 if (stmt->name ==
"lu_table_template")
732 if (!stmt->args.empty())
733 if (
auto name = dyn_cast<StringAttr>(stmt->args[0]))
734 tableTemplates[name.getValue()] = stmt.get();
738 DenseSet<StringAttr> seenCells;
739 for (
auto &stmt : libertyLib.subGroups) {
740 if (stmt->name !=
"cell")
742 StringAttr cellNameAttr;
743 if (lowerCell(*stmt, cellNameAttr, tableTemplates))
745 if (!seenCells.insert(cellNameAttr).second)
746 return emitError(stmt->loc,
"redefinition of cell '" +
747 cellNameAttr.getValue() +
"'");
750 libertyLib.eraseSubGroup(
751 [](
const LibertyGroup &group) {
return group.name ==
"cell"; });
752 auto attr = convertGroupToAttr(libertyLib);
753 module->setAttr("synth.liberty.library", attr);
759Attribute LibertyParser::convertGroupToAttr(
const LibertyGroup &group) {
760 SmallVector<NamedAttribute> attrs;
761 if (!group.args.empty())
763 builder.getNamedAttr(
"args", builder.getArrayAttr(group.args)));
765 for (
const auto &attr : group.attrs)
766 attrs.push_back(builder.getNamedAttr(attr.name, attr.value));
768 llvm::StringMap<SmallVector<Attribute>> subGroups;
769 for (
const auto &sub : group.subGroups)
770 subGroups[sub->name].push_back(convertGroupToAttr(*sub));
772 for (
auto &it : subGroups)
774 builder.getNamedAttr(it.getKey(), builder.getArrayAttr(it.getValue())));
776 return builder.getDictionaryAttr(attrs);
780LibertyParser::parseLibertyFloatList(StringRef value, SMLoc loc,
781 SmallVectorImpl<double> &result)
const {
782 SmallVector<StringRef> parts;
783 value.split(parts,
',');
784 for (
auto part : parts) {
789 if (part.getAsDouble(val))
790 return emitError(loc,
"expected floating point value in NLDM table");
791 result.push_back(val);
796ParseResult LibertyParser::parseNLDMTable(
797 const LibertyGroup &group,
798 const llvm::StringMap<const LibertyGroup *> &tableTemplates,
799 synth::NLDMTableAttr &table) {
800 SmallVector<double> index1, index2, values;
802 auto parseList = [&](
const LibertyGroup &source, StringRef name,
803 SmallVectorImpl<double> &result) -> ParseResult {
804 if (
auto [attr, loc] = source.getAttribute(name); attr) {
805 auto stringAttr = dyn_cast<StringAttr>(attr);
807 return emitError(loc,
"expected string value for NLDM table entry");
808 if (failed(parseLibertyFloatList(stringAttr.getValue(), loc, result)))
813 for (
const auto &subGroup : source.subGroups) {
814 if (subGroup->name != name)
816 if (subGroup->args.empty())
817 return emitError(subGroup->loc,
"NLDM table entry missing value");
818 for (
auto arg : subGroup->args) {
819 auto stringAttr = dyn_cast<StringAttr>(arg);
821 return emitError(subGroup->loc,
822 "expected string value for NLDM table entry");
823 if (failed(parseLibertyFloatList(stringAttr.getValue(), subGroup->loc,
834 if (parseList(group,
"index_1", index1) ||
835 parseList(group,
"index_2", index2) || parseList(group,
"values", values))
838 if (!group.args.empty()) {
839 auto templateName = dyn_cast<StringAttr>(group.args[0]);
841 return emitError(group.loc,
"NLDM table template name must be a string");
843 auto it = tableTemplates.find(templateName.getValue());
844 if (it == tableTemplates.end())
845 return emitError(group.loc,
"unknown NLDM table template '")
846 << templateName.getValue() <<
"'";
848 if (index1.empty() && parseList(*it->second,
"index_1", index1))
850 if (index2.empty() && parseList(*it->second,
"index_2", index2))
855 return emitError(group.loc,
"NLDM table missing index_1");
857 return emitError(group.loc,
"NLDM table missing index_2");
859 return emitError(group.loc,
"NLDM table missing values");
861 if (values.size() != index1.size() * index2.size()) {
862 return emitError(group.loc,
"NLDM table has ")
863 << values.size() <<
" values, expected "
864 << index1.size() * index2.size() <<
" for " << index1.size() <<
" x "
865 << index2.size() <<
" indices";
868 table = synth::NLDMTableAttr::get(
869 builder.getContext(),
870 DenseF64ArrayAttr::get(builder.getContext(), index1),
871 DenseF64ArrayAttr::get(builder.getContext(), index2),
872 DenseF64ArrayAttr::get(builder.getContext(), values));
876static bool isNLDMTableGroup(StringRef name) {
877 return name ==
"cell_rise" || name ==
"cell_fall" ||
878 name ==
"rise_transition" || name ==
"fall_transition";
881LogicalResult LibertyParser::buildTimingArcs(
882 const LibertyGroup &pinGroup,
883 const llvm::StringMap<const LibertyGroup *> &tableTemplates,
884 SmallVector<Attribute> &timingArcs) {
885 auto pinName = cast<StringAttr>(pinGroup.args[0]);
887 for (
const auto &child : pinGroup.subGroups) {
888 if (child->name !=
"timing")
892 dyn_cast_or_null<StringAttr>(child->getAttribute(
"related_pin").first);
894 dyn_cast_or_null<StringAttr>(child->getAttribute(
"timing_sense").first);
895 if (!relatedPin || !timingSense)
896 return emitError(child->loc,
897 "timing related_pin and timing_sense must be strings");
899 synth::NLDMTableAttr cellRise, cellFall, riseTransition, fallTransition;
900 for (
const auto &table : child->subGroups) {
901 if (!isNLDMTableGroup(table->name))
904 synth::NLDMTableAttr parsedTable;
905 if (parseNLDMTable(*table, tableTemplates, parsedTable))
908 if (table->name ==
"cell_rise")
909 cellRise = parsedTable;
910 else if (table->name ==
"cell_fall")
911 cellFall = parsedTable;
912 else if (table->name ==
"rise_transition")
913 riseTransition = parsedTable;
914 else if (table->name ==
"fall_transition")
915 fallTransition = parsedTable;
918 if (!cellRise || !cellFall || !riseTransition || !fallTransition)
919 return emitError(child->loc,
920 "NLDM timing arc requires cell_rise, cell_fall, "
921 "rise_transition, and fall_transition tables");
923 timingArcs.push_back(synth::NLDMTimingArcAttr::get(
924 builder.getContext(), pinName, relatedPin, timingSense, cellRise,
925 cellFall, riseTransition, fallTransition));
930LogicalResult LibertyParser::collectPorts(
931 const LibertyGroup &cellGroup,
932 const llvm::StringMap<const LibertyGroup *> &tableTemplates,
933 SmallVector<hw::PortInfo> &ports,
934 SmallVector<const LibertyGroup *> &pinGroups,
935 SmallVector<Attribute> &timingArcs,
size_t &numOutputPinMissingFunction) {
937 llvm::DenseSet<StringAttr> seenPins;
940 for (
const auto &sub : cellGroup.subGroups) {
941 if (sub->name !=
"pin")
944 pinGroups.push_back(sub.get());
945 if (sub->args.empty())
946 return emitError(sub->loc,
"pin missing name");
948 StringAttr pinName = dyn_cast<StringAttr>(sub->args[0]);
949 if (!seenPins.insert(pinName).second)
950 return emitError(sub->loc,
951 "redefinition of pin '" + pinName.getValue() +
"'");
953 std::optional<hw::ModulePort::Direction> dir;
954 SmallVector<NamedAttribute> pinAttrs;
955 bool functionExist =
false;
958 for (
const auto &attr : sub->attrs) {
959 if (attr.name ==
"direction") {
960 auto val = dyn_cast<StringAttr>(attr.value);
962 return emitError(sub->loc,
"pin direction must be a string");
963 if (val.getValue() ==
"input")
964 dir = hw::ModulePort::Direction::Input;
965 else if (val.getValue() ==
"output")
966 dir = hw::ModulePort::Direction::Output;
967 else if (val.getValue() ==
"inout")
968 dir = hw::ModulePort::Direction::InOut;
970 return emitError(sub->loc,
971 "pin direction must be input, output, or inout");
974 if (attr.name ==
"function")
975 functionExist =
true;
976 pinAttrs.push_back(builder.getNamedAttr(attr.name, attr.value));
980 return emitError(sub->loc,
"pin direction must be specified");
982 if (dir == hw::ModulePort::Direction::Output && !functionExist)
983 ++numOutputPinMissingFunction;
986 if (failed(buildTimingArcs(*sub, tableTemplates, timingArcs)))
990 llvm::StringMap<SmallVector<Attribute>> subGroupAttrs;
991 for (
const auto &child : sub->subGroups)
992 if (child->name !=
"timing")
993 subGroupAttrs[child->name].push_back(convertGroupToAttr(*child));
995 for (
auto &it : subGroupAttrs)
996 pinAttrs.push_back(builder.getNamedAttr(
997 it.getKey(), builder.getArrayAttr(it.getValue())));
999 auto libertyAttrs = builder.getDictionaryAttr(pinAttrs);
1000 auto attrs = builder.getDictionaryAttr(
1001 builder.getNamedAttr(
"synth.liberty.pin", libertyAttrs));
1004 port.
name = pinName;
1005 port.
type = builder.getI1Type();
1008 ports.push_back(port);
1015 ArrayRef<hw::PortInfo> ports,
1016 ArrayRef<const LibertyGroup *> pinGroups) {
1019 OpBuilder::InsertionGuard guard(builder);
1020 builder.setInsertionPointToStart(moduleOp.getBodyBlock());
1022 llvm::StringMap<Value> portValues;
1023 for (
const auto &port : ports)
1024 if (port.dir == hw::ModulePort::Direction::Input)
1025 portValues[port.name.getValue()] =
1026 moduleOp.getBodyBlock()->getArgument(port.argNum);
1028 SmallVector<Value> outputs;
1029 for (
const auto &port : ports) {
1030 if (port.dir != hw::ModulePort::Direction::Output)
1033 auto *it = llvm::find_if(pinGroups, [&](
const LibertyGroup *g) {
1034 assert(g->name ==
"pin" &&
"expected pin group");
1036 return cast<StringAttr>(g->args[0]) == port.name;
1042 const LibertyGroup *pg = *it;
1043 auto attrPair = pg->getAttribute(
"function");
1044 assert(attrPair.first &&
"output pin missing function attribute");
1047 if (parseExpression(val, cast<StringAttr>(attrPair.first).getValue(),
1048 portValues, attrPair.second))
1050 outputs.push_back(val);
1053 moduleOp.getBodyBlock()->getTerminator()->setOperands(outputs);
1057ParseResult LibertyParser::lowerCell(
1058 const LibertyGroup &group, StringAttr &cellNameAttr,
1059 const llvm::StringMap<const LibertyGroup *> &tableTemplates) {
1061 if (group.args.empty())
1062 return emitError(group.loc,
"cell missing name");
1063 cellNameAttr = dyn_cast<StringAttr>(group.args[0]);
1065 return emitError(group.loc,
"cell name must be a string");
1067 SmallVector<hw::PortInfo> ports;
1068 SmallVector<const LibertyGroup *> pinGroups;
1069 SmallVector<Attribute> timingArcs;
1070 size_t numOutputPinMissingFunction = 0;
1072 if (failed(collectPorts(group, tableTemplates, ports, pinGroups, timingArcs,
1073 numOutputPinMissingFunction)))
1078 for (
auto &p : ports)
1079 if (p.dir == hw::ModulePort::Direction::Input)
1080 p.argNum = inputIdx++;
1084 auto loc = lexer.translateLocation(group.loc);
1085 auto numOutput = ports.size() - inputIdx;
1092 if (numOutputPinMissingFunction != 0 &&
1093 numOutputPinMissingFunction != numOutput)
1094 return emitError(group.loc,
"cell '")
1095 << cellNameAttr.getValue()
1096 <<
"' has mixed output pins with and without 'function' attribute";
1099 if (numOutputPinMissingFunction == numOutput) {
1101 hw::HWModuleExternOp::create(builder, loc, cellNameAttr, ports);
1102 if (!timingArcs.empty())
1103 externOp->setAttr(
"synth.timing.nldm", builder.getArrayAttr(timingArcs));
1108 auto moduleOp = hw::HWModuleOp::create(builder, loc, cellNameAttr, ports);
1110 if (failed(buildCellLogic(moduleOp, ports, pinGroups)))
1113 if (!timingArcs.empty())
1114 moduleOp->setAttr(
"synth.timing.nldm", builder.getArrayAttr(timingArcs));
1119ParseResult LibertyParser::parseGroupBody(LibertyGroup &group) {
1121 if (lexer.peekToken().kind == LibertyTokenKind::LParen) {
1123 while (lexer.peekToken().kind != LibertyTokenKind::RParen) {
1125 if (parseAttribute(arg))
1127 group.args.push_back(arg);
1128 if (lexer.peekToken().kind == LibertyTokenKind::Comma)
1131 if (consume(LibertyTokenKind::RParen,
"expected ')'"))
1136 if (lexer.peekToken().kind == LibertyTokenKind::LBrace) {
1138 while (lexer.peekToken().kind != LibertyTokenKind::RBrace &&
1139 lexer.peekToken().kind != LibertyTokenKind::EndOfFile) {
1140 if (parseStatement(group))
1143 if (consume(LibertyTokenKind::RBrace,
"expected '}'"))
1147 if (lexer.peekToken().kind == LibertyTokenKind::Semi)
1154ParseResult LibertyParser::parseStatement(LibertyGroup &parent) {
1155 auto nameTok = lexer.nextToken();
1156 if (nameTok.kind != LibertyTokenKind::Identifier)
1157 return emitError(nameTok.location,
"expected identifier");
1158 StringRef name = nameTok.spelling;
1161 if (lexer.peekToken().kind == LibertyTokenKind::Colon) {
1164 auto loc = lexer.peekToken().location;
1165 if (parseAttribute(val))
1167 parent.attrs.emplace_back(name, val, loc);
1168 return consume(LibertyTokenKind::Semi,
"expected ';'");
1172 if (lexer.peekToken().kind == LibertyTokenKind::LParen) {
1173 auto subGroup = std::make_unique<LibertyGroup>();
1174 subGroup->name = name;
1175 subGroup->loc = nameTok.location;
1176 if (parseGroupBody(*subGroup))
1178 parent.subGroups.push_back(std::move(subGroup));
1184 return emitError(nameTok.location,
"expected ':' or '('");
1191ParseResult LibertyParser::parseAttribute(Attribute &result) {
1192 auto token = lexer.peekToken();
1194 if (token.is(LibertyTokenKind::Number)) {
1196 StringRef numStr = token.spelling;
1198 if (!numStr.getAsDouble(val)) {
1199 result = builder.getF64FloatAttr(val);
1202 return emitError(token.location,
"expected number value");
1206 if (token.is(LibertyTokenKind::Identifier)) {
1208 result = builder.getStringAttr(token.spelling);
1212 if (token.is(LibertyTokenKind::String)) {
1214 result = builder.getStringAttr(getTokenSpelling(token));
1218 return emitError(token.location,
"expected attribute value");
1223ParseResult LibertyParser::parseExpression(Value &result, StringRef expr,
1224 const llvm::StringMap<Value> &values,
1226 ExpressionParser parser(lexer, builder, expr, values, loc);
1227 return parser.parse(result);
1234 TranslateToMLIRRegistration reg(
1235 "import-liberty",
"Import Liberty file",
1236 [](llvm::SourceMgr &sourceMgr, MLIRContext *
context) {
1237 ModuleOp
module = ModuleOp::create(UnknownLoc::get(context));
1238 LibertyParser parser(sourceMgr,
context, module);
1240 context->loadDialect<hw::HWDialect>();
1241 context->loadDialect<comb::CombDialect>();
1242 context->loadDialect<synth::SynthDialect>();
1244 if (failed(parser.parse()))
1248 [](DialectRegistry ®istry) {
1249 registry.insert<HWDialect>();
1250 registry.insert<comb::CombDialect>();
1251 registry.insert<synth::SynthDialect>();
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
static Location getLoc(DefSlot slot)
void registerImportLibertyTranslation()
Register the Liberty importer in the translation registry.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
This holds the name, type, direction of a module's ports.
DictionaryAttr attrs
The optional symbol for this port.