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/LEB128.h"
33#include "llvm/Support/SMLoc.h"
34#include "llvm/Support/SourceMgr.h"
35#include "llvm/Support/raw_ostream.h"
47#define DEBUG_TYPE "import-aiger"
52enum class AIGERTokenKind {
71 AIGERToken(AIGERTokenKind kind, StringRef spelling, SMLoc location)
72 : kind(kind), spelling(spelling), location(location) {}
82 AIGERLexer(
const llvm::SourceMgr &sourceMgr, MLIRContext *
context)
83 : sourceMgr(sourceMgr),
86 sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID())->getBuffer()),
87 curPtr(curBuffer.begin()) {}
90 AIGERToken nextToken();
93 AIGERToken lexAsSymbol();
96 AIGERToken peekToken();
99 bool isAtEOF()
const {
return curPtr >= curBuffer.end(); }
102 ParseResult readLEB128(
unsigned &result);
105 SMLoc getCurrentLoc()
const {
return SMLoc::getFromPointer(curPtr); }
109 Location translateLocation(llvm::SMLoc loc) {
111 unsigned mainFileID = sourceMgr.getMainFileID();
112 auto lineAndColumn = sourceMgr.getLineAndColumn(loc, mainFileID);
113 return FileLineColLoc::get(bufferNameIdentifier, lineAndColumn.first,
114 lineAndColumn.second);
118 AIGERToken emitError(
const char *loc,
const Twine &message) {
119 mlir::emitError(translateLocation(SMLoc::getFromPointer(loc)), message);
120 return AIGERToken(AIGERTokenKind::Error, StringRef(loc, 1),
121 SMLoc::getFromPointer(loc));
125 const llvm::SourceMgr &sourceMgr;
126 StringAttr bufferNameIdentifier;
134 auto mainBuffer = sourceMgr.getMemoryBuffer(sourceMgr.getMainFileID());
135 StringRef bufferName = mainBuffer->getBufferIdentifier();
136 if (bufferName.empty())
137 bufferName =
"<unknown>";
138 return StringAttr::get(
context, bufferName);
142 void skipWhitespace();
145 void skipUntilNewline();
148 AIGERToken lexNumber();
151 AIGERToken lexIdentifier();
154 AIGERToken makeToken(AIGERTokenKind kind,
const char *start) {
155 return AIGERToken(kind, StringRef(start, curPtr - start),
156 SMLoc::getFromPointer(start));
171 AIGERParser(
const llvm::SourceMgr &sourceMgr, MLIRContext *context,
173 : lexer(sourceMgr, context), context(context), module(module),
174 options(options), builder(context) {}
181 MLIRContext *context;
187 unsigned maxVarIndex = 0;
188 unsigned numInputs = 0;
189 unsigned numLatches = 0;
190 unsigned numOutputs = 0;
191 unsigned numAnds = 0;
192 bool isBinaryFormat =
false;
196 enum SymbolKind :
unsigned {
Input, Latch,
Output };
197 DenseMap<std::pair<SymbolKind, unsigned>, StringAttr> symbolTable;
200 SmallVector<unsigned> inputLiterals;
201 SmallVector<std::tuple<unsigned, unsigned, SMLoc>>
203 SmallVector<std::pair<unsigned, SMLoc>> outputLiterals;
204 SmallVector<std::tuple<unsigned, unsigned, unsigned, SMLoc>>
208 ParseResult parseHeader();
211 ParseResult parseInputs();
214 ParseResult parseLatches();
217 ParseResult parseOutputs();
220 ParseResult parseAndGates();
223 ParseResult parseAndGatesASCII();
226 ParseResult parseAndGatesBinary();
229 ParseResult parseSymbolTable();
232 ParseResult parseComments();
240 Value getLiteralValue(
unsigned literal,
241 DenseMap<unsigned, Backedge> &backedges, Location loc);
244 ParseResult createModule();
246 InFlightDiagnostic emitError(llvm::SMLoc loc,
const Twine &message) {
247 return mlir::emitError(lexer.translateLocation(loc), message);
251 InFlightDiagnostic emitError(
const Twine &message) {
252 return emitError(lexer.getCurrentLoc(), message);
256 ParseResult parseNumber(
unsigned &result, SMLoc *loc =
nullptr);
259 ParseResult parseBinaryNumber(
unsigned &result);
262 ParseResult parseNewLine();
271void AIGERLexer::skipWhitespace() {
272 while (curPtr < curBuffer.end()) {
274 if (*curPtr ==
' ' || *curPtr ==
'\t' || *curPtr ==
'\r') {
281 if (*curPtr ==
'/' &&
282 (curPtr + 1 < curBuffer.end() && *(curPtr + 1) ==
'/')) {
290void AIGERLexer::skipUntilNewline() {
291 while (curPtr < curBuffer.end() && *curPtr !=
'\n')
293 if (curPtr < curBuffer.end() && *curPtr ==
'\n')
297AIGERToken AIGERLexer::lexNumber() {
298 const char *start = curPtr;
299 while (curPtr < curBuffer.end() && llvm::isDigit(*curPtr))
301 return makeToken(AIGERTokenKind::Number, start);
304AIGERToken AIGERLexer::lexIdentifier() {
305 const char *start = curPtr;
306 while (curPtr < curBuffer.end() && (llvm::isAlnum(*curPtr) || *curPtr ==
'_'))
309 StringRef spelling(start, curPtr - start);
310 AIGERTokenKind kind = AIGERTokenKind::Identifier;
312 return makeToken(kind, start);
315AIGERToken AIGERLexer::nextToken() {
318 auto impl = [
this]() {
319 if (curPtr >= curBuffer.end())
320 return makeToken(AIGERTokenKind::EndOfFile, curPtr);
322 const char *start = curPtr;
327 return makeToken(AIGERTokenKind::Newline, start);
331 llvm_unreachable(
"Whitespace should have been skipped");
332 return makeToken(AIGERTokenKind::Error, start);
334 if (llvm::isDigit(c)) {
338 if (llvm::isAlpha(c) || c ==
'_') {
340 return lexIdentifier();
342 assert((c !=
'/' || *curPtr !=
'/') &&
"// should have been skipped");
343 return makeToken(AIGERTokenKind::Error, start);
351AIGERToken AIGERLexer::lexAsSymbol() {
353 const char *start = curPtr;
354 while (curPtr < curBuffer.end() &&
355 (llvm::isPrint(*curPtr) && !llvm::isSpace(*curPtr)))
357 return makeToken(AIGERTokenKind::Identifier, start);
360AIGERToken AIGERLexer::peekToken() {
361 const char *savedPtr = curPtr;
362 AIGERToken token = nextToken();
367ParseResult AIGERLexer::readLEB128(
unsigned &result) {
370 llvm::decodeULEB128(
reinterpret_cast<const uint8_t *
>(curPtr), &len,
371 reinterpret_cast<const uint8_t *
>(curBuffer.end()));
372 if (len == 0 || value > std::numeric_limits<unsigned>::max())
375 result =
static_cast<unsigned>(value);
383ParseResult AIGERParser::parse() {
384 if (parseHeader() || parseInputs() || parseLatches() || parseOutputs() ||
385 parseAndGates() || parseSymbolTable() || parseComments())
388 return createModule();
391ParseResult AIGERParser::parseNumber(
unsigned &result, SMLoc *loc) {
392 auto token = lexer.nextToken();
394 *loc = token.location;
396 if (token.kind != AIGERTokenKind::Number)
397 return emitError(token.location,
"expected number");
399 if (token.spelling.getAsInteger(10, result))
400 return emitError(token.location,
"invalid number format");
405ParseResult AIGERParser::parseBinaryNumber(
unsigned &result) {
406 return lexer.readLEB128(result);
409ParseResult AIGERParser::parseHeader() {
410 LLVM_DEBUG(llvm::dbgs() <<
"Parsing AIGER header\n");
413 while (lexer.peekToken().kind != AIGERTokenKind::Identifier)
416 auto formatToken = lexer.nextToken();
417 if (formatToken.spelling ==
"aag") {
418 isBinaryFormat =
false;
419 LLVM_DEBUG(llvm::dbgs() <<
"Format: aag (ASCII)\n");
420 }
else if (formatToken.spelling ==
"aig") {
421 isBinaryFormat =
true;
422 LLVM_DEBUG(llvm::dbgs() <<
"Format: aig (binary)\n");
424 return emitError(formatToken.location,
425 "expected 'aag' or 'aig' format identifier");
430 if (parseNumber(maxVarIndex, &loc))
431 return emitError(loc,
"failed to parse M (max variable index)");
433 if (parseNumber(numInputs, &loc))
434 return emitError(loc,
"failed to parse I (number of inputs)");
436 if (parseNumber(numLatches, &loc))
437 return emitError(loc,
"failed to parse L (number of latches)");
439 if (parseNumber(numOutputs, &loc))
440 return emitError(loc,
"failed to parse O (number of outputs)");
442 if (parseNumber(numAnds, &loc))
443 return emitError(loc,
"failed to parse A (number of AND gates)");
445 LLVM_DEBUG(llvm::dbgs() <<
"Header: M=" << maxVarIndex <<
" I=" << numInputs
446 <<
" L=" << numLatches <<
" O=" << numOutputs
447 <<
" A=" << numAnds <<
"\n");
450 return parseNewLine();
453ParseResult AIGERParser::parseNewLine() {
454 auto token = lexer.nextToken();
455 if (token.kind != AIGERTokenKind::Newline)
456 return emitError(token.location,
"expected newline");
461ParseResult AIGERParser::parseInputs() {
462 LLVM_DEBUG(llvm::dbgs() <<
"Parsing " << numInputs <<
" inputs\n");
463 if (isBinaryFormat) {
465 for (
unsigned i = 0; i < numInputs; ++i)
466 inputLiterals.push_back(2 * (i + 1));
470 for (
unsigned i = 0; i < numInputs; ++i) {
473 if (parseNumber(literal, &loc) || parseNewLine())
474 return emitError(loc,
"failed to parse input literal");
475 inputLiterals.push_back(literal);
481ParseResult AIGERParser::parseLatches() {
482 LLVM_DEBUG(llvm::dbgs() <<
"Parsing " << numLatches <<
" latches\n");
483 if (isBinaryFormat) {
485 for (
unsigned i = 0; i < numLatches; ++i) {
488 if (parseNumber(literal, &loc))
489 return emitError(loc,
"failed to parse latch next state literal");
491 latchDefs.push_back({2 * (i + 1 + numInputs), literal, loc});
501 for (
unsigned i = 0; i < numLatches; ++i) {
502 unsigned currentState, nextState;
504 if (parseNumber(currentState, &loc) || parseNumber(nextState) ||
506 return emitError(loc,
"failed to parse latch definition");
508 LLVM_DEBUG(llvm::dbgs() <<
"Latch " << i <<
": " << currentState <<
" -> "
509 << nextState <<
"\n");
512 if (currentState % 2 != 0 || currentState == 0)
513 return emitError(loc,
"invalid latch current state literal");
515 latchDefs.push_back({currentState, nextState, loc});
521ParseResult AIGERParser::parseOutputs() {
522 LLVM_DEBUG(llvm::dbgs() <<
"Parsing " << numOutputs <<
" outputs\n");
525 for (
unsigned i = 0; i < numOutputs; ++i) {
528 if (parseNumber(literal, &loc) || parseNewLine())
529 return emitError(loc,
"failed to parse output literal");
531 LLVM_DEBUG(llvm::dbgs() <<
"Output " << i <<
": " << literal <<
"\n");
534 outputLiterals.push_back({literal, loc});
540ParseResult AIGERParser::parseAndGates() {
541 LLVM_DEBUG(llvm::dbgs() <<
"Parsing " << numAnds <<
" AND gates\n");
543 if (isBinaryFormat) {
544 return parseAndGatesBinary();
546 return parseAndGatesASCII();
549ParseResult AIGERParser::parseAndGatesASCII() {
551 for (
unsigned i = 0; i < numAnds; ++i) {
552 unsigned lhs, rhs0, rhs1;
554 if (parseNumber(lhs, &loc) || parseNumber(rhs0) || parseNumber(rhs1) ||
556 return emitError(loc,
"failed to parse AND gate definition");
558 LLVM_DEBUG(llvm::dbgs() <<
"AND Gate " << i <<
": " << lhs <<
" = " << rhs0
559 <<
" & " << rhs1 <<
"\n");
562 if (lhs % 2 != 0 || lhs == 0)
563 return emitError(loc,
"invalid AND gate LHS literal");
566 if (lhs / 2 > maxVarIndex || rhs0 / 2 > maxVarIndex ||
567 rhs1 / 2 > maxVarIndex)
568 return emitError(loc,
"AND gate literal exceeds maximum variable index");
570 andGateDefs.push_back({lhs, rhs0, rhs1, loc});
576ParseResult AIGERParser::parseAndGatesBinary() {
581 LLVM_DEBUG(llvm::dbgs() <<
"Starting binary AND gate parsing\n");
589 auto currentLHS = 2 * (numInputs + numLatches + 1);
591 LLVM_DEBUG(llvm::dbgs() <<
"First AND gate LHS should be: " << currentLHS
594 for (
unsigned i = 0; i < numAnds; ++i) {
595 unsigned delta0, delta1;
596 SMLoc loc = lexer.getCurrentLoc();
597 if (parseBinaryNumber(delta0) || parseBinaryNumber(delta1))
598 return emitError(loc,
"failed to parse binary AND gate deltas");
600 auto lhs =
static_cast<int64_t
>(currentLHS);
603 if (delta0 > lhs || delta1 > (lhs - delta0)) {
604 LLVM_DEBUG(llvm::dbgs() <<
"Delta underflow: lhs=" << lhs <<
", delta0="
605 << delta0 <<
", delta1=" << delta1 <<
"\n");
606 return emitError(
"invalid binary AND gate: delta causes underflow");
609 auto rhs0 = lhs - delta0;
610 auto rhs1 = rhs0 - delta1;
612 LLVM_DEBUG(llvm::dbgs() <<
"Binary AND Gate " << i <<
": " << lhs <<
" = "
613 << rhs0 <<
" & " << rhs1 <<
" (deltas: " << delta0
614 <<
", " << delta1 <<
")\n");
616 if (lhs / 2 > maxVarIndex || rhs0 / 2 > maxVarIndex ||
617 rhs1 / 2 > maxVarIndex)
619 "binary AND gate literal exceeds maximum variable index");
621 assert(lhs > rhs0 && rhs0 >= rhs1 &&
622 "invalid binary AND gate: ordering constraint violated");
624 andGateDefs.push_back({
static_cast<unsigned>(lhs),
625 static_cast<unsigned>(rhs0),
626 static_cast<unsigned>(rhs1), loc});
633ParseResult AIGERParser::parseSymbolTable() {
636 while (!lexer.isAtEOF()) {
637 auto token = lexer.peekToken();
638 if (token.kind != AIGERTokenKind::Identifier)
640 (void)lexer.nextToken();
642 char symbolType = token.spelling.front();
643 if (symbolType !=
'i' && symbolType !=
'l' && symbolType !=
'o')
647 if (token.spelling.drop_front().getAsInteger(10, literal))
648 return emitError(
"failed to parse symbol position");
651 switch (symbolType) {
653 kind = SymbolKind::Input;
656 kind = SymbolKind::Latch;
659 kind = SymbolKind::Output;
663 auto nextToken = lexer.lexAsSymbol();
664 if (nextToken.kind != AIGERTokenKind::Identifier)
665 return emitError(
"expected symbol name");
667 LLVM_DEBUG(llvm::dbgs()
668 <<
"Symbol " << literal <<
": " << nextToken.spelling <<
"\n");
670 symbolTable[{kind, literal}] = StringAttr::get(
context, nextToken.spelling);
678ParseResult AIGERParser::parseComments() {
680 auto token = lexer.peekToken();
681 if (token.kind == AIGERTokenKind::Identifier && token.spelling ==
"c") {
689Value AIGERParser::getLiteralValue(
unsigned literal,
690 DenseMap<unsigned, Backedge> &backedges,
692 LLVM_DEBUG(llvm::dbgs() <<
"Getting value for literal " << literal <<
"\n");
698 builder, loc, builder.getI1Type(),
699 builder.getIntegerAttr(builder.getI1Type(), 0));
705 builder, loc, builder.getI1Type(),
706 builder.getIntegerAttr(builder.getI1Type(), 1));
710 unsigned variable = literal / 2;
711 bool inverted = literal % 2;
712 unsigned baseLiteral = variable * 2;
714 LLVM_DEBUG(llvm::dbgs() <<
" Variable: " << variable
715 <<
", inverted: " << inverted
716 <<
", baseLiteral: " << baseLiteral <<
"\n");
719 if (variable > maxVarIndex) {
720 LLVM_DEBUG(llvm::dbgs() <<
" ERROR: Variable " << variable
721 <<
" exceeds maxVarIndex " << maxVarIndex <<
"\n");
726 auto backedgeIt = backedges.find(baseLiteral);
727 if (backedgeIt == backedges.end()) {
728 LLVM_DEBUG(llvm::dbgs() <<
" ERROR: No backedge found for literal "
729 << baseLiteral <<
"\n");
733 Value baseValue = backedgeIt->second;
735 LLVM_DEBUG(llvm::dbgs() <<
" ERROR: Backedge value is null for literal "
736 << baseLiteral <<
"\n");
743 SmallVector<bool> inverts = {
true};
744 return aig::AndInverterOp::create(builder, loc, builder.getI1Type(),
745 ValueRange{baseValue}, inverts);
751ParseResult AIGERParser::createModule() {
754 std::string moduleName = options.topLevelModule;
755 if (moduleName.empty())
756 moduleName =
"aiger_top";
759 builder.setInsertionPointToStart(module.getBody());
762 SmallVector<hw::PortInfo> ports;
765 for (
unsigned i = 0; i < numInputs; ++i) {
767 auto name = symbolTable.lookup({SymbolKind::Input, i});
769 name ? name : builder.getStringAttr(
"input_" + std::to_string(i));
770 port.
type = builder.getI1Type();
771 port.
dir = hw::ModulePort::Direction::Input;
773 ports.push_back(port);
777 for (
unsigned i = 0; i < numOutputs; ++i) {
779 auto name = symbolTable.lookup({SymbolKind::Output, i});
781 name ? name : builder.getStringAttr(
"output_" + std::to_string(i));
782 port.
type = builder.getI1Type();
783 port.
dir = hw::ModulePort::Direction::Output;
784 port.
argNum = numInputs + i;
785 ports.push_back(port);
789 if (numLatches > 0) {
791 clockPort.
name = builder.getStringAttr(
"clock");
792 clockPort.
type = seq::ClockType::get(builder.getContext());
793 clockPort.
dir = hw::ModulePort::Direction::Input;
794 clockPort.
argNum = numInputs + numOutputs;
795 ports.push_back(clockPort);
800 hw::HWModuleOp::create(builder, builder.getUnknownLoc(),
801 builder.getStringAttr(moduleName), ports);
804 builder.setInsertionPointToStart(hwModule.getBodyBlock());
809 clockValue = hwModule.getBodyBlock()->getArgument(numInputs);
813 DenseMap<unsigned, Backedge> backedges;
816 for (
unsigned i = 0; i < numInputs; ++i) {
817 auto literal = inputLiterals[i];
818 backedges[literal] = bb.get(builder.getI1Type());
820 for (
auto [currentState, nextState, _] : latchDefs)
821 backedges[currentState] = bb.
get(builder.getI1Type());
823 for (
auto [lhs, rhs0, rhs1, loc] : andGateDefs)
824 backedges[lhs] = bb.
get(builder.getI1Type());
827 for (
unsigned i = 0; i < numInputs; ++i) {
828 auto inputValue = hwModule.getBodyBlock()->getArgument(i);
829 auto literal = inputLiterals[i];
830 backedges[literal].setValue(inputValue);
834 for (
auto [i, latchDef] :
llvm::enumerate(latchDefs)) {
835 auto [currentState, nextState, loc] = latchDef;
837 auto nextBackedge = bb.get(builder.getI1Type());
841 builder, lexer.translateLocation(loc), (Value)nextBackedge, clockValue);
842 if (
auto name = symbolTable.lookup({SymbolKind::Latch, i}))
843 regValue.setNameAttr(name);
846 backedges[currentState].setValue(regValue);
850 for (
auto [lhs, rhs0, rhs1, loc] : andGateDefs) {
852 auto location = lexer.translateLocation(loc);
853 auto rhs0Value = getLiteralValue(rhs0 & ~1u, backedges, location);
854 auto rhs1Value = getLiteralValue(rhs1 & ~1u, backedges, location);
856 if (!rhs0Value || !rhs1Value)
857 return emitError(loc,
"failed to get operand values for AND gate");
860 SmallVector<bool> inverts = {
static_cast<bool>(rhs0 % 2),
861 static_cast<bool>(rhs1 % 2)};
865 aig::AndInverterOp::create(builder, location, builder.getI1Type(),
866 ValueRange{rhs0Value, rhs1Value}, inverts);
869 backedges[lhs].setValue(andResult);
875 for (
auto [currentState, nextState, sourceLoc] : latchDefs) {
876 auto loc = lexer.translateLocation(sourceLoc);
877 auto nextValue = getLiteralValue(nextState, backedges, loc);
879 return emitError(sourceLoc,
"undefined literal in latch next state");
882 Value currentValue = backedges[currentState];
884 regOp.getInputMutable().assign(nextValue);
886 return emitError(sourceLoc,
"failed to find register for latch");
890 SmallVector<Value> outputValues;
891 for (
auto [literal, sourceLoc] : outputLiterals) {
892 auto loc = lexer.translateLocation(sourceLoc);
893 auto outputValue = getLiteralValue(literal, backedges, loc);
895 return emitError(sourceLoc,
"undefined literal in output");
896 outputValues.push_back(outputValue);
900 auto *outputOp = hwModule.getBodyBlock()->getTerminator();
901 outputOp->setOperands(outputValues);
912 mlir::TimingScope &ts, ModuleOp module,
915 context->loadDialect<hw::HWDialect>();
916 context->loadDialect<synth::SynthDialect>();
917 context->loadDialect<seq::SeqDialect>();
922 options = &defaultOptions;
925 AIGERParser parser(sourceMgr,
context, module, *options);
926 return parser.parse();
934 static mlir::TranslateToMLIRRegistration fromAIGER(
935 "import-aiger",
"import AIGER file",
936 [](llvm::SourceMgr &sourceMgr, MLIRContext *
context) {
937 mlir::TimingScope ts;
939 ModuleOp::create(UnknownLoc::get(
context)));
assert(baseType &&"element must be base type")
static std::unique_ptr< Context > context
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.