18#include "mlir/IR/Builders.h"
19#include "mlir/IR/BuiltinOps.h"
20#include "mlir/IR/Diagnostics.h"
21#include "mlir/IR/Location.h"
22#include "mlir/IR/MLIRContext.h"
23#include "mlir/Support/FileUtilities.h"
24#include "mlir/Support/LogicalResult.h"
25#include "mlir/Support/Timing.h"
26#include "mlir/Tools/mlir-translate/Translation.h"
27#include "llvm/ADT/DenseMap.h"
28#include "llvm/ADT/StringExtras.h"
29#include "llvm/ADT/StringRef.h"
30#include "llvm/Support/Debug.h"
31#include "llvm/Support/ErrorHandling.h"
32#include "llvm/Support/SMLoc.h"
33#include "llvm/Support/SourceMgr.h"
34#include "llvm/Support/raw_ostream.h"
45#define DEBUG_TYPE "import-aiger"
50enum class AIGERTokenKind {
69 AIGERToken(AIGERTokenKind kind, StringRef spelling, SMLoc location)
70 : kind(kind), spelling(spelling), location(location) {}
80 AIGERLexer(
const llvm::SourceMgr &sourceMgr, MLIRContext *context)
81 : sourceMgr(sourceMgr),
84 sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID())->getBuffer()),
85 curPtr(curBuffer.begin()) {}
88 AIGERToken nextToken();
91 AIGERToken lexAsSymbol();
94 AIGERToken peekToken();
97 bool isAtEOF()
const {
return curPtr >= curBuffer.end(); }
100 ParseResult readByte(
unsigned char &
byte) {
101 if (curPtr >= curBuffer.end())
108 SMLoc getCurrentLoc()
const {
return SMLoc::getFromPointer(curPtr); }
112 Location translateLocation(llvm::SMLoc loc) {
114 unsigned mainFileID = sourceMgr.getMainFileID();
115 auto lineAndColumn = sourceMgr.getLineAndColumn(loc, mainFileID);
116 return FileLineColLoc::get(bufferNameIdentifier, lineAndColumn.first,
117 lineAndColumn.second);
121 AIGERToken emitError(
const char *loc,
const Twine &message) {
122 mlir::emitError(translateLocation(SMLoc::getFromPointer(loc)), message);
123 return AIGERToken(AIGERTokenKind::Error, StringRef(loc, 1),
124 SMLoc::getFromPointer(loc));
128 const llvm::SourceMgr &sourceMgr;
129 StringAttr bufferNameIdentifier;
136 MLIRContext *context) {
137 auto mainBuffer = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
138 StringRef bufferName = mainBuffer->getBufferIdentifier();
139 if (bufferName.empty())
140 bufferName =
"<unknown>";
141 return StringAttr::get(context, bufferName);
145 void skipWhitespace();
148 void skipUntilNewline();
151 AIGERToken lexNumber();
154 AIGERToken lexIdentifier();
157 AIGERToken makeToken(AIGERTokenKind kind,
const char *start) {
158 return AIGERToken(kind, StringRef(start, curPtr - start),
159 SMLoc::getFromPointer(start));
174 AIGERParser(
const llvm::SourceMgr &sourceMgr, MLIRContext *context,
176 : lexer(sourceMgr, context), context(context), module(module),
177 options(options), builder(context) {}
184 MLIRContext *context;
190 unsigned maxVarIndex = 0;
191 unsigned numInputs = 0;
192 unsigned numLatches = 0;
193 unsigned numOutputs = 0;
194 unsigned numAnds = 0;
195 bool isBinaryFormat =
false;
199 enum SymbolKind :
unsigned {
Input, Latch,
Output };
200 DenseMap<std::pair<SymbolKind, unsigned>, StringAttr> symbolTable;
203 SmallVector<unsigned> inputLiterals;
204 SmallVector<std::tuple<unsigned, unsigned, SMLoc>>
206 SmallVector<std::pair<unsigned, SMLoc>> outputLiterals;
207 SmallVector<std::tuple<unsigned, unsigned, unsigned, SMLoc>>
211 ParseResult parseHeader();
214 ParseResult parseInputs();
217 ParseResult parseLatches();
220 ParseResult parseOutputs();
223 ParseResult parseAndGates();
226 ParseResult parseAndGatesASCII();
229 ParseResult parseAndGatesBinary();
232 ParseResult parseSymbolTable();
235 ParseResult parseComments();
243 Value getLiteralValue(
unsigned literal,
244 DenseMap<unsigned, Backedge> &backedges, Location loc);
247 ParseResult createModule();
249 InFlightDiagnostic emitError(llvm::SMLoc loc,
const Twine &message) {
250 return mlir::emitError(lexer.translateLocation(loc), message);
254 InFlightDiagnostic emitError(
const Twine &message) {
255 return emitError(lexer.getCurrentLoc(), message);
259 ParseResult parseNumber(
unsigned &result, SMLoc *loc =
nullptr);
262 ParseResult parseBinaryNumber(
unsigned &result);
265 ParseResult parseNewLine();
274void AIGERLexer::skipWhitespace() {
275 while (curPtr < curBuffer.end()) {
277 if (*curPtr ==
' ' || *curPtr ==
'\t' || *curPtr ==
'\r') {
284 if (*curPtr ==
'/' &&
285 (curPtr + 1 < curBuffer.end() && *(curPtr + 1) ==
'/')) {
293void AIGERLexer::skipUntilNewline() {
294 while (curPtr < curBuffer.end() && *curPtr !=
'\n')
296 if (curPtr < curBuffer.end() && *curPtr ==
'\n')
300AIGERToken AIGERLexer::lexNumber() {
301 const char *start = curPtr;
302 while (curPtr < curBuffer.end() && llvm::isDigit(*curPtr))
304 return makeToken(AIGERTokenKind::Number, start);
307AIGERToken AIGERLexer::lexIdentifier() {
308 const char *start = curPtr;
309 while (curPtr < curBuffer.end() && (llvm::isAlnum(*curPtr) || *curPtr ==
'_'))
312 StringRef spelling(start, curPtr - start);
313 AIGERTokenKind kind = AIGERTokenKind::Identifier;
315 return makeToken(kind, start);
318AIGERToken AIGERLexer::nextToken() {
321 auto impl = [
this]() {
322 if (curPtr >= curBuffer.end())
323 return makeToken(AIGERTokenKind::EndOfFile, curPtr);
325 const char *start = curPtr;
330 return makeToken(AIGERTokenKind::Newline, start);
334 llvm_unreachable(
"Whitespace should have been skipped");
335 return makeToken(AIGERTokenKind::Error, start);
337 if (llvm::isDigit(c)) {
341 if (llvm::isAlpha(c) || c ==
'_') {
343 return lexIdentifier();
345 assert((c !=
'/' || *curPtr !=
'/') &&
"// should have been skipped");
346 return makeToken(AIGERTokenKind::Error, start);
354AIGERToken AIGERLexer::lexAsSymbol() {
356 const char *start = curPtr;
357 while (curPtr < curBuffer.end() &&
358 (llvm::isPrint(*curPtr) && !llvm::isSpace(*curPtr)))
360 return makeToken(AIGERTokenKind::Identifier, start);
363AIGERToken AIGERLexer::peekToken() {
364 const char *savedPtr = curPtr;
365 AIGERToken token = nextToken();
374ParseResult AIGERParser::parse() {
375 if (parseHeader() || parseInputs() || parseLatches() || parseOutputs() ||
376 parseAndGates() || parseSymbolTable() || parseComments())
379 return createModule();
382ParseResult AIGERParser::parseNumber(
unsigned &result, SMLoc *loc) {
383 auto token = lexer.nextToken();
385 *loc = token.location;
387 if (token.kind != AIGERTokenKind::Number)
388 return emitError(token.location,
"expected number");
390 if (token.spelling.getAsInteger(10, result))
391 return emitError(token.location,
"invalid number format");
396ParseResult AIGERParser::parseBinaryNumber(
unsigned &result) {
406 if (lexer.readByte(
byte))
407 return emitError(
"unexpected end of file in binary number");
409 LLVM_DEBUG(llvm::dbgs() <<
"Read byte: 0x" << llvm::utohexstr(
byte) <<
" ("
410 << (
unsigned)
byte <<
")\n");
412 result |= (
byte & 0x7F) << shift;
414 if ((
byte & 0x80) == 0) {
415 LLVM_DEBUG(llvm::dbgs() <<
"Decoded binary number: " << result <<
"\n");
421 return emitError(
"binary number too large");
427ParseResult AIGERParser::parseHeader() {
428 LLVM_DEBUG(llvm::dbgs() <<
"Parsing AIGER header\n");
431 while (lexer.peekToken().kind != AIGERTokenKind::Identifier)
434 auto formatToken = lexer.nextToken();
435 if (formatToken.spelling ==
"aag") {
436 isBinaryFormat =
false;
437 LLVM_DEBUG(llvm::dbgs() <<
"Format: aag (ASCII)\n");
438 }
else if (formatToken.spelling ==
"aig") {
439 isBinaryFormat =
true;
440 LLVM_DEBUG(llvm::dbgs() <<
"Format: aig (binary)\n");
442 return emitError(formatToken.location,
443 "expected 'aag' or 'aig' format identifier");
448 if (parseNumber(maxVarIndex, &loc))
449 return emitError(loc,
"failed to parse M (max variable index)");
451 if (parseNumber(numInputs, &loc))
452 return emitError(loc,
"failed to parse I (number of inputs)");
454 if (parseNumber(numLatches, &loc))
455 return emitError(loc,
"failed to parse L (number of latches)");
457 if (parseNumber(numOutputs, &loc))
458 return emitError(loc,
"failed to parse O (number of outputs)");
460 if (parseNumber(numAnds, &loc))
461 return emitError(loc,
"failed to parse A (number of AND gates)");
463 LLVM_DEBUG(llvm::dbgs() <<
"Header: M=" << maxVarIndex <<
" I=" << numInputs
464 <<
" L=" << numLatches <<
" O=" << numOutputs
465 <<
" A=" << numAnds <<
"\n");
468 return parseNewLine();
471ParseResult AIGERParser::parseNewLine() {
472 auto token = lexer.nextToken();
473 if (token.kind != AIGERTokenKind::Newline)
474 return emitError(token.location,
"expected newline");
479ParseResult AIGERParser::parseInputs() {
480 LLVM_DEBUG(llvm::dbgs() <<
"Parsing " << numInputs <<
" inputs\n");
481 if (isBinaryFormat) {
483 for (
unsigned i = 0; i < numInputs; ++i)
484 inputLiterals.push_back(2 * (i + 1));
488 for (
unsigned i = 0; i < numInputs; ++i) {
491 if (parseNumber(literal, &loc) || parseNewLine())
492 return emitError(loc,
"failed to parse input literal");
493 inputLiterals.push_back(literal);
499ParseResult AIGERParser::parseLatches() {
500 LLVM_DEBUG(llvm::dbgs() <<
"Parsing " << numLatches <<
" latches\n");
501 if (isBinaryFormat) {
503 for (
unsigned i = 0; i < numLatches; ++i) {
506 if (parseNumber(literal, &loc))
507 return emitError(loc,
"failed to parse latch next state literal");
509 latchDefs.push_back({2 * (i + 1 + numInputs), literal, loc});
519 for (
unsigned i = 0; i < numLatches; ++i) {
520 unsigned currentState, nextState;
522 if (parseNumber(currentState, &loc) || parseNumber(nextState) ||
524 return emitError(loc,
"failed to parse latch definition");
526 LLVM_DEBUG(llvm::dbgs() <<
"Latch " << i <<
": " << currentState <<
" -> "
527 << nextState <<
"\n");
530 if (currentState % 2 != 0 || currentState == 0)
531 return emitError(loc,
"invalid latch current state literal");
533 latchDefs.push_back({currentState, nextState, loc});
539ParseResult AIGERParser::parseOutputs() {
540 LLVM_DEBUG(llvm::dbgs() <<
"Parsing " << numOutputs <<
" outputs\n");
543 for (
unsigned i = 0; i < numOutputs; ++i) {
546 if (parseNumber(literal, &loc) || parseNewLine())
547 return emitError(loc,
"failed to parse output literal");
549 LLVM_DEBUG(llvm::dbgs() <<
"Output " << i <<
": " << literal <<
"\n");
552 outputLiterals.push_back({literal, loc});
558ParseResult AIGERParser::parseAndGates() {
559 LLVM_DEBUG(llvm::dbgs() <<
"Parsing " << numAnds <<
" AND gates\n");
561 if (isBinaryFormat) {
562 return parseAndGatesBinary();
564 return parseAndGatesASCII();
567ParseResult AIGERParser::parseAndGatesASCII() {
569 for (
unsigned i = 0; i < numAnds; ++i) {
570 unsigned lhs, rhs0, rhs1;
572 if (parseNumber(lhs, &loc) || parseNumber(rhs0) || parseNumber(rhs1) ||
574 return emitError(loc,
"failed to parse AND gate definition");
576 LLVM_DEBUG(llvm::dbgs() <<
"AND Gate " << i <<
": " << lhs <<
" = " << rhs0
577 <<
" & " << rhs1 <<
"\n");
580 if (lhs % 2 != 0 || lhs == 0)
581 return emitError(loc,
"invalid AND gate LHS literal");
584 if (lhs / 2 > maxVarIndex || rhs0 / 2 > maxVarIndex ||
585 rhs1 / 2 > maxVarIndex)
586 return emitError(loc,
"AND gate literal exceeds maximum variable index");
588 andGateDefs.push_back({lhs, rhs0, rhs1, loc});
594ParseResult AIGERParser::parseAndGatesBinary() {
599 LLVM_DEBUG(llvm::dbgs() <<
"Starting binary AND gate parsing\n");
607 auto currentLHS = 2 * (numInputs + numLatches + 1);
609 LLVM_DEBUG(llvm::dbgs() <<
"First AND gate LHS should be: " << currentLHS
612 for (
unsigned i = 0; i < numAnds; ++i) {
613 unsigned delta0, delta1;
614 SMLoc loc = lexer.getCurrentLoc();
615 if (parseBinaryNumber(delta0) || parseBinaryNumber(delta1))
616 return emitError(loc,
"failed to parse binary AND gate deltas");
618 auto lhs =
static_cast<int64_t
>(currentLHS);
621 if (delta0 > lhs || delta1 > (lhs - delta0)) {
622 LLVM_DEBUG(llvm::dbgs() <<
"Delta underflow: lhs=" << lhs <<
", delta0="
623 << delta0 <<
", delta1=" << delta1 <<
"\n");
624 return emitError(
"invalid binary AND gate: delta causes underflow");
627 auto rhs0 = lhs - delta0;
628 auto rhs1 = rhs0 - delta1;
630 LLVM_DEBUG(llvm::dbgs() <<
"Binary AND Gate " << i <<
": " << lhs <<
" = "
631 << rhs0 <<
" & " << rhs1 <<
" (deltas: " << delta0
632 <<
", " << delta1 <<
")\n");
634 if (lhs / 2 > maxVarIndex || rhs0 / 2 > maxVarIndex ||
635 rhs1 / 2 > maxVarIndex)
637 "binary AND gate literal exceeds maximum variable index");
639 assert(lhs > rhs0 && rhs0 >= rhs1 &&
640 "invalid binary AND gate: ordering constraint violated");
642 andGateDefs.push_back({
static_cast<unsigned>(lhs),
643 static_cast<unsigned>(rhs0),
644 static_cast<unsigned>(rhs1), loc});
651ParseResult AIGERParser::parseSymbolTable() {
654 while (!lexer.isAtEOF()) {
655 auto token = lexer.peekToken();
656 if (token.kind != AIGERTokenKind::Identifier)
658 (void)lexer.nextToken();
660 char symbolType = token.spelling.front();
661 if (symbolType !=
'i' && symbolType !=
'l' && symbolType !=
'o')
665 if (token.spelling.drop_front().getAsInteger(10, literal))
666 return emitError(
"failed to parse symbol position");
669 switch (symbolType) {
671 kind = SymbolKind::Input;
674 kind = SymbolKind::Latch;
677 kind = SymbolKind::Output;
681 auto nextToken = lexer.lexAsSymbol();
682 if (nextToken.kind != AIGERTokenKind::Identifier)
683 return emitError(
"expected symbol name");
685 LLVM_DEBUG(llvm::dbgs()
686 <<
"Symbol " << literal <<
": " << nextToken.spelling <<
"\n");
688 symbolTable[{kind, literal}] = StringAttr::get(context, nextToken.spelling);
696ParseResult AIGERParser::parseComments() {
698 auto token = lexer.peekToken();
699 if (token.kind == AIGERTokenKind::Identifier && token.spelling ==
"c") {
707Value AIGERParser::getLiteralValue(
unsigned literal,
708 DenseMap<unsigned, Backedge> &backedges,
710 LLVM_DEBUG(llvm::dbgs() <<
"Getting value for literal " << literal <<
"\n");
716 builder, loc, builder.getI1Type(),
717 builder.getIntegerAttr(builder.getI1Type(), 0));
723 builder, loc, builder.getI1Type(),
724 builder.getIntegerAttr(builder.getI1Type(), 1));
728 unsigned variable = literal / 2;
729 bool inverted = literal % 2;
730 unsigned baseLiteral = variable * 2;
732 LLVM_DEBUG(llvm::dbgs() <<
" Variable: " << variable
733 <<
", inverted: " << inverted
734 <<
", baseLiteral: " << baseLiteral <<
"\n");
737 if (variable > maxVarIndex) {
738 LLVM_DEBUG(llvm::dbgs() <<
" ERROR: Variable " << variable
739 <<
" exceeds maxVarIndex " << maxVarIndex <<
"\n");
744 auto backedgeIt = backedges.find(baseLiteral);
745 if (backedgeIt == backedges.end()) {
746 LLVM_DEBUG(llvm::dbgs() <<
" ERROR: No backedge found for literal "
747 << baseLiteral <<
"\n");
751 Value baseValue = backedgeIt->second;
753 LLVM_DEBUG(llvm::dbgs() <<
" ERROR: Backedge value is null for literal "
754 << baseLiteral <<
"\n");
761 SmallVector<bool> inverts = {
true};
762 return aig::AndInverterOp::create(builder, loc, builder.getI1Type(),
763 ValueRange{baseValue}, inverts);
769ParseResult AIGERParser::createModule() {
772 std::string moduleName = options.topLevelModule;
773 if (moduleName.empty())
774 moduleName =
"aiger_top";
777 builder.setInsertionPointToStart(module.getBody());
780 SmallVector<hw::PortInfo> ports;
783 for (
unsigned i = 0; i < numInputs; ++i) {
785 auto name = symbolTable.lookup({SymbolKind::Input, i});
787 name ? name : builder.getStringAttr(
"input_" + std::to_string(i));
788 port.
type = builder.getI1Type();
789 port.
dir = hw::ModulePort::Direction::Input;
791 ports.push_back(port);
795 for (
unsigned i = 0; i < numOutputs; ++i) {
797 auto name = symbolTable.lookup({SymbolKind::Output, i});
799 name ? name : builder.getStringAttr(
"output_" + std::to_string(i));
800 port.
type = builder.getI1Type();
801 port.
dir = hw::ModulePort::Direction::Output;
802 port.
argNum = numInputs + i;
803 ports.push_back(port);
807 if (numLatches > 0) {
809 clockPort.
name = builder.getStringAttr(
"clock");
810 clockPort.
type = seq::ClockType::get(builder.getContext());
811 clockPort.
dir = hw::ModulePort::Direction::Input;
812 clockPort.
argNum = numInputs + numOutputs;
813 ports.push_back(clockPort);
818 hw::HWModuleOp::create(builder, builder.getUnknownLoc(),
819 builder.getStringAttr(moduleName), ports);
822 builder.setInsertionPointToStart(hwModule.getBodyBlock());
827 clockValue = hwModule.getBodyBlock()->getArgument(numInputs);
831 DenseMap<unsigned, Backedge> backedges;
834 for (
unsigned i = 0; i < numInputs; ++i) {
835 auto literal = inputLiterals[i];
836 backedges[literal] = bb.get(builder.getI1Type());
838 for (
auto [currentState, nextState, _] : latchDefs)
839 backedges[currentState] = bb.
get(builder.getI1Type());
841 for (
auto [lhs, rhs0, rhs1, loc] : andGateDefs)
842 backedges[lhs] = bb.
get(builder.getI1Type());
845 for (
unsigned i = 0; i < numInputs; ++i) {
846 auto inputValue = hwModule.getBodyBlock()->getArgument(i);
847 auto literal = inputLiterals[i];
848 backedges[literal].setValue(inputValue);
852 for (
auto [i, latchDef] :
llvm::enumerate(latchDefs)) {
853 auto [currentState, nextState, loc] = latchDef;
855 auto nextBackedge = bb.get(builder.getI1Type());
859 builder, lexer.translateLocation(loc), (Value)nextBackedge, clockValue);
860 if (
auto name = symbolTable.lookup({SymbolKind::Latch, i}))
861 regValue.setNameAttr(name);
864 backedges[currentState].setValue(regValue);
868 for (
auto [lhs, rhs0, rhs1, loc] : andGateDefs) {
870 auto location = lexer.translateLocation(loc);
871 auto rhs0Value = getLiteralValue(rhs0 & ~1u, backedges, location);
872 auto rhs1Value = getLiteralValue(rhs1 & ~1u, backedges, location);
874 if (!rhs0Value || !rhs1Value)
875 return emitError(loc,
"failed to get operand values for AND gate");
878 SmallVector<bool> inverts = {
static_cast<bool>(rhs0 % 2),
879 static_cast<bool>(rhs1 % 2)};
883 aig::AndInverterOp::create(builder, location, builder.getI1Type(),
884 ValueRange{rhs0Value, rhs1Value}, inverts);
887 backedges[lhs].setValue(andResult);
893 for (
auto [currentState, nextState, sourceLoc] : latchDefs) {
894 auto loc = lexer.translateLocation(sourceLoc);
895 auto nextValue = getLiteralValue(nextState, backedges, loc);
897 return emitError(sourceLoc,
"undefined literal in latch next state");
900 Value currentValue = backedges[currentState];
902 regOp.getInputMutable().assign(nextValue);
904 return emitError(sourceLoc,
"failed to find register for latch");
908 SmallVector<Value> outputValues;
909 for (
auto [literal, sourceLoc] : outputLiterals) {
910 auto loc = lexer.translateLocation(sourceLoc);
911 auto outputValue = getLiteralValue(literal, backedges, loc);
913 return emitError(sourceLoc,
"undefined literal in output");
914 outputValues.push_back(outputValue);
918 auto *outputOp = hwModule.getBodyBlock()->getTerminator();
919 outputOp->setOperands(outputValues);
929 MLIRContext *context,
930 mlir::TimingScope &ts, ModuleOp module,
933 context->loadDialect<hw::HWDialect>();
934 context->loadDialect<synth::SynthDialect>();
935 context->loadDialect<seq::SeqDialect>();
940 options = &defaultOptions;
943 AIGERParser parser(sourceMgr, context, module, *options);
944 return parser.parse();
952 static mlir::TranslateToMLIRRegistration fromAIGER(
953 "import-aiger",
"import AIGER file",
954 [](llvm::SourceMgr &sourceMgr, MLIRContext *context) {
955 mlir::TimingScope ts;
957 ModuleOp::create(UnknownLoc::get(context)));
959 if (failed(
importAIGER(sourceMgr, context, ts, module.get(), &options)))
assert(baseType &&"element must be base type")
static StringAttr getMainBufferNameIdentifier(const llvm::SourceMgr &sourceMgr, MLIRContext *context)
Instantiate one of these and use it to build typed backedges.
create(cls, result_type, reset=None, reset_value=None, name=None, sym_name=None, **kwargs)
mlir::LogicalResult importAIGER(llvm::SourceMgr &sourceMgr, mlir::MLIRContext *context, mlir::TimingScope &ts, mlir::ModuleOp module, const ImportAIGEROptions *options=nullptr)
Parse an AIGER file and populate the given MLIR module with corresponding AIG dialect operations.
void registerImportAIGERTranslation()
Register the import-aiger MLIR translation.
Direction get(bool isOutput)
Returns an output direction if isOutput is true, otherwise returns an input direction.
The InstanceGraph op interface, see InstanceGraphInterface.td for more details.
Options for AIGER import.
This holds the name, type, direction of a module's ports.
size_t argNum
This is the argument index or the result index depending on the direction.