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;
205 InFlightDiagnostic emitWarning(llvm::SMLoc loc,
const Twine &message)
const;
212ExpressionParser::ExpressionParser(LibertyLexer &lexer, OpBuilder &builder,
214 const llvm::StringMap<Value> &values,
216 : lexer(lexer), builder(builder), values(values), baseLoc(baseLoc),
217 exprStart(expr.begin()) {
221ParseResult ExpressionParser::parse(Value &result) {
222 return parseOrExpr(result);
225SMLoc ExpressionParser::getLoc(
const char *ptr) {
226 size_t offset = ptr - exprStart;
227 return SMLoc::getFromPointer(baseLoc.getPointer() + 1 + offset);
230void ExpressionParser::tokenize(StringRef expr) {
231 const char *ptr = expr.begin();
232 const char *end = expr.end();
244 if (isalnum(*ptr) || *ptr ==
'_') {
245 const char *start = ptr;
246 while (ptr < end && (isalnum(*ptr) || *ptr ==
'_'))
248 tokens.push_back({TokenKind::ID, StringRef(start, ptr - start), loc});
256 tokens.push_back({TokenKind::AND, StringRef(ptr, 1), loc});
260 tokens.push_back({TokenKind::OR, StringRef(ptr, 1), loc});
263 tokens.push_back({TokenKind::XOR, StringRef(ptr, 1), loc});
266 tokens.push_back({TokenKind::PREFIX_NOT, StringRef(ptr, 1), loc});
269 tokens.push_back({TokenKind::POSTFIX_NOT, StringRef(ptr, 1), loc});
272 tokens.push_back({TokenKind::LPAREN, StringRef(ptr, 1), loc});
275 tokens.push_back({TokenKind::RPAREN, StringRef(ptr, 1), loc});
281 tokens.push_back({TokenKind::END,
"",
getLoc(ptr)});
284ExpressionParser::Token ExpressionParser::peek()
const {
return tokens[pos]; }
286ExpressionParser::Token ExpressionParser::consume() {
return tokens[pos++]; }
288Value ExpressionParser::createNot(Value val, SMLoc loc) {
291 builder.getI1Type(), 1);
292 return comb::XorOp::create(builder, lexer.translateLocation(loc), val,
299ParseResult ExpressionParser::parseOrExpr(Value &result) {
301 if (parseXorExpr(lhs))
303 while (peek().kind == TokenKind::OR) {
304 auto loc = consume().loc;
306 if (parseXorExpr(rhs))
308 lhs = comb::OrOp::create(builder, lexer.translateLocation(loc), lhs, rhs);
317ParseResult ExpressionParser::parseXorExpr(Value &result) {
319 if (parseAndExpr(lhs))
321 while (peek().kind == TokenKind::XOR) {
322 auto loc = consume().loc;
324 if (parseAndExpr(rhs))
326 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 auto loc = consume().loc;
342 if (parseUnaryExpr(rhs))
344 lhs = comb::AndOp::create(builder, lexer.translateLocation(loc), lhs, rhs);
354ParseResult ExpressionParser::parseUnaryExpr(Value &result) {
356 if (peek().kind == TokenKind::PREFIX_NOT) {
357 auto loc = consume().loc;
359 if (parseUnaryExpr(val))
361 result = createNot(val, loc);
366 if (peek().kind == TokenKind::LPAREN) {
369 if (parseOrExpr(val))
371 if (peek().kind != TokenKind::RPAREN)
375 if (peek().kind == TokenKind::POSTFIX_NOT) {
376 auto loc = consume().loc;
377 val = createNot(val, loc);
384 if (peek().kind == TokenKind::ID) {
385 auto tok = consume();
386 StringRef name = tok.spelling;
387 auto it = values.find(name);
388 if (it == values.end())
389 return emitError(tok.loc,
"variable not found");
390 Value val = it->second;
392 if (peek().kind == TokenKind::POSTFIX_NOT) {
393 auto loc = consume().loc;
394 val = createNot(val, loc);
400 return emitError(peek().loc,
"expected expression");
403InFlightDiagnostic ExpressionParser::emitError(llvm::SMLoc loc,
404 const Twine &message)
const {
405 return mlir::emitError(lexer.translateLocation(loc), message);
408InFlightDiagnostic ExpressionParser::emitWarning(llvm::SMLoc loc,
409 const Twine &message)
const {
410 return mlir::emitWarning(lexer.translateLocation(loc), message);
417 SmallVector<Attribute> args;
422 AttrEntry(StringRef name, Attribute value, SMLoc loc)
423 : name(name), value(value), loc(loc) {}
425 SmallVector<AttrEntry> attrs;
426 SmallVector<std::unique_ptr<LibertyGroup>> subGroups;
429 std::pair<Attribute, SMLoc> getAttribute(StringRef name)
const {
430 for (
const auto &attr : attrs)
431 if (attr.name == name)
432 return {attr.value, attr.loc};
436 void eraseSubGroup(llvm::function_ref<
bool(
const LibertyGroup &)> pred) {
438 std::remove_if(subGroups.begin(), subGroups.end(),
439 [pred](
const auto &group) { return pred(*group); }),
443 LogicalResult checkArgs(
445 llvm::function_ref<LogicalResult(
size_t idx, Attribute)> pred)
const {
446 if (args.size() != n)
448 for (
size_t i = 0; i < n; ++i)
449 if (failed(pred(i, args[i])))
457 LibertyParser(
const llvm::SourceMgr &sourceMgr, MLIRContext *
context,
459 : lexer(sourceMgr,
context), module(module),
460 builder(module.getBodyRegion()) {}
470 ParseResult parseLibrary();
471 ParseResult parseGroupBody(LibertyGroup &group);
472 ParseResult parseStatement(LibertyGroup &parent);
475 ParseResult lowerCell(
const LibertyGroup &group, StringAttr &cellNameAttr);
481 Attribute convertGroupToAttr(
const LibertyGroup &group);
484 ParseResult parseAttribute(Attribute &result);
485 static ParseResult parseAttribute(Attribute &result, OpBuilder &builder,
489 ParseResult parseExpression(Value &result, StringRef expr,
490 const llvm::StringMap<Value> &values, SMLoc loc);
492 InFlightDiagnostic emitError(llvm::SMLoc loc,
const Twine &message)
const {
493 return mlir::emitError(lexer.translateLocation(loc), message);
496 InFlightDiagnostic emitWarning(llvm::SMLoc loc,
const Twine &message)
const {
497 return mlir::emitWarning(lexer.translateLocation(loc), message);
500 ParseResult consume(LibertyTokenKind kind,
const Twine &msg) {
501 if (lexer.nextToken().is(kind))
503 return emitError(lexer.getCurrentLoc(), msg);
506 ParseResult consumeUntil(LibertyTokenKind kind) {
507 while (!lexer.peekToken().is(kind) &&
508 lexer.peekToken().kind != LibertyTokenKind::EndOfFile)
510 if (lexer.peekToken().is(kind))
512 return emitError(lexer.getCurrentLoc(),
513 " expected " + stringifyTokenKind(kind));
516 ParseResult consume(LibertyTokenKind kind) {
517 if (lexer.nextToken().is(kind))
519 return emitError(lexer.getCurrentLoc(),
520 " expected " + stringifyTokenKind(kind));
523 ParseResult expect(LibertyTokenKind kind) {
524 if (!lexer.peekToken().is(kind))
525 return emitError(lexer.getCurrentLoc(),
526 " expected " + stringifyTokenKind(kind));
531 StringRef getTokenSpelling(
const LibertyToken &token) {
532 StringRef str = token.spelling;
533 if (token.kind == LibertyTokenKind::String)
534 str = str.drop_front().drop_back();
543void LibertyLexer::skipWhitespaceAndComments() {
544 while (curPtr < curBuffer.end()) {
545 if (isspace(*curPtr)) {
551 if (*curPtr ==
'/' && curPtr + 1 < curBuffer.end()) {
552 if (*(curPtr + 1) ==
'*') {
554 while (curPtr + 1 < curBuffer.end() &&
555 (*curPtr !=
'*' || *(curPtr + 1) !=
'/'))
557 if (curPtr + 1 < curBuffer.end())
561 if (*(curPtr + 1) ==
'/') {
562 while (curPtr < curBuffer.end() && *curPtr !=
'\n')
569 if (*curPtr ==
'\\' && curPtr + 1 < curBuffer.end() &&
570 *(curPtr + 1) ==
'\n') {
579LibertyToken LibertyLexer::lexIdentifier() {
580 const char *start = curPtr;
581 while (curPtr < curBuffer.end() &&
582 (isalnum(*curPtr) || *curPtr ==
'_' || *curPtr ==
'.'))
584 return makeToken(LibertyTokenKind::Identifier, start);
587LibertyToken LibertyLexer::lexString() {
588 const char *start = curPtr;
590 while (curPtr < curBuffer.end() && *curPtr !=
'"') {
591 if (*curPtr ==
'\\' && curPtr + 1 < curBuffer.end())
595 if (curPtr < curBuffer.end())
597 return makeToken(LibertyTokenKind::String, start);
600LibertyToken LibertyLexer::lexNumber() {
601 const char *start = curPtr;
602 bool seenDot =
false;
603 while (curPtr < curBuffer.end()) {
606 }
else if (*curPtr ==
'.') {
608 mlir::emitError(translateLocation(SMLoc::getFromPointer(curPtr)),
609 "multiple decimal points in number");
610 return makeToken(LibertyTokenKind::Error, start);
618 return makeToken(LibertyTokenKind::Number, start);
621LibertyToken LibertyLexer::makeToken(LibertyTokenKind kind,
const char *start) {
622 return LibertyToken(kind, StringRef(start, curPtr - start),
623 SMLoc::getFromPointer(start));
626LibertyToken LibertyLexer::nextToken() {
627 skipWhitespaceAndComments();
629 if (curPtr >= curBuffer.end())
630 return makeToken(LibertyTokenKind::EndOfFile, curPtr);
632 const char *start = curPtr;
636 return lexIdentifier();
639 (c ==
'.' && curPtr + 1 < curBuffer.end() &&
isdigit(*(curPtr + 1))))
648 return makeToken(LibertyTokenKind::LBrace, start);
650 return makeToken(LibertyTokenKind::RBrace, start);
652 return makeToken(LibertyTokenKind::LParen, start);
654 return makeToken(LibertyTokenKind::RParen, start);
656 return makeToken(LibertyTokenKind::Colon, start);
658 return makeToken(LibertyTokenKind::Semi, start);
660 return makeToken(LibertyTokenKind::Comma, start);
663 return makeToken(LibertyTokenKind::Error, start);
667LibertyToken LibertyLexer::peekToken() {
668 const char *savedPtr = curPtr;
669 LibertyToken token = nextToken();
678ParseResult LibertyParser::parse() {
679 while (lexer.peekToken().kind != LibertyTokenKind::EndOfFile) {
680 auto token = lexer.peekToken();
682 if (token.kind != LibertyTokenKind::Identifier ||
683 token.spelling !=
"library") {
684 return emitError(token.location,
"expected `library` keyword");
693ParseResult LibertyParser::parseLibrary() {
694 LibertyGroup libertyLib;
695 if (parseGroupBody(libertyLib))
698 DenseSet<StringAttr> seenCells;
699 for (
auto &stmt : libertyLib.subGroups) {
701 if (stmt->name ==
"cell") {
702 StringAttr cellNameAttr;
703 if (lowerCell(*stmt, cellNameAttr))
705 if (!seenCells.insert(cellNameAttr).second)
706 return emitError(stmt->loc,
"redefinition of cell '" +
707 cellNameAttr.getValue() +
"'");
712 libertyLib.eraseSubGroup(
713 [](
const LibertyGroup &group) {
return group.name ==
"cell"; });
714 auto attr = convertGroupToAttr(libertyLib);
715 module->setAttr("synth.liberty.library", attr);
721Attribute LibertyParser::convertGroupToAttr(
const LibertyGroup &group) {
722 SmallVector<NamedAttribute> attrs;
723 if (!group.args.empty())
725 builder.getNamedAttr(
"args", builder.getArrayAttr(group.args)));
727 for (
const auto &attr : group.attrs)
728 attrs.push_back(builder.getNamedAttr(attr.name, attr.value));
730 llvm::StringMap<SmallVector<Attribute>> subGroups;
731 for (
const auto &sub : group.subGroups)
732 subGroups[sub->name].push_back(convertGroupToAttr(*sub));
734 for (
auto &it : subGroups)
736 builder.getNamedAttr(it.getKey(), builder.getArrayAttr(it.getValue())));
738 return builder.getDictionaryAttr(attrs);
741ParseResult LibertyParser::lowerCell(
const LibertyGroup &group,
742 StringAttr &cellNameAttr) {
743 if (group.args.empty())
744 return emitError(group.loc,
"cell missing name");
746 cellNameAttr = dyn_cast<StringAttr>(group.args[0]);
748 return emitError(group.loc,
"cell name must be a string");
750 SmallVector<hw::PortInfo> ports;
751 SmallVector<const LibertyGroup *> pinGroups;
752 llvm::DenseSet<StringAttr> seenPins;
755 for (
const auto &sub : group.subGroups) {
756 if (sub->name !=
"pin")
759 pinGroups.push_back(sub.get());
760 if (sub->args.empty())
761 return emitError(sub->loc,
"pin missing name");
763 StringAttr pinName = dyn_cast<StringAttr>(sub->args[0]);
764 if (!seenPins.insert(pinName).second)
765 return emitError(sub->loc,
766 "redefinition of pin '" + pinName.getValue() +
"'");
768 std::optional<hw::ModulePort::Direction> dir;
769 SmallVector<NamedAttribute> pinAttrs;
771 for (
const auto &attr : sub->attrs) {
772 if (attr.name ==
"direction") {
773 if (
auto val = dyn_cast<StringAttr>(attr.value)) {
774 if (val.getValue() ==
"input")
775 dir = hw::ModulePort::Direction::Input;
776 else if (val.getValue() ==
"output")
777 dir = hw::ModulePort::Direction::Output;
778 else if (val.getValue() ==
"inout")
779 dir = hw::ModulePort::Direction::InOut;
781 return emitError(sub->loc,
782 "pin direction must be input, output, or inout");
784 return emitError(sub->loc,
785 "pin direction must be a string attribute");
789 pinAttrs.push_back(builder.getNamedAttr(attr.name, attr.value));
793 return emitError(sub->loc,
"pin direction must be specified");
795 llvm::StringMap<SmallVector<Attribute>> subGroups;
796 for (
const auto &child : sub->subGroups) {
798 subGroups[child->name].push_back(convertGroupToAttr(*child));
801 for (
auto &it : subGroups)
802 pinAttrs.push_back(builder.getNamedAttr(
803 it.getKey(), builder.getArrayAttr(it.getValue())));
805 auto libertyAttrs = builder.getDictionaryAttr(pinAttrs);
806 auto attrs = builder.getDictionaryAttr(
807 builder.getNamedAttr(
"synth.liberty.pin", libertyAttrs));
811 port.
type = builder.getI1Type();
814 ports.push_back(port);
819 for (
auto &p : ports) {
820 if (p.dir == hw::ModulePort::Direction::Input)
821 p.argNum = inputIdx++;
826 auto loc = lexer.translateLocation(group.loc);
827 auto moduleOp = hw::HWModuleOp::create(builder, loc, cellNameAttr, ports);
829 OpBuilder::InsertionGuard guard(builder);
830 builder.setInsertionPointToStart(moduleOp.getBodyBlock());
832 llvm::StringMap<Value> portValues;
833 for (
const auto &port : ports)
834 if (port.dir == hw::ModulePort::Direction::Input)
835 portValues[port.name.getValue()] =
836 moduleOp.getBodyBlock()->getArgument(port.argNum);
838 SmallVector<Value> outputs;
839 for (
const auto &port : ports) {
840 if (port.dir != hw::ModulePort::Direction::Output)
843 auto *it = llvm::find_if(pinGroups, [&](
const LibertyGroup *g) {
844 assert(g->name ==
"pin" &&
"expected pin group");
846 return cast<StringAttr>(g->args[0]) == port.name;
851 const LibertyGroup *pg = *it;
852 auto attrPair = pg->getAttribute(
"function");
854 return emitError(pg->loc,
"expected function attribute");
856 if (parseExpression(val, cast<StringAttr>(attrPair.first).getValue(),
857 portValues, attrPair.second))
859 outputs.push_back(val);
862 auto *block = moduleOp.getBodyBlock();
863 block->getTerminator()->setOperands(outputs);
867ParseResult LibertyParser::parseGroupBody(LibertyGroup &group) {
869 if (lexer.peekToken().kind == LibertyTokenKind::LParen) {
871 while (lexer.peekToken().kind != LibertyTokenKind::RParen) {
873 if (parseAttribute(arg))
875 group.args.push_back(arg);
876 if (lexer.peekToken().kind == LibertyTokenKind::Comma)
879 if (consume(LibertyTokenKind::RParen,
"expected ')'"))
884 if (lexer.peekToken().kind == LibertyTokenKind::LBrace) {
886 while (lexer.peekToken().kind != LibertyTokenKind::RBrace &&
887 lexer.peekToken().kind != LibertyTokenKind::EndOfFile) {
888 if (parseStatement(group))
891 if (consume(LibertyTokenKind::RBrace,
"expected '}'"))
895 if (lexer.peekToken().kind == LibertyTokenKind::Semi)
902ParseResult LibertyParser::parseStatement(LibertyGroup &parent) {
903 auto nameTok = lexer.nextToken();
904 if (nameTok.kind != LibertyTokenKind::Identifier)
905 return emitError(nameTok.location,
"expected identifier");
906 StringRef name = nameTok.spelling;
909 if (lexer.peekToken().kind == LibertyTokenKind::Colon) {
912 auto loc = lexer.peekToken().location;
913 if (parseAttribute(val))
915 parent.attrs.emplace_back(name, val, loc);
916 return consume(LibertyTokenKind::Semi,
"expected ';'");
920 if (lexer.peekToken().kind == LibertyTokenKind::LParen) {
921 auto subGroup = std::make_unique<LibertyGroup>();
922 subGroup->name = name;
923 subGroup->loc = nameTok.location;
924 if (parseGroupBody(*subGroup))
926 parent.subGroups.push_back(std::move(subGroup));
932 return emitError(nameTok.location,
"expected ':' or '('");
935ParseResult LibertyParser::parseAttribute(Attribute &result, OpBuilder &builder,
938 if (!attr.getAsDouble(val)) {
939 result = builder.getF64FloatAttr(val);
942 result = builder.getStringAttr(attr);
950ParseResult LibertyParser::parseAttribute(Attribute &result) {
951 auto token = lexer.peekToken();
953 if (token.is(LibertyTokenKind::Number)) {
955 StringRef numStr = token.spelling;
957 if (!numStr.getAsDouble(val)) {
958 result = builder.getF64FloatAttr(val);
961 return emitError(token.location,
"expected number value");
965 if (token.is(LibertyTokenKind::Identifier)) {
967 result = builder.getStringAttr(token.spelling);
971 if (token.is(LibertyTokenKind::String)) {
973 StringRef str = getTokenSpelling(token);
974 result = builder.getStringAttr(str);
979 return emitError(token.location,
"expected attribute value");
984ParseResult LibertyParser::parseExpression(Value &result, StringRef expr,
985 const llvm::StringMap<Value> &values,
987 ExpressionParser parser(lexer, builder, expr, values, loc);
988 return parser.parse(result);
995 TranslateToMLIRRegistration reg(
996 "import-liberty",
"Import Liberty file",
997 [](llvm::SourceMgr &sourceMgr, MLIRContext *
context) {
998 ModuleOp
module = ModuleOp::create(UnknownLoc::get(context));
999 LibertyParser parser(sourceMgr,
context, module);
1001 context->loadDialect<hw::HWDialect>();
1002 context->loadDialect<comb::CombDialect>();
1003 if (failed(parser.parse()))
1007 [](DialectRegistry ®istry) {
1008 registry.insert<HWDialect>();
1009 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.