21#include "mlir/IR/Attributes.h"
22#include "mlir/IR/Builders.h"
23#include "mlir/IR/BuiltinAttributes.h"
24#include "mlir/IR/BuiltinOps.h"
25#include "mlir/IR/BuiltinTypes.h"
26#include "mlir/IR/Diagnostics.h"
27#include "mlir/IR/Location.h"
28#include "mlir/IR/MLIRContext.h"
29#include "mlir/IR/Value.h"
30#include "mlir/Support/FileUtilities.h"
31#include "mlir/Support/LogicalResult.h"
32#include "mlir/Tools/mlir-translate/Translation.h"
33#include "llvm/ADT/STLExtras.h"
34#include "llvm/ADT/StringRef.h"
35#include "llvm/Support/LogicalResult.h"
36#include "llvm/Support/SourceMgr.h"
38#define DEBUG_TYPE "import-liberty"
48enum class LibertyTokenKind {
68StringRef stringifyTokenKind(LibertyTokenKind kind) {
70 case LibertyTokenKind::Identifier:
72 case LibertyTokenKind::String:
74 case LibertyTokenKind::Number:
76 case LibertyTokenKind::LBrace:
78 case LibertyTokenKind::RBrace:
80 case LibertyTokenKind::LParen:
82 case LibertyTokenKind::RParen:
84 case LibertyTokenKind::Colon:
86 case LibertyTokenKind::Semi:
88 case LibertyTokenKind::Comma:
91 case LibertyTokenKind::EndOfFile:
93 case LibertyTokenKind::Error:
100 LibertyTokenKind kind;
104 LibertyToken(LibertyTokenKind kind, StringRef spelling, SMLoc location)
105 : kind(kind), spelling(spelling), location(location) {}
107 bool is(LibertyTokenKind k)
const {
return kind == k; }
112 LibertyLexer(
const llvm::SourceMgr &sourceMgr, MLIRContext *
context)
115 sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID())->getBuffer()),
116 curPtr(curBuffer.begin()) {}
118 LibertyToken nextToken();
119 LibertyToken peekToken();
121 SMLoc getCurrentLoc()
const {
return SMLoc::getFromPointer(curPtr); }
123 Location translateLocation(llvm::SMLoc loc)
const {
124 unsigned mainFileID = sourceMgr.getMainFileID();
125 auto lineAndColumn = sourceMgr.getLineAndColumn(loc, mainFileID);
126 return FileLineColLoc::get(
129 sourceMgr.getMemoryBuffer(mainFileID)->getBufferIdentifier()),
130 lineAndColumn.first, lineAndColumn.second);
133 bool isAtEnd()
const {
return curPtr >= curBuffer.end(); }
136 const llvm::SourceMgr &sourceMgr;
141 void skipWhitespaceAndComments();
142 LibertyToken lexIdentifier();
143 LibertyToken lexString();
144 LibertyToken lexNumber();
145 LibertyToken makeToken(LibertyTokenKind kind,
const char *start);
162class ExpressionParser {
164 ExpressionParser(LibertyLexer &lexer, OpBuilder &builder, StringRef expr,
165 const llvm::StringMap<Value> &values, SMLoc baseLoc);
167 ParseResult parse(Value &result);
170 enum class TokenKind {
190 const llvm::StringMap<Value> &values;
192 const char *exprStart;
193 SmallVector<Token> tokens;
195 Value trueVal =
nullptr;
197 SMLoc
getLoc(
const char *ptr);
198 void tokenize(StringRef expr);
201 Value createNot(Value val, SMLoc loc);
203 ParseResult parseOrExpr(Value &result);
204 ParseResult parseXorExpr(Value &result);
205 ParseResult parseAndExpr(Value &result);
206 ParseResult parseUnaryExpr(Value &result);
208 InFlightDiagnostic emitError(llvm::SMLoc loc,
const Twine &message)
const;
215ExpressionParser::ExpressionParser(LibertyLexer &lexer, OpBuilder &builder,
217 const llvm::StringMap<Value> &values,
219 : lexer(lexer), builder(builder), values(values), baseLoc(baseLoc),
220 exprStart(expr.begin()) {
224ParseResult ExpressionParser::parse(Value &result) {
225 return parseOrExpr(result);
228SMLoc ExpressionParser::getLoc(
const char *ptr) {
229 size_t offset = ptr - exprStart;
230 return SMLoc::getFromPointer(baseLoc.getPointer() + 1 + offset);
233void ExpressionParser::tokenize(StringRef expr) {
234 const char *ptr = expr.begin();
235 const char *end = expr.end();
247 if (isalnum(*ptr) || *ptr ==
'_') {
248 const char *start = ptr;
249 while (ptr < end && (isalnum(*ptr) || *ptr ==
'_'))
251 tokens.push_back({TokenKind::ID, StringRef(start, ptr - start), loc});
259 tokens.push_back({TokenKind::AND, StringRef(ptr, 1), loc});
263 tokens.push_back({TokenKind::OR, StringRef(ptr, 1), loc});
266 tokens.push_back({TokenKind::XOR, StringRef(ptr, 1), loc});
269 tokens.push_back({TokenKind::PREFIX_NOT, StringRef(ptr, 1), loc});
272 tokens.push_back({TokenKind::POSTFIX_NOT, StringRef(ptr, 1), loc});
275 tokens.push_back({TokenKind::LPAREN, StringRef(ptr, 1), loc});
278 tokens.push_back({TokenKind::RPAREN, StringRef(ptr, 1), loc});
284 tokens.push_back({TokenKind::END,
"",
getLoc(ptr)});
287ExpressionParser::Token ExpressionParser::peek()
const {
return tokens[pos]; }
289ExpressionParser::Token ExpressionParser::consume() {
return tokens[pos++]; }
291Value ExpressionParser::createNot(Value val, SMLoc loc) {
294 builder.getI1Type(), 1);
295 return comb::XorOp::create(builder, lexer.translateLocation(loc), val,
302ParseResult ExpressionParser::parseOrExpr(Value &result) {
304 if (parseXorExpr(lhs))
306 while (peek().kind == TokenKind::OR) {
307 auto loc = consume().loc;
309 if (parseXorExpr(rhs))
311 lhs = comb::OrOp::create(builder, lexer.translateLocation(loc), lhs, rhs);
320ParseResult ExpressionParser::parseXorExpr(Value &result) {
322 if (parseAndExpr(lhs))
324 while (peek().kind == TokenKind::XOR) {
325 auto loc = consume().loc;
327 if (parseAndExpr(rhs))
329 lhs = comb::XorOp::create(builder, lexer.translateLocation(loc), lhs, rhs);
339ParseResult ExpressionParser::parseAndExpr(Value &result) {
341 if (parseUnaryExpr(lhs))
343 while (peek().kind == TokenKind::AND ||
344 (peek().kind == TokenKind::ID || peek().kind == TokenKind::LPAREN ||
345 peek().kind == TokenKind::PREFIX_NOT)) {
346 auto loc = peek().loc;
347 if (peek().kind == TokenKind::AND)
350 if (parseUnaryExpr(rhs))
352 lhs = comb::AndOp::create(builder, lexer.translateLocation(loc), lhs, rhs);
362ParseResult ExpressionParser::parseUnaryExpr(Value &result) {
364 if (peek().kind == TokenKind::PREFIX_NOT) {
365 auto loc = consume().loc;
367 if (parseUnaryExpr(val))
369 result = createNot(val, loc);
374 if (peek().kind == TokenKind::LPAREN) {
377 if (parseOrExpr(val))
379 if (peek().kind != TokenKind::RPAREN)
383 if (peek().kind == TokenKind::POSTFIX_NOT) {
384 auto loc = consume().loc;
385 val = createNot(val, loc);
392 if (peek().kind == TokenKind::ID) {
393 auto tok = consume();
394 StringRef name = tok.spelling;
395 auto it = values.find(name);
396 if (it == values.end())
397 return emitError(tok.loc,
"variable not found");
398 Value val = it->second;
400 if (peek().kind == TokenKind::POSTFIX_NOT) {
401 auto loc = consume().loc;
402 val = createNot(val, loc);
408 return emitError(peek().loc,
"expected expression");
411InFlightDiagnostic ExpressionParser::emitError(llvm::SMLoc loc,
412 const Twine &message)
const {
413 return mlir::emitError(lexer.translateLocation(loc), message);
420 SmallVector<Attribute> args;
425 AttrEntry(StringRef name, Attribute value, SMLoc loc)
426 : name(name), value(value), loc(loc) {}
428 SmallVector<AttrEntry>
attrs;
429 SmallVector<std::unique_ptr<LibertyGroup>> subGroups;
432 std::pair<Attribute, SMLoc> getAttribute(StringRef name)
const {
433 for (
const auto &attr :
attrs)
434 if (attr.name == name)
435 return {attr.value, attr.loc};
439 void eraseSubGroup(llvm::function_ref<
bool(
const LibertyGroup &)> pred) {
441 llvm::remove_if(subGroups,
442 [pred](
const auto &group) {
return pred(*group); }),
446 LogicalResult checkArgs(
448 llvm::function_ref<LogicalResult(
size_t idx, Attribute)> pred)
const {
449 if (args.size() != n)
451 for (
size_t i = 0; i < n; ++i)
452 if (failed(pred(i, args[i])))
460 LibertyParser(
const llvm::SourceMgr &sourceMgr, MLIRContext *
context,
462 : lexer(sourceMgr,
context), module(module),
463 builder(module.getBodyRegion()) {}
473 ParseResult parseLibrary();
474 ParseResult parseGroupBody(LibertyGroup &group);
475 ParseResult parseStatement(LibertyGroup &parent);
479 lowerCell(
const LibertyGroup &group, StringAttr &cellNameAttr,
480 const llvm::StringMap<const LibertyGroup *> &tableTemplates);
483 parseNLDMTable(
const LibertyGroup &group,
484 const llvm::StringMap<const LibertyGroup *> &tableTemplates,
485 synth::NLDMTableAttr &table);
488 buildTimingArcs(
const LibertyGroup &pinGroup,
489 const llvm::StringMap<const LibertyGroup *> &tableTemplates,
490 SmallVector<Attribute> &timingArcs);
493 collectPorts(
const LibertyGroup &cellGroup,
494 const llvm::StringMap<const LibertyGroup *> &tableTemplates,
495 SmallVector<hw::PortInfo> &ports,
496 SmallVector<const LibertyGroup *> &pinGroups,
497 SmallVector<Attribute> &timingArcs,
498 size_t &numOutputPinMissingFunction);
501 ArrayRef<hw::PortInfo> ports,
502 ArrayRef<const LibertyGroup *> pinGroups);
504 LogicalResult parseLibertyFloatList(StringRef value, SMLoc loc,
505 SmallVectorImpl<double> &result)
const;
511 Attribute convertGroupToAttr(
const LibertyGroup &group);
514 ParseResult parseAttribute(Attribute &result);
517 ParseResult parseExpression(Value &result, StringRef expr,
518 const llvm::StringMap<Value> &values, SMLoc loc);
520 InFlightDiagnostic emitError(llvm::SMLoc loc,
const Twine &message)
const {
521 return mlir::emitError(lexer.translateLocation(loc), message);
524 InFlightDiagnostic emitWarning(llvm::SMLoc loc,
const Twine &message)
const {
525 return mlir::emitWarning(lexer.translateLocation(loc), message);
528 ParseResult consume(LibertyTokenKind kind,
const Twine &msg) {
529 if (lexer.nextToken().is(kind))
531 return emitError(lexer.getCurrentLoc(), msg);
534 ParseResult consumeUntil(LibertyTokenKind kind) {
535 while (!lexer.peekToken().is(kind) &&
536 lexer.peekToken().kind != LibertyTokenKind::EndOfFile)
538 if (lexer.peekToken().is(kind))
540 return emitError(lexer.getCurrentLoc(),
541 " expected " + stringifyTokenKind(kind));
544 ParseResult consume(LibertyTokenKind kind) {
545 if (lexer.nextToken().is(kind))
547 return emitError(lexer.getCurrentLoc(),
548 " expected " + stringifyTokenKind(kind));
551 ParseResult expect(LibertyTokenKind kind) {
552 if (!lexer.peekToken().is(kind))
553 return emitError(lexer.getCurrentLoc(),
554 " expected " + stringifyTokenKind(kind));
559 StringRef getTokenSpelling(
const LibertyToken &token) {
560 StringRef str = token.spelling;
561 if (token.kind == LibertyTokenKind::String)
562 str = str.drop_front().drop_back();
571void LibertyLexer::skipWhitespaceAndComments() {
572 while (curPtr < curBuffer.end()) {
573 if (isspace(*curPtr)) {
579 if (*curPtr ==
'/' && curPtr + 1 < curBuffer.end()) {
580 if (*(curPtr + 1) ==
'*') {
582 while (curPtr + 1 < curBuffer.end() &&
583 (*curPtr !=
'*' || *(curPtr + 1) !=
'/'))
585 if (curPtr + 1 < curBuffer.end())
589 if (*(curPtr + 1) ==
'/') {
590 while (curPtr < curBuffer.end() && *curPtr !=
'\n')
597 if (*curPtr ==
'\\' && curPtr + 1 < curBuffer.end() &&
598 *(curPtr + 1) ==
'\n') {
607LibertyToken LibertyLexer::lexIdentifier() {
608 const char *start = curPtr;
609 while (curPtr < curBuffer.end() &&
610 (isalnum(*curPtr) || *curPtr ==
'_' || *curPtr ==
'.'))
612 return makeToken(LibertyTokenKind::Identifier, start);
615LibertyToken LibertyLexer::lexString() {
616 const char *start = curPtr;
618 while (curPtr < curBuffer.end() && *curPtr !=
'"') {
619 if (*curPtr ==
'\\' && curPtr + 1 < curBuffer.end())
623 if (curPtr < curBuffer.end())
625 return makeToken(LibertyTokenKind::String, start);
628LibertyToken LibertyLexer::lexNumber() {
629 const char *start = curPtr;
630 bool seenDot =
false;
631 while (curPtr < curBuffer.end()) {
634 }
else if (*curPtr ==
'.') {
636 mlir::emitError(translateLocation(SMLoc::getFromPointer(curPtr)),
637 "multiple decimal points in number");
638 return makeToken(LibertyTokenKind::Error, start);
646 return makeToken(LibertyTokenKind::Number, start);
649LibertyToken LibertyLexer::makeToken(LibertyTokenKind kind,
const char *start) {
650 return LibertyToken(kind, StringRef(start, curPtr - start),
651 SMLoc::getFromPointer(start));
654LibertyToken LibertyLexer::nextToken() {
655 skipWhitespaceAndComments();
657 if (curPtr >= curBuffer.end())
658 return makeToken(LibertyTokenKind::EndOfFile, curPtr);
660 const char *start = curPtr;
664 return lexIdentifier();
667 (c ==
'.' && curPtr + 1 < curBuffer.end() &&
isdigit(*(curPtr + 1))))
676 return makeToken(LibertyTokenKind::LBrace, start);
678 return makeToken(LibertyTokenKind::RBrace, start);
680 return makeToken(LibertyTokenKind::LParen, start);
682 return makeToken(LibertyTokenKind::RParen, start);
684 return makeToken(LibertyTokenKind::Colon, start);
686 return makeToken(LibertyTokenKind::Semi, start);
688 return makeToken(LibertyTokenKind::Comma, start);
691 return makeToken(LibertyTokenKind::Error, start);
695LibertyToken LibertyLexer::peekToken() {
696 const char *savedPtr = curPtr;
697 LibertyToken token = nextToken();
706ParseResult LibertyParser::parse() {
707 while (lexer.peekToken().kind != LibertyTokenKind::EndOfFile) {
708 auto token = lexer.peekToken();
710 if (token.kind != LibertyTokenKind::Identifier ||
711 token.spelling !=
"library") {
712 return emitError(token.location,
"expected `library` keyword");
721ParseResult LibertyParser::parseLibrary() {
722 LibertyGroup libertyLib;
723 if (parseGroupBody(libertyLib))
731 llvm::StringMap<const LibertyGroup *> tableTemplates;
732 for (
const auto &stmt : libertyLib.subGroups)
733 if (stmt->name ==
"lu_table_template")
734 if (!stmt->args.empty())
735 if (
auto name = dyn_cast<StringAttr>(stmt->args[0]))
736 tableTemplates[name.getValue()] = stmt.get();
740 DenseSet<StringAttr> seenCells;
741 for (
auto &stmt : libertyLib.subGroups) {
742 if (stmt->name !=
"cell")
744 StringAttr cellNameAttr;
745 if (lowerCell(*stmt, cellNameAttr, tableTemplates))
747 if (!seenCells.insert(cellNameAttr).second)
748 return emitError(stmt->loc,
"redefinition of cell '" +
749 cellNameAttr.getValue() +
"'");
752 libertyLib.eraseSubGroup(
753 [](
const LibertyGroup &group) {
return group.name ==
"cell"; });
754 auto attr = convertGroupToAttr(libertyLib);
755 module->setAttr("synth.liberty.library", attr);
761Attribute LibertyParser::convertGroupToAttr(
const LibertyGroup &group) {
762 SmallVector<NamedAttribute>
attrs;
763 if (!group.args.empty())
765 builder.getNamedAttr(
"args", builder.getArrayAttr(group.args)));
767 for (
const auto &attr : group.attrs)
768 attrs.push_back(builder.getNamedAttr(attr.name, attr.value));
770 llvm::StringMap<SmallVector<Attribute>> subGroups;
771 for (
const auto &sub : group.subGroups)
772 subGroups[sub->name].push_back(convertGroupToAttr(*sub));
774 for (
auto &it : subGroups)
776 builder.getNamedAttr(it.getKey(), builder.getArrayAttr(it.getValue())));
778 return builder.getDictionaryAttr(
attrs);
782LibertyParser::parseLibertyFloatList(StringRef value, SMLoc loc,
783 SmallVectorImpl<double> &result)
const {
784 SmallVector<StringRef> parts;
785 value.split(parts,
',');
786 for (
auto part : parts) {
791 if (part.getAsDouble(val))
792 return emitError(loc,
"expected floating point value in NLDM table");
793 result.push_back(val);
798ParseResult LibertyParser::parseNLDMTable(
799 const LibertyGroup &group,
800 const llvm::StringMap<const LibertyGroup *> &tableTemplates,
801 synth::NLDMTableAttr &table) {
802 SmallVector<double> index1, index2, values;
804 auto parseList = [&](
const LibertyGroup &source, StringRef name,
805 SmallVectorImpl<double> &result) -> ParseResult {
806 if (
auto [attr, loc] = source.getAttribute(name); attr) {
807 auto stringAttr = dyn_cast<StringAttr>(attr);
809 return emitError(loc,
"expected string value for NLDM table entry");
810 if (failed(parseLibertyFloatList(stringAttr.getValue(), loc, result)))
815 for (
const auto &subGroup : source.subGroups) {
816 if (subGroup->name != name)
818 if (subGroup->args.empty())
819 return emitError(subGroup->loc,
"NLDM table entry missing value");
820 for (
auto arg : subGroup->args) {
821 auto stringAttr = dyn_cast<StringAttr>(arg);
823 return emitError(subGroup->loc,
824 "expected string value for NLDM table entry");
825 if (failed(parseLibertyFloatList(stringAttr.getValue(), subGroup->loc,
836 if (parseList(group,
"index_1", index1) ||
837 parseList(group,
"index_2", index2) || parseList(group,
"values", values))
840 if (!group.args.empty()) {
841 auto templateName = dyn_cast<StringAttr>(group.args[0]);
843 return emitError(group.loc,
"NLDM table template name must be a string");
845 auto it = tableTemplates.find(templateName.getValue());
846 if (it == tableTemplates.end())
847 return emitError(group.loc,
"unknown NLDM table template '")
848 << templateName.getValue() <<
"'";
850 if (index1.empty() && parseList(*it->second,
"index_1", index1))
852 if (index2.empty() && parseList(*it->second,
"index_2", index2))
857 return emitError(group.loc,
"NLDM table missing index_1");
859 return emitError(group.loc,
"NLDM table missing index_2");
861 return emitError(group.loc,
"NLDM table missing values");
863 if (values.size() != index1.size() * index2.size()) {
864 return emitError(group.loc,
"NLDM table has ")
865 << values.size() <<
" values, expected "
866 << index1.size() * index2.size() <<
" for " << index1.size() <<
" x "
867 << index2.size() <<
" indices";
870 table = synth::NLDMTableAttr::get(
871 builder.getContext(),
872 DenseF64ArrayAttr::get(builder.getContext(), index1),
873 DenseF64ArrayAttr::get(builder.getContext(), index2),
874 DenseF64ArrayAttr::get(builder.getContext(), values));
878static bool isNLDMTableGroup(StringRef name) {
879 return name ==
"cell_rise" || name ==
"cell_fall" ||
880 name ==
"rise_transition" || name ==
"fall_transition";
883LogicalResult LibertyParser::buildTimingArcs(
884 const LibertyGroup &pinGroup,
885 const llvm::StringMap<const LibertyGroup *> &tableTemplates,
886 SmallVector<Attribute> &timingArcs) {
887 auto pinName = cast<StringAttr>(pinGroup.args[0]);
889 for (
const auto &child : pinGroup.subGroups) {
890 if (child->name !=
"timing")
894 dyn_cast_or_null<StringAttr>(child->getAttribute(
"related_pin").first);
896 dyn_cast_or_null<StringAttr>(child->getAttribute(
"timing_sense").first);
897 if (!relatedPin || !timingSense)
898 return emitError(child->loc,
899 "timing related_pin and timing_sense must be strings");
901 synth::NLDMTableAttr cellRise, cellFall, riseTransition, fallTransition;
902 for (
const auto &table : child->subGroups) {
903 if (!isNLDMTableGroup(table->name))
906 synth::NLDMTableAttr parsedTable;
907 if (parseNLDMTable(*table, tableTemplates, parsedTable))
910 if (table->name ==
"cell_rise")
911 cellRise = parsedTable;
912 else if (table->name ==
"cell_fall")
913 cellFall = parsedTable;
914 else if (table->name ==
"rise_transition")
915 riseTransition = parsedTable;
916 else if (table->name ==
"fall_transition")
917 fallTransition = parsedTable;
920 if (!cellRise || !cellFall || !riseTransition || !fallTransition)
921 return emitError(child->loc,
922 "NLDM timing arc requires cell_rise, cell_fall, "
923 "rise_transition, and fall_transition tables");
925 timingArcs.push_back(synth::NLDMTimingArcAttr::get(
926 builder.getContext(), pinName, relatedPin, timingSense, cellRise,
927 cellFall, riseTransition, fallTransition));
932LogicalResult LibertyParser::collectPorts(
933 const LibertyGroup &cellGroup,
934 const llvm::StringMap<const LibertyGroup *> &tableTemplates,
935 SmallVector<hw::PortInfo> &ports,
936 SmallVector<const LibertyGroup *> &pinGroups,
937 SmallVector<Attribute> &timingArcs,
size_t &numOutputPinMissingFunction) {
939 llvm::DenseSet<StringAttr> seenPins;
942 for (
const auto &sub : cellGroup.subGroups) {
943 if (sub->name !=
"pin")
946 pinGroups.push_back(sub.get());
947 if (sub->args.empty())
948 return emitError(sub->loc,
"pin missing name");
950 StringAttr pinName = dyn_cast<StringAttr>(sub->args[0]);
951 if (!seenPins.insert(pinName).second)
952 return emitError(sub->loc,
953 "redefinition of pin '" + pinName.getValue() +
"'");
955 std::optional<hw::ModulePort::Direction> dir;
956 SmallVector<NamedAttribute> pinAttrs;
957 bool functionExist =
false;
960 bool isInOut =
false;
961 for (
const auto &attr : sub->attrs) {
962 if (attr.name ==
"direction") {
963 auto val = dyn_cast<StringAttr>(attr.value);
965 return emitError(sub->loc,
"pin direction must be a string");
966 if (val.getValue() ==
"input")
968 else if (val.getValue() ==
"output")
970 else if (val.getValue() ==
"inout") {
974 return emitError(sub->loc,
975 "pin direction must be input, output, or inout");
978 if (attr.name ==
"function")
979 functionExist =
true;
980 pinAttrs.push_back(builder.getNamedAttr(attr.name, attr.value));
984 return emitError(sub->loc,
"pin direction must be specified");
987 ++numOutputPinMissingFunction;
990 if (failed(buildTimingArcs(*sub, tableTemplates, timingArcs)))
994 llvm::StringMap<SmallVector<Attribute>> subGroupAttrs;
995 for (
const auto &child : sub->subGroups)
996 if (child->name !=
"timing")
997 subGroupAttrs[child->name].push_back(convertGroupToAttr(*child));
999 for (
auto &it : subGroupAttrs)
1000 pinAttrs.push_back(builder.getNamedAttr(
1001 it.getKey(), builder.getArrayAttr(it.getValue())));
1003 auto libertyAttrs = builder.getDictionaryAttr(pinAttrs);
1004 auto attrs = builder.getDictionaryAttr(
1005 builder.getNamedAttr(
"synth.liberty.pin", libertyAttrs));
1006 mlir::Type portType = builder.getI1Type();
1008 portType = sv::NetType::get(portType);
1011 port.
name = pinName;
1012 port.
type = portType;
1015 ports.push_back(port);
1022 ArrayRef<hw::PortInfo> ports,
1023 ArrayRef<const LibertyGroup *> pinGroups) {
1026 OpBuilder::InsertionGuard guard(builder);
1027 builder.setInsertionPointToStart(moduleOp.getBodyBlock());
1029 llvm::StringMap<Value> portValues;
1030 for (
const auto &port : ports)
1032 portValues[port.name.getValue()] =
1033 moduleOp.getBodyBlock()->getArgument(port.argNum);
1035 SmallVector<Value> outputs;
1036 for (
const auto &port : ports) {
1040 auto *it = llvm::find_if(pinGroups, [&](
const LibertyGroup *g) {
1041 assert(g->name ==
"pin" &&
"expected pin group");
1043 return cast<StringAttr>(g->args[0]) == port.name;
1049 const LibertyGroup *pg = *it;
1050 auto attrPair = pg->getAttribute(
"function");
1051 assert(attrPair.first &&
"output pin missing function attribute");
1054 if (parseExpression(val, cast<StringAttr>(attrPair.first).getValue(),
1055 portValues, attrPair.second))
1057 outputs.push_back(val);
1060 moduleOp.getBodyBlock()->getTerminator()->setOperands(outputs);
1064ParseResult LibertyParser::lowerCell(
1065 const LibertyGroup &group, StringAttr &cellNameAttr,
1066 const llvm::StringMap<const LibertyGroup *> &tableTemplates) {
1068 if (group.args.empty())
1069 return emitError(group.loc,
"cell missing name");
1070 cellNameAttr = dyn_cast<StringAttr>(group.args[0]);
1072 return emitError(group.loc,
"cell name must be a string");
1074 SmallVector<hw::PortInfo> ports;
1075 SmallVector<const LibertyGroup *> pinGroups;
1076 SmallVector<Attribute> timingArcs;
1077 size_t numOutputPinMissingFunction = 0;
1079 if (failed(collectPorts(group, tableTemplates, ports, pinGroups, timingArcs,
1080 numOutputPinMissingFunction)))
1085 for (
auto &p : ports)
1087 p.argNum = inputIdx++;
1091 auto loc = lexer.translateLocation(group.loc);
1092 auto numOutput = ports.size() - inputIdx;
1099 if (numOutputPinMissingFunction != 0 &&
1100 numOutputPinMissingFunction != numOutput)
1101 return emitError(group.loc,
"cell '")
1102 << cellNameAttr.getValue()
1103 <<
"' has mixed output pins with and without 'function' attribute";
1106 if (numOutputPinMissingFunction == numOutput) {
1108 hw::HWModuleExternOp::create(builder, loc, cellNameAttr, ports);
1109 if (!timingArcs.empty())
1110 externOp->setAttr(
"synth.timing.nldm", builder.getArrayAttr(timingArcs));
1115 auto moduleOp = hw::HWModuleOp::create(builder, loc, cellNameAttr, ports);
1117 if (failed(buildCellLogic(moduleOp, ports, pinGroups)))
1120 if (!timingArcs.empty())
1121 moduleOp->setAttr(
"synth.timing.nldm", builder.getArrayAttr(timingArcs));
1126ParseResult LibertyParser::parseGroupBody(LibertyGroup &group) {
1128 if (lexer.peekToken().kind == LibertyTokenKind::LParen) {
1130 while (lexer.peekToken().kind != LibertyTokenKind::RParen) {
1132 if (parseAttribute(arg))
1134 group.args.push_back(arg);
1135 if (lexer.peekToken().kind == LibertyTokenKind::Comma)
1138 if (consume(LibertyTokenKind::RParen,
"expected ')'"))
1143 if (lexer.peekToken().kind == LibertyTokenKind::LBrace) {
1145 while (lexer.peekToken().kind != LibertyTokenKind::RBrace &&
1146 lexer.peekToken().kind != LibertyTokenKind::EndOfFile) {
1147 if (parseStatement(group))
1150 if (consume(LibertyTokenKind::RBrace,
"expected '}'"))
1154 if (lexer.peekToken().kind == LibertyTokenKind::Semi)
1161ParseResult LibertyParser::parseStatement(LibertyGroup &parent) {
1162 auto nameTok = lexer.nextToken();
1163 if (nameTok.kind != LibertyTokenKind::Identifier)
1164 return emitError(nameTok.location,
"expected identifier");
1165 StringRef name = nameTok.spelling;
1168 if (lexer.peekToken().kind == LibertyTokenKind::Colon) {
1171 auto loc = lexer.peekToken().location;
1172 if (parseAttribute(val))
1174 parent.attrs.emplace_back(name, val, loc);
1175 return consume(LibertyTokenKind::Semi,
"expected ';'");
1179 if (lexer.peekToken().kind == LibertyTokenKind::LParen) {
1180 auto subGroup = std::make_unique<LibertyGroup>();
1181 subGroup->name = name;
1182 subGroup->loc = nameTok.location;
1183 if (parseGroupBody(*subGroup))
1185 parent.subGroups.push_back(std::move(subGroup));
1191 return emitError(nameTok.location,
"expected ':' or '('");
1198ParseResult LibertyParser::parseAttribute(Attribute &result) {
1199 auto token = lexer.peekToken();
1201 if (token.is(LibertyTokenKind::Number)) {
1203 StringRef numStr = token.spelling;
1205 if (!numStr.getAsDouble(val)) {
1206 result = builder.getF64FloatAttr(val);
1209 return emitError(token.location,
"expected number value");
1213 if (token.is(LibertyTokenKind::Identifier)) {
1215 result = builder.getStringAttr(token.spelling);
1219 if (token.is(LibertyTokenKind::String)) {
1221 result = builder.getStringAttr(getTokenSpelling(token));
1225 return emitError(token.location,
"expected attribute value");
1230ParseResult LibertyParser::parseExpression(Value &result, StringRef expr,
1231 const llvm::StringMap<Value> &values,
1233 ExpressionParser parser(lexer, builder, expr, values, loc);
1234 return parser.parse(result);
1239namespace circt::liberty {
1241 TranslateToMLIRRegistration reg(
1242 "import-liberty",
"Import Liberty file",
1243 [](llvm::SourceMgr &sourceMgr, MLIRContext *
context) {
1244 ModuleOp module = ModuleOp::create(UnknownLoc::get(
context));
1245 LibertyParser parser(sourceMgr,
context, module);
1247 context->loadDialect<hw::HWDialect>();
1248 context->loadDialect<sv::SVDialect>();
1249 context->loadDialect<comb::CombDialect>();
1250 context->loadDialect<synth::SynthDialect>();
1252 if (failed(parser.parse()))
1256 [](DialectRegistry ®istry) {
1257 registry.insert<HWDialect>();
1258 registry.insert<sv::SVDialect>();
1259 registry.insert<comb::CombDialect>();
1260 registry.insert<synth::SynthDialect>();
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
static Location getLoc(DefSlot slot)
false return failure()
Parse an optional keyword or string and set instance into 'result'.
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.