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);
336ParseResult ExpressionParser::parseAndExpr(Value &result) {
338 if (parseUnaryExpr(lhs))
340 while (peek().kind == TokenKind::AND ||
341 (peek().kind == TokenKind::ID || peek().kind == TokenKind::LPAREN ||
342 peek().kind == TokenKind::PREFIX_NOT)) {
343 auto loc = peek().loc;
344 if (peek().kind == TokenKind::AND)
347 if (parseUnaryExpr(rhs))
349 lhs = comb::AndOp::create(builder, lexer.translateLocation(loc), lhs, rhs);
359ParseResult ExpressionParser::parseUnaryExpr(Value &result) {
361 if (peek().kind == TokenKind::PREFIX_NOT) {
362 auto loc = consume().loc;
364 if (parseUnaryExpr(val))
366 result = createNot(val, loc);
371 if (peek().kind == TokenKind::LPAREN) {
374 if (parseOrExpr(val))
376 if (peek().kind != TokenKind::RPAREN)
380 if (peek().kind == TokenKind::POSTFIX_NOT) {
381 auto loc = consume().loc;
382 val = createNot(val, loc);
389 if (peek().kind == TokenKind::ID) {
390 auto tok = consume();
391 StringRef name = tok.spelling;
392 auto it = values.find(name);
393 if (it == values.end())
394 return emitError(tok.loc,
"variable not found");
395 Value val = it->second;
397 if (peek().kind == TokenKind::POSTFIX_NOT) {
398 auto loc = consume().loc;
399 val = createNot(val, loc);
405 return emitError(peek().loc,
"expected expression");
408InFlightDiagnostic ExpressionParser::emitError(llvm::SMLoc loc,
409 const Twine &message)
const {
410 return mlir::emitError(lexer.translateLocation(loc), message);
413InFlightDiagnostic ExpressionParser::emitWarning(llvm::SMLoc loc,
414 const Twine &message)
const {
415 return mlir::emitWarning(lexer.translateLocation(loc), message);
422 SmallVector<Attribute> args;
427 AttrEntry(StringRef name, Attribute value, SMLoc loc)
428 : name(name), value(value), loc(loc) {}
430 SmallVector<AttrEntry> attrs;
431 SmallVector<std::unique_ptr<LibertyGroup>> subGroups;
434 std::pair<Attribute, SMLoc> getAttribute(StringRef name)
const {
435 for (
const auto &attr : attrs)
436 if (attr.name == name)
437 return {attr.value, attr.loc};
441 void eraseSubGroup(llvm::function_ref<
bool(
const LibertyGroup &)> pred) {
443 std::remove_if(subGroups.begin(), subGroups.end(),
444 [pred](
const auto &group) { return pred(*group); }),
448 LogicalResult checkArgs(
450 llvm::function_ref<LogicalResult(
size_t idx, Attribute)> pred)
const {
451 if (args.size() != n)
453 for (
size_t i = 0; i < n; ++i)
454 if (failed(pred(i, args[i])))
462 LibertyParser(
const llvm::SourceMgr &sourceMgr, MLIRContext *
context,
464 : lexer(sourceMgr,
context), module(module),
465 builder(module.getBodyRegion()) {}
475 ParseResult parseLibrary();
476 ParseResult parseGroupBody(LibertyGroup &group);
477 ParseResult parseStatement(LibertyGroup &parent);
480 ParseResult lowerCell(
const LibertyGroup &group, StringAttr &cellNameAttr);
486 Attribute convertGroupToAttr(
const LibertyGroup &group);
489 ParseResult parseAttribute(Attribute &result);
490 static ParseResult parseAttribute(Attribute &result, OpBuilder &builder,
494 ParseResult parseExpression(Value &result, StringRef expr,
495 const llvm::StringMap<Value> &values, SMLoc loc);
497 InFlightDiagnostic emitError(llvm::SMLoc loc,
const Twine &message)
const {
498 return mlir::emitError(lexer.translateLocation(loc), message);
501 InFlightDiagnostic emitWarning(llvm::SMLoc loc,
const Twine &message)
const {
502 return mlir::emitWarning(lexer.translateLocation(loc), message);
505 ParseResult consume(LibertyTokenKind kind,
const Twine &msg) {
506 if (lexer.nextToken().is(kind))
508 return emitError(lexer.getCurrentLoc(), msg);
511 ParseResult consumeUntil(LibertyTokenKind kind) {
512 while (!lexer.peekToken().is(kind) &&
513 lexer.peekToken().kind != LibertyTokenKind::EndOfFile)
515 if (lexer.peekToken().is(kind))
517 return emitError(lexer.getCurrentLoc(),
518 " expected " + stringifyTokenKind(kind));
521 ParseResult consume(LibertyTokenKind kind) {
522 if (lexer.nextToken().is(kind))
524 return emitError(lexer.getCurrentLoc(),
525 " expected " + stringifyTokenKind(kind));
528 ParseResult expect(LibertyTokenKind kind) {
529 if (!lexer.peekToken().is(kind))
530 return emitError(lexer.getCurrentLoc(),
531 " expected " + stringifyTokenKind(kind));
536 StringRef getTokenSpelling(
const LibertyToken &token) {
537 StringRef str = token.spelling;
538 if (token.kind == LibertyTokenKind::String)
539 str = str.drop_front().drop_back();
548void LibertyLexer::skipWhitespaceAndComments() {
549 while (curPtr < curBuffer.end()) {
550 if (isspace(*curPtr)) {
556 if (*curPtr ==
'/' && curPtr + 1 < curBuffer.end()) {
557 if (*(curPtr + 1) ==
'*') {
559 while (curPtr + 1 < curBuffer.end() &&
560 (*curPtr !=
'*' || *(curPtr + 1) !=
'/'))
562 if (curPtr + 1 < curBuffer.end())
566 if (*(curPtr + 1) ==
'/') {
567 while (curPtr < curBuffer.end() && *curPtr !=
'\n')
574 if (*curPtr ==
'\\' && curPtr + 1 < curBuffer.end() &&
575 *(curPtr + 1) ==
'\n') {
584LibertyToken LibertyLexer::lexIdentifier() {
585 const char *start = curPtr;
586 while (curPtr < curBuffer.end() &&
587 (isalnum(*curPtr) || *curPtr ==
'_' || *curPtr ==
'.'))
589 return makeToken(LibertyTokenKind::Identifier, start);
592LibertyToken LibertyLexer::lexString() {
593 const char *start = curPtr;
595 while (curPtr < curBuffer.end() && *curPtr !=
'"') {
596 if (*curPtr ==
'\\' && curPtr + 1 < curBuffer.end())
600 if (curPtr < curBuffer.end())
602 return makeToken(LibertyTokenKind::String, start);
605LibertyToken LibertyLexer::lexNumber() {
606 const char *start = curPtr;
607 bool seenDot =
false;
608 while (curPtr < curBuffer.end()) {
611 }
else if (*curPtr ==
'.') {
613 mlir::emitError(translateLocation(SMLoc::getFromPointer(curPtr)),
614 "multiple decimal points in number");
615 return makeToken(LibertyTokenKind::Error, start);
623 return makeToken(LibertyTokenKind::Number, start);
626LibertyToken LibertyLexer::makeToken(LibertyTokenKind kind,
const char *start) {
627 return LibertyToken(kind, StringRef(start, curPtr - start),
628 SMLoc::getFromPointer(start));
631LibertyToken LibertyLexer::nextToken() {
632 skipWhitespaceAndComments();
634 if (curPtr >= curBuffer.end())
635 return makeToken(LibertyTokenKind::EndOfFile, curPtr);
637 const char *start = curPtr;
641 return lexIdentifier();
644 (c ==
'.' && curPtr + 1 < curBuffer.end() &&
isdigit(*(curPtr + 1))))
653 return makeToken(LibertyTokenKind::LBrace, start);
655 return makeToken(LibertyTokenKind::RBrace, start);
657 return makeToken(LibertyTokenKind::LParen, start);
659 return makeToken(LibertyTokenKind::RParen, start);
661 return makeToken(LibertyTokenKind::Colon, start);
663 return makeToken(LibertyTokenKind::Semi, start);
665 return makeToken(LibertyTokenKind::Comma, start);
668 return makeToken(LibertyTokenKind::Error, start);
672LibertyToken LibertyLexer::peekToken() {
673 const char *savedPtr = curPtr;
674 LibertyToken token = nextToken();
683ParseResult LibertyParser::parse() {
684 while (lexer.peekToken().kind != LibertyTokenKind::EndOfFile) {
685 auto token = lexer.peekToken();
687 if (token.kind != LibertyTokenKind::Identifier ||
688 token.spelling !=
"library") {
689 return emitError(token.location,
"expected `library` keyword");
698ParseResult LibertyParser::parseLibrary() {
699 LibertyGroup libertyLib;
700 if (parseGroupBody(libertyLib))
703 DenseSet<StringAttr> seenCells;
704 for (
auto &stmt : libertyLib.subGroups) {
706 if (stmt->name ==
"cell") {
707 StringAttr cellNameAttr;
708 if (lowerCell(*stmt, cellNameAttr))
710 if (!seenCells.insert(cellNameAttr).second)
711 return emitError(stmt->loc,
"redefinition of cell '" +
712 cellNameAttr.getValue() +
"'");
717 libertyLib.eraseSubGroup(
718 [](
const LibertyGroup &group) {
return group.name ==
"cell"; });
719 auto attr = convertGroupToAttr(libertyLib);
720 module->setAttr("synth.liberty.library", attr);
726Attribute LibertyParser::convertGroupToAttr(
const LibertyGroup &group) {
727 SmallVector<NamedAttribute> attrs;
728 if (!group.args.empty())
730 builder.getNamedAttr(
"args", builder.getArrayAttr(group.args)));
732 for (
const auto &attr : group.attrs)
733 attrs.push_back(builder.getNamedAttr(attr.name, attr.value));
735 llvm::StringMap<SmallVector<Attribute>> subGroups;
736 for (
const auto &sub : group.subGroups)
737 subGroups[sub->name].push_back(convertGroupToAttr(*sub));
739 for (
auto &it : subGroups)
741 builder.getNamedAttr(it.getKey(), builder.getArrayAttr(it.getValue())));
743 return builder.getDictionaryAttr(attrs);
746ParseResult LibertyParser::lowerCell(
const LibertyGroup &group,
747 StringAttr &cellNameAttr) {
748 if (group.args.empty())
749 return emitError(group.loc,
"cell missing name");
751 cellNameAttr = dyn_cast<StringAttr>(group.args[0]);
753 return emitError(group.loc,
"cell name must be a string");
755 SmallVector<hw::PortInfo> ports;
756 SmallVector<const LibertyGroup *> pinGroups;
757 llvm::DenseSet<StringAttr> seenPins;
760 for (
const auto &sub : group.subGroups) {
761 if (sub->name !=
"pin")
764 pinGroups.push_back(sub.get());
765 if (sub->args.empty())
766 return emitError(sub->loc,
"pin missing name");
768 StringAttr pinName = dyn_cast<StringAttr>(sub->args[0]);
769 if (!seenPins.insert(pinName).second)
770 return emitError(sub->loc,
771 "redefinition of pin '" + pinName.getValue() +
"'");
773 std::optional<hw::ModulePort::Direction> dir;
774 SmallVector<NamedAttribute> pinAttrs;
776 for (
const auto &attr : sub->attrs) {
777 if (attr.name ==
"direction") {
778 if (
auto val = dyn_cast<StringAttr>(attr.value)) {
779 if (val.getValue() ==
"input")
780 dir = hw::ModulePort::Direction::Input;
781 else if (val.getValue() ==
"output")
782 dir = hw::ModulePort::Direction::Output;
783 else if (val.getValue() ==
"inout")
784 dir = hw::ModulePort::Direction::InOut;
786 return emitError(sub->loc,
787 "pin direction must be input, output, or inout");
789 return emitError(sub->loc,
790 "pin direction must be a string attribute");
794 pinAttrs.push_back(builder.getNamedAttr(attr.name, attr.value));
798 return emitError(sub->loc,
"pin direction must be specified");
800 llvm::StringMap<SmallVector<Attribute>> subGroups;
801 for (
const auto &child : sub->subGroups) {
803 subGroups[child->name].push_back(convertGroupToAttr(*child));
806 for (
auto &it : subGroups)
807 pinAttrs.push_back(builder.getNamedAttr(
808 it.getKey(), builder.getArrayAttr(it.getValue())));
810 auto libertyAttrs = builder.getDictionaryAttr(pinAttrs);
811 auto attrs = builder.getDictionaryAttr(
812 builder.getNamedAttr(
"synth.liberty.pin", libertyAttrs));
816 port.
type = builder.getI1Type();
819 ports.push_back(port);
824 for (
auto &p : ports) {
825 if (p.dir == hw::ModulePort::Direction::Input)
826 p.argNum = inputIdx++;
831 auto loc = lexer.translateLocation(group.loc);
832 auto moduleOp = hw::HWModuleOp::create(builder, loc, cellNameAttr, ports);
834 OpBuilder::InsertionGuard guard(builder);
835 builder.setInsertionPointToStart(moduleOp.getBodyBlock());
837 llvm::StringMap<Value> portValues;
838 for (
const auto &port : ports)
839 if (port.dir == hw::ModulePort::Direction::Input)
840 portValues[port.name.getValue()] =
841 moduleOp.getBodyBlock()->getArgument(port.argNum);
843 SmallVector<Value> outputs;
844 for (
const auto &port : ports) {
845 if (port.dir != hw::ModulePort::Direction::Output)
848 auto *it = llvm::find_if(pinGroups, [&](
const LibertyGroup *g) {
849 assert(g->name ==
"pin" &&
"expected pin group");
851 return cast<StringAttr>(g->args[0]) == port.name;
856 const LibertyGroup *pg = *it;
857 auto attrPair = pg->getAttribute(
"function");
859 return emitError(pg->loc,
"expected function attribute");
861 if (parseExpression(val, cast<StringAttr>(attrPair.first).getValue(),
862 portValues, attrPair.second))
864 outputs.push_back(val);
867 auto *block = moduleOp.getBodyBlock();
868 block->getTerminator()->setOperands(outputs);
872ParseResult LibertyParser::parseGroupBody(LibertyGroup &group) {
874 if (lexer.peekToken().kind == LibertyTokenKind::LParen) {
876 while (lexer.peekToken().kind != LibertyTokenKind::RParen) {
878 if (parseAttribute(arg))
880 group.args.push_back(arg);
881 if (lexer.peekToken().kind == LibertyTokenKind::Comma)
884 if (consume(LibertyTokenKind::RParen,
"expected ')'"))
889 if (lexer.peekToken().kind == LibertyTokenKind::LBrace) {
891 while (lexer.peekToken().kind != LibertyTokenKind::RBrace &&
892 lexer.peekToken().kind != LibertyTokenKind::EndOfFile) {
893 if (parseStatement(group))
896 if (consume(LibertyTokenKind::RBrace,
"expected '}'"))
900 if (lexer.peekToken().kind == LibertyTokenKind::Semi)
907ParseResult LibertyParser::parseStatement(LibertyGroup &parent) {
908 auto nameTok = lexer.nextToken();
909 if (nameTok.kind != LibertyTokenKind::Identifier)
910 return emitError(nameTok.location,
"expected identifier");
911 StringRef name = nameTok.spelling;
914 if (lexer.peekToken().kind == LibertyTokenKind::Colon) {
917 auto loc = lexer.peekToken().location;
918 if (parseAttribute(val))
920 parent.attrs.emplace_back(name, val, loc);
921 return consume(LibertyTokenKind::Semi,
"expected ';'");
925 if (lexer.peekToken().kind == LibertyTokenKind::LParen) {
926 auto subGroup = std::make_unique<LibertyGroup>();
927 subGroup->name = name;
928 subGroup->loc = nameTok.location;
929 if (parseGroupBody(*subGroup))
931 parent.subGroups.push_back(std::move(subGroup));
937 return emitError(nameTok.location,
"expected ':' or '('");
940ParseResult LibertyParser::parseAttribute(Attribute &result, OpBuilder &builder,
943 if (!attr.getAsDouble(val)) {
944 result = builder.getF64FloatAttr(val);
947 result = builder.getStringAttr(attr);
955ParseResult LibertyParser::parseAttribute(Attribute &result) {
956 auto token = lexer.peekToken();
958 if (token.is(LibertyTokenKind::Number)) {
960 StringRef numStr = token.spelling;
962 if (!numStr.getAsDouble(val)) {
963 result = builder.getF64FloatAttr(val);
966 return emitError(token.location,
"expected number value");
970 if (token.is(LibertyTokenKind::Identifier)) {
972 result = builder.getStringAttr(token.spelling);
976 if (token.is(LibertyTokenKind::String)) {
978 StringRef str = getTokenSpelling(token);
979 result = builder.getStringAttr(str);
984 return emitError(token.location,
"expected attribute value");
989ParseResult LibertyParser::parseExpression(Value &result, StringRef expr,
990 const llvm::StringMap<Value> &values,
992 ExpressionParser parser(lexer, builder, expr, values, loc);
993 return parser.parse(result);
1000 TranslateToMLIRRegistration reg(
1001 "import-liberty",
"Import Liberty file",
1002 [](llvm::SourceMgr &sourceMgr, MLIRContext *
context) {
1003 ModuleOp
module = ModuleOp::create(UnknownLoc::get(context));
1004 LibertyParser parser(sourceMgr,
context, module);
1006 context->loadDialect<hw::HWDialect>();
1007 context->loadDialect<comb::CombDialect>();
1008 if (failed(parser.parse()))
1012 [](DialectRegistry ®istry) {
1013 registry.insert<HWDialect>();
1014 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.