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 expectToken(AIGERTokenKind kind,
const Twine &message);
262 ParseResult parseNumber(
unsigned &result, SMLoc *loc =
nullptr);
265 ParseResult parseBinaryNumber(
unsigned &result);
268 ParseResult parseNewLine();
277void AIGERLexer::skipWhitespace() {
278 while (curPtr < curBuffer.end()) {
280 if (*curPtr ==
' ' || *curPtr ==
'\t' || *curPtr ==
'\r') {
287 if (*curPtr ==
'/' &&
288 (curPtr + 1 < curBuffer.end() && *(curPtr + 1) ==
'/')) {
296void AIGERLexer::skipUntilNewline() {
297 while (curPtr < curBuffer.end() && *curPtr !=
'\n')
299 if (curPtr < curBuffer.end() && *curPtr ==
'\n')
303AIGERToken AIGERLexer::lexNumber() {
304 const char *start = curPtr;
305 while (curPtr < curBuffer.end() && llvm::isDigit(*curPtr))
307 return makeToken(AIGERTokenKind::Number, start);
310AIGERToken AIGERLexer::lexIdentifier() {
311 const char *start = curPtr;
312 while (curPtr < curBuffer.end() && (llvm::isAlnum(*curPtr) || *curPtr ==
'_'))
315 StringRef spelling(start, curPtr - start);
316 AIGERTokenKind kind = AIGERTokenKind::Identifier;
318 return makeToken(kind, start);
321AIGERToken AIGERLexer::nextToken() {
324 auto impl = [
this]() {
325 if (curPtr >= curBuffer.end())
326 return makeToken(AIGERTokenKind::EndOfFile, curPtr);
328 const char *start = curPtr;
333 return makeToken(AIGERTokenKind::Newline, start);
337 llvm_unreachable(
"Whitespace should have been skipped");
338 return makeToken(AIGERTokenKind::Error, start);
340 if (llvm::isDigit(c)) {
344 if (llvm::isAlpha(c) || c ==
'_') {
346 return lexIdentifier();
348 assert((c !=
'/' || *curPtr !=
'/') &&
"// should have been skipped");
349 return makeToken(AIGERTokenKind::Error, start);
357AIGERToken AIGERLexer::lexAsSymbol() {
359 const char *start = curPtr;
360 while (curPtr < curBuffer.end() &&
361 (llvm::isPrint(*curPtr) && !llvm::isSpace(*curPtr)))
363 return makeToken(AIGERTokenKind::Identifier, start);
366AIGERToken AIGERLexer::peekToken() {
367 const char *savedPtr = curPtr;
368 AIGERToken token = nextToken();
377ParseResult AIGERParser::parse() {
378 if (parseHeader() || parseInputs() || parseLatches() || parseOutputs() ||
379 parseAndGates() || parseSymbolTable() || parseComments())
382 return createModule();
385ParseResult AIGERParser::expectToken(AIGERTokenKind kind,
386 const Twine &message) {
387 AIGERToken token = lexer.nextToken();
388 if (token.kind != kind)
389 return emitError(message);
393ParseResult AIGERParser::parseNumber(
unsigned &result, SMLoc *loc) {
394 auto token = lexer.nextToken();
396 *loc = token.location;
398 if (token.kind != AIGERTokenKind::Number)
399 return emitError(token.location,
"expected number");
401 if (token.spelling.getAsInteger(10, result))
402 return emitError(token.location,
"invalid number format");
407ParseResult AIGERParser::parseBinaryNumber(
unsigned &result) {
417 if (lexer.readByte(
byte))
418 return emitError(
"unexpected end of file in binary number");
420 LLVM_DEBUG(llvm::dbgs() <<
"Read byte: 0x" << llvm::utohexstr(
byte) <<
" ("
421 << (
unsigned)
byte <<
")\n");
423 result |= (
byte & 0x7F) << shift;
425 if ((
byte & 0x80) == 0) {
426 LLVM_DEBUG(llvm::dbgs() <<
"Decoded binary number: " << result <<
"\n");
432 return emitError(
"binary number too large");
438ParseResult AIGERParser::parseHeader() {
439 LLVM_DEBUG(llvm::dbgs() <<
"Parsing AIGER header\n");
442 while (lexer.peekToken().kind != AIGERTokenKind::Identifier)
445 auto formatToken = lexer.nextToken();
446 if (formatToken.spelling ==
"aag") {
447 isBinaryFormat =
false;
448 LLVM_DEBUG(llvm::dbgs() <<
"Format: aag (ASCII)\n");
449 }
else if (formatToken.spelling ==
"aig") {
450 isBinaryFormat =
true;
451 LLVM_DEBUG(llvm::dbgs() <<
"Format: aig (binary)\n");
453 return emitError(formatToken.location,
454 "expected 'aag' or 'aig' format identifier");
459 if (parseNumber(maxVarIndex, &loc))
460 return emitError(loc,
"failed to parse M (max variable index)");
462 if (parseNumber(numInputs, &loc))
463 return emitError(loc,
"failed to parse I (number of inputs)");
465 if (parseNumber(numLatches, &loc))
466 return emitError(loc,
"failed to parse L (number of latches)");
468 if (parseNumber(numOutputs, &loc))
469 return emitError(loc,
"failed to parse O (number of outputs)");
471 if (parseNumber(numAnds, &loc))
472 return emitError(loc,
"failed to parse A (number of AND gates)");
474 LLVM_DEBUG(llvm::dbgs() <<
"Header: M=" << maxVarIndex <<
" I=" << numInputs
475 <<
" L=" << numLatches <<
" O=" << numOutputs
476 <<
" A=" << numAnds <<
"\n");
479 return parseNewLine();
482ParseResult AIGERParser::parseNewLine() {
483 auto token = lexer.nextToken();
484 if (token.kind != AIGERTokenKind::Newline)
485 return emitError(token.location,
"expected newline");
490ParseResult AIGERParser::parseInputs() {
491 LLVM_DEBUG(llvm::dbgs() <<
"Parsing " << numInputs <<
" inputs\n");
492 if (isBinaryFormat) {
494 for (
unsigned i = 0; i < numInputs; ++i)
495 inputLiterals.push_back(2 * (i + 1));
499 for (
unsigned i = 0; i < numInputs; ++i) {
502 if (parseNumber(literal, &loc) || parseNewLine())
503 return emitError(loc,
"failed to parse input literal");
504 inputLiterals.push_back(literal);
510ParseResult AIGERParser::parseLatches() {
511 LLVM_DEBUG(llvm::dbgs() <<
"Parsing " << numLatches <<
" latches\n");
512 if (isBinaryFormat) {
514 for (
unsigned i = 0; i < numLatches; ++i) {
517 if (parseNumber(literal, &loc))
518 return emitError(loc,
"failed to parse latch next state literal");
520 latchDefs.push_back({2 * (i + 1 + numInputs), literal, loc});
530 for (
unsigned i = 0; i < numLatches; ++i) {
531 unsigned currentState, nextState;
533 if (parseNumber(currentState, &loc) || parseNumber(nextState) ||
535 return emitError(loc,
"failed to parse latch definition");
537 LLVM_DEBUG(llvm::dbgs() <<
"Latch " << i <<
": " << currentState <<
" -> "
538 << nextState <<
"\n");
541 if (currentState % 2 != 0 || currentState == 0)
542 return emitError(loc,
"invalid latch current state literal");
544 latchDefs.push_back({currentState, nextState, loc});
550ParseResult AIGERParser::parseOutputs() {
551 LLVM_DEBUG(llvm::dbgs() <<
"Parsing " << numOutputs <<
" outputs\n");
554 for (
unsigned i = 0; i < numOutputs; ++i) {
557 if (parseNumber(literal, &loc) || parseNewLine())
558 return emitError(loc,
"failed to parse output literal");
560 LLVM_DEBUG(llvm::dbgs() <<
"Output " << i <<
": " << literal <<
"\n");
563 outputLiterals.push_back({literal, loc});
569ParseResult AIGERParser::parseAndGates() {
570 LLVM_DEBUG(llvm::dbgs() <<
"Parsing " << numAnds <<
" AND gates\n");
572 if (isBinaryFormat) {
573 return parseAndGatesBinary();
575 return parseAndGatesASCII();
578ParseResult AIGERParser::parseAndGatesASCII() {
580 for (
unsigned i = 0; i < numAnds; ++i) {
581 unsigned lhs, rhs0, rhs1;
583 if (parseNumber(lhs, &loc) || parseNumber(rhs0) || parseNumber(rhs1) ||
585 return emitError(loc,
"failed to parse AND gate definition");
587 LLVM_DEBUG(llvm::dbgs() <<
"AND Gate " << i <<
": " << lhs <<
" = " << rhs0
588 <<
" & " << rhs1 <<
"\n");
591 if (lhs % 2 != 0 || lhs == 0)
592 return emitError(loc,
"invalid AND gate LHS literal");
595 if (lhs / 2 > maxVarIndex || rhs0 / 2 > maxVarIndex ||
596 rhs1 / 2 > maxVarIndex)
597 return emitError(loc,
"AND gate literal exceeds maximum variable index");
599 andGateDefs.push_back({lhs, rhs0, rhs1, loc});
605ParseResult AIGERParser::parseAndGatesBinary() {
610 LLVM_DEBUG(llvm::dbgs() <<
"Starting binary AND gate parsing\n");
618 auto currentLHS = 2 * (numInputs + numLatches + 1);
620 LLVM_DEBUG(llvm::dbgs() <<
"First AND gate LHS should be: " << currentLHS
623 for (
unsigned i = 0; i < numAnds; ++i) {
624 unsigned delta0, delta1;
625 SMLoc loc = lexer.getCurrentLoc();
626 if (parseBinaryNumber(delta0) || parseBinaryNumber(delta1))
627 return emitError(loc,
"failed to parse binary AND gate deltas");
629 auto lhs =
static_cast<int64_t
>(currentLHS);
632 if (delta0 > lhs || delta1 > (lhs - delta0)) {
633 LLVM_DEBUG(llvm::dbgs() <<
"Delta underflow: lhs=" << lhs <<
", delta0="
634 << delta0 <<
", delta1=" << delta1 <<
"\n");
635 return emitError(
"invalid binary AND gate: delta causes underflow");
638 auto rhs0 = lhs - delta0;
639 auto rhs1 = rhs0 - delta1;
641 LLVM_DEBUG(llvm::dbgs() <<
"Binary AND Gate " << i <<
": " << lhs <<
" = "
642 << rhs0 <<
" & " << rhs1 <<
" (deltas: " << delta0
643 <<
", " << delta1 <<
")\n");
645 if (lhs / 2 > maxVarIndex || rhs0 / 2 > maxVarIndex ||
646 rhs1 / 2 > maxVarIndex)
648 "binary AND gate literal exceeds maximum variable index");
650 assert(lhs > rhs0 && rhs0 >= rhs1 &&
651 "invalid binary AND gate: ordering constraint violated");
653 andGateDefs.push_back({
static_cast<unsigned>(lhs),
654 static_cast<unsigned>(rhs0),
655 static_cast<unsigned>(rhs1), loc});
662ParseResult AIGERParser::parseSymbolTable() {
665 while (!lexer.isAtEOF()) {
666 auto token = lexer.peekToken();
667 if (token.kind != AIGERTokenKind::Identifier)
669 (void)lexer.nextToken();
671 char symbolType = token.spelling.front();
672 if (symbolType !=
'i' && symbolType !=
'l' && symbolType !=
'o')
676 if (token.spelling.drop_front().getAsInteger(10, literal))
677 return emitError(
"failed to parse symbol position");
680 switch (symbolType) {
682 kind = SymbolKind::Input;
685 kind = SymbolKind::Latch;
688 kind = SymbolKind::Output;
692 auto nextToken = lexer.lexAsSymbol();
693 if (nextToken.kind != AIGERTokenKind::Identifier)
694 return emitError(
"expected symbol name");
696 LLVM_DEBUG(llvm::dbgs()
697 <<
"Symbol " << literal <<
": " << nextToken.spelling <<
"\n");
699 symbolTable[{kind, literal}] = StringAttr::get(context, nextToken.spelling);
707ParseResult AIGERParser::parseComments() {
709 auto token = lexer.peekToken();
710 if (token.kind == AIGERTokenKind::Identifier && token.spelling ==
"c") {
718Value AIGERParser::getLiteralValue(
unsigned literal,
719 DenseMap<unsigned, Backedge> &backedges,
721 LLVM_DEBUG(llvm::dbgs() <<
"Getting value for literal " << literal <<
"\n");
727 loc, builder.getI1Type(),
728 builder.getIntegerAttr(builder.getI1Type(), 0));
734 loc, builder.getI1Type(),
735 builder.getIntegerAttr(builder.getI1Type(), 1));
739 unsigned variable = literal / 2;
740 bool inverted = literal % 2;
741 unsigned baseLiteral = variable * 2;
743 LLVM_DEBUG(llvm::dbgs() <<
" Variable: " << variable
744 <<
", inverted: " << inverted
745 <<
", baseLiteral: " << baseLiteral <<
"\n");
748 if (variable > maxVarIndex) {
749 LLVM_DEBUG(llvm::dbgs() <<
" ERROR: Variable " << variable
750 <<
" exceeds maxVarIndex " << maxVarIndex <<
"\n");
755 auto backedgeIt = backedges.find(baseLiteral);
756 if (backedgeIt == backedges.end()) {
757 LLVM_DEBUG(llvm::dbgs() <<
" ERROR: No backedge found for literal "
758 << baseLiteral <<
"\n");
762 Value baseValue = backedgeIt->second;
764 LLVM_DEBUG(llvm::dbgs() <<
" ERROR: Backedge value is null for literal "
765 << baseLiteral <<
"\n");
772 SmallVector<bool> inverts = {
true};
773 return builder.create<aig::AndInverterOp>(loc, builder.getI1Type(),
774 ValueRange{baseValue}, inverts);
780ParseResult AIGERParser::createModule() {
783 std::string moduleName = options.topLevelModule;
784 if (moduleName.empty())
785 moduleName =
"aiger_top";
788 builder.setInsertionPointToStart(module.getBody());
791 SmallVector<hw::PortInfo> ports;
794 for (
unsigned i = 0; i < numInputs; ++i) {
796 auto name = symbolTable.lookup({SymbolKind::Input, i});
798 name ? name : builder.getStringAttr(
"input_" + std::to_string(i));
799 port.
type = builder.getI1Type();
800 port.
dir = hw::ModulePort::Direction::Input;
802 ports.push_back(port);
806 for (
unsigned i = 0; i < numOutputs; ++i) {
808 auto name = symbolTable.lookup({SymbolKind::Output, i});
810 name ? name : builder.getStringAttr(
"output_" + std::to_string(i));
811 port.
type = builder.getI1Type();
812 port.
dir = hw::ModulePort::Direction::Output;
813 port.
argNum = numInputs + i;
814 ports.push_back(port);
818 if (numLatches > 0) {
820 clockPort.
name = builder.getStringAttr(
"clock");
821 clockPort.
type = seq::ClockType::get(builder.getContext());
822 clockPort.
dir = hw::ModulePort::Direction::Input;
823 clockPort.
argNum = numInputs + numOutputs;
824 ports.push_back(clockPort);
829 builder.getUnknownLoc(), builder.getStringAttr(moduleName), ports);
832 builder.setInsertionPointToStart(hwModule.getBodyBlock());
837 clockValue = hwModule.getBodyBlock()->getArgument(numInputs);
841 DenseMap<unsigned, Backedge> backedges;
844 for (
unsigned i = 0; i < numInputs; ++i) {
845 auto literal = inputLiterals[i];
846 backedges[literal] = bb.get(builder.getI1Type());
848 for (
auto [currentState, nextState, _] : latchDefs)
849 backedges[currentState] = bb.
get(builder.getI1Type());
851 for (
auto [lhs, rhs0, rhs1, loc] : andGateDefs)
852 backedges[lhs] = bb.
get(builder.getI1Type());
855 for (
unsigned i = 0; i < numInputs; ++i) {
856 auto inputValue = hwModule.getBodyBlock()->getArgument(i);
857 auto literal = inputLiterals[i];
858 backedges[literal].setValue(inputValue);
862 for (
auto [i, latchDef] :
llvm::enumerate(latchDefs)) {
863 auto [currentState, nextState, loc] = latchDef;
865 auto nextBackedge = bb.get(builder.getI1Type());
869 lexer.translateLocation(loc), (Value)nextBackedge, clockValue);
870 if (
auto name = symbolTable.lookup({SymbolKind::Latch, i}))
871 regValue.setNameAttr(name);
874 backedges[currentState].setValue(regValue);
878 for (
auto [lhs, rhs0, rhs1, loc] : andGateDefs) {
880 auto location = lexer.translateLocation(loc);
881 auto rhs0Value = getLiteralValue(rhs0 & ~1u, backedges, location);
882 auto rhs1Value = getLiteralValue(rhs1 & ~1u, backedges, location);
884 if (!rhs0Value || !rhs1Value)
885 return emitError(loc,
"failed to get operand values for AND gate");
888 SmallVector<bool> inverts = {
static_cast<bool>(rhs0 % 2),
889 static_cast<bool>(rhs1 % 2)};
892 auto andResult = builder.create<aig::AndInverterOp>(
893 location, builder.getI1Type(), ValueRange{rhs0Value, rhs1Value},
897 backedges[lhs].setValue(andResult);
903 for (
auto [currentState, nextState, sourceLoc] : latchDefs) {
904 auto loc = lexer.translateLocation(sourceLoc);
905 auto nextValue = getLiteralValue(nextState, backedges, loc);
907 return emitError(sourceLoc,
"undefined literal in latch next state");
910 Value currentValue = backedges[currentState];
912 regOp.getInputMutable().assign(nextValue);
914 return emitError(sourceLoc,
"failed to find register for latch");
918 SmallVector<Value> outputValues;
919 for (
auto [literal, sourceLoc] : outputLiterals) {
920 auto loc = lexer.translateLocation(sourceLoc);
921 auto outputValue = getLiteralValue(literal, backedges, loc);
923 return emitError(sourceLoc,
"undefined literal in output");
924 outputValues.push_back(outputValue);
928 auto *outputOp = hwModule.getBodyBlock()->getTerminator();
929 outputOp->setOperands(outputValues);
939 MLIRContext *context,
940 mlir::TimingScope &ts, ModuleOp module,
943 context->loadDialect<hw::HWDialect>();
944 context->loadDialect<aig::AIGDialect>();
945 context->loadDialect<seq::SeqDialect>();
950 options = &defaultOptions;
953 AIGERParser parser(sourceMgr, context, module, *options);
954 return parser.parse();
962 static mlir::TranslateToMLIRRegistration fromAIGER(
963 "import-aiger",
"import AIGER file",
964 [](llvm::SourceMgr &sourceMgr, MLIRContext *context) {
965 mlir::TimingScope ts;
967 ModuleOp::create(UnknownLoc::get(context)));
969 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.
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.