Skip to content

Commit

Permalink
[HW] [NFC] Extract out printing/parsing functions for modules (#1773)
Browse files Browse the repository at this point in the history
  • Loading branch information
teqdruid committed Sep 15, 2021
1 parent 4730fe8 commit af8b1f5
Show file tree
Hide file tree
Showing 4 changed files with 233 additions and 89 deletions.
59 changes: 59 additions & 0 deletions include/circt/Dialect/HW/ModuleImplementation.h
@@ -0,0 +1,59 @@
//===- ModuleImplementation.h - Module-like Op utilities --------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//
//
// This file provides utility functions for implementing module-like
// operations, in particular, parsing, and printing common to module-like
// operations.
//
//===----------------------------------------------------------------------===//

#ifndef CIRCT_DIALECT_HW_MODULEIMPLEMENTATION_H
#define CIRCT_DIALECT_HW_MODULEIMPLEMENTATION_H

#include "circt/Support/LLVM.h"

#include "mlir/IR/DialectImplementation.h"

namespace circt {
namespace hw {

namespace module_like_impl {

/// Parse a portname as a keyword or a quote surrounded string, followed by a
/// colon.
StringAttr parsePortName(OpAsmParser &parser);

/// Get the portname from an SSA value string, if said value name is not a
/// number.
StringAttr getPortNameAttr(MLIRContext *context, StringRef name);

/// This is a variant of mlor::parseFunctionSignature that allows names on
/// result arguments.
ParseResult parseModuleFunctionSignature(
OpAsmParser &parser, SmallVectorImpl<OpAsmParser::OperandType> &argNames,
SmallVectorImpl<Type> &argTypes, SmallVectorImpl<NamedAttrList> &argAttrs,
bool &isVariadic, SmallVectorImpl<Type> &resultTypes,
SmallVectorImpl<NamedAttrList> &resultAttrs,
SmallVectorImpl<Attribute> &resultNames);

/// Parse a function result list with named results.
ParseResult parseFunctionResultList(OpAsmParser &parser,
SmallVectorImpl<Type> &resultTypes,
SmallVectorImpl<NamedAttrList> &resultAttrs,
SmallVectorImpl<Attribute> &resultNames);

/// Print a module signature with named results.
void printModuleSignature(OpAsmPrinter &p, Operation *op,
ArrayRef<Type> argTypes, bool isVariadic,
ArrayRef<Type> resultTypes, bool &needArgNamesAttr);

} // namespace module_like_impl
} // namespace hw
} // namespace circt

#endif // CIRCT_DIALECT_HW_MODULEIMPLEMENTATION_H
6 changes: 4 additions & 2 deletions lib/Dialect/HW/CMakeLists.txt
@@ -1,6 +1,8 @@
file(GLOB globbed *.cpp)
add_circt_dialect_library(CIRCTHW
${globbed}
HWDialect.cpp
HWOps.cpp
HWTypes.cpp
ModuleImplementation.cpp

ADDITIONAL_HEADER_DIRS
${CIRCT_MAIN_INCLUDE_DIR}/circt/Dialect/HW
Expand Down
94 changes: 7 additions & 87 deletions lib/Dialect/HW/HWOps.cpp
Expand Up @@ -13,6 +13,7 @@
#include "circt/Dialect/HW/HWOps.h"
#include "circt/Dialect/Comb/CombOps.h"
#include "circt/Dialect/HW/HWVisitors.h"
#include "circt/Dialect/HW/ModuleImplementation.h"
#include "mlir/IR/Builders.h"
#include "mlir/IR/FunctionImplementation.h"

Expand All @@ -31,19 +32,6 @@ static bool isValidKeyword(StringRef name) {
return true;
}

// Parse a portname as a keyword or a quote surrounded string, followed by a
// colon.
static StringAttr parsePortName(OpAsmParser &parser) {
StringAttr result;
StringRef keyword;
if (succeeded(parser.parseOptionalKeyword(&keyword))) {
result = parser.getBuilder().getStringAttr(keyword);
} else if (parser.parseAttribute(result,
parser.getBuilder().getType<NoneType>()))
return {};
return succeeded(parser.parseColon()) ? result : StringAttr();
}

/// Return true if the specified operation is a combinatorial logic op.
bool hw::isCombinatorial(Operation *op) {
struct IsCombClassifier : public TypeOpVisitor<IsCombClassifier, bool> {
Expand Down Expand Up @@ -385,74 +373,6 @@ SmallVector<PortInfo> hw::getAllModulePortInfos(Operation *op) {
return results;
}

static StringAttr getPortNameAttr(MLIRContext *context, StringRef name) {
if (!name.empty()) {
// Ignore numeric names like %42
assert(name.size() > 1 && name[0] == '%' && "Unknown MLIR name");
if (isdigit(name[1]))
name = StringRef();
else
name = name.drop_front();
}
return StringAttr::get(context, name);
}

/// Parse a function result list.
///
/// function-result-list ::= function-result-list-parens
/// function-result-list-parens ::= `(` `)`
/// | `(` function-result-list-no-parens `)`
/// function-result-list-no-parens ::= function-result (`,` function-result)*
/// function-result ::= (percent-identifier `:`) type attribute-dict?
///
static ParseResult
parseFunctionResultList(OpAsmParser &parser, SmallVectorImpl<Type> &resultTypes,
SmallVectorImpl<NamedAttrList> &resultAttrs,
SmallVectorImpl<Attribute> &resultNames) {
if (parser.parseLParen())
return failure();

// Special case for an empty set of parens.
if (succeeded(parser.parseOptionalRParen()))
return success();

// Parse individual function results.
do {
resultNames.push_back(parsePortName(parser));
if (!resultNames.back())
return failure();

resultTypes.emplace_back();
resultAttrs.emplace_back();
if (parser.parseType(resultTypes.back()) ||
parser.parseOptionalAttrDict(resultAttrs.back()))
return failure();
} while (succeeded(parser.parseOptionalComma()));
return parser.parseRParen();
}

/// This is a variant of mlor::parseFunctionSignature that allows names on
/// result arguments.
static ParseResult parseModuleFunctionSignature(
OpAsmParser &parser, SmallVectorImpl<OpAsmParser::OperandType> &argNames,
SmallVectorImpl<Type> &argTypes, SmallVectorImpl<NamedAttrList> &argAttrs,
bool &isVariadic, SmallVectorImpl<Type> &resultTypes,
SmallVectorImpl<NamedAttrList> &resultAttrs,
SmallVectorImpl<Attribute> &resultNames) {

using namespace mlir::function_like_impl;
bool allowArgAttrs = true;
bool allowVariadic = false;
if (parseFunctionArgumentList(parser, allowArgAttrs, allowVariadic, argNames,
argTypes, argAttrs, isVariadic))
return failure();

if (succeeded(parser.parseOptionalArrow()))
return parseFunctionResultList(parser, resultTypes, resultAttrs,
resultNames);
return success();
}

static bool hasAttribute(StringRef name, ArrayRef<NamedAttribute> attrs) {
for (auto &argAttr : attrs)
if (argAttr.first == name)
Expand Down Expand Up @@ -490,9 +410,9 @@ static ParseResult parseHWModuleOp(OpAsmParser &parser, OperationState &result,
// Parse the function signature.
bool isVariadic = false;
SmallVector<Attribute> resultNames;
if (parseModuleFunctionSignature(parser, entryArgs, argTypes, argAttrs,
isVariadic, resultTypes, resultAttrs,
resultNames))
if (module_like_impl::parseModuleFunctionSignature(
parser, entryArgs, argTypes, argAttrs, isVariadic, resultTypes,
resultAttrs, resultNames))
return failure();

// Record the argument and result types as an attribute. This is necessary
Expand All @@ -517,7 +437,7 @@ static ParseResult parseHWModuleOp(OpAsmParser &parser, OperationState &result,
SmallVector<Attribute> argNames;
if (!entryArgs.empty()) {
for (auto &arg : entryArgs)
argNames.push_back(getPortNameAttr(context, arg.name));
argNames.push_back(module_like_impl::getPortNameAttr(context, arg.name));
} else if (!argTypes.empty()) {
// The parser returns empty names in a special way.
argNames.assign(argTypes.size(), StringAttr::get(context, ""));
Expand Down Expand Up @@ -907,7 +827,7 @@ static ParseResult parseInstanceOp(OpAsmParser &parser,
result.attributes) ||
parser.getCurrentLocation(&inputsOperandsLoc) ||
parseCommaSeparatedList([&]() -> ParseResult {
argNames.push_back(parsePortName(parser));
argNames.push_back(module_like_impl::parsePortName(parser));
if (!argNames.back())
return failure();
inputsOperands.push_back({});
Expand All @@ -919,7 +839,7 @@ static ParseResult parseInstanceOp(OpAsmParser &parser,
parser.resolveOperands(inputsOperands, inputsTypes, inputsOperandsLoc,
result.operands) ||
parser.parseArrow() || parseCommaSeparatedList([&]() -> ParseResult {
resultNames.push_back(parsePortName(parser));
resultNames.push_back(module_like_impl::parsePortName(parser));
if (!resultNames.back())
return failure();
allResultTypes.push_back({});
Expand Down
163 changes: 163 additions & 0 deletions lib/Dialect/HW/ModuleImplementation.cpp
@@ -0,0 +1,163 @@
//===- ModuleImplementation.cpp - Utilities for module-like ops -----------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "circt/Dialect/HW/ModuleImplementation.h"
#include "circt/Dialect/HW/HWOps.h"
#include "circt/Support/LLVM.h"

#include "mlir/IR/Builders.h"
#include "mlir/IR/DialectImplementation.h"
#include "mlir/IR/FunctionImplementation.h"

using namespace mlir;
using namespace circt::hw;

/// Get the portname from an SSA value string, if said value name is not a
/// number
StringAttr module_like_impl::getPortNameAttr(MLIRContext *context,
StringRef name) {
if (!name.empty()) {
// Ignore numeric names like %42
assert(name.size() > 1 && name[0] == '%' && "Unknown MLIR name");
if (isdigit(name[1]))
name = StringRef();
else
name = name.drop_front();
}
return StringAttr::get(context, name);
}

/// Parse a portname as a keyword or a quote surrounded string, followed by a
/// colon.
StringAttr module_like_impl::parsePortName(OpAsmParser &parser) {
StringAttr result;
StringRef keyword;
if (succeeded(parser.parseOptionalKeyword(&keyword))) {
result = parser.getBuilder().getStringAttr(keyword);
} else if (parser.parseAttribute(result,
parser.getBuilder().getType<NoneType>()))
return {};
return succeeded(parser.parseColon()) ? result : StringAttr();
}

/// Parse a function result list.
///
/// function-result-list ::= function-result-list-parens
/// function-result-list-parens ::= `(` `)`
/// | `(` function-result-list-no-parens `)`
/// function-result-list-no-parens ::= function-result (`,` function-result)*
/// function-result ::= (percent-identifier `:`) type attribute-dict?
///
ParseResult module_like_impl::parseFunctionResultList(
OpAsmParser &parser, SmallVectorImpl<Type> &resultTypes,
SmallVectorImpl<NamedAttrList> &resultAttrs,
SmallVectorImpl<Attribute> &resultNames) {
if (parser.parseLParen())
return failure();

// Special case for an empty set of parens.
if (succeeded(parser.parseOptionalRParen()))
return success();

// Parse individual function results.
do {
resultNames.push_back(parsePortName(parser));
if (!resultNames.back())
return failure();

resultTypes.emplace_back();
resultAttrs.emplace_back();
if (parser.parseType(resultTypes.back()) ||
parser.parseOptionalAttrDict(resultAttrs.back()))
return failure();
} while (succeeded(parser.parseOptionalComma()));
return parser.parseRParen();
}

/// This is a variant of mlor::parseFunctionSignature that allows names on
/// result arguments.
ParseResult module_like_impl::parseModuleFunctionSignature(
OpAsmParser &parser, SmallVectorImpl<OpAsmParser::OperandType> &argNames,
SmallVectorImpl<Type> &argTypes, SmallVectorImpl<NamedAttrList> &argAttrs,
bool &isVariadic, SmallVectorImpl<Type> &resultTypes,
SmallVectorImpl<NamedAttrList> &resultAttrs,
SmallVectorImpl<Attribute> &resultNames) {

using namespace mlir::function_like_impl;
bool allowArgAttrs = true;
bool allowVariadic = false;
if (parseFunctionArgumentList(parser, allowArgAttrs, allowVariadic, argNames,
argTypes, argAttrs, isVariadic))
return failure();

if (succeeded(parser.parseOptionalArrow()))
return parseFunctionResultList(parser, resultTypes, resultAttrs,
resultNames);
return success();
}

void circt::hw::module_like_impl::printModuleSignature(
OpAsmPrinter &p, Operation *op, ArrayRef<Type> argTypes, bool isVariadic,
ArrayRef<Type> resultTypes, bool &needArgNamesAttr) {
Region &body = op->getRegion(0);
bool isExternal = body.empty();
SmallString<32> resultNameStr;

p << '(';
for (unsigned i = 0, e = argTypes.size(); i < e; ++i) {
if (i > 0)
p << ", ";

auto argName = getModuleArgumentName(op, i);

if (!isExternal) {
// Get the printed format for the argument name.
resultNameStr.clear();
llvm::raw_svector_ostream tmpStream(resultNameStr);
p.printOperand(body.front().getArgument(i), tmpStream);

// If the name wasn't printable in a way that agreed with argName, make
// sure to print out an explicit argNames attribute.
if (tmpStream.str().drop_front() != argName)
needArgNamesAttr = true;

p << tmpStream.str() << ": ";
} else if (!argName.empty()) {
p << '%' << argName << ": ";
}

p.printType(argTypes[i]);
p.printOptionalAttrDict(::mlir::function_like_impl::getArgAttrs(op, i));
}

if (isVariadic) {
if (!argTypes.empty())
p << ", ";
p << "...";
}

p << ')';

// We print result types specially since we support named arguments.
if (!resultTypes.empty()) {
auto &os = p.getStream();
os << " -> (";
for (size_t i = 0, e = resultTypes.size(); i < e; ++i) {
if (i != 0)
os << ", ";
StringRef name = getModuleResultName(op, i);
if (!name.empty())
os << '%' << name << ": ";

p.printType(resultTypes[i]);
p.printOptionalAttrDict(
::mlir::function_like_impl::getResultAttrs(op, i));
}
os << ')';
}
}

0 comments on commit af8b1f5

Please sign in to comment.