Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SV][ExportVerilog] Add sv.func, sv.func.call{.procedural}, sv.func.dpi.import #6977

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/circt/Conversion/ExportVerilog.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@
#include "mlir/Pass/Pass.h"

namespace circt {
namespace hw {
class HWModuleLike;
} // namespace hw

std::unique_ptr<mlir::Pass>
createTestApplyLoweringOptionPass(llvm::StringRef options);
Expand Down
4 changes: 2 additions & 2 deletions include/circt/Conversion/Passes.td
Original file line number Diff line number Diff line change
Expand Up @@ -118,8 +118,8 @@ def HWLowerInstanceChoices : Pass<"hw-lower-instance-choices",
];
}

def PrepareForEmission : Pass<"prepare-for-emission",
"hw::HWModuleOp"> {
def PrepareForEmission : InterfacePass<"prepare-for-emission",
"hw::HWModuleLike"> {
let summary = "Prepare IR for ExportVerilog";
let description = [{
This pass runs only PrepareForEmission.
Expand Down
10 changes: 10 additions & 0 deletions include/circt/Dialect/HW/ModuleImplementation.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "circt/Dialect/HW/HWTypes.h"
#include "circt/Support/LLVM.h"
#include "mlir/IR/DialectImplementation.h"
#include "mlir/IR/OpImplementation.h"

namespace circt {
namespace hw {
Expand Down Expand Up @@ -50,7 +51,16 @@ void printModuleSignature(OpAsmPrinter &p, Operation *op,
ParseResult parseModuleSignature(OpAsmParser &parser,
SmallVectorImpl<PortParse> &args,
TypeAttr &modType);

void printModuleSignatureNew(OpAsmPrinter &p, Region &body,
hw::ModuleType modType,
ArrayRef<Attribute> portAttrs,
ArrayRef<Location> locAttrs);
void printModuleSignatureNew(OpAsmPrinter &p, HWModuleLike op);
void getAsmBlockArgumentNamesImpl(mlir::Region &region,
OpAsmSetValueNameFn setNameFn);

SmallVector<Location> getAllPortLocsImpl(hw::ModuleType modType);

} // namespace module_like_impl
} // namespace hw
Expand Down
2 changes: 1 addition & 1 deletion include/circt/Dialect/SV/SVDialect.td
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ def SVDialect : Dialect {
This dialect defines the `sv` dialect, which represents various
SystemVerilog-specific constructs in an AST-like representation.
}];
let dependentDialects = ["circt::comb::CombDialect"];
let dependentDialects = ["circt::comb::CombDialect", "circt::hw::HWDialect"];

let useDefaultTypePrinterParser = 1;
let useDefaultAttributePrinterParser = 1;
Expand Down
178 changes: 178 additions & 0 deletions include/circt/Dialect/SV/SVStatements.td
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,9 @@

include "mlir/IR/EnumAttr.td"
include "mlir/IR/OpAsmInterface.td"
include "mlir/Interfaces/FunctionInterfaces.td"
include "mlir/Interfaces/ControlFlowInterfaces.td"
include "circt/Dialect/Emit/EmitOpInterfaces.td"

//===----------------------------------------------------------------------===//
// Control flow like-operations
Expand Down Expand Up @@ -879,3 +882,178 @@ def MacroDefOp : SVOp<"macro.def",
MacroDeclOp getReferencedMacro(const hw::HWSymbolCache *cache);
}];
}


//===----------------------------------------------------------------------===//
// Function/Call
//===----------------------------------------------------------------------===//

def FuncDPIImportOp: SVOp<"func.dpi.import",
[DeclareOpInterfaceMethods<SymbolUserOpInterface>]> {
let summary = "Emit a dpi import statement. See SV spec 35.4";

let arguments = (ins FlatSymbolRefAttr:$callee,
OptionalAttr<StrAttr>: $linkage_name);
let results = (outs);

let assemblyFormat = "(`linkage` $linkage_name^)? $callee attr-dict";
}

def FuncOp : SVOp<"func",
[IsolatedFromAbove, Symbol, OpAsmOpInterface, ProceduralRegion,
DeclareOpInterfaceMethods<HWModuleLike>,
DeclareOpInterfaceMethods<PortList>,
FunctionOpInterface, HasParent<"mlir::ModuleOp">]> {
let summary = "A System Verilog function";
let description = [{
`sv.func` reresents System Verilog function in SV spec 13.4.
Similar to HW module, it's allowed to mix the order of input
and output arguments. `sv.func` can be used for both function
declaration and definition, i.e. a function without a body
region is a declaration.

In SV there are two representations for function results,
"output argument" and "return value". Currently an output argument
is considered as as a return value if it's is the last argument
and has a special attribute `sv.func.explicitly_returned`.
}];

let arguments = (ins
SymbolNameAttr:$sym_name,
TypeAttrOf<ModuleType>:$module_type,
OptionalAttr<DictArrayAttr>:$per_argument_attrs,
OptionalAttr<LocationArrayAttr>:$input_locs, // Null for actual definition.
OptionalAttr<LocationArrayAttr>:$result_locs,
OptionalAttr<StrAttr>:$verilogName
);

let results = (outs);
let regions = (region AnyRegion:$body);

let hasCustomAssemblyFormat = 1;
let extraClassDeclaration = [{
static mlir::StringRef getExplicitlyReturnedAttrName() {
return "sv.func.explicitly_returned";
}

mlir::FunctionType getFunctionType() {
return getModuleType().getFuncType();
}

void setFunctionTypeAttr(mlir::TypeAttr mlirType) {
setModuleType(cast<hw::ModuleType>(mlirType.getValue()));
}

/// Returns the argument types of this function.
ArrayRef<Type> getArgumentTypes() { return getFunctionType().getInputs(); }

/// Returns the result types of this function.
ArrayRef<Type> getResultTypes() { return getFunctionType().getResults(); }

Type getExplicitlyReturnedType();

size_t getNumOutputs() {
return getResultTypes().size();
}

size_t getNumInputs() {
return getArgumentTypes().size();
}

::mlir::Region *getCallableRegion() { return isExternal() ? nullptr : &getBody(); }
bool isDeclaration() { return isExternal(); }

/// OpAsmInterface
void getAsmBlockArgumentNames(mlir::Region &region,
mlir::OpAsmSetValueNameFn setNameFn);
SmallVector<hw::PortInfo> getPortList(bool excludeExplicitReturn);
}];
let extraClassDefinition = [{
hw::ModuleType $cppClass::getHWModuleType() {
return getModuleType();
}
void $cppClass::setHWModuleType(hw::ModuleType type) {
return setModuleType(type);
}
void $cppClass::setAllPortNames(llvm::ArrayRef<mlir::Attribute>) {
}

size_t $cppClass::getNumPorts() {
auto modty = getHWModuleType();
return modty.getNumPorts();
}

size_t $cppClass::getNumInputPorts() {
auto modty = getHWModuleType();
return modty.getNumInputs();
}

size_t $cppClass::getNumOutputPorts() {
auto modty = getHWModuleType();
return modty.getNumOutputs();
}

size_t $cppClass::getPortIdForInputId(size_t idx) {
auto modty = getHWModuleType();
return modty.getPortIdForInputId(idx);
}

size_t $cppClass::getPortIdForOutputId(size_t idx) {
auto modty = getHWModuleType();
return modty.getPortIdForOutputId(idx);
}
}];
}

class SVFuncCallBase<string mnemonic, list<Trait> traits = []>: SVOp<mnemonic,
traits # [CallOpInterface, DeclareOpInterfaceMethods<SymbolUserOpInterface>]> {

let arguments = (ins FlatSymbolRefAttr:$callee, Variadic<AnyType>:$inputs);
let results = (outs Variadic<AnyType>);

let assemblyFormat =
"$callee `(` $inputs `)` attr-dict `:` functional-type($inputs, results)";

let extraClassDeclaration = [{
Value getExplicitlyReturnedValue(sv::FuncOp op);

operand_range getArgOperands() {
return getInputs();
}
MutableOperandRange getArgOperandsMutable() {
return getInputsMutable();
}
mlir::CallInterfaceCallable getCallableForCallee() {
return (*this)->getAttrOfType<mlir::SymbolRefAttr>("callee");
}

/// Set the callee for this operation.
void setCalleeFromCallable(mlir::CallInterfaceCallable callee) {
(*this)->setAttr(getCalleeAttrName(), callee.get<mlir::SymbolRefAttr>());
}
}];
}

def FuncCallProceduralOp : SVFuncCallBase<"func.call.procedural", [ProceduralOp]> {
let summary = "Function call in a procedural region";
}

def FuncCallOp : SVFuncCallBase<"func.call", [NonProceduralOp]> {
let summary = "Function call in a non-procedural region";
let description = [{
This op represents a function call in a non-procedural region.
A function call in a non-procedural region must have a return
value and no output argument.
}];
}

def ReturnOp : SVOp<"return",
[Pure, ReturnLike, Terminator, HasParent<"FuncOp">]> {
let summary = "Function return operation";

let arguments = (ins Variadic<AnyType>:$operands);

let hasCustomAssemblyFormat = 1;
let assemblyFormat = "attr-dict ($operands^ `:` type($operands))?";
let hasVerifier = 1;
}
11 changes: 9 additions & 2 deletions include/circt/Dialect/SV/SVVisitors.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,11 +39,13 @@ class Visitor {
AlwaysCombOp, AlwaysFFOp, InitialOp, CaseOp,
// Other Statements.
AssignOp, BPAssignOp, PAssignOp, ForceOp, ReleaseOp, AliasOp,
FWriteOp, SystemFunctionOp, VerbatimOp,
FWriteOp, SystemFunctionOp, VerbatimOp, FuncCallOp,
FuncCallProceduralOp, ReturnOp,
// Type declarations.
InterfaceOp, InterfaceSignalOp, InterfaceModportOp,
InterfaceInstanceOp, GetModportOp, AssignInterfaceSignalOp,
ReadInterfaceSignalOp, MacroDeclOp, MacroDefOp,
ReadInterfaceSignalOp, MacroDeclOp, MacroDefOp, FuncDPIImportOp,
FuncOp,
// Verification statements.
AssertOp, AssumeOp, CoverOp, AssertConcurrentOp, AssumeConcurrentOp,
CoverConcurrentOp,
Expand Down Expand Up @@ -127,6 +129,9 @@ class Visitor {
HANDLE(AliasOp, Unhandled);
HANDLE(FWriteOp, Unhandled);
HANDLE(SystemFunctionOp, Unhandled);
HANDLE(FuncCallProceduralOp, Unhandled);
HANDLE(FuncCallOp, Unhandled);
HANDLE(ReturnOp, Unhandled);
HANDLE(VerbatimOp, Unhandled);

// Type declarations.
Expand All @@ -139,6 +144,8 @@ class Visitor {
HANDLE(ReadInterfaceSignalOp, Unhandled);
HANDLE(MacroDefOp, Unhandled);
HANDLE(MacroDeclOp, Unhandled);
HANDLE(FuncDPIImportOp, Unhandled);
HANDLE(FuncOp, Unhandled);

// Verification statements.
HANDLE(AssertOp, Unhandled);
Expand Down
Loading
Loading