17#include "mlir/IR/Attributes.h"
18#include "mlir/IR/Builders.h"
19#include "mlir/IR/BuiltinAttributes.h"
20#include "mlir/IR/BuiltinOps.h"
21#include "mlir/IR/BuiltinTypes.h"
22#include "mlir/IR/Diagnostics.h"
23#include "mlir/IR/Location.h"
24#include "mlir/IR/MLIRContext.h"
25#include "mlir/IR/Value.h"
26#include "mlir/Support/FileUtilities.h"
27#include "mlir/Support/LogicalResult.h"
28#include "mlir/Tools/mlir-translate/Translation.h"
29#include "llvm/ADT/STLExtras.h"
30#include "llvm/ADT/StringRef.h"
31#include "llvm/Support/LogicalResult.h"
32#include "llvm/Support/SourceMgr.h"
34#define DEBUG_TYPE "import-liberty"
44enum class LibertyTokenKind {
64StringRef stringifyTokenKind(LibertyTokenKind kind) {
66 case LibertyTokenKind::Identifier:
68 case LibertyTokenKind::String:
70 case LibertyTokenKind::Number:
72 case LibertyTokenKind::LBrace:
74 case LibertyTokenKind::RBrace:
76 case LibertyTokenKind::LParen:
78 case LibertyTokenKind::RParen:
80 case LibertyTokenKind::Colon:
82 case LibertyTokenKind::Semi:
84 case LibertyTokenKind::Comma:
87 case LibertyTokenKind::EndOfFile:
89 case LibertyTokenKind::Error:
96 LibertyTokenKind kind;
100 LibertyToken(LibertyTokenKind kind, StringRef spelling, SMLoc location)
101 : kind(kind), spelling(spelling), location(location) {}
103 bool is(LibertyTokenKind k)
const {
return kind == k; }
108 LibertyLexer(
const llvm::SourceMgr &sourceMgr, MLIRContext *context)
109 : sourceMgr(sourceMgr), context(context),
111 sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID())->getBuffer()),
112 curPtr(curBuffer.begin()) {}
114 LibertyToken nextToken();
115 LibertyToken peekToken();
117 SMLoc getCurrentLoc()
const {
return SMLoc::getFromPointer(curPtr); }
119 Location translateLocation(llvm::SMLoc loc)
const {
120 unsigned mainFileID = sourceMgr.getMainFileID();
121 auto lineAndColumn = sourceMgr.getLineAndColumn(loc, mainFileID);
122 return FileLineColLoc::get(
125 sourceMgr.getMemoryBuffer(mainFileID)->getBufferIdentifier()),
126 lineAndColumn.first, lineAndColumn.second);
129 bool isAtEnd()
const {
return curPtr >= curBuffer.end(); }
132 const llvm::SourceMgr &sourceMgr;
133 MLIRContext *context;
137 void skipWhitespaceAndComments();
138 LibertyToken lexIdentifier();
139 LibertyToken lexString();
140 LibertyToken lexNumber();
141 LibertyToken makeToken(LibertyTokenKind kind,
const char *start);
158class ExpressionParser {
160 ExpressionParser(LibertyLexer &lexer, OpBuilder &builder, StringRef expr,
161 const llvm::StringMap<Value> &values, SMLoc baseLoc);
163 ParseResult parse(Value &result);
166 enum class TokenKind {
186 const llvm::StringMap<Value> &values;
188 const char *exprStart;
189 SmallVector<Token> tokens;
191 Value trueVal =
nullptr;
193 SMLoc
getLoc(
const char *ptr);
194 void tokenize(StringRef expr);
197 Value createNot(Value val, SMLoc loc);
199 ParseResult parseOrExpr(Value &result);
200 ParseResult parseXorExpr(Value &result);
201 ParseResult parseAndExpr(Value &result);
202 ParseResult parseUnaryExpr(Value &result);
204 InFlightDiagnostic emitError(llvm::SMLoc loc,
const Twine &message)
const;
211ExpressionParser::ExpressionParser(LibertyLexer &lexer, OpBuilder &builder,
213 const llvm::StringMap<Value> &values,
215 : lexer(lexer), builder(builder), values(values), baseLoc(baseLoc),
216 exprStart(expr.begin()) {
220ParseResult ExpressionParser::parse(Value &result) {
221 return parseOrExpr(result);
224SMLoc ExpressionParser::getLoc(
const char *ptr) {
225 size_t offset = ptr - exprStart;
226 return SMLoc::getFromPointer(baseLoc.getPointer() + 1 + offset);
229void ExpressionParser::tokenize(StringRef expr) {
230 const char *ptr = expr.begin();
231 const char *end = expr.end();
243 if (isalnum(*ptr) || *ptr ==
'_') {
244 const char *start = ptr;
245 while (ptr < end && (isalnum(*ptr) || *ptr ==
'_'))
247 tokens.push_back({TokenKind::ID, StringRef(start, ptr - start), loc});
255 tokens.push_back({TokenKind::AND, StringRef(ptr, 1), loc});
259 tokens.push_back({TokenKind::OR, StringRef(ptr, 1), loc});
262 tokens.push_back({TokenKind::XOR, StringRef(ptr, 1), loc});
265 tokens.push_back({TokenKind::PREFIX_NOT, StringRef(ptr, 1), loc});
268 tokens.push_back({TokenKind::POSTFIX_NOT, StringRef(ptr, 1), loc});
271 tokens.push_back({TokenKind::LPAREN, StringRef(ptr, 1), loc});
274 tokens.push_back({TokenKind::RPAREN, StringRef(ptr, 1), loc});
280 tokens.push_back({TokenKind::END,
"",
getLoc(ptr)});
283ExpressionParser::Token ExpressionParser::peek()
const {
return tokens[pos]; }
285ExpressionParser::Token ExpressionParser::consume() {
return tokens[pos++]; }
287Value ExpressionParser::createNot(Value val, SMLoc loc) {
290 builder.getI1Type(), 1);
291 return comb::XorOp::create(builder, lexer.translateLocation(loc), val,
298ParseResult ExpressionParser::parseOrExpr(Value &result) {
300 if (parseXorExpr(lhs))
302 while (peek().kind == TokenKind::OR) {
303 auto loc = consume().loc;
305 if (parseXorExpr(rhs))
307 lhs = comb::OrOp::create(builder, lexer.translateLocation(loc), lhs, rhs);
316ParseResult ExpressionParser::parseXorExpr(Value &result) {
318 if (parseAndExpr(lhs))
320 while (peek().kind == TokenKind::XOR) {
321 auto loc = consume().loc;
323 if (parseAndExpr(rhs))
325 lhs = comb::XorOp::create(builder, lexer.translateLocation(loc), lhs, rhs);
335ParseResult ExpressionParser::parseAndExpr(Value &result) {
337 if (parseUnaryExpr(lhs))
339 while (peek().kind == TokenKind::AND ||
340 (peek().kind == TokenKind::ID || peek().kind == TokenKind::LPAREN ||
341 peek().kind == TokenKind::PREFIX_NOT)) {
342 auto loc = peek().loc;
343 if (peek().kind == TokenKind::AND)
346 if (parseUnaryExpr(rhs))
348 lhs = comb::AndOp::create(builder, lexer.translateLocation(loc), lhs, rhs);
358ParseResult ExpressionParser::parseUnaryExpr(Value &result) {
360 if (peek().kind == TokenKind::PREFIX_NOT) {
361 auto loc = consume().loc;
363 if (parseUnaryExpr(val))
365 result = createNot(val, loc);
370 if (peek().kind == TokenKind::LPAREN) {
373 if (parseOrExpr(val))
375 if (peek().kind != TokenKind::RPAREN)
379 if (peek().kind == TokenKind::POSTFIX_NOT) {
380 auto loc = consume().loc;
381 val = createNot(val, loc);
388 if (peek().kind == TokenKind::ID) {
389 auto tok = consume();
390 StringRef name = tok.spelling;
391 auto it = values.find(name);
392 if (it == values.end())
393 return emitError(tok.loc,
"variable not found");
394 Value val = it->second;
396 if (peek().kind == TokenKind::POSTFIX_NOT) {
397 auto loc = consume().loc;
398 val = createNot(val, loc);
404 return emitError(peek().loc,
"expected expression");
407InFlightDiagnostic ExpressionParser::emitError(llvm::SMLoc loc,
408 const Twine &message)
const {
409 return mlir::emitError(lexer.translateLocation(loc), message);
416 SmallVector<Attribute> args;
421 AttrEntry(StringRef name, Attribute value, SMLoc loc)
422 : name(name), value(value), loc(loc) {}
424 SmallVector<AttrEntry> attrs;
425 SmallVector<std::unique_ptr<LibertyGroup>> subGroups;
428 std::pair<Attribute, SMLoc> getAttribute(StringRef name)
const {
429 for (
const auto &attr : attrs)
430 if (attr.name == name)
431 return {attr.value, attr.loc};
435 void eraseSubGroup(llvm::function_ref<
bool(
const LibertyGroup &)> pred) {
437 std::remove_if(subGroups.begin(), subGroups.end(),
438 [pred](
const auto &group) { return pred(*group); }),
442 LogicalResult checkArgs(
444 llvm::function_ref<LogicalResult(
size_t idx, Attribute)> pred)
const {
445 if (args.size() != n)
447 for (
size_t i = 0; i < n; ++i)
448 if (failed(pred(i, args[i])))
456 LibertyParser(
const llvm::SourceMgr &sourceMgr, MLIRContext *
context,
458 : lexer(sourceMgr,
context), module(module),
459 builder(module.getBodyRegion()) {}
469 ParseResult parseLibrary();
470 ParseResult parseGroupBody(LibertyGroup &group);
471 ParseResult parseStatement(LibertyGroup &parent);
474 ParseResult lowerCell(
const LibertyGroup &group, StringAttr &cellNameAttr);
480 Attribute convertGroupToAttr(
const LibertyGroup &group);
483 ParseResult parseAttribute(Attribute &result);
486 ParseResult parseExpression(Value &result, StringRef expr,
487 const llvm::StringMap<Value> &values, SMLoc loc);
489 InFlightDiagnostic emitError(llvm::SMLoc loc,
const Twine &message)
const {
490 return mlir::emitError(lexer.translateLocation(loc), message);
493 InFlightDiagnostic emitWarning(llvm::SMLoc loc,
const Twine &message)
const {
494 return mlir::emitWarning(lexer.translateLocation(loc), message);
497 ParseResult consume(LibertyTokenKind kind,
const Twine &msg) {
498 if (lexer.nextToken().is(kind))
500 return emitError(lexer.getCurrentLoc(), msg);
503 ParseResult consumeUntil(LibertyTokenKind kind) {
504 while (!lexer.peekToken().is(kind) &&
505 lexer.peekToken().kind != LibertyTokenKind::EndOfFile)
507 if (lexer.peekToken().is(kind))
509 return emitError(lexer.getCurrentLoc(),
510 " expected " + stringifyTokenKind(kind));
513 ParseResult consume(LibertyTokenKind kind) {
514 if (lexer.nextToken().is(kind))
516 return emitError(lexer.getCurrentLoc(),
517 " expected " + stringifyTokenKind(kind));
520 ParseResult expect(LibertyTokenKind kind) {
521 if (!lexer.peekToken().is(kind))
522 return emitError(lexer.getCurrentLoc(),
523 " expected " + stringifyTokenKind(kind));
528 StringRef getTokenSpelling(
const LibertyToken &token) {
529 StringRef str = token.spelling;
530 if (token.kind == LibertyTokenKind::String)
531 str = str.drop_front().drop_back();
540void LibertyLexer::skipWhitespaceAndComments() {
541 while (curPtr < curBuffer.end()) {
542 if (isspace(*curPtr)) {
548 if (*curPtr ==
'/' && curPtr + 1 < curBuffer.end()) {
549 if (*(curPtr + 1) ==
'*') {
551 while (curPtr + 1 < curBuffer.end() &&
552 (*curPtr !=
'*' || *(curPtr + 1) !=
'/'))
554 if (curPtr + 1 < curBuffer.end())
558 if (*(curPtr + 1) ==
'/') {
559 while (curPtr < curBuffer.end() && *curPtr !=
'\n')
566 if (*curPtr ==
'\\' && curPtr + 1 < curBuffer.end() &&
567 *(curPtr + 1) ==
'\n') {
576LibertyToken LibertyLexer::lexIdentifier() {
577 const char *start = curPtr;
578 while (curPtr < curBuffer.end() &&
579 (isalnum(*curPtr) || *curPtr ==
'_' || *curPtr ==
'.'))
581 return makeToken(LibertyTokenKind::Identifier, start);
584LibertyToken LibertyLexer::lexString() {
585 const char *start = curPtr;
587 while (curPtr < curBuffer.end() && *curPtr !=
'"') {
588 if (*curPtr ==
'\\' && curPtr + 1 < curBuffer.end())
592 if (curPtr < curBuffer.end())
594 return makeToken(LibertyTokenKind::String, start);
597LibertyToken LibertyLexer::lexNumber() {
598 const char *start = curPtr;
599 bool seenDot =
false;
600 while (curPtr < curBuffer.end()) {
603 }
else if (*curPtr ==
'.') {
605 mlir::emitError(translateLocation(SMLoc::getFromPointer(curPtr)),
606 "multiple decimal points in number");
607 return makeToken(LibertyTokenKind::Error, start);
615 return makeToken(LibertyTokenKind::Number, start);
618LibertyToken LibertyLexer::makeToken(LibertyTokenKind kind,
const char *start) {
619 return LibertyToken(kind, StringRef(start, curPtr - start),
620 SMLoc::getFromPointer(start));
623LibertyToken LibertyLexer::nextToken() {
624 skipWhitespaceAndComments();
626 if (curPtr >= curBuffer.end())
627 return makeToken(LibertyTokenKind::EndOfFile, curPtr);
629 const char *start = curPtr;
633 return lexIdentifier();
636 (c ==
'.' && curPtr + 1 < curBuffer.end() &&
isdigit(*(curPtr + 1))))
645 return makeToken(LibertyTokenKind::LBrace, start);
647 return makeToken(LibertyTokenKind::RBrace, start);
649 return makeToken(LibertyTokenKind::LParen, start);
651 return makeToken(LibertyTokenKind::RParen, start);
653 return makeToken(LibertyTokenKind::Colon, start);
655 return makeToken(LibertyTokenKind::Semi, start);
657 return makeToken(LibertyTokenKind::Comma, start);
660 return makeToken(LibertyTokenKind::Error, start);
664LibertyToken LibertyLexer::peekToken() {
665 const char *savedPtr = curPtr;
666 LibertyToken token = nextToken();
675ParseResult LibertyParser::parse() {
676 while (lexer.peekToken().kind != LibertyTokenKind::EndOfFile) {
677 auto token = lexer.peekToken();
679 if (token.kind != LibertyTokenKind::Identifier ||
680 token.spelling !=
"library") {
681 return emitError(token.location,
"expected `library` keyword");
690ParseResult LibertyParser::parseLibrary() {
691 LibertyGroup libertyLib;
692 if (parseGroupBody(libertyLib))
695 DenseSet<StringAttr> seenCells;
696 for (
auto &stmt : libertyLib.subGroups) {
698 if (stmt->name ==
"cell") {
699 StringAttr cellNameAttr;
700 if (lowerCell(*stmt, cellNameAttr))
702 if (!seenCells.insert(cellNameAttr).second)
703 return emitError(stmt->loc,
"redefinition of cell '" +
704 cellNameAttr.getValue() +
"'");
709 libertyLib.eraseSubGroup(
710 [](
const LibertyGroup &group) {
return group.name ==
"cell"; });
711 auto attr = convertGroupToAttr(libertyLib);
712 module->setAttr("synth.liberty.library", attr);
718Attribute LibertyParser::convertGroupToAttr(
const LibertyGroup &group) {
719 SmallVector<NamedAttribute> attrs;
720 if (!group.args.empty())
722 builder.getNamedAttr(
"args", builder.getArrayAttr(group.args)));
724 for (
const auto &attr : group.attrs)
725 attrs.push_back(builder.getNamedAttr(attr.name, attr.value));
727 llvm::StringMap<SmallVector<Attribute>> subGroups;
728 for (
const auto &sub : group.subGroups)
729 subGroups[sub->name].push_back(convertGroupToAttr(*sub));
731 for (
auto &it : subGroups)
733 builder.getNamedAttr(it.getKey(), builder.getArrayAttr(it.getValue())));
735 return builder.getDictionaryAttr(attrs);
738ParseResult LibertyParser::lowerCell(
const LibertyGroup &group,
739 StringAttr &cellNameAttr) {
740 if (group.args.empty())
741 return emitError(group.loc,
"cell missing name");
743 cellNameAttr = dyn_cast<StringAttr>(group.args[0]);
745 return emitError(group.loc,
"cell name must be a string");
747 SmallVector<hw::PortInfo> ports;
748 SmallVector<const LibertyGroup *> pinGroups;
749 llvm::DenseSet<StringAttr> seenPins;
753 size_t numOutputPinMissingFunction = 0;
754 for (
const auto &sub : group.subGroups) {
755 if (sub->name !=
"pin")
758 pinGroups.push_back(sub.get());
759 if (sub->args.empty())
760 return emitError(sub->loc,
"pin missing name");
762 StringAttr pinName = dyn_cast<StringAttr>(sub->args[0]);
763 if (!seenPins.insert(pinName).second)
764 return emitError(sub->loc,
765 "redefinition of pin '" + pinName.getValue() +
"'");
767 std::optional<hw::ModulePort::Direction> dir;
768 SmallVector<NamedAttribute> pinAttrs;
771 bool functionExist =
false;
772 for (
const auto &attr : sub->attrs) {
773 if (attr.name ==
"direction") {
774 if (
auto val = dyn_cast<StringAttr>(attr.value)) {
775 if (val.getValue() ==
"input")
776 dir = hw::ModulePort::Direction::Input;
777 else if (val.getValue() ==
"output")
778 dir = hw::ModulePort::Direction::Output;
779 else if (val.getValue() ==
"inout")
780 dir = hw::ModulePort::Direction::InOut;
782 return emitError(sub->loc,
783 "pin direction must be input, output, or inout");
785 return emitError(sub->loc,
786 "pin direction must be a string attribute");
791 if (attr.name ==
"function")
792 functionExist =
true;
794 pinAttrs.push_back(builder.getNamedAttr(attr.name, attr.value));
798 return emitError(sub->loc,
"pin direction must be specified");
800 if (dir == hw::ModulePort::Direction::Output && !functionExist)
801 ++numOutputPinMissingFunction;
803 llvm::StringMap<SmallVector<Attribute>> subGroups;
804 for (
const auto &child : sub->subGroups) {
806 subGroups[child->name].push_back(convertGroupToAttr(*child));
809 for (
auto &it : subGroups)
810 pinAttrs.push_back(builder.getNamedAttr(
811 it.getKey(), builder.getArrayAttr(it.getValue())));
813 auto libertyAttrs = builder.getDictionaryAttr(pinAttrs);
814 auto attrs = builder.getDictionaryAttr(
815 builder.getNamedAttr(
"synth.liberty.pin", libertyAttrs));
819 port.
type = builder.getI1Type();
822 ports.push_back(port);
827 for (
auto &p : ports) {
828 if (p.dir == hw::ModulePort::Direction::Input)
829 p.argNum = inputIdx++;
834 auto loc = lexer.translateLocation(group.loc);
835 auto numOutput = ports.size() - inputIdx;
842 if (numOutputPinMissingFunction != 0 &&
843 numOutputPinMissingFunction != numOutput)
844 return emitError(group.loc,
"cell '")
845 << cellNameAttr.getValue()
846 <<
"' has mixed output pins with and without "
847 "'function' attribute";
850 if (numOutputPinMissingFunction == numOutput) {
851 hw::HWModuleExternOp::create(builder, loc, cellNameAttr, ports);
856 auto moduleOp = hw::HWModuleOp::create(builder, loc, cellNameAttr, ports);
858 OpBuilder::InsertionGuard guard(builder);
859 builder.setInsertionPointToStart(moduleOp.getBodyBlock());
861 llvm::StringMap<Value> portValues;
862 for (
const auto &port : ports)
863 if (port.dir == hw::ModulePort::Direction::Input)
864 portValues[port.name.getValue()] =
865 moduleOp.getBodyBlock()->getArgument(port.argNum);
867 SmallVector<Value> outputs;
868 for (
const auto &port : ports) {
869 if (port.dir != hw::ModulePort::Direction::Output)
872 auto *it = llvm::find_if(pinGroups, [&](
const LibertyGroup *g) {
873 assert(g->name ==
"pin" &&
"expected pin group");
875 return cast<StringAttr>(g->args[0]) == port.name;
880 const LibertyGroup *pg = *it;
881 auto attrPair = pg->getAttribute(
"function");
882 assert(attrPair.first &&
"output pin missing function attribute");
884 if (parseExpression(val, cast<StringAttr>(attrPair.first).getValue(),
885 portValues, attrPair.second))
887 outputs.push_back(val);
890 auto *block = moduleOp.getBodyBlock();
891 block->getTerminator()->setOperands(outputs);
895ParseResult LibertyParser::parseGroupBody(LibertyGroup &group) {
897 if (lexer.peekToken().kind == LibertyTokenKind::LParen) {
899 while (lexer.peekToken().kind != LibertyTokenKind::RParen) {
901 if (parseAttribute(arg))
903 group.args.push_back(arg);
904 if (lexer.peekToken().kind == LibertyTokenKind::Comma)
907 if (consume(LibertyTokenKind::RParen,
"expected ')'"))
912 if (lexer.peekToken().kind == LibertyTokenKind::LBrace) {
914 while (lexer.peekToken().kind != LibertyTokenKind::RBrace &&
915 lexer.peekToken().kind != LibertyTokenKind::EndOfFile) {
916 if (parseStatement(group))
919 if (consume(LibertyTokenKind::RBrace,
"expected '}'"))
923 if (lexer.peekToken().kind == LibertyTokenKind::Semi)
930ParseResult LibertyParser::parseStatement(LibertyGroup &parent) {
931 auto nameTok = lexer.nextToken();
932 if (nameTok.kind != LibertyTokenKind::Identifier)
933 return emitError(nameTok.location,
"expected identifier");
934 StringRef name = nameTok.spelling;
937 if (lexer.peekToken().kind == LibertyTokenKind::Colon) {
940 auto loc = lexer.peekToken().location;
941 if (parseAttribute(val))
943 parent.attrs.emplace_back(name, val, loc);
944 return consume(LibertyTokenKind::Semi,
"expected ';'");
948 if (lexer.peekToken().kind == LibertyTokenKind::LParen) {
949 auto subGroup = std::make_unique<LibertyGroup>();
950 subGroup->name = name;
951 subGroup->loc = nameTok.location;
952 if (parseGroupBody(*subGroup))
954 parent.subGroups.push_back(std::move(subGroup));
960 return emitError(nameTok.location,
"expected ':' or '('");
967ParseResult LibertyParser::parseAttribute(Attribute &result) {
968 auto token = lexer.peekToken();
970 if (token.is(LibertyTokenKind::Number)) {
972 StringRef numStr = token.spelling;
974 if (!numStr.getAsDouble(val)) {
975 result = builder.getF64FloatAttr(val);
978 return emitError(token.location,
"expected number value");
982 if (token.is(LibertyTokenKind::Identifier)) {
984 result = builder.getStringAttr(token.spelling);
988 if (token.is(LibertyTokenKind::String)) {
990 StringRef str = getTokenSpelling(token);
991 result = builder.getStringAttr(str);
996 return emitError(token.location,
"expected attribute value");
1001ParseResult LibertyParser::parseExpression(Value &result, StringRef expr,
1002 const llvm::StringMap<Value> &values,
1004 ExpressionParser parser(lexer, builder, expr, values, loc);
1005 return parser.parse(result);
1012 TranslateToMLIRRegistration reg(
1013 "import-liberty",
"Import Liberty file",
1014 [](llvm::SourceMgr &sourceMgr, MLIRContext *
context) {
1015 ModuleOp
module = ModuleOp::create(UnknownLoc::get(context));
1016 LibertyParser parser(sourceMgr,
context, module);
1018 context->loadDialect<hw::HWDialect>();
1019 context->loadDialect<comb::CombDialect>();
1020 if (failed(parser.parse()))
1024 [](DialectRegistry ®istry) {
1025 registry.insert<HWDialect>();
1026 registry.insert<comb::CombDialect>();
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.