Skip to content

Commit

Permalink
[SV] Add sv.func, sv.func.call{.procedural}, sv.func.dpi.import
Browse files Browse the repository at this point in the history
  • Loading branch information
uenoku committed May 8, 2024
1 parent bdc8503 commit e5c706f
Show file tree
Hide file tree
Showing 21 changed files with 1,028 additions and 55 deletions.
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

0 comments on commit e5c706f

Please sign in to comment.