From 6b467f4a367b2c701b240e6458fc011a8e286056 Mon Sep 17 00:00:00 2001 From: Hideto Ueno Date: Sat, 26 Oct 2024 01:49:07 +0900 Subject: [PATCH] Address comments --- include/circt/Conversion/CombToAIG.h | 4 +- include/circt/Dialect/AIG/AIG.td | 5 +- include/circt/Dialect/AIG/AIGDialect.h | 2 +- include/circt/Dialect/AIG/AIGOps.h | 2 +- include/circt/Dialect/AIG/AIGOps.td | 17 +++-- include/circt/Dialect/AIG/AIGPasses.h | 10 +-- include/circt/Dialect/AIG/AIGPasses.td | 12 ++-- lib/Conversion/CombToAIG/CombToAIG.cpp | 3 + lib/Dialect/AIG/AIGDialect.cpp | 3 +- lib/Dialect/AIG/AIGOps.cpp | 66 ++++++++----------- lib/Dialect/AIG/CMakeLists.txt | 3 +- .../AIG/Transforms/GreedyCutDecomp.cpp | 41 ++++-------- lib/Dialect/AIG/Transforms/LowerCutToLUT.cpp | 20 ++---- lib/Dialect/AIG/Transforms/LowerVariadic.cpp | 23 ++----- .../AIG/Transforms/LowerWordToBits.cpp | 9 +-- test/Conversion/CombToAIG/comb-to-aig.mlir | 17 +++-- test/Dialect/AIG/canonicalizer.mlir | 13 ++-- test/Dialect/AIG/greedy-decomp.mlir | 20 +++--- test/Dialect/AIG/lower-cut-to-lut.mlir | 3 +- test/Dialect/AIG/lower-variadic.mlir | 10 +-- test/Dialect/AIG/lower-word-to-bits.mlir | 16 ++--- test/Dialect/AIG/round-trip.mlir | 15 ++++- test/circt-synth/basic.mlir | 2 +- tools/circt-synth/circt-synth.cpp | 20 +++--- 24 files changed, 154 insertions(+), 182 deletions(-) diff --git a/include/circt/Conversion/CombToAIG.h b/include/circt/Conversion/CombToAIG.h index 27d529a39dc2..960414f8d107 100644 --- a/include/circt/Conversion/CombToAIG.h +++ b/include/circt/Conversion/CombToAIG.h @@ -1,4 +1,4 @@ -//===- CombToAIG.h - Comb to AIG dialect conversion ---------*- C++ -*-===// +//===- CombToAIG.h - Comb to AIG dialect conversion --------------- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -22,4 +22,4 @@ class HWModuleOp; } // namespace circt -#endif // CIRCT_CONVERSION_COMBTOARITH_H +#endif // CIRCT_CONVERSION_COMBTOAIG_H diff --git a/include/circt/Dialect/AIG/AIG.td b/include/circt/Dialect/AIG/AIG.td index 62cb778b5691..ff04617316a7 100644 --- a/include/circt/Dialect/AIG/AIG.td +++ b/include/circt/Dialect/AIG/AIG.td @@ -1,4 +1,4 @@ -//===- AIG.td - AIG Definitions ----------*- tablegen -*-===// +//===- AIG.td - AIG Definitions ----------------------------*- tablegen -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -10,14 +10,11 @@ #define CIRCT_AIG_DIALECT_TD include "mlir/IR/DialectBase.td" -include "mlir/IR/OpBase.td" def AIG_Dialect : Dialect { let name = "aig"; let cppNamespace = "::circt::aig"; let summary = "Representation of AIGs"; - - let usePropertiesForAttributes = 0; } include "circt/Dialect/AIG/AIGOps.td" diff --git a/include/circt/Dialect/AIG/AIGDialect.h b/include/circt/Dialect/AIG/AIGDialect.h index acd0f712ae7a..f8622359e106 100644 --- a/include/circt/Dialect/AIG/AIGDialect.h +++ b/include/circt/Dialect/AIG/AIGDialect.h @@ -1,4 +1,4 @@ -//===- AIGDialect.h - AIG Definitions --------------------------*- C++ -*-===// +//===- AIGDialect.h - AIG Definitions ---------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/include/circt/Dialect/AIG/AIGOps.h b/include/circt/Dialect/AIG/AIGOps.h index ff36bd69919c..0a298cd71a7c 100644 --- a/include/circt/Dialect/AIG/AIGOps.h +++ b/include/circt/Dialect/AIG/AIGOps.h @@ -1,4 +1,4 @@ -//===- AIGOps.h - AIG Op Definitions ---------------------------*- C++ -*-===// +//===- AIGOps.h - AIG Op Definitions ----------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. diff --git a/include/circt/Dialect/AIG/AIGOps.td b/include/circt/Dialect/AIG/AIGOps.td index ca6e99da8f3d..ddfd2bb6bd9f 100644 --- a/include/circt/Dialect/AIG/AIGOps.td +++ b/include/circt/Dialect/AIG/AIGOps.td @@ -27,7 +27,7 @@ def AndInverterOp : AIGOp<"and_inv", [SameOperandsAndResultType, Pure]> { let summary = "AIG dialect AND operation"; let description = [{ The `aig.and_inv` operation represents an And-Inverter in the AIG dialect. - Unlike comb.and, operands can be inverted respectively. + Unlike `comb.and`, operands can be inverted respectively. Example: ```mlir @@ -81,27 +81,30 @@ def CutOp : AIGOp<"cut", [IsolatedFromAbove, SingleBlock]> { ^bb0(%arg0: i1, %arg1: i1, %arg2: i1, %arg3: i1): %0 = aig.and_inv not %arg0, %arg1 : i1 %1 = aig.and_inv %arg1, %arg3 : i1 - aig.output %0, %1 : i1 - } + aig.output %0, %1 : i1 } ``` }]; + + // TODO: Restrict to HWIntegerType. let arguments = (ins Variadic:$inputs); let results = (outs Variadic:$results); - let regions = (region SizedRegion<1>:$body); + let regions = (region SizedRegion<1>:$bodyRegion); let assemblyFormat = [{ - $inputs attr-dict `:` functional-type($inputs, $results) $body + $inputs attr-dict `:` functional-type($inputs, $results) $bodyRegion }]; let builders = [ OpBuilder<(ins CArg<"TypeRange", "{}">:$resultTypes, CArg<"ValueRange", "{}">:$inputs, - CArg<"std::function", "{}">:$ctor)> + CArg<"std::function", "{}">:$ctor)> ]; + let hasVerifier = 1; + let extraClassDeclaration = [{ - Block *getBodyBlock() { return &getBody().front(); } + Block *getBodyBlock() { return getBody(); } }]; } diff --git a/include/circt/Dialect/AIG/AIGPasses.h b/include/circt/Dialect/AIG/AIGPasses.h index 4226bc35711b..95cee626cfad 100644 --- a/include/circt/Dialect/AIG/AIGPasses.h +++ b/include/circt/Dialect/AIG/AIGPasses.h @@ -25,11 +25,11 @@ namespace aig { #define GEN_PASS_DECL #include "circt/Dialect/AIG/AIGPasses.h.inc" -std::unique_ptr createLowerCutToLUTPass(); -std::unique_ptr createLowerVariadicPass(); -std::unique_ptr createLowerWordToBitsPass(); -std::unique_ptr -createGreedyCutDecompPass(const GreedyCutDecompOptions &options = {}); +// std::unique_ptr createLowerCutToLUTPass(); +// std::unique_ptr createLowerVariadicPass(); +// std::unique_ptr createLowerWordToBitsPass(); +// std::unique_ptr +// createGreedyCutDecompPass(const GreedyCutDecompOptions &options = {}); #define GEN_PASS_REGISTRATION #include "circt/Dialect/AIG/AIGPasses.h.inc" diff --git a/include/circt/Dialect/AIG/AIGPasses.td b/include/circt/Dialect/AIG/AIGPasses.td index 8c570245c17f..368de261ee0f 100644 --- a/include/circt/Dialect/AIG/AIGPasses.td +++ b/include/circt/Dialect/AIG/AIGPasses.td @@ -1,4 +1,4 @@ -//===- ArcPasses.td - Arc dialect passes -------------------*- tablegen -*-===// +//===- AIGPasses.td - AIG dialect passes -------------------*- tablegen -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -6,36 +6,32 @@ // //===----------------------------------------------------------------------===// -#ifndef CIRCT_DIALECT_ARC_ARCPASSES_TD -#define CIRCT_DIALECT_ARC_ARCPASSES_TD +#ifndef CIRCT_DIALECT_AIG_AIGPASSES_TD +#define CIRCT_DIALECT_AIG_AIGPASSES_TD include "mlir/Pass/PassBase.td" def LowerCutToLUT : Pass<"aig-lower-cut-to-lut", "hw::HWModuleOp"> { let summary = "Lower a cut to a LUT"; let dependentDialects = ["comb::CombDialect"]; - let constructor = "circt::aig::createLowerCutToLUTPass()"; } def LowerVariadic : Pass<"aig-lower-variadic", "hw::HWModuleOp"> { let summary = "Lower variadic AndInverter operations to binary AndInverter"; - let constructor = "circt::aig::createLowerVariadicPass()"; } def LowerWordToBits : Pass<"aig-lower-word-to-bits", "hw::HWModuleOp"> { let summary = "Lower multi-bit AIG operations to single-bit ones"; let dependentDialects = ["comb::CombDialect"]; - let constructor = "circt::aig::createLowerWordToBitsPass()"; } def GreedyCutDecomp : Pass<"aig-greedy-cut-decomp", "hw::HWModuleOp"> { let summary = "Decompose AIGs into k-feasible Cuts using a greedy algorithm"; let dependentDialects = ["comb::CombDialect"]; - let constructor = "circt::aig::createGreedyCutDecompPass()"; let options = [ Option<"cutSizes", "cut-sizes", "uint32_t", "6", "The sizes of the cuts to decompose">, ]; } -#endif // CIRCT_DIALECT_ARC_ARCPASSES_TD +#endif // CIRCT_DIALECT_AIG_AIGPASSES_TD diff --git a/lib/Conversion/CombToAIG/CombToAIG.cpp b/lib/Conversion/CombToAIG/CombToAIG.cpp index 6d95c831d544..ab0ccea944d4 100644 --- a/lib/Conversion/CombToAIG/CombToAIG.cpp +++ b/lib/Conversion/CombToAIG/CombToAIG.cpp @@ -65,7 +65,10 @@ struct CombXorOpConversion : OpConversionPattern { LogicalResult matchAndRewrite(XorOp op, OpAdaptor adaptor, ConversionPatternRewriter &rewriter) const override { + if (op.getNumOperands() != 2) + return failure(); // Xor using And with invert flags: a ^ b = (a | b) & (~a | ~b) + // (a | b) = ~(~a & ~b) // (~a | ~b) = ~(a & b) auto inputs = adaptor.getInputs(); diff --git a/lib/Dialect/AIG/AIGDialect.cpp b/lib/Dialect/AIG/AIGDialect.cpp index 0acb1e1b8b2a..ff5b0df17a7c 100644 --- a/lib/Dialect/AIG/AIGDialect.cpp +++ b/lib/Dialect/AIG/AIGDialect.cpp @@ -1,4 +1,4 @@ -//===- AIGDialect.cpp - Implement the AIG dialect -----------------------===// +//===- AIGDialect.cpp - Implement the AIG dialect -------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -12,7 +12,6 @@ #include "circt/Dialect/AIG/AIGDialect.h" #include "circt/Dialect/AIG/AIGOps.h" -#include "circt/Dialect/HW/HWOps.h" #include "mlir/IR/Builders.h" #include "mlir/IR/BuiltinTypes.h" #include "mlir/IR/DialectImplementation.h" diff --git a/lib/Dialect/AIG/AIGOps.cpp b/lib/Dialect/AIG/AIGOps.cpp index 0a62bcbffb97..e0bdf9697539 100644 --- a/lib/Dialect/AIG/AIGOps.cpp +++ b/lib/Dialect/AIG/AIGOps.cpp @@ -1,4 +1,4 @@ -//===- LoopScheduleOps.cpp - LoopSchedule CIRCT Operations ------*- C++ -*-===// +//===- AIGOps.cpp - AIG Dialect Operations ----------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -101,11 +101,7 @@ mlir::ParseResult AndInverterOp::parse(mlir::OpAsmParser &parser, auto loc = parser.getCurrentLocation(); while (true) { - if (succeeded(parser.parseOptionalKeyword("not"))) { - inverts.push_back(true); - } else { - inverts.push_back(false); - } + inverts.push_back(succeeded(parser.parseOptionalKeyword("not"))); operands.push_back(OpAsmParser::UnresolvedOperand()); if (parser.parseOperand(operands.back())) @@ -114,28 +110,17 @@ mlir::ParseResult AndInverterOp::parse(mlir::OpAsmParser &parser, break; } - if (parser.parseOptionalAttrDict(result.attributes)) - return mlir::failure(); - - if (parser.parseColon()) - return mlir::failure(); - - mlir::Type resultRawType{}; - llvm::ArrayRef resultTypes(&resultRawType, 1); - - { - mlir::Type type; - if (parser.parseCustomTypeWithFallback(type)) - return mlir::failure(); - resultRawType = type; - } + mlir::Type type; + if (parser.parseOptionalAttrDict(result.attributes) || parser.parseColon() || + parser.parseCustomTypeWithFallback(type)) + return failure(); - result.addTypes(resultTypes); + result.addTypes({type}); result.addAttribute("inverted", parser.getBuilder().getDenseBoolArrayAttr(inverts)); - if (parser.resolveOperands(operands, resultTypes[0], loc, result.operands)) - return mlir::failure(); - return mlir::success(); + if (parser.resolveOperands(operands, type, loc, result.operands)) + return failure(); + return success(); } void AndInverterOp::print(mlir::OpAsmPrinter &odsPrinter) { @@ -148,18 +133,9 @@ void AndInverterOp::print(mlir::OpAsmPrinter &odsPrinter) { } odsPrinter << input; }); - llvm::SmallVector elidedAttrs; - elidedAttrs.push_back("inverted"); + llvm::SmallVector elidedAttrs{"inverted"}; odsPrinter.printOptionalAttrDict((*this)->getAttrs(), elidedAttrs); - odsPrinter << ' ' << ":"; - odsPrinter << ' '; - { - auto type = getResult().getType(); - if (auto validType = llvm::dyn_cast(type)) - odsPrinter.printStrippedAttrOrType(validType); - else - odsPrinter << type; - } + odsPrinter << " : " << getResult().getType(); } APInt AndInverterOp::evaluate(ArrayRef inputs) { @@ -178,7 +154,7 @@ APInt AndInverterOp::evaluate(ArrayRef inputs) { void CutOp::build(OpBuilder &builder, OperationState &result, TypeRange resultTypes, ValueRange inputs, - std::function ctor) { + std::function ctor) { OpBuilder::InsertionGuard guard(builder); auto *block = builder.createBlock(result.addRegion()); @@ -188,5 +164,19 @@ void CutOp::build(OpBuilder &builder, OperationState &result, block->addArgument(input.getType(), input.getLoc()); if (ctor) - ctor(); + ctor(block->getArguments()); +} + +LogicalResult CutOp::verify() { + if (getInputs().size() != getBodyBlock()->getNumArguments()) + return emitOpError("the number of inputs and the number of block arguments " + "do not match. Expected ") + << getInputs().size() << " but got " + << getBodyBlock()->getNumArguments(); + if (getNumResults() != getBodyBlock()->getTerminator()->getNumOperands()) + return emitOpError("the number of results and the number of terminator " + "operands do not match. Expected ") + << getNumResults() << " but got " + << getBodyBlock()->getTerminator()->getNumOperands(); + return success(); } diff --git a/lib/Dialect/AIG/CMakeLists.txt b/lib/Dialect/AIG/CMakeLists.txt index 6b6d4ca0766c..3f785288f30a 100644 --- a/lib/Dialect/AIG/CMakeLists.txt +++ b/lib/Dialect/AIG/CMakeLists.txt @@ -10,8 +10,7 @@ add_circt_dialect_library(CIRCTAIG CIRCTHW DEPENDS - CIRCTHW MLIRAIGIncGen ) -add_subdirectory(Transforms) \ No newline at end of file +add_subdirectory(Transforms) diff --git a/lib/Dialect/AIG/Transforms/GreedyCutDecomp.cpp b/lib/Dialect/AIG/Transforms/GreedyCutDecomp.cpp index 89e9cf760021..636a5560a042 100644 --- a/lib/Dialect/AIG/Transforms/GreedyCutDecomp.cpp +++ b/lib/Dialect/AIG/Transforms/GreedyCutDecomp.cpp @@ -1,4 +1,4 @@ -//===- GreedyCutDecomp.cpp ---------------------------------------------===// +//===- GreedyCutDecomp.cpp ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -7,7 +7,7 @@ //===----------------------------------------------------------------------===// // // This pass performs cut decomposition on AIGs based on a naive greedy -// algorithm. We first convert all `aig.and_inv` to `aig.cut` that has a single +// algorithm. We first convert all `aig.and_inv` to `aig.cut` that have a single // operation and then try to merge cut operations on inputs. // //===----------------------------------------------------------------------===// @@ -19,6 +19,7 @@ #include "mlir/Analysis/TopologicalSortUtils.h" #include "mlir/Transforms/DialectConversion.h" #include "mlir/Transforms/GreedyPatternRewriteDriver.h" + #define DEBUG_TYPE "aig-greedy-cut-decomp" namespace circt { @@ -42,14 +43,15 @@ struct AndInverterOpToCutPattern : public OpRewritePattern { LogicalResult matchAndRewrite(aig::AndInverterOp op, PatternRewriter &rewriter) const override { - if (isa(op->getParentOp())) + if (op->getParentOfType()) return failure(); auto cutOp = rewriter.create( - op.getLoc(), op.getResult().getType(), op.getInputs(), [&]() { + op.getLoc(), op.getResult().getType(), op.getInputs(), + [&](Block::BlockArgListType args) { auto result = rewriter.create( - op.getLoc(), op.getResult().getType(), - rewriter.getBlock()->getArguments(), op.getInvertedAttr()); + op.getLoc(), op.getResult().getType(), args, + op.getInvertedAttr()); rewriter.create(op.getLoc(), ValueRange{result}); }); @@ -67,10 +69,10 @@ static aig::CutOp mergeCuts(Location loc, MutableArrayRef cuts, assert(cuts.size() >= 2); DenseMap valueToNewValue, inputsToBlockArg; - auto cutOp = - rewriter.create(loc, output.getType(), inputs, [&]() { + auto cutOp = rewriter.create( + loc, output.getType(), inputs, [&](Block::BlockArgListType args) { for (auto [i, input] : llvm::enumerate(inputs)) - inputsToBlockArg[input] = rewriter.getBlock()->getArgument(i); + inputsToBlockArg[input] = args[i]; for (auto [i, cut] : llvm::enumerate(cuts)) { auto cutOp = cast(cut); @@ -103,7 +105,7 @@ static aig::CutOp mergeCuts(Location loc, MutableArrayRef cuts, for (auto oldCut : llvm::reverse(cuts)) { auto *oldCutBlock = cast(oldCut).getBodyBlock(); auto oldCutOutput = oldCutBlock->getTerminator(); - oldCutOutput->erase(); + rewriter.eraseOp(oldCutOutput); // Erase arguments before inlining. Arguments are already replaced. oldCutBlock->eraseArguments([](BlockArgument block) { return true; }); rewriter.inlineBlockBefore(oldCutBlock, cutOp.getBodyBlock(), @@ -241,18 +243,8 @@ struct SinkConstantPattern : public mlir::OpRewritePattern { block->eraseArguments(eraseArgs); } - auto newCut = rewriter.create(op.getLoc(), op.getResultTypes(), - oldInputs, [&]() {}); - - for (auto [newArg, oldArg] : - llvm::zip(newCut.getBodyBlock()->getArguments(), oldArgs)) - rewriter.replaceAllUsesWith(oldArg, newArg); - - // Erase arguments before inlining. Arguments are already replaced. - block->eraseArguments([](BlockArgument arg) { return true; }); - rewriter.inlineBlockBefore(block, newCut.getBodyBlock(), - newCut.getBodyBlock()->begin()); - rewriter.replaceOp(op, newCut); + rewriter.modifyOpInPlace( + op, [&]() { op.getInputsMutable().assign(oldInputs); }); return success(); } }; @@ -285,8 +277,3 @@ void GreedyCutDecompPass::runOnOperation() { mlir::applyPatternsAndFoldGreedily(getOperation(), frozen, config))) return signalPassFailure(); } - -std::unique_ptr -aig::createGreedyCutDecompPass(const GreedyCutDecompOptions &options) { - return std::make_unique(options); -} diff --git a/lib/Dialect/AIG/Transforms/LowerCutToLUT.cpp b/lib/Dialect/AIG/Transforms/LowerCutToLUT.cpp index 244988f716cd..f57b44691d10 100644 --- a/lib/Dialect/AIG/Transforms/LowerCutToLUT.cpp +++ b/lib/Dialect/AIG/Transforms/LowerCutToLUT.cpp @@ -55,9 +55,9 @@ CutToLUTPattern::matchAndRewrite(CutOp cutOp, PatternRewriter &rewriter) const { uint32_t tableSize = 1 << lutWidth; DenseMap mapping; auto &body = cutOp.getBodyRegion().front(); - for (uint32_t i = 0; i < lutWidth; i++) { + for (uint32_t i = 0; i < lutWidth; ++i) { APInt value(tableSize, 0); - for (uint32_t j = 0; j < tableSize; j++) { + for (uint32_t j = 0; j < tableSize; ++j) { // Make sure the order of the bits is correct. value.setBitVal(j, (j >> i) & 1); } @@ -69,12 +69,12 @@ CutToLUTPattern::matchAndRewrite(CutOp cutOp, PatternRewriter &rewriter) const { if (auto constOp = dyn_cast(&op)) { mapping[constOp.getResult()] = APInt(tableSize, constOp.getValue().getZExtValue()); - } else if (auto AndInverterOp = dyn_cast(&op)) { + } else if (auto andInverterOp = dyn_cast(&op)) { // TODO: Avoid this copy. SmallVector inputs; - for (auto input : AndInverterOp.getInputs()) + for (auto input : andInverterOp.getInputs()) inputs.push_back(mapping[input]); - mapping[AndInverterOp.getResult()] = AndInverterOp.evaluate(inputs); + mapping[andInverterOp.getResult()] = andInverterOp.evaluate(inputs); } else if (auto outputOp = dyn_cast(&op)) { assert(outputOp.getOutputs().size() == 1 && "expected single output"); auto value = mapping.at(outputOp.getOutputs().front()); @@ -127,10 +127,8 @@ void LowerCutToLUTPass::runOnOperation() { return cutOp.emitError("expected i1 type"); } - for (auto result : cutOp.getResults()) { - if (result.getType() != i1Type) - return cutOp.emitError("expected i1 type"); - } + if (cutOp.getResult(0).getType() != i1Type) + return cutOp.emitError("expected i1 type"); uint32_t lutWidth = cutOp.getNumOperands(); if (lutWidth >= 32) @@ -153,7 +151,3 @@ void LowerCutToLUTPass::runOnOperation() { std::move(patterns)))) return signalPassFailure(); } - -std::unique_ptr aig::createLowerCutToLUTPass() { - return std::make_unique(); -} diff --git a/lib/Dialect/AIG/Transforms/LowerVariadic.cpp b/lib/Dialect/AIG/Transforms/LowerVariadic.cpp index d8821a3ae2d1..52e3ccf5bdbe 100644 --- a/lib/Dialect/AIG/Transforms/LowerVariadic.cpp +++ b/lib/Dialect/AIG/Transforms/LowerVariadic.cpp @@ -1,4 +1,4 @@ -//===- LowerVariadic.cpp ---------------------------------------------===// +//===- LowerVariadic.cpp --------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -13,9 +13,7 @@ #include "circt/Dialect/AIG/AIGOps.h" #include "circt/Dialect/AIG/AIGPasses.h" -#include "circt/Dialect/Comb/CombOps.h" #include "circt/Dialect/HW/HWOps.h" -#include "mlir/Transforms/DialectConversion.h" #include "mlir/Transforms/GreedyPatternRewriteDriver.h" #define DEBUG_TYPE "aig-lower-variadic" @@ -38,7 +36,6 @@ namespace { static Value lowerFullyAssociativeOp(AndInverterOp op, OperandRange operands, ArrayRef inverts, PatternRewriter &rewriter) { - Value lhs, rhs; switch (operands.size()) { case 0: assert(0 && "cannot be called with empty operand range"); @@ -49,16 +46,14 @@ static Value lowerFullyAssociativeOp(AndInverterOp op, OperandRange operands, else return operands[0]; case 2: - lhs = operands[0]; - rhs = operands[1]; - return rewriter.create(op.getLoc(), lhs, rhs, inverts[0], - inverts[1]); + return rewriter.create(op.getLoc(), operands[0], operands[1], + inverts[0], inverts[1]); default: auto firstHalf = operands.size() / 2; - lhs = lowerFullyAssociativeOp(op, operands.take_front(firstHalf), - inverts.take_front(firstHalf), rewriter); - rhs = lowerFullyAssociativeOp(op, operands.drop_front(firstHalf), - inverts.drop_front(firstHalf), rewriter); + auto lhs = lowerFullyAssociativeOp(op, operands.take_front(firstHalf), + inverts.take_front(firstHalf), rewriter); + auto rhs = lowerFullyAssociativeOp(op, operands.drop_front(firstHalf), + inverts.drop_front(firstHalf), rewriter); return rewriter.create(op.getLoc(), lhs, rhs); } } @@ -106,7 +101,3 @@ void LowerVariadicPass::runOnOperation() { mlir::applyPatternsAndFoldGreedily(getOperation(), frozen, config))) return signalPassFailure(); } - -std::unique_ptr aig::createLowerVariadicPass() { - return std::make_unique(); -} diff --git a/lib/Dialect/AIG/Transforms/LowerWordToBits.cpp b/lib/Dialect/AIG/Transforms/LowerWordToBits.cpp index 3f4a49a8c09d..97c28c15707a 100644 --- a/lib/Dialect/AIG/Transforms/LowerWordToBits.cpp +++ b/lib/Dialect/AIG/Transforms/LowerWordToBits.cpp @@ -1,4 +1,4 @@ -//===- LowerWordToBits.cpp ---------------------------------------------===// +//===- LowerWordToBits.cpp ------------------------------------------------===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. @@ -55,8 +55,7 @@ struct WordRewritePattern : public OpRewritePattern { result.push_back(andInverter); } - auto concat = rewriter.create(op.getLoc(), result); - rewriter.replaceOp(op, concat); + rewriter.replaceOpWithNewOp(op, result); return success(); } }; @@ -85,7 +84,3 @@ void LowerWordToBitsPass::runOnOperation() { config))) return signalPassFailure(); } - -std::unique_ptr aig::createLowerWordToBitsPass() { - return std::make_unique(); -} diff --git a/test/Conversion/CombToAIG/comb-to-aig.mlir b/test/Conversion/CombToAIG/comb-to-aig.mlir index de740b40e192..550bae1569b0 100644 --- a/test/Conversion/CombToAIG/comb-to-aig.mlir +++ b/test/Conversion/CombToAIG/comb-to-aig.mlir @@ -1,9 +1,16 @@ // RUN: circt-opt %s --convert-comb-to-aig | FileCheck %s // CHECK-LABEL: @test -hw.module @test(in %arg0: i32, in %arg1: i32, in %arg2: i32, in %arg3: i32, in %arg4: i1, out out: i32) { - // CHECK-NEXT: %0 = aig.and_inv not %arg0, not %arg1, not %arg2, not %arg3 : i32 - // CHECK-NEXT: %1 = aig.and_inv not %0 : i32 +hw.module @test(in %arg0: i32, in %arg1: i32, in %arg2: i32, in %arg3: i32, out out0: i32, out out1: i32, out out2: i32) { + // CHECK-NEXT: %[[OR_TMP:.+]] = aig.and_inv not %arg0, not %arg1, not %arg2, not %arg3 : i32 + // CHECK-NEXT: %[[OR:.+]] = aig.and_inv not %0 : i32 + // CHECK-NEXT: %[[AND:.+]] = aig.and_inv %arg0, %arg1, %arg2, %arg3 : i32 + // CHECK-NEXT: %[[XOR_NOT_AND:.+]] = aig.and_inv not %arg0, not %arg1 : i32 + // CHECK-NEXT: %[[XOR_AND:.+]] = aig.and_inv %arg0, %arg1 : i32 + // CHECK-NEXT: %[[XOR:.+]] = aig.and_inv not %[[XOR_NOT_AND]], not %[[XOR_AND]] : i32 + // CHECK-NEXT: hw.output %[[OR]], %[[AND]], %[[XOR]] : i32, i32, i32 %0 = comb.or %arg0, %arg1, %arg2, %arg3 : i32 - hw.output %0 : i32 -} \ No newline at end of file + %1 = comb.and %arg0, %arg1, %arg2, %arg3 : i32 + %2 = comb.xor %arg0, %arg1 : i32 + hw.output %0, %1, %2 : i32, i32, i32 +} diff --git a/test/Dialect/AIG/canonicalizer.mlir b/test/Dialect/AIG/canonicalizer.mlir index 2147673a20c6..6d00aa68ba56 100644 --- a/test/Dialect/AIG/canonicalizer.mlir +++ b/test/Dialect/AIG/canonicalizer.mlir @@ -4,22 +4,22 @@ hw.module @And(in %a: i4, in %b: i4, out o1: i4, out o2: i4, out o3: i4, out o4: i4, out o5: i4, out o6: i4, out o7: i4, out o8: i4) { - // CHECK-NEXT: %c0_i4 = hw.constant 0 : i4 // CHECK-NEXT: %c-1_i4 = hw.constant -1 : i4 + // CHECK-NEXT: %c0_i4 = hw.constant 0 : i4 // CHECK-NEXT: %c5_i4 = hw.constant 5 : i4 // CHECK-NEXT: %[[TMP1:.+]] = aig.and_inv %a, %c5_i4 : i4 // CHECK-NEXT: %[[TMP2:.+]] = aig.and_inv %a, %b : i4 // CHECK-NEXT: hw.output %c0_i4, %[[TMP1]], %a, %a, %c0_i4, %[[TMP2]], %c0_i4, %c-1_i4 : i4, i4, i4, i4, i4, i4, i4, i4 %c0 = hw.constant 0 : i4 %c2 = hw.constant 2 : i4 - %c8 = hw.constant 7 : i4 + %c7 = hw.constant 7 : i4 %c15 = hw.constant 15 : i4 // a & 0 -> 0 %0 = aig.and_inv %a, %c0 : i4 // a & 7 & ~2 -> a & 5 - %1 = aig.and_inv %a, %c8, not %c2 : i4 + %1 = aig.and_inv %a, %c7, not %c2 : i4 // a & 15 -> a %2 = aig.and_inv %a, %c15 : i4 @@ -31,12 +31,13 @@ hw.module @And(in %a: i4, in %b: i4, out o1: i4, out o2: i4, %4 = aig.and_inv %a, not %c15 : i4 // a & a & b -> a & b - %5 = aig.and_inv %a, %b : i4 + %5 = aig.and_inv %a, %a, %b : i4 // a & ~a & b -> 0 - %6 = hw.constant 0 : i4 + %6 = aig.and_inv %a, not %a, %b : i4 // 15 & 15 -> 15 - %7 = hw.constant -1 : i4 + %7 = aig.and_inv %c15, %c15 : i4 + hw.output %0, %1, %2, %3, %4, %5, %6, %7 : i4, i4, i4, i4, i4, i4, i4, i4 } diff --git a/test/Dialect/AIG/greedy-decomp.mlir b/test/Dialect/AIG/greedy-decomp.mlir index 9827b0394dea..0a5e36811215 100644 --- a/test/Dialect/AIG/greedy-decomp.mlir +++ b/test/Dialect/AIG/greedy-decomp.mlir @@ -10,17 +10,17 @@ hw.module @variadic(in %a : i1, in %b : i1, in %c : i1, in %d : i1, in %e : i1, %5 = aig.and_inv %1, %4 : i1 hw.output %5 : i1 } -// CHECK-NEXT: %0 = aig.cut %a, %b, %c : (i1, i1, i1) -> i1 { +// CHECK-NEXT: %[[RES0:.+]] = aig.cut %a, %b, %c : (i1, i1, i1) -> i1 { // CHECK-NEXT: ^bb0(%arg0: i1, %arg1: i1, %arg2: i1): -// CHECK-NEXT: %2 = aig.and_inv %arg1, %arg2 : i1 -// CHECK-NEXT: %3 = aig.and_inv %arg0, %2 : i1 -// CHECK-NEXT: aig.output %3 : i1 +// CHECK-NEXT: %[[RES2:.+]] = aig.and_inv %arg1, %arg2 : i1 +// CHECK-NEXT: %[[RES3:.+]] = aig.and_inv %arg0, %[[RES2]] : i1 +// CHECK-NEXT: aig.output %[[RES3]] : i1 // CHECK-NEXT: } -// CHECK-NEXT: %1 = aig.cut %0, %d, %e, %f, %g : (i1, i1, i1, i1, i1) -> i1 { +// CHECK-NEXT: %[[RES1:.+]] = aig.cut %0, %d, %e, %f, %g : (i1, i1, i1, i1, i1) -> i1 { // CHECK-NEXT: ^bb0(%arg0: i1, %arg1: i1, %arg2: i1, %arg3: i1, %arg4: i1): -// CHECK-NEXT: %2 = aig.and_inv %arg1, %arg2 : i1 -// CHECK-NEXT: %3 = aig.and_inv %arg3, %arg4 : i1 -// CHECK-NEXT: %4 = aig.and_inv %2, %3 : i1 -// CHECK-NEXT: %5 = aig.and_inv %arg0, %4 : i1 -// CHECK-NEXT: aig.output %5 : i1 +// CHECK-NEXT: %[[RES2:.+]] = aig.and_inv %arg1, %arg2 : i1 +// CHECK-NEXT: %[[RES3:.+]] = aig.and_inv %arg3, %arg4 : i1 +// CHECK-NEXT: %[[RES4:.+]] = aig.and_inv %[[RES2]], %[[RES3]] : i1 +// CHECK-NEXT: %[[RES5:.+]] = aig.and_inv %arg0, %[[RES4]] : i1 +// CHECK-NEXT: aig.output %[[RES5]] : i1 // CHECK-NEXT: } diff --git a/test/Dialect/AIG/lower-cut-to-lut.mlir b/test/Dialect/AIG/lower-cut-to-lut.mlir index 71e5514784c5..f15cddcfb10d 100644 --- a/test/Dialect/AIG/lower-cut-to-lut.mlir +++ b/test/Dialect/AIG/lower-cut-to-lut.mlir @@ -1,9 +1,10 @@ // RUN: circt-opt %s --aig-lower-cut-to-lut | FileCheck %s // CHECK: hw.module @Cut hw.module @Cut(in %a: i1, in %b: i1, in %c: i1, in %d: i1, out e: i1) { - // CHECK-NEXT: %0 = comb.truth_table %a, %b, %c, %d + // CHECK-NEXT: %[[RES0:.+]] = comb.truth_table %a, %b, %c, %d // CHECK-SAME: -> [false, false, false, false, false, true, true, true, // CHECK-SAME: false, false, false, false, false, false, false, false] + // CHECK-NEXT: hw.output %[[RES0]] : i1 %0 = aig.cut %a, %b, %c, %d : (i1, i1, i1, i1) -> (i1) { ^bb0(%arg0: i1, %arg1: i1, %arg2: i1, %arg3: i1): %1 = aig.and_inv not %arg0, not %arg1 : i1 diff --git a/test/Dialect/AIG/lower-variadic.mlir b/test/Dialect/AIG/lower-variadic.mlir index df1dca9279eb..29e755fa20fd 100644 --- a/test/Dialect/AIG/lower-variadic.mlir +++ b/test/Dialect/AIG/lower-variadic.mlir @@ -1,11 +1,11 @@ // RUN: circt-opt %s --aig-lower-variadic | FileCheck %s // CHECK: hw.module @Basic hw.module @Basic(in %a: i2, in %b: i2, in %c: i2, in %d: i2, in %e: i2, out f: i2) { - // CHECK: %0 = aig.and_inv not %a, %b : i2 - // CHECK-NEXT: %1 = aig.and_inv not %d, %e : i2 - // CHECK-NEXT: %2 = aig.and_inv %c, %1 : i2 - // CHECK-NEXT: %3 = aig.and_inv %0, %2 : i2 - // CHECK-NEXT: hw.output %3 : i2 + // CHECK: %[[RES0:.+]] = aig.and_inv not %a, %b : i2 + // CHECK-NEXT: %[[RES1:.+]] = aig.and_inv not %d, %e : i2 + // CHECK-NEXT: %[[RES2:.+]] = aig.and_inv %c, %[[RES1]] : i2 + // CHECK-NEXT: %[[RES3:.+]] = aig.and_inv %[[RES0]], %[[RES2]] : i2 + // CHECK-NEXT: hw.output %[[RES3]] : i2 %0 = aig.and_inv not %a, %b, %c, not %d, %e : i2 hw.output %0 : i2 } diff --git a/test/Dialect/AIG/lower-word-to-bits.mlir b/test/Dialect/AIG/lower-word-to-bits.mlir index 9202a8c6eb98..98d2a77dc274 100644 --- a/test/Dialect/AIG/lower-word-to-bits.mlir +++ b/test/Dialect/AIG/lower-word-to-bits.mlir @@ -1,14 +1,14 @@ // RUN: circt-opt %s --aig-lower-word-to-bits | FileCheck %s // CHECK: hw.module @Basic hw.module @Basic(in %a: i2, in %b: i2, out f: i2) { - // CHECK-NEXT: %0 = comb.extract %a from 0 : (i2) -> i1 - // CHECK-NEXT: %1 = comb.extract %b from 0 : (i2) -> i1 - // CHECK-NEXT: %2 = aig.and_inv not %0, %1 : i1 - // CHECK-NEXT: %3 = comb.extract %a from 1 : (i2) -> i1 - // CHECK-NEXT: %4 = comb.extract %b from 1 : (i2) -> i1 - // CHECK-NEXT: %5 = aig.and_inv not %3, %4 : i1 - // CHECK-NEXT: %6 = comb.concat %2, %5 : i1, i1 - // CHECK-NEXT: hw.output %6 : i2 + // CHECK-NEXT: %[[RES0:.+]] = comb.extract %a from 0 : (i2) -> i1 + // CHECK-NEXT: %[[RES1:.+]] = comb.extract %b from 0 : (i2) -> i1 + // CHECK-NEXT: %[[RES2:.+]] = aig.and_inv not %[[RES0]], %[[RES1]] : i1 + // CHECK-NEXT: %[[RES3:.+]] = comb.extract %a from 1 : (i2) -> i1 + // CHECK-NEXT: %[[RES4:.+]] = comb.extract %b from 1 : (i2) -> i1 + // CHECK-NEXT: %[[RES5:.+]] = aig.and_inv not %[[RES3]], %[[RES4]] : i1 + // CHECK-NEXT: %[[RES6:.+]] = comb.concat %[[RES2]], %[[RES5]] : i1, i1 + // CHECK-NEXT: hw.output %[[RES6]] : i2 %0 = aig.and_inv not %a, %b : i2 hw.output %0 : i2 } diff --git a/test/Dialect/AIG/round-trip.mlir b/test/Dialect/AIG/round-trip.mlir index 78f9e6bd8574..1cce29084a3e 100644 --- a/test/Dialect/AIG/round-trip.mlir +++ b/test/Dialect/AIG/round-trip.mlir @@ -1,15 +1,24 @@ // RUN: circt-opt %s | circt-opt | FileCheck %s // CHECK-LABEL: @And -// CHECK-NEXT: aig.and_inv %b, %b : i4 -// CHECK-NEXT: aig.and_inv %b, not %b : i4 -// CHECK-NEXT: aig.and_inv not %a, not %a : i1 +// CHECK-NEXT: %[[RES0:.+]] = aig.and_inv %b, %b : i4 +// CHECK-NEXT: %[[RES1:.+]] = aig.and_inv %b, not %b : i4 +// CHECK-NEXT: %[[RES2:.+]] = aig.and_inv not %a, not %a : i1 hw.module @And(in %a: i1, in %b: i4) { %0 = aig.and_inv %b, %b : i4 %1 = aig.and_inv %b, not %b : i4 %2 = aig.and_inv not %a, not %a : i1 } +// CHECK-LABEL: @Cut +// CHECK-NEXT: %[[RES:.+]]:2 = aig.cut %a, %b : (i1, i1) -> (i1, i1) { +// CHECK-NEXT: ^bb0(%arg0: i1, %arg1: i1): +// CHECK-NEXT: %[[C:.+]] = aig.and_inv %arg0, not %arg1 : i1 +// CHECK-NEXT: %[[D:.+]] = aig.and_inv %arg0, %arg1 : i1 +// CHECK-NEXT: aig.output %[[C]], %[[D]] : i1, i1 +// CHECK-NEXT: } +// CHECK-NEXT: hw.output %[[RES]]#0, %[[RES]]#1 : i1, i1 + hw.module @Cut(in %a: i1, in %b: i1, out c: i1, out d: i1) { %0, %1 = aig.cut %a, %b : (i1, i1) -> (i1, i1) { ^bb0(%arg0: i1, %arg1: i1): diff --git a/test/circt-synth/basic.mlir b/test/circt-synth/basic.mlir index 82c96020f9e3..4d5d3faa4be8 100644 --- a/test/circt-synth/basic.mlir +++ b/test/circt-synth/basic.mlir @@ -43,4 +43,4 @@ hw.module @variadic(in %a: i1, in %b: i1, in %c: i1, // CHECK-SAME: true // CHECK-SAME: ] hw.output %0 : i1 -} \ No newline at end of file +} diff --git a/tools/circt-synth/circt-synth.cpp b/tools/circt-synth/circt-synth.cpp index b08050b230a3..ee19b582d2a4 100644 --- a/tools/circt-synth/circt-synth.cpp +++ b/tools/circt-synth/circt-synth.cpp @@ -6,7 +6,7 @@ // //===----------------------------------------------------------------------===// /// -/// This file initiliazes the 'circt-synth' tool, which performs logic +/// This file initializes the 'circt-synth' tool, which performs logic /// synthesis. Currently, it only performs backend-agnostic FPGA synthesis, /// mapping core dialects into FPGA-specific primitives, such as LUTs. /// @@ -44,7 +44,7 @@ using namespace circt; static cl::OptionCategory mainCategory("circt-synth Options"); -static cl::opt inputFilename(cl::Positional, cl::Required, +static cl::opt inputFilename(cl::Positional, cl::init("-"), cl::desc("Specify an input file"), cl::value_desc("filename"), cl::cat(mainCategory)); @@ -80,8 +80,8 @@ static llvm::cl::opt runUntilAfter( "until-after", llvm::cl::desc("Stop pipeline after a specified point"), runUntilValues, llvm::cl::init(UntilEnd), llvm::cl::cat(mainCategory)); -// LUT-k parameter. This needs to be unifined to a more fine-grained target -// architecture information. +// LUT-k parameter. This needs to be extended to provide more fine-grained +// target architecture information. static cl::opt lutSize("lut-size", cl::desc("Size of LUT to use for mapping"), cl::init(6), cl::cat(mainCategory)); @@ -96,7 +96,7 @@ static bool untilReached(Until until) { //===----------------------------------------------------------------------===// // Tool implementation -//===-----------------------------------------------------------------------===// +//===----------------------------------------------------------------------===// static void populateSynthesisPipeline(PassManager &pm) { auto &mpm = pm.nest(); @@ -112,8 +112,8 @@ static void populateSynthesisPipeline(PassManager &pm) { if (untilReached(UntilAIGOpt)) return; - mpm.addPass(aig::createLowerVariadicPass()); - mpm.addPass(aig::createLowerWordToBitsPass()); + mpm.addPass(aig::createLowerVariadic()); + mpm.addPass(aig::createLowerWordToBits()); mpm.addPass(createCSEPass()); mpm.addPass(createSimpleCanonicalizerPass()); @@ -124,11 +124,11 @@ static void populateSynthesisPipeline(PassManager &pm) { mpm.addPass(createCSEPass()); aig::GreedyCutDecompOptions options; options.cutSizes = lutSize; - mpm.addPass(aig::createGreedyCutDecompPass(options)); - mpm.addPass(aig::createLowerCutToLUTPass()); + mpm.addPass(aig::createGreedyCutDecomp(options)); + mpm.addPass(aig::createLowerCutToLUT()); } -/// This functions initializes the various components of the tool and +/// This function initializes the various components of the tool and /// orchestrates the work to be done. static LogicalResult executeSynthesis(MLIRContext &context) { // Create the timing manager we use to sample execution times.