mirror of https://github.com/llvm/circt.git
Bump LLVM to 7ce613fc77af092dd6e9db71ce3747b75bc5616e (#6342)
This commit is contained in:
parent
58662f4415
commit
34c320f474
|
@ -165,7 +165,7 @@ public:
|
|||
/// Remove the NLA from the Module. This updates the module name to NLA
|
||||
/// tracking.
|
||||
void removeNLAfromModule(hw::HierPathOp nla, StringAttr mod) {
|
||||
llvm::erase_value(nodeMap[mod], nla);
|
||||
llvm::erase(nodeMap[mod], nla);
|
||||
}
|
||||
|
||||
/// Remove all the nlas in the set `nlas` from the module. This updates the
|
||||
|
|
|
@ -71,7 +71,6 @@ declare_mlir_dialect_python_bindings(
|
|||
TD_FILE dialects/CombOps.td
|
||||
SOURCES
|
||||
dialects/comb.py
|
||||
dialects/_comb_ops_ext.py
|
||||
DIALECT_NAME comb)
|
||||
|
||||
declare_mlir_dialect_python_bindings(
|
||||
|
@ -80,7 +79,6 @@ declare_mlir_dialect_python_bindings(
|
|||
TD_FILE dialects/ESIOps.td
|
||||
SOURCES
|
||||
dialects/esi.py
|
||||
dialects/_esi_ops_ext.py
|
||||
DIALECT_NAME esi)
|
||||
|
||||
declare_mlir_dialect_python_bindings(
|
||||
|
@ -89,7 +87,6 @@ declare_mlir_dialect_python_bindings(
|
|||
TD_FILE dialects/HWOps.td
|
||||
SOURCES
|
||||
dialects/hw.py
|
||||
dialects/_hw_ops_ext.py
|
||||
DIALECT_NAME hw)
|
||||
|
||||
declare_mlir_dialect_python_bindings(
|
||||
|
@ -98,7 +95,6 @@ declare_mlir_dialect_python_bindings(
|
|||
TD_FILE dialects/MSFTOps.td
|
||||
SOURCES
|
||||
dialects/msft.py
|
||||
dialects/_msft_ops_ext.py
|
||||
DIALECT_NAME msft)
|
||||
|
||||
declare_mlir_dialect_python_bindings(
|
||||
|
@ -115,7 +111,6 @@ declare_mlir_dialect_python_bindings(
|
|||
TD_FILE dialects/SeqOps.td
|
||||
SOURCES
|
||||
dialects/seq.py
|
||||
dialects/_seq_ops_ext.py
|
||||
DIALECT_NAME seq)
|
||||
|
||||
declare_mlir_dialect_python_bindings(
|
||||
|
@ -124,7 +119,6 @@ declare_mlir_dialect_python_bindings(
|
|||
TD_FILE dialects/SVOps.td
|
||||
SOURCES
|
||||
dialects/sv.py
|
||||
dialects/_sv_ops_ext.py
|
||||
DIALECT_NAME sv)
|
||||
|
||||
declare_mlir_dialect_python_bindings(
|
||||
|
@ -133,7 +127,6 @@ declare_mlir_dialect_python_bindings(
|
|||
TD_FILE dialects/FSMOps.td
|
||||
SOURCES
|
||||
dialects/fsm.py
|
||||
dialects/_fsm_ops_ext.py
|
||||
DIALECT_NAME fsm)
|
||||
|
||||
declare_mlir_dialect_python_bindings(
|
||||
|
@ -142,7 +135,6 @@ declare_mlir_dialect_python_bindings(
|
|||
TD_FILE dialects/HWArithOps.td
|
||||
SOURCES
|
||||
dialects/hwarith.py
|
||||
dialects/_hwarith_ops_ext.py
|
||||
DIALECT_NAME hwarith)
|
||||
|
||||
declare_mlir_dialect_python_bindings(
|
||||
|
|
|
@ -1,178 +0,0 @@
|
|||
from . import comb
|
||||
from ..support import NamedValueOpView, get_value
|
||||
from ..ir import IntegerAttr, IntegerType
|
||||
|
||||
|
||||
# Builder base classes for non-variadic unary and binary ops.
|
||||
class UnaryOpBuilder(NamedValueOpView):
|
||||
|
||||
def operand_names(self):
|
||||
return ["input"]
|
||||
|
||||
def result_names(self):
|
||||
return ["result"]
|
||||
|
||||
|
||||
def UnaryOp(base):
|
||||
|
||||
class _Class(base):
|
||||
|
||||
@classmethod
|
||||
def create(cls, input=None, result_type=None):
|
||||
mapping = {"input": input} if input else {}
|
||||
return UnaryOpBuilder(cls, result_type, mapping)
|
||||
|
||||
return _Class
|
||||
|
||||
|
||||
class ExtractOpBuilder(UnaryOpBuilder):
|
||||
|
||||
def __init__(self, low_bit, data_type, input_port_mapping={}, **kwargs):
|
||||
low_bit = IntegerAttr.get(IntegerType.get_signless(32), low_bit)
|
||||
super().__init__(comb.ExtractOp, data_type, input_port_mapping, [],
|
||||
[low_bit], **kwargs)
|
||||
|
||||
|
||||
class BinaryOpBuilder(NamedValueOpView):
|
||||
|
||||
def operand_names(self):
|
||||
return ["lhs", "rhs"]
|
||||
|
||||
def result_names(self):
|
||||
return ["result"]
|
||||
|
||||
|
||||
def BinaryOp(base):
|
||||
|
||||
class _Class(base):
|
||||
|
||||
@classmethod
|
||||
def create(cls, lhs=None, rhs=None, result_type=None):
|
||||
mapping = {}
|
||||
if lhs:
|
||||
mapping["lhs"] = lhs
|
||||
if rhs:
|
||||
mapping["rhs"] = rhs
|
||||
return BinaryOpBuilder(cls, result_type, mapping)
|
||||
|
||||
return _Class
|
||||
|
||||
|
||||
# Base classes for the variadic ops.
|
||||
def VariadicOp(base):
|
||||
|
||||
class _Class(base):
|
||||
|
||||
@classmethod
|
||||
def create(cls, *args):
|
||||
return cls([get_value(a) for a in args])
|
||||
|
||||
return _Class
|
||||
|
||||
|
||||
# Base class for miscellaneous ops that can't be abstracted but should provide a
|
||||
# create method for uniformity.
|
||||
def CreatableOp(base):
|
||||
|
||||
class _Class(base):
|
||||
|
||||
@classmethod
|
||||
def create(cls, *args, **kwargs):
|
||||
return cls(*args, **kwargs)
|
||||
|
||||
return _Class
|
||||
|
||||
|
||||
# Sugar classes for the various non-variadic unary ops.
|
||||
class ExtractOp:
|
||||
|
||||
@staticmethod
|
||||
def create(low_bit, result_type, input=None):
|
||||
mapping = {"input": input} if input else {}
|
||||
return ExtractOpBuilder(low_bit,
|
||||
result_type,
|
||||
mapping,
|
||||
needs_result_type=True)
|
||||
|
||||
|
||||
@UnaryOp
|
||||
class ParityOp:
|
||||
pass
|
||||
|
||||
|
||||
# Sugar classes for the various non-variadic binary ops.
|
||||
@BinaryOp
|
||||
class DivSOp:
|
||||
pass
|
||||
|
||||
|
||||
@BinaryOp
|
||||
class DivUOp:
|
||||
pass
|
||||
|
||||
|
||||
@BinaryOp
|
||||
class ModSOp:
|
||||
pass
|
||||
|
||||
|
||||
@BinaryOp
|
||||
class ModUOp:
|
||||
pass
|
||||
|
||||
|
||||
@BinaryOp
|
||||
class ShlOp:
|
||||
pass
|
||||
|
||||
|
||||
@BinaryOp
|
||||
class ShrSOp:
|
||||
pass
|
||||
|
||||
|
||||
@BinaryOp
|
||||
class ShrUOp:
|
||||
pass
|
||||
|
||||
|
||||
@BinaryOp
|
||||
class SubOp:
|
||||
pass
|
||||
|
||||
|
||||
# Sugar classes for the variadic ops.
|
||||
@VariadicOp
|
||||
class AddOp:
|
||||
pass
|
||||
|
||||
|
||||
@VariadicOp
|
||||
class MulOp:
|
||||
pass
|
||||
|
||||
|
||||
@VariadicOp
|
||||
class AndOp:
|
||||
pass
|
||||
|
||||
|
||||
@VariadicOp
|
||||
class OrOp:
|
||||
pass
|
||||
|
||||
|
||||
@VariadicOp
|
||||
class XorOp:
|
||||
pass
|
||||
|
||||
|
||||
@VariadicOp
|
||||
class ConcatOp:
|
||||
pass
|
||||
|
||||
|
||||
# Sugar classes for miscellaneous ops.
|
||||
@CreatableOp
|
||||
class MuxOp:
|
||||
pass
|
|
@ -1,44 +0,0 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import Dict, List, Optional, Sequence, Type
|
||||
|
||||
from . import esi
|
||||
from .. import support
|
||||
|
||||
from .. import ir
|
||||
|
||||
|
||||
class RequestToServerConnectionOp:
|
||||
|
||||
@property
|
||||
def clientNamePath(self) -> List[str]:
|
||||
return [
|
||||
ir.StringAttr(x).value
|
||||
for x in ir.ArrayAttr(self.attributes["clientNamePath"])
|
||||
]
|
||||
|
||||
|
||||
class RequestToClientConnectionOp:
|
||||
|
||||
@property
|
||||
def clientNamePath(self) -> List[str]:
|
||||
return [
|
||||
ir.StringAttr(x).value
|
||||
for x in ir.ArrayAttr(self.attributes["clientNamePath"])
|
||||
]
|
||||
|
||||
|
||||
class RandomAccessMemoryDeclOp:
|
||||
|
||||
@property
|
||||
def innerType(self):
|
||||
return ir.TypeAttr(self.attributes["innerType"])
|
||||
|
||||
|
||||
class ESIPureModuleOp:
|
||||
|
||||
def add_entry_block(self):
|
||||
if len(self.body.blocks) > 0:
|
||||
raise IndexError('The module already has an entry block')
|
||||
self.body.blocks.append()
|
||||
return self.body.blocks[0]
|
|
@ -1,167 +0,0 @@
|
|||
# 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
|
||||
|
||||
from . import fsm as fsm
|
||||
from .. import support
|
||||
from ..ir import *
|
||||
|
||||
|
||||
def _get_or_add_single_block(region, args=[]):
|
||||
if len(region.blocks) == 0:
|
||||
region.blocks.append(*args)
|
||||
return region.blocks[0]
|
||||
|
||||
|
||||
class MachineOp:
|
||||
|
||||
def __init__(self,
|
||||
name,
|
||||
initial_state,
|
||||
input_ports,
|
||||
output_ports,
|
||||
*,
|
||||
attributes={},
|
||||
loc=None,
|
||||
ip=None):
|
||||
attributes["sym_name"] = StringAttr.get(name)
|
||||
attributes["initialState"] = StringAttr.get(initial_state)
|
||||
|
||||
input_types = []
|
||||
output_types = []
|
||||
for (i, (_, port_type)) in enumerate(input_ports):
|
||||
input_types.append(port_type)
|
||||
|
||||
for (i, (_, port_type)) in enumerate(output_ports):
|
||||
output_types.append(port_type)
|
||||
|
||||
attributes["function_type"] = TypeAttr.get(
|
||||
FunctionType.get(inputs=input_types, results=output_types))
|
||||
|
||||
OpView.__init__(
|
||||
self,
|
||||
self.build_generic(attributes=attributes,
|
||||
results=[],
|
||||
operands=[],
|
||||
successors=None,
|
||||
regions=1,
|
||||
loc=loc,
|
||||
ip=ip))
|
||||
|
||||
_get_or_add_single_block(self.body, self.type.inputs)
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return FunctionType(TypeAttr(self.attributes["function_type"]).value)
|
||||
|
||||
def instantiate(self, name: str, loc=None, ip=None, **kwargs):
|
||||
""" FSM Instantiation function"""
|
||||
in_names = support.attribute_to_var(self.attributes['in_names'])
|
||||
inputs = [kwargs[port].value for port in in_names]
|
||||
|
||||
# Clock and resets are not part of the input ports of the FSM, but
|
||||
# it is at the point of `fsm.hw_instance` instantiation that they
|
||||
# must be connected.
|
||||
# Attach backedges to these, and associate these backedges to the operation.
|
||||
# They can then be accessed at the point of instantiation and assigned.
|
||||
clock = support.BackedgeBuilder().create(
|
||||
IntegerType.get_signed(1),
|
||||
StringAttr(self.attributes['clock_name']).value, self)
|
||||
reset = support.BackedgeBuilder().create(
|
||||
IntegerType.get_signed(1),
|
||||
StringAttr(self.attributes['reset_name']).value, self)
|
||||
|
||||
op = fsm.HWInstanceOp(outputs=self.type.results,
|
||||
inputs=inputs,
|
||||
sym_name=StringAttr.get(name),
|
||||
machine=FlatSymbolRefAttr.get(self.sym_name.value),
|
||||
clock=clock.result,
|
||||
reset=reset.result if reset else None,
|
||||
loc=loc,
|
||||
ip=ip)
|
||||
op.backedges = {}
|
||||
|
||||
def set_OpOperand(name, backedge):
|
||||
index = None
|
||||
for i, operand in enumerate(op.operands):
|
||||
if operand == backedge.result:
|
||||
index = i
|
||||
break
|
||||
assert index is not None
|
||||
op_operand = support.OpOperand(op, index, op.operands[index], op)
|
||||
setattr(op, f'_{name}_backedge', op_operand)
|
||||
op.backedges[i] = backedge
|
||||
|
||||
set_OpOperand('clock', clock)
|
||||
if reset:
|
||||
set_OpOperand('reset', reset)
|
||||
|
||||
return op
|
||||
|
||||
|
||||
class TransitionOp:
|
||||
|
||||
def __init__(self, next_state, *, loc=None, ip=None):
|
||||
attributes = {
|
||||
"nextState": FlatSymbolRefAttr.get(next_state),
|
||||
}
|
||||
super().__init__(
|
||||
self.build_generic(attributes=attributes,
|
||||
results=[],
|
||||
operands=[],
|
||||
successors=None,
|
||||
regions=2,
|
||||
loc=loc,
|
||||
ip=ip))
|
||||
|
||||
@staticmethod
|
||||
def create(to_state):
|
||||
op = fsm.TransitionOp(to_state)
|
||||
return op
|
||||
|
||||
def set_guard(self, guard_fn):
|
||||
"""Executes a function to generate a guard for the transition.
|
||||
The function is executed within the guard region of this operation."""
|
||||
guard_block = _get_or_add_single_block(self.guard)
|
||||
with InsertionPoint(guard_block):
|
||||
guard = guard_fn()
|
||||
guard_type = support.type_to_pytype(guard.type)
|
||||
if guard_type.width != 1:
|
||||
raise ValueError('The guard must be a single bit')
|
||||
fsm.ReturnOp(operand=guard)
|
||||
|
||||
|
||||
class StateOp:
|
||||
|
||||
def __init__(self, name, *, loc=None, ip=None):
|
||||
attributes = {}
|
||||
attributes["sym_name"] = StringAttr.get(name)
|
||||
|
||||
OpView.__init__(
|
||||
self,
|
||||
self.build_generic(attributes=attributes,
|
||||
results=[],
|
||||
operands=[],
|
||||
successors=None,
|
||||
regions=2,
|
||||
loc=loc,
|
||||
ip=ip))
|
||||
|
||||
@staticmethod
|
||||
def create(name):
|
||||
return fsm.StateOp(name)
|
||||
|
||||
@property
|
||||
def output(self):
|
||||
return _get_or_add_single_block(super().output)
|
||||
|
||||
@property
|
||||
def transitions(self):
|
||||
return _get_or_add_single_block(super().transitions)
|
||||
|
||||
|
||||
class OutputOp:
|
||||
|
||||
@staticmethod
|
||||
def create(*operands):
|
||||
return fsm.OutputOp(operands)
|
|
@ -1,529 +0,0 @@
|
|||
from __future__ import annotations
|
||||
|
||||
from typing import Dict, Type
|
||||
|
||||
from . import hw
|
||||
from .. import support
|
||||
from ..ir import *
|
||||
|
||||
|
||||
def create_parameters(parameters: dict[str, _ir.Attribute], module: ModuleLike):
|
||||
# Compute mapping from parameter name to index, and initialize array.
|
||||
mod_param_decls = module.parameters
|
||||
mod_param_decls_idxs = {
|
||||
decl.name: idx for (idx, decl) in enumerate(mod_param_decls)
|
||||
}
|
||||
inst_param_array = [None] * len(module.parameters)
|
||||
|
||||
# Fill in all the parameters specified.
|
||||
if isinstance(parameters, DictAttr):
|
||||
parameters = {i.name: i.attr for i in parameters}
|
||||
for (pname, pval) in parameters.items():
|
||||
if pname not in mod_param_decls_idxs:
|
||||
raise ValueError(
|
||||
f"Could not find parameter '{pname}' in module parameter decls")
|
||||
idx = mod_param_decls_idxs[pname]
|
||||
param_decl = mod_param_decls[idx]
|
||||
inst_param_array[idx] = hw.ParamDeclAttr.get(pname, param_decl.param_type,
|
||||
pval)
|
||||
|
||||
# Fill in the defaults from the module param decl.
|
||||
for (idx, pval) in enumerate(inst_param_array):
|
||||
if pval is not None:
|
||||
continue
|
||||
inst_param_array[idx] = mod_param_decls[idx]
|
||||
|
||||
return inst_param_array
|
||||
|
||||
|
||||
class InstanceBuilder(support.NamedValueOpView):
|
||||
"""Helper class to incrementally construct an instance of a module."""
|
||||
|
||||
def __init__(self,
|
||||
module,
|
||||
name,
|
||||
input_port_mapping,
|
||||
*,
|
||||
results=None,
|
||||
parameters={},
|
||||
sym_name=None,
|
||||
loc=None,
|
||||
ip=None):
|
||||
self.module = module
|
||||
instance_name = StringAttr.get(name)
|
||||
module_name = FlatSymbolRefAttr.get(StringAttr(module.name).value)
|
||||
inst_param_array = create_parameters(parameters, module)
|
||||
if sym_name:
|
||||
inner_sym = hw.InnerSymAttr.get(StringAttr.get(sym_name))
|
||||
else:
|
||||
inner_sym = None
|
||||
pre_args = [instance_name, module_name]
|
||||
post_args = [
|
||||
ArrayAttr.get([StringAttr.get(x) for x in self.operand_names()]),
|
||||
ArrayAttr.get([StringAttr.get(x) for x in self.result_names()]),
|
||||
ArrayAttr.get(inst_param_array)
|
||||
]
|
||||
if results is None:
|
||||
results = module.type.output_types
|
||||
|
||||
if not isinstance(module, hw.HWModuleExternOp):
|
||||
input_name_type_lookup = {
|
||||
name: support.type_to_pytype(ty)
|
||||
for name, ty in zip(self.operand_names(), module.type.input_types)
|
||||
}
|
||||
for input_name, input_value in input_port_mapping.items():
|
||||
if input_name not in input_name_type_lookup:
|
||||
continue # This error gets caught and raised later.
|
||||
mod_input_type = input_name_type_lookup[input_name]
|
||||
if support.type_to_pytype(input_value.type) != mod_input_type:
|
||||
raise TypeError(f"Input '{input_name}' has type '{input_value.type}' "
|
||||
f"but expected '{mod_input_type}'")
|
||||
|
||||
super().__init__(hw.InstanceOp,
|
||||
results,
|
||||
input_port_mapping,
|
||||
pre_args,
|
||||
post_args,
|
||||
needs_result_type=True,
|
||||
inner_sym=inner_sym,
|
||||
loc=loc,
|
||||
ip=ip)
|
||||
|
||||
def create_default_value(self, index, data_type, arg_name):
|
||||
type = self.module.type.input_types[index]
|
||||
return support.BackedgeBuilder.create(type,
|
||||
arg_name,
|
||||
self,
|
||||
instance_of=self.module)
|
||||
|
||||
def operand_names(self):
|
||||
return self.module.type.input_names
|
||||
|
||||
def result_names(self):
|
||||
return self.module.type.output_names
|
||||
|
||||
|
||||
class ModuleLike:
|
||||
"""Custom Python base class for module-like operations."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name,
|
||||
input_ports=[],
|
||||
output_ports=[],
|
||||
*,
|
||||
parameters=[],
|
||||
attributes={},
|
||||
body_builder=None,
|
||||
loc=None,
|
||||
ip=None,
|
||||
):
|
||||
"""
|
||||
Create a module-like with the provided `name`, `input_ports`, and
|
||||
`output_ports`.
|
||||
- `name` is a string representing the module name.
|
||||
- `input_ports` is a list of pairs of string names and mlir.ir types.
|
||||
- `output_ports` is a list of pairs of string names and mlir.ir types.
|
||||
- `body_builder` is an optional callback, when provided a new entry block
|
||||
is created and the callback is invoked with the new op as argument within
|
||||
an InsertionPoint context already set for the block. The callback is
|
||||
expected to insert a terminator in the block.
|
||||
"""
|
||||
# Copy the mutable default arguments. 'Cause python.
|
||||
input_ports = list(input_ports)
|
||||
output_ports = list(output_ports)
|
||||
parameters = list(parameters)
|
||||
attributes = dict(attributes)
|
||||
|
||||
operands = []
|
||||
results = []
|
||||
attributes["sym_name"] = StringAttr.get(str(name))
|
||||
|
||||
module_ports = []
|
||||
input_names = []
|
||||
port_locs = []
|
||||
unknownLoc = Location.unknown().attr
|
||||
for (i, (port_name, port_type)) in enumerate(input_ports):
|
||||
input_name = StringAttr.get(str(port_name))
|
||||
input_dir = hw.ModulePortDirection.INPUT
|
||||
input_port = hw.ModulePort(input_name, port_type, input_dir)
|
||||
module_ports.append(input_port)
|
||||
input_names.append(input_name)
|
||||
port_locs.append(unknownLoc)
|
||||
|
||||
output_types = []
|
||||
output_names = []
|
||||
for (i, (port_name, port_type)) in enumerate(output_ports):
|
||||
output_name = StringAttr.get(str(port_name))
|
||||
output_dir = hw.ModulePortDirection.OUTPUT
|
||||
output_port = hw.ModulePort(output_name, port_type, output_dir)
|
||||
module_ports.append(output_port)
|
||||
output_names.append(output_name)
|
||||
port_locs.append(unknownLoc)
|
||||
attributes["port_locs"] = ArrayAttr.get(port_locs)
|
||||
attributes["per_port_attrs"] = ArrayAttr.get([])
|
||||
|
||||
if len(parameters) > 0 or "parameters" not in attributes:
|
||||
attributes["parameters"] = ArrayAttr.get(parameters)
|
||||
|
||||
attributes["module_type"] = TypeAttr.get(hw.ModuleType.get(module_ports))
|
||||
|
||||
super().__init__(
|
||||
self.build_generic(attributes=attributes,
|
||||
results=results,
|
||||
operands=operands,
|
||||
loc=loc,
|
||||
ip=ip))
|
||||
|
||||
if body_builder:
|
||||
entry_block = self.add_entry_block()
|
||||
|
||||
with InsertionPoint(entry_block):
|
||||
with support.BackedgeBuilder():
|
||||
outputs = body_builder(self)
|
||||
_create_output_op(name, output_ports, entry_block, outputs)
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return hw.ModuleType(TypeAttr(self.attributes["module_type"]).value)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.attributes["sym_name"]
|
||||
|
||||
@property
|
||||
def is_external(self):
|
||||
return len(self.regions[0].blocks) == 0
|
||||
|
||||
@property
|
||||
def parameters(self) -> list[ParamDeclAttr]:
|
||||
return [
|
||||
hw.ParamDeclAttr(a) for a in ArrayAttr(self.attributes["parameters"])
|
||||
]
|
||||
|
||||
def instantiate(self,
|
||||
name: str,
|
||||
parameters: Dict[str, object] = {},
|
||||
results=None,
|
||||
sym_name=None,
|
||||
loc=None,
|
||||
ip=None,
|
||||
**kwargs):
|
||||
return InstanceBuilder(self,
|
||||
name,
|
||||
kwargs,
|
||||
parameters=parameters,
|
||||
results=results,
|
||||
sym_name=sym_name,
|
||||
loc=loc,
|
||||
ip=ip)
|
||||
|
||||
|
||||
def _create_output_op(cls_name, output_ports, entry_block, bb_ret):
|
||||
"""Create the hw.OutputOp from the body_builder return."""
|
||||
|
||||
# Determine if the body already has an output op.
|
||||
block_len = len(entry_block.operations)
|
||||
if block_len > 0:
|
||||
last_op = entry_block.operations[block_len - 1]
|
||||
if isinstance(last_op, hw.OutputOp):
|
||||
# If it does, the return from body_builder must be None.
|
||||
if bb_ret is not None and bb_ret != last_op:
|
||||
raise support.ConnectionError(
|
||||
f"In {cls_name}, cannot return value from body_builder and "
|
||||
"create hw.OutputOp")
|
||||
return
|
||||
|
||||
# If builder didn't create an output op and didn't return anything, this op
|
||||
# mustn't have any outputs.
|
||||
if bb_ret is None:
|
||||
if len(output_ports) == 0:
|
||||
hw.OutputOp([])
|
||||
return
|
||||
raise support.ConnectionError(
|
||||
f"In {cls_name}, must return module output values")
|
||||
|
||||
# Now create the output op depending on the object type returned
|
||||
outputs: list[Value] = list()
|
||||
|
||||
# Only acceptable return is a dict of port, value mappings.
|
||||
if not isinstance(bb_ret, dict):
|
||||
raise support.ConnectionError(
|
||||
f"In {cls_name}, can only return a dict of port, value mappings "
|
||||
"from body_builder.")
|
||||
|
||||
# A dict of `OutputPortName` -> ValueLike must be converted to a list in port
|
||||
# order.
|
||||
unconnected_ports = []
|
||||
for (name, port_type) in output_ports:
|
||||
if name not in bb_ret:
|
||||
unconnected_ports.append(name)
|
||||
outputs.append(None)
|
||||
else:
|
||||
val = support.get_value(bb_ret[name])
|
||||
if val is None:
|
||||
field_type = type(bb_ret[name])
|
||||
raise TypeError(
|
||||
f"In {cls_name}, body_builder return doesn't support type "
|
||||
f"'{field_type}'")
|
||||
if val.type != port_type:
|
||||
if isinstance(port_type, hw.TypeAliasType) and \
|
||||
port_type.inner_type == val.type:
|
||||
val = hw.BitcastOp.create(port_type, val).result
|
||||
else:
|
||||
raise TypeError(
|
||||
f"In {cls_name}, output port '{name}' type ({val.type}) doesn't "
|
||||
f"match declared type ({port_type})")
|
||||
outputs.append(val)
|
||||
bb_ret.pop(name)
|
||||
if len(unconnected_ports) > 0:
|
||||
raise support.UnconnectedSignalError(cls_name, unconnected_ports)
|
||||
if len(bb_ret) > 0:
|
||||
raise support.ConnectionError(
|
||||
f"Could not map the following to output ports in {cls_name}: " +
|
||||
",".join(bb_ret.keys()))
|
||||
|
||||
hw.OutputOp(outputs)
|
||||
|
||||
|
||||
class HWModuleOp(ModuleLike):
|
||||
"""Specialization for the HW module op class."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name,
|
||||
input_ports=[],
|
||||
output_ports=[],
|
||||
*,
|
||||
parameters=[],
|
||||
attributes={},
|
||||
body_builder=None,
|
||||
loc=None,
|
||||
ip=None,
|
||||
):
|
||||
if "comment" not in attributes:
|
||||
attributes["comment"] = StringAttr.get("")
|
||||
super().__init__(name,
|
||||
input_ports,
|
||||
output_ports,
|
||||
parameters=parameters,
|
||||
attributes=attributes,
|
||||
body_builder=body_builder,
|
||||
loc=loc,
|
||||
ip=ip)
|
||||
|
||||
@property
|
||||
def body(self):
|
||||
return self.regions[0]
|
||||
|
||||
@property
|
||||
def entry_block(self):
|
||||
return self.regions[0].blocks[0]
|
||||
|
||||
@property
|
||||
def input_indices(self):
|
||||
indices: dict[int, str] = {}
|
||||
op_names = self.type.input_names
|
||||
for idx, name in enumerate(op_names):
|
||||
indices[name] = idx
|
||||
return indices
|
||||
|
||||
# Support attribute access to block arguments by name
|
||||
def __getattr__(self, name):
|
||||
if name in self.input_indices:
|
||||
index = self.input_indices[name]
|
||||
return self.entry_block.arguments[index]
|
||||
raise AttributeError(f"unknown input port name {name}")
|
||||
|
||||
def inputs(self) -> dict[str:Value]:
|
||||
ret = {}
|
||||
for (name, idx) in self.input_indices.items():
|
||||
ret[name] = self.entry_block.arguments[idx]
|
||||
return ret
|
||||
|
||||
def outputs(self) -> dict[str:Type]:
|
||||
result_names = self.type.output_names
|
||||
result_types = self.type.output_types
|
||||
return dict(zip(result_names, result_types))
|
||||
|
||||
def add_entry_block(self):
|
||||
if not self.is_external:
|
||||
raise IndexError('The module already has an entry block')
|
||||
self.body.blocks.append(*self.type.input_types)
|
||||
return self.body.blocks[0]
|
||||
|
||||
|
||||
class HWModuleExternOp(ModuleLike):
|
||||
"""Specialization for the HW module op class."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name,
|
||||
input_ports=[],
|
||||
output_ports=[],
|
||||
*,
|
||||
parameters=[],
|
||||
attributes={},
|
||||
body_builder=None,
|
||||
loc=None,
|
||||
ip=None,
|
||||
):
|
||||
if "comment" not in attributes:
|
||||
attributes["comment"] = StringAttr.get("")
|
||||
super().__init__(name,
|
||||
input_ports,
|
||||
output_ports,
|
||||
parameters=parameters,
|
||||
attributes=attributes,
|
||||
body_builder=body_builder,
|
||||
loc=loc,
|
||||
ip=ip)
|
||||
|
||||
|
||||
class ConstantOp:
|
||||
|
||||
@staticmethod
|
||||
def create(data_type, value):
|
||||
return hw.ConstantOp(IntegerAttr.get(data_type, value))
|
||||
|
||||
|
||||
class BitcastOp:
|
||||
|
||||
@staticmethod
|
||||
def create(data_type, value):
|
||||
value = support.get_value(value)
|
||||
return hw.BitcastOp(data_type, value)
|
||||
|
||||
|
||||
class ArrayGetOp:
|
||||
|
||||
@staticmethod
|
||||
def create(array_value, idx):
|
||||
array_value = support.get_value(array_value)
|
||||
array_type = support.get_self_or_inner(array_value.type)
|
||||
if isinstance(idx, int):
|
||||
idx_width = (array_type.size - 1).bit_length()
|
||||
idx_val = ConstantOp.create(IntegerType.get_signless(idx_width),
|
||||
idx).result
|
||||
else:
|
||||
idx_val = support.get_value(idx)
|
||||
return hw.ArrayGetOp(array_value, idx_val)
|
||||
|
||||
|
||||
class ArraySliceOp:
|
||||
|
||||
@staticmethod
|
||||
def create(array_value, low_index, ret_type):
|
||||
array_value = support.get_value(array_value)
|
||||
array_type = support.get_self_or_inner(array_value.type)
|
||||
if isinstance(low_index, int):
|
||||
idx_width = (array_type.size - 1).bit_length()
|
||||
idx_width = max(1, idx_width) # hw.constant cannot produce i0.
|
||||
idx_val = ConstantOp.create(IntegerType.get_signless(idx_width),
|
||||
low_index).result
|
||||
else:
|
||||
idx_val = support.get_value(low_index)
|
||||
return hw.ArraySliceOp(ret_type, array_value, idx_val)
|
||||
|
||||
|
||||
class ArrayCreateOp:
|
||||
|
||||
@staticmethod
|
||||
def create(elements):
|
||||
if not elements:
|
||||
raise ValueError("Cannot 'create' an array of length zero")
|
||||
vals = []
|
||||
type = None
|
||||
for i, arg in enumerate(elements):
|
||||
arg_val = support.get_value(arg)
|
||||
vals.append(arg_val)
|
||||
if type is None:
|
||||
type = arg_val.type
|
||||
elif type != arg_val.type:
|
||||
raise TypeError(
|
||||
f"Argument {i} has a different element type ({arg_val.type}) than the element type of the array ({type})"
|
||||
)
|
||||
return hw.ArrayCreateOp(hw.ArrayType.get(type, len(vals)), vals)
|
||||
|
||||
|
||||
class ArrayConcatOp:
|
||||
|
||||
@staticmethod
|
||||
def create(*sub_arrays):
|
||||
vals = []
|
||||
types = []
|
||||
element_type = None
|
||||
for i, array in enumerate(sub_arrays):
|
||||
array_value = support.get_value(array)
|
||||
array_type = support.type_to_pytype(array_value.type)
|
||||
if array_value is None or not isinstance(array_type, hw.ArrayType):
|
||||
raise TypeError(f"Cannot concatenate {array_value}")
|
||||
if element_type is None:
|
||||
element_type = array_type.element_type
|
||||
elif element_type != array_type.element_type:
|
||||
raise TypeError(
|
||||
f"Argument {i} has a different element type ({element_type}) than the element type of the array ({array_type.element_type})"
|
||||
)
|
||||
|
||||
vals.append(array_value)
|
||||
types.append(array_type)
|
||||
|
||||
size = sum(t.size for t in types)
|
||||
combined_type = hw.ArrayType.get(element_type, size)
|
||||
return hw.ArrayConcatOp(combined_type, vals)
|
||||
|
||||
|
||||
class StructCreateOp:
|
||||
|
||||
@staticmethod
|
||||
def create(elements, result_type: Type = None):
|
||||
elem_name_values = [
|
||||
(name, support.get_value(value)) for (name, value) in elements
|
||||
]
|
||||
struct_fields = [(name, value.type) for (name, value) in elem_name_values]
|
||||
struct_type = hw.StructType.get(struct_fields)
|
||||
|
||||
if result_type is None:
|
||||
result_type = struct_type
|
||||
else:
|
||||
result_type_inner = support.get_self_or_inner(result_type)
|
||||
if result_type_inner != struct_type:
|
||||
raise TypeError(
|
||||
f"result type:\n\t{result_type_inner}\nmust match generated struct type:\n\t{struct_type}"
|
||||
)
|
||||
|
||||
return hw.StructCreateOp(result_type,
|
||||
[value for (_, value) in elem_name_values])
|
||||
|
||||
|
||||
class StructExtractOp:
|
||||
|
||||
@staticmethod
|
||||
def create(struct_value, field_name: str):
|
||||
struct_value = support.get_value(struct_value)
|
||||
struct_type = support.get_self_or_inner(struct_value.type)
|
||||
field_type = struct_type.get_field(field_name)
|
||||
return hw.StructExtractOp(field_type, struct_value,
|
||||
StringAttr.get(field_name))
|
||||
|
||||
|
||||
class TypedeclOp:
|
||||
|
||||
@staticmethod
|
||||
def create(sym_name: str, type: Type, verilog_name: str = None):
|
||||
return hw.TypedeclOp(StringAttr.get(sym_name),
|
||||
TypeAttr.get(type),
|
||||
verilogName=verilog_name)
|
||||
|
||||
|
||||
class TypeScopeOp:
|
||||
|
||||
@staticmethod
|
||||
def create(sym_name: str):
|
||||
op = hw.TypeScopeOp(StringAttr.get(sym_name))
|
||||
op.regions[0].blocks.append()
|
||||
return op
|
||||
|
||||
@property
|
||||
def body(self):
|
||||
return self.regions[0].blocks[0]
|
|
@ -1,76 +0,0 @@
|
|||
from ..support import NamedValueOpView, get_value
|
||||
from ..ir import IntegerAttr, IntegerType
|
||||
|
||||
|
||||
class BinaryOpBuilder(NamedValueOpView):
|
||||
|
||||
def operand_names(self):
|
||||
return ["lhs", "rhs"]
|
||||
|
||||
def result_names(self):
|
||||
return ["result"]
|
||||
|
||||
|
||||
def BinaryOp(base):
|
||||
|
||||
class _Class(base):
|
||||
|
||||
@classmethod
|
||||
def create(cls, lhs=None, rhs=None, result_type=None):
|
||||
return cls([get_value(lhs), get_value(rhs)])
|
||||
|
||||
return _Class
|
||||
|
||||
|
||||
@BinaryOp
|
||||
class DivOp:
|
||||
pass
|
||||
|
||||
|
||||
@BinaryOp
|
||||
class SubOp:
|
||||
pass
|
||||
|
||||
|
||||
@BinaryOp
|
||||
class AddOp:
|
||||
pass
|
||||
|
||||
|
||||
@BinaryOp
|
||||
class MulOp:
|
||||
pass
|
||||
|
||||
|
||||
class CastOp:
|
||||
|
||||
@classmethod
|
||||
def create(cls, value, result_type):
|
||||
return cls(result_type, value)
|
||||
|
||||
|
||||
class ICmpOp:
|
||||
# Predicate constants.
|
||||
|
||||
# `==` and `!=`
|
||||
PRED_EQ = 0b000
|
||||
PRED_NE = 0b001
|
||||
# `<` and `>=`
|
||||
PRED_LT = 0b010
|
||||
PRED_GE = 0b011
|
||||
# `<=` and `>`
|
||||
PRED_LE = 0b100
|
||||
PRED_GT = 0b101
|
||||
|
||||
@classmethod
|
||||
def create(cls, pred, a, b):
|
||||
if isinstance(pred, int):
|
||||
pred = IntegerAttr.get(IntegerType.get_signless(64), pred)
|
||||
return cls(pred, a, b)
|
||||
|
||||
|
||||
class ConstantOp:
|
||||
|
||||
@classmethod
|
||||
def create(cls, data_type, value):
|
||||
return cls(IntegerAttr.get(data_type, value))
|
|
@ -1,79 +0,0 @@
|
|||
# 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
|
||||
|
||||
from typing import Dict, List, Type
|
||||
|
||||
from . import hw, msft as _msft
|
||||
from . import _hw_ops_ext as _hw_ext
|
||||
from .. import support
|
||||
|
||||
from .. import ir as _ir
|
||||
|
||||
|
||||
class PhysicalRegionOp:
|
||||
|
||||
def add_bounds(self, bounds):
|
||||
existing_bounds = [b for b in _ir.ArrayAttr(self.attributes["bounds"])]
|
||||
existing_bounds.append(bounds)
|
||||
new_bounds = _ir.ArrayAttr.get(existing_bounds)
|
||||
self.attributes["bounds"] = new_bounds
|
||||
|
||||
|
||||
class InstanceOp:
|
||||
|
||||
@property
|
||||
def moduleName(self):
|
||||
return _ir.FlatSymbolRefAttr(self.attributes["moduleName"])
|
||||
|
||||
|
||||
class EntityExternOp:
|
||||
|
||||
@staticmethod
|
||||
def create(symbol, metadata=""):
|
||||
symbol_attr = support.var_to_attribute(symbol)
|
||||
metadata_attr = support.var_to_attribute(metadata)
|
||||
return _msft.EntityExternOp(symbol_attr, metadata_attr)
|
||||
|
||||
|
||||
class InstanceHierarchyOp:
|
||||
|
||||
@staticmethod
|
||||
def create(root_mod, instance_name=None):
|
||||
hier = _msft.InstanceHierarchyOp(root_mod, instName=instance_name)
|
||||
hier.body.blocks.append()
|
||||
return hier
|
||||
|
||||
@property
|
||||
def top_module_ref(self):
|
||||
return self.attributes["topModuleRef"]
|
||||
|
||||
|
||||
class DynamicInstanceOp:
|
||||
|
||||
@staticmethod
|
||||
def create(name_ref):
|
||||
inst = _msft.DynamicInstanceOp(name_ref)
|
||||
inst.body.blocks.append()
|
||||
return inst
|
||||
|
||||
@property
|
||||
def instance_path(self):
|
||||
path = []
|
||||
next = self
|
||||
while isinstance(next, DynamicInstanceOp):
|
||||
path.append(next.attributes["instanceRef"])
|
||||
next = next.operation.parent.opview
|
||||
path.reverse()
|
||||
return _ir.ArrayAttr.get(path)
|
||||
|
||||
@property
|
||||
def instanceRef(self):
|
||||
return self.attributes["instanceRef"]
|
||||
|
||||
|
||||
class PDPhysLocationOp:
|
||||
|
||||
@property
|
||||
def loc(self):
|
||||
return _msft.PhysLocationAttr(self.attributes["loc"])
|
|
@ -1,133 +0,0 @@
|
|||
from ..support import BackedgeBuilder, NamedValueOpView
|
||||
from ..ir import IntegerType, OpView, StringAttr
|
||||
from . import hw
|
||||
|
||||
|
||||
class CompRegLikeBuilder(NamedValueOpView):
|
||||
|
||||
def result_names(self):
|
||||
return ["data"]
|
||||
|
||||
def create_initial_value(self, index, data_type, arg_name):
|
||||
if arg_name == "input":
|
||||
operand_type = data_type
|
||||
else:
|
||||
operand_type = IntegerType.get_signless(1)
|
||||
return BackedgeBuilder.create(operand_type, arg_name, self)
|
||||
|
||||
|
||||
class CompRegLike:
|
||||
|
||||
def __init__(self,
|
||||
data_type,
|
||||
input,
|
||||
clk,
|
||||
clockEnable=None,
|
||||
*,
|
||||
reset=None,
|
||||
reset_value=None,
|
||||
power_on_value=None,
|
||||
name=None,
|
||||
sym_name=None,
|
||||
loc=None,
|
||||
ip=None):
|
||||
operands = [input, clk]
|
||||
results = []
|
||||
attributes = {}
|
||||
results.append(data_type)
|
||||
operand_segment_sizes = [1, 1]
|
||||
if isinstance(self, CompRegOp):
|
||||
if clockEnable is not None:
|
||||
raise Exception("Clock enable not supported on compreg")
|
||||
elif isinstance(self, CompRegClockEnabledOp):
|
||||
if clockEnable is None:
|
||||
raise Exception("Clock enable required on compreg.ce")
|
||||
operands.append(clockEnable)
|
||||
operand_segment_sizes.append(1)
|
||||
else:
|
||||
assert False, "Class not recognized"
|
||||
if reset is not None and reset_value is not None:
|
||||
operands.append(reset)
|
||||
operands.append(reset_value)
|
||||
operand_segment_sizes += [1, 1]
|
||||
else:
|
||||
operand_segment_sizes += [0, 0]
|
||||
operands += [None, None]
|
||||
|
||||
if power_on_value is not None:
|
||||
operands.append(power_on_value)
|
||||
operand_segment_sizes.append(1)
|
||||
else:
|
||||
operands.append(None)
|
||||
operand_segment_sizes.append(0)
|
||||
if name is None:
|
||||
attributes["name"] = StringAttr.get("")
|
||||
else:
|
||||
attributes["name"] = StringAttr.get(name)
|
||||
if sym_name is not None:
|
||||
attributes["inner_sym"] = hw.InnerSymAttr.get(StringAttr.get(sym_name))
|
||||
|
||||
self._ODS_OPERAND_SEGMENTS = operand_segment_sizes
|
||||
|
||||
OpView.__init__(
|
||||
self,
|
||||
self.build_generic(
|
||||
attributes=attributes,
|
||||
results=results,
|
||||
operands=operands,
|
||||
loc=loc,
|
||||
ip=ip,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class CompRegBuilder(CompRegLikeBuilder):
|
||||
|
||||
def operand_names(self):
|
||||
return ["input", "clk"]
|
||||
|
||||
|
||||
class CompRegOp(CompRegLike):
|
||||
|
||||
@classmethod
|
||||
def create(cls,
|
||||
result_type,
|
||||
reset=None,
|
||||
reset_value=None,
|
||||
name=None,
|
||||
sym_name=None,
|
||||
**kwargs):
|
||||
return CompRegBuilder(cls,
|
||||
result_type,
|
||||
kwargs,
|
||||
reset=reset,
|
||||
reset_value=reset_value,
|
||||
name=name,
|
||||
sym_name=sym_name,
|
||||
needs_result_type=True)
|
||||
|
||||
|
||||
class CompRegClockEnabledBuilder(CompRegLikeBuilder):
|
||||
|
||||
def operand_names(self):
|
||||
return ["input", "clk", "clockEnable"]
|
||||
|
||||
|
||||
class CompRegClockEnabledOp(CompRegLike):
|
||||
|
||||
@classmethod
|
||||
def create(cls,
|
||||
result_type,
|
||||
reset=None,
|
||||
reset_value=None,
|
||||
name=None,
|
||||
sym_name=None,
|
||||
**kwargs):
|
||||
return CompRegClockEnabledBuilder(cls,
|
||||
result_type,
|
||||
kwargs,
|
||||
reset=reset,
|
||||
reset_value=reset_value,
|
||||
name=name,
|
||||
sym_name=sym_name,
|
||||
needs_result_type=True)
|
|
@ -1,100 +0,0 @@
|
|||
# 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
|
||||
|
||||
from ..ir import ArrayAttr, Attribute, FlatSymbolRefAttr, OpView, StringAttr
|
||||
from . import sv, hw
|
||||
from .. import support
|
||||
|
||||
|
||||
class IfDefOp:
|
||||
|
||||
def __init__(self, cond: Attribute, *, loc=None, ip=None):
|
||||
operands = []
|
||||
results = []
|
||||
attributes = {"cond": cond}
|
||||
regions = 2
|
||||
super().__init__(
|
||||
self.build_generic(attributes=attributes,
|
||||
results=results,
|
||||
operands=operands,
|
||||
successors=None,
|
||||
regions=regions,
|
||||
loc=loc,
|
||||
ip=ip))
|
||||
self.regions[0].blocks.append()
|
||||
self.regions[1].blocks.append()
|
||||
|
||||
|
||||
class WireOp:
|
||||
|
||||
def __init__(self,
|
||||
data_type,
|
||||
name,
|
||||
*,
|
||||
sym_name=None,
|
||||
svAttributes=None,
|
||||
loc=None,
|
||||
ip=None):
|
||||
attributes = {"name": StringAttr.get(name)}
|
||||
if sym_name is not None:
|
||||
attributes["inner_sym"] = hw.InnerSymAttr.get(StringAttr.get(sym_name))
|
||||
if svAttributes is not None:
|
||||
attributes["svAttributes"] = ArrayAttr.get(svAttributes)
|
||||
OpView.__init__(
|
||||
self,
|
||||
self.build_generic(attributes=attributes,
|
||||
results=[data_type],
|
||||
operands=[],
|
||||
successors=None,
|
||||
regions=0,
|
||||
loc=loc,
|
||||
ip=ip))
|
||||
|
||||
@staticmethod
|
||||
def create(data_type, name=None, sym_name=None):
|
||||
if not isinstance(data_type, hw.InOutType):
|
||||
data_type = hw.InOutType.get(data_type)
|
||||
return sv.WireOp(data_type, name, sym_name=sym_name)
|
||||
|
||||
|
||||
class RegOp:
|
||||
|
||||
def __init__(self,
|
||||
data_type,
|
||||
name,
|
||||
*,
|
||||
sym_name=None,
|
||||
svAttributes=None,
|
||||
loc=None,
|
||||
ip=None):
|
||||
attributes = {"name": StringAttr.get(name)}
|
||||
if sym_name is not None:
|
||||
attributes["inner_sym"] = hw.InnerSymAttr.get(StringAttr.get(sym_name))
|
||||
if svAttributes is not None:
|
||||
attributes["svAttributes"] = ArrayAttr.get(svAttributes)
|
||||
OpView.__init__(
|
||||
self,
|
||||
self.build_generic(attributes=attributes,
|
||||
results=[data_type],
|
||||
operands=[],
|
||||
successors=None,
|
||||
regions=0,
|
||||
loc=loc,
|
||||
ip=ip))
|
||||
|
||||
|
||||
class AssignOp:
|
||||
|
||||
@staticmethod
|
||||
def create(dest, src):
|
||||
return sv.AssignOp(dest=dest, src=src)
|
||||
|
||||
|
||||
class ReadInOutOp:
|
||||
|
||||
@staticmethod
|
||||
def create(value):
|
||||
value = support.get_value(value)
|
||||
type = support.get_self_or_inner(value.type).element_type
|
||||
return sv.ReadInOutOp(value)
|
|
@ -2,11 +2,12 @@
|
|||
# See https://llvm.org/LICENSE.txt for license information.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
from ._comb_ops_gen import *
|
||||
|
||||
from ..support import NamedValueOpView
|
||||
|
||||
from . import comb
|
||||
from ..dialects._ods_common import _cext as _ods_cext
|
||||
from ..ir import IntegerAttr, IntegerType, OpView
|
||||
from ..support import NamedValueOpView, get_value
|
||||
from ._comb_ops_gen import *
|
||||
from ._comb_ops_gen import _Dialect
|
||||
|
||||
|
||||
# Sugar classes for the various possible verions of ICmpOp.
|
||||
|
@ -96,3 +97,195 @@ class GtUOp:
|
|||
@CompareOp(9)
|
||||
class GeUOp:
|
||||
pass
|
||||
|
||||
|
||||
# Builder base classes for non-variadic unary and binary ops.
|
||||
class UnaryOpBuilder(NamedValueOpView):
|
||||
|
||||
def operand_names(self):
|
||||
return ["input"]
|
||||
|
||||
def result_names(self):
|
||||
return ["result"]
|
||||
|
||||
|
||||
def UnaryOp(base):
|
||||
|
||||
class _Class(base):
|
||||
|
||||
@classmethod
|
||||
def create(cls, input=None, result_type=None):
|
||||
mapping = {"input": input} if input else {}
|
||||
return UnaryOpBuilder(cls, result_type, mapping)
|
||||
|
||||
return _Class
|
||||
|
||||
|
||||
class ExtractOpBuilder(UnaryOpBuilder):
|
||||
|
||||
def __init__(self, low_bit, data_type, input_port_mapping={}, **kwargs):
|
||||
low_bit = IntegerAttr.get(IntegerType.get_signless(32), low_bit)
|
||||
super().__init__(comb.ExtractOp, data_type, input_port_mapping, [],
|
||||
[low_bit], **kwargs)
|
||||
|
||||
|
||||
class BinaryOpBuilder(NamedValueOpView):
|
||||
|
||||
def operand_names(self):
|
||||
return ["lhs", "rhs"]
|
||||
|
||||
def result_names(self):
|
||||
return ["result"]
|
||||
|
||||
|
||||
def BinaryOp(base):
|
||||
|
||||
class _Class(base):
|
||||
|
||||
@classmethod
|
||||
def create(cls, lhs=None, rhs=None, result_type=None):
|
||||
mapping = {}
|
||||
if lhs:
|
||||
mapping["lhs"] = lhs
|
||||
if rhs:
|
||||
mapping["rhs"] = rhs
|
||||
return BinaryOpBuilder(cls, result_type, mapping)
|
||||
|
||||
return _Class
|
||||
|
||||
|
||||
# Base classes for the variadic ops.
|
||||
def VariadicOp(base):
|
||||
|
||||
class _Class(base):
|
||||
|
||||
@classmethod
|
||||
def create(cls, *args):
|
||||
return cls([get_value(a) for a in args])
|
||||
|
||||
return _Class
|
||||
|
||||
|
||||
# Base class for miscellaneous ops that can't be abstracted but should provide a
|
||||
# create method for uniformity.
|
||||
def CreatableOp(base):
|
||||
|
||||
class _Class(base):
|
||||
|
||||
@classmethod
|
||||
def create(cls, *args, **kwargs):
|
||||
return cls(*args, **kwargs)
|
||||
|
||||
return _Class
|
||||
|
||||
|
||||
# Sugar classes for the various non-variadic unary ops.
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class ExtractOp(ExtractOp):
|
||||
|
||||
@staticmethod
|
||||
def create(low_bit, result_type, input=None):
|
||||
mapping = {"input": input} if input else {}
|
||||
return ExtractOpBuilder(low_bit,
|
||||
result_type,
|
||||
mapping,
|
||||
needs_result_type=True)
|
||||
|
||||
|
||||
@UnaryOp
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class ParityOp(ParityOp):
|
||||
pass
|
||||
|
||||
|
||||
# Sugar classes for the various non-variadic binary ops.
|
||||
@BinaryOp
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class DivSOp(DivSOp):
|
||||
pass
|
||||
|
||||
|
||||
@BinaryOp
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class DivUOp(DivUOp):
|
||||
pass
|
||||
|
||||
|
||||
@BinaryOp
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class ModSOp(ModSOp):
|
||||
pass
|
||||
|
||||
|
||||
@BinaryOp
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class ModUOp(ModUOp):
|
||||
pass
|
||||
|
||||
|
||||
@BinaryOp
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class ShlOp(ShlOp):
|
||||
pass
|
||||
|
||||
|
||||
@BinaryOp
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class ShrSOp(ShrSOp):
|
||||
pass
|
||||
|
||||
|
||||
@BinaryOp
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class ShrUOp(ShrUOp):
|
||||
pass
|
||||
|
||||
|
||||
@BinaryOp
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class SubOp(SubOp):
|
||||
pass
|
||||
|
||||
|
||||
# Sugar classes for the variadic ops.
|
||||
@VariadicOp
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class AddOp(AddOp):
|
||||
pass
|
||||
|
||||
|
||||
@VariadicOp
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class MulOp(MulOp):
|
||||
pass
|
||||
|
||||
|
||||
@VariadicOp
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class AndOp(AndOp):
|
||||
pass
|
||||
|
||||
|
||||
@VariadicOp
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class OrOp(OrOp):
|
||||
pass
|
||||
|
||||
|
||||
@VariadicOp
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class XorOp(XorOp):
|
||||
pass
|
||||
|
||||
|
||||
@VariadicOp
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class ConcatOp(ConcatOp):
|
||||
pass
|
||||
|
||||
|
||||
# Sugar classes for miscellaneous ops.
|
||||
@CreatableOp
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class MuxOp(MuxOp):
|
||||
pass
|
||||
|
|
|
@ -2,10 +2,58 @@
|
|||
# See https://llvm.org/LICENSE.txt for license information.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
from ._esi_ops_gen import *
|
||||
from __future__ import annotations
|
||||
|
||||
from . import esi
|
||||
from .. import ir
|
||||
from .. import support
|
||||
from .._mlir_libs._circt._esi import *
|
||||
from ..dialects._ods_common import _cext as _ods_cext
|
||||
from ._esi_ops_gen import *
|
||||
from ._esi_ops_gen import _Dialect
|
||||
from typing import Dict, List, Optional, Sequence, Type
|
||||
|
||||
|
||||
class ChannelSignaling:
|
||||
ValidReady = 0
|
||||
FIFO0 = 1
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class RequestToServerConnectionOp(RequestToServerConnectionOp):
|
||||
|
||||
@property
|
||||
def clientNamePath(self) -> List[str]:
|
||||
return [
|
||||
ir.StringAttr(x).value
|
||||
for x in ir.ArrayAttr(self.attributes["clientNamePath"])
|
||||
]
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class RequestToClientConnectionOp(RequestToClientConnectionOp):
|
||||
|
||||
@property
|
||||
def clientNamePath(self) -> List[str]:
|
||||
return [
|
||||
ir.StringAttr(x).value
|
||||
for x in ir.ArrayAttr(self.attributes["clientNamePath"])
|
||||
]
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class RandomAccessMemoryDeclOp(RandomAccessMemoryDeclOp):
|
||||
|
||||
@property
|
||||
def innerType(self):
|
||||
return ir.TypeAttr(self.attributes["innerType"])
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class ESIPureModuleOp(ESIPureModuleOp):
|
||||
|
||||
def add_entry_block(self):
|
||||
if len(self.body.blocks) > 0:
|
||||
raise IndexError('The module already has an entry block')
|
||||
self.body.blocks.append()
|
||||
return self.body.blocks[0]
|
||||
|
|
|
@ -2,4 +2,173 @@
|
|||
# See https://llvm.org/LICENSE.txt for license information.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
from . import fsm as fsm
|
||||
from .. import support
|
||||
from ..dialects._ods_common import _cext as _ods_cext
|
||||
from ..ir import *
|
||||
from ._fsm_ops_gen import *
|
||||
from ._fsm_ops_gen import _Dialect
|
||||
|
||||
|
||||
def _get_or_add_single_block(region, args=[]):
|
||||
if len(region.blocks) == 0:
|
||||
region.blocks.append(*args)
|
||||
return region.blocks[0]
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class MachineOp(MachineOp):
|
||||
|
||||
def __init__(self,
|
||||
name,
|
||||
initial_state,
|
||||
input_ports,
|
||||
output_ports,
|
||||
*,
|
||||
attributes={},
|
||||
loc=None,
|
||||
ip=None):
|
||||
attributes["sym_name"] = StringAttr.get(name)
|
||||
attributes["initialState"] = StringAttr.get(initial_state)
|
||||
|
||||
input_types = []
|
||||
output_types = []
|
||||
for (i, (_, port_type)) in enumerate(input_ports):
|
||||
input_types.append(port_type)
|
||||
|
||||
for (i, (_, port_type)) in enumerate(output_ports):
|
||||
output_types.append(port_type)
|
||||
|
||||
attributes["function_type"] = TypeAttr.get(
|
||||
FunctionType.get(inputs=input_types, results=output_types))
|
||||
|
||||
OpView.__init__(
|
||||
self,
|
||||
self.build_generic(attributes=attributes,
|
||||
results=[],
|
||||
operands=[],
|
||||
successors=None,
|
||||
regions=1,
|
||||
loc=loc,
|
||||
ip=ip))
|
||||
|
||||
_get_or_add_single_block(self.body, self.type.inputs)
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return FunctionType(TypeAttr(self.attributes["function_type"]).value)
|
||||
|
||||
def instantiate(self, name: str, loc=None, ip=None, **kwargs):
|
||||
""" FSM Instantiation function"""
|
||||
in_names = support.attribute_to_var(self.attributes['in_names'])
|
||||
inputs = [kwargs[port].value for port in in_names]
|
||||
|
||||
# Clock and resets are not part of the input ports of the FSM, but
|
||||
# it is at the point of `fsm.hw_instance` instantiation that they
|
||||
# must be connected.
|
||||
# Attach backedges to these, and associate these backedges to the operation.
|
||||
# They can then be accessed at the point of instantiation and assigned.
|
||||
clock = support.BackedgeBuilder().create(
|
||||
IntegerType.get_signed(1),
|
||||
StringAttr(self.attributes['clock_name']).value, self)
|
||||
reset = support.BackedgeBuilder().create(
|
||||
IntegerType.get_signed(1),
|
||||
StringAttr(self.attributes['reset_name']).value, self)
|
||||
|
||||
op = fsm.HWInstanceOp(outputs=self.type.results,
|
||||
inputs=inputs,
|
||||
sym_name=StringAttr.get(name),
|
||||
machine=FlatSymbolRefAttr.get(self.sym_name.value),
|
||||
clock=clock.result,
|
||||
reset=reset.result if reset else None,
|
||||
loc=loc,
|
||||
ip=ip)
|
||||
op.backedges = {}
|
||||
|
||||
def set_OpOperand(name, backedge):
|
||||
index = None
|
||||
for i, operand in enumerate(op.operands):
|
||||
if operand == backedge.result:
|
||||
index = i
|
||||
break
|
||||
assert index is not None
|
||||
op_operand = support.OpOperand(op, index, op.operands[index], op)
|
||||
setattr(op, f'_{name}_backedge', op_operand)
|
||||
op.backedges[i] = backedge
|
||||
|
||||
set_OpOperand('clock', clock)
|
||||
if reset:
|
||||
set_OpOperand('reset', reset)
|
||||
|
||||
return op
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class TransitionOp(TransitionOp):
|
||||
|
||||
def __init__(self, next_state, *, loc=None, ip=None):
|
||||
attributes = {
|
||||
"nextState": FlatSymbolRefAttr.get(next_state),
|
||||
}
|
||||
super().__init__(
|
||||
self.build_generic(attributes=attributes,
|
||||
results=[],
|
||||
operands=[],
|
||||
successors=None,
|
||||
regions=2,
|
||||
loc=loc,
|
||||
ip=ip))
|
||||
|
||||
@staticmethod
|
||||
def create(to_state):
|
||||
op = fsm.TransitionOp(to_state)
|
||||
return op
|
||||
|
||||
def set_guard(self, guard_fn):
|
||||
"""Executes a function to generate a guard for the transition.
|
||||
The function is executed within the guard region of this operation."""
|
||||
guard_block = _get_or_add_single_block(self.guard)
|
||||
with InsertionPoint(guard_block):
|
||||
guard = guard_fn()
|
||||
guard_type = support.type_to_pytype(guard.type)
|
||||
if guard_type.width != 1:
|
||||
raise ValueError('The guard must be a single bit')
|
||||
fsm.ReturnOp(operand=guard)
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class StateOp(StateOp):
|
||||
|
||||
def __init__(self, name, *, loc=None, ip=None):
|
||||
attributes = {}
|
||||
attributes["sym_name"] = StringAttr.get(name)
|
||||
|
||||
OpView.__init__(
|
||||
self,
|
||||
self.build_generic(attributes=attributes,
|
||||
results=[],
|
||||
operands=[],
|
||||
successors=None,
|
||||
regions=2,
|
||||
loc=loc,
|
||||
ip=ip))
|
||||
|
||||
@staticmethod
|
||||
def create(name):
|
||||
return fsm.StateOp(name)
|
||||
|
||||
@property
|
||||
def output(self):
|
||||
return _get_or_add_single_block(super().output)
|
||||
|
||||
@property
|
||||
def transitions(self):
|
||||
return _get_or_add_single_block(super().transitions)
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class OutputOp(OutputOp):
|
||||
|
||||
@staticmethod
|
||||
def create(*operands):
|
||||
return fsm.OutputOp(operands)
|
||||
|
|
|
@ -2,5 +2,548 @@
|
|||
# See https://llvm.org/LICENSE.txt for license information.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
from ._hw_ops_gen import *
|
||||
from __future__ import annotations
|
||||
|
||||
from . import hw
|
||||
from .. import support
|
||||
from .._mlir_libs._circt._hw import *
|
||||
from ..dialects._ods_common import _cext as _ods_cext
|
||||
from ..ir import *
|
||||
from ._hw_ops_gen import *
|
||||
from ._hw_ops_gen import _Dialect
|
||||
from typing import Dict, Type
|
||||
|
||||
|
||||
def create_parameters(parameters: dict[str, Attribute], module: ModuleLike):
|
||||
# Compute mapping from parameter name to index, and initialize array.
|
||||
mod_param_decls = module.parameters
|
||||
mod_param_decls_idxs = {
|
||||
decl.name: idx for (idx, decl) in enumerate(mod_param_decls)
|
||||
}
|
||||
inst_param_array = [None] * len(module.parameters)
|
||||
|
||||
# Fill in all the parameters specified.
|
||||
if isinstance(parameters, DictAttr):
|
||||
parameters = {i.name: i.attr for i in parameters}
|
||||
for (pname, pval) in parameters.items():
|
||||
if pname not in mod_param_decls_idxs:
|
||||
raise ValueError(
|
||||
f"Could not find parameter '{pname}' in module parameter decls")
|
||||
idx = mod_param_decls_idxs[pname]
|
||||
param_decl = mod_param_decls[idx]
|
||||
inst_param_array[idx] = hw.ParamDeclAttr.get(pname, param_decl.param_type,
|
||||
pval)
|
||||
|
||||
# Fill in the defaults from the module param decl.
|
||||
for (idx, pval) in enumerate(inst_param_array):
|
||||
if pval is not None:
|
||||
continue
|
||||
inst_param_array[idx] = mod_param_decls[idx]
|
||||
|
||||
return inst_param_array
|
||||
|
||||
|
||||
class InstanceBuilder(support.NamedValueOpView):
|
||||
"""Helper class to incrementally construct an instance of a module."""
|
||||
|
||||
def __init__(self,
|
||||
module,
|
||||
name,
|
||||
input_port_mapping,
|
||||
*,
|
||||
results=None,
|
||||
parameters={},
|
||||
sym_name=None,
|
||||
loc=None,
|
||||
ip=None):
|
||||
self.module = module
|
||||
instance_name = StringAttr.get(name)
|
||||
module_name = FlatSymbolRefAttr.get(StringAttr(module.name).value)
|
||||
inst_param_array = create_parameters(parameters, module)
|
||||
if sym_name:
|
||||
inner_sym = hw.InnerSymAttr.get(StringAttr.get(sym_name))
|
||||
else:
|
||||
inner_sym = None
|
||||
pre_args = [instance_name, module_name]
|
||||
post_args = [
|
||||
ArrayAttr.get([StringAttr.get(x) for x in self.operand_names()]),
|
||||
ArrayAttr.get([StringAttr.get(x) for x in self.result_names()]),
|
||||
ArrayAttr.get(inst_param_array)
|
||||
]
|
||||
if results is None:
|
||||
results = module.type.output_types
|
||||
|
||||
if not isinstance(module, hw.HWModuleExternOp):
|
||||
input_name_type_lookup = {
|
||||
name: support.type_to_pytype(ty)
|
||||
for name, ty in zip(self.operand_names(), module.type.input_types)
|
||||
}
|
||||
for input_name, input_value in input_port_mapping.items():
|
||||
if input_name not in input_name_type_lookup:
|
||||
continue # This error gets caught and raised later.
|
||||
mod_input_type = input_name_type_lookup[input_name]
|
||||
if support.type_to_pytype(input_value.type) != mod_input_type:
|
||||
raise TypeError(f"Input '{input_name}' has type '{input_value.type}' "
|
||||
f"but expected '{mod_input_type}'")
|
||||
|
||||
super().__init__(hw.InstanceOp,
|
||||
results,
|
||||
input_port_mapping,
|
||||
pre_args,
|
||||
post_args,
|
||||
needs_result_type=True,
|
||||
inner_sym=inner_sym,
|
||||
loc=loc,
|
||||
ip=ip)
|
||||
|
||||
def create_default_value(self, index, data_type, arg_name):
|
||||
type = self.module.type.input_types[index]
|
||||
return support.BackedgeBuilder.create(type,
|
||||
arg_name,
|
||||
self,
|
||||
instance_of=self.module)
|
||||
|
||||
def operand_names(self):
|
||||
return self.module.type.input_names
|
||||
|
||||
def result_names(self):
|
||||
return self.module.type.output_names
|
||||
|
||||
|
||||
class ModuleLike:
|
||||
"""Custom Python base class for module-like operations."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name,
|
||||
input_ports=[],
|
||||
output_ports=[],
|
||||
*,
|
||||
parameters=[],
|
||||
attributes={},
|
||||
body_builder=None,
|
||||
loc=None,
|
||||
ip=None,
|
||||
):
|
||||
"""
|
||||
Create a module-like with the provided `name`, `input_ports`, and
|
||||
`output_ports`.
|
||||
- `name` is a string representing the module name.
|
||||
- `input_ports` is a list of pairs of string names and mlir.ir types.
|
||||
- `output_ports` is a list of pairs of string names and mlir.ir types.
|
||||
- `body_builder` is an optional callback, when provided a new entry block
|
||||
is created and the callback is invoked with the new op as argument within
|
||||
an InsertionPoint context already set for the block. The callback is
|
||||
expected to insert a terminator in the block.
|
||||
"""
|
||||
# Copy the mutable default arguments. 'Cause python.
|
||||
input_ports = list(input_ports)
|
||||
output_ports = list(output_ports)
|
||||
parameters = list(parameters)
|
||||
attributes = dict(attributes)
|
||||
|
||||
operands = []
|
||||
results = []
|
||||
attributes["sym_name"] = StringAttr.get(str(name))
|
||||
|
||||
module_ports = []
|
||||
input_names = []
|
||||
port_locs = []
|
||||
unknownLoc = Location.unknown().attr
|
||||
for (i, (port_name, port_type)) in enumerate(input_ports):
|
||||
input_name = StringAttr.get(str(port_name))
|
||||
input_dir = hw.ModulePortDirection.INPUT
|
||||
input_port = hw.ModulePort(input_name, port_type, input_dir)
|
||||
module_ports.append(input_port)
|
||||
input_names.append(input_name)
|
||||
port_locs.append(unknownLoc)
|
||||
|
||||
output_types = []
|
||||
output_names = []
|
||||
for (i, (port_name, port_type)) in enumerate(output_ports):
|
||||
output_name = StringAttr.get(str(port_name))
|
||||
output_dir = hw.ModulePortDirection.OUTPUT
|
||||
output_port = hw.ModulePort(output_name, port_type, output_dir)
|
||||
module_ports.append(output_port)
|
||||
output_names.append(output_name)
|
||||
port_locs.append(unknownLoc)
|
||||
attributes["port_locs"] = ArrayAttr.get(port_locs)
|
||||
attributes["per_port_attrs"] = ArrayAttr.get([])
|
||||
|
||||
if len(parameters) > 0 or "parameters" not in attributes:
|
||||
attributes["parameters"] = ArrayAttr.get(parameters)
|
||||
|
||||
attributes["module_type"] = TypeAttr.get(hw.ModuleType.get(module_ports))
|
||||
|
||||
_ods_cext.ir.OpView.__init__(
|
||||
self,
|
||||
self.build_generic(attributes=attributes,
|
||||
results=results,
|
||||
operands=operands,
|
||||
loc=loc,
|
||||
ip=ip))
|
||||
|
||||
if body_builder:
|
||||
entry_block = self.add_entry_block()
|
||||
|
||||
with InsertionPoint(entry_block):
|
||||
with support.BackedgeBuilder():
|
||||
outputs = body_builder(self)
|
||||
_create_output_op(name, output_ports, entry_block, outputs)
|
||||
|
||||
@property
|
||||
def type(self):
|
||||
return hw.ModuleType(TypeAttr(self.attributes["module_type"]).value)
|
||||
|
||||
@property
|
||||
def name(self):
|
||||
return self.attributes["sym_name"]
|
||||
|
||||
@property
|
||||
def is_external(self):
|
||||
return len(self.regions[0].blocks) == 0
|
||||
|
||||
@property
|
||||
def parameters(self) -> list[ParamDeclAttr]:
|
||||
return [
|
||||
hw.ParamDeclAttr(a) for a in ArrayAttr(self.attributes["parameters"])
|
||||
]
|
||||
|
||||
def instantiate(self,
|
||||
name: str,
|
||||
parameters: Dict[str, object] = {},
|
||||
results=None,
|
||||
sym_name=None,
|
||||
loc=None,
|
||||
ip=None,
|
||||
**kwargs):
|
||||
return InstanceBuilder(self,
|
||||
name,
|
||||
kwargs,
|
||||
parameters=parameters,
|
||||
results=results,
|
||||
sym_name=sym_name,
|
||||
loc=loc,
|
||||
ip=ip)
|
||||
|
||||
|
||||
def _create_output_op(cls_name, output_ports, entry_block, bb_ret):
|
||||
"""Create the hw.OutputOp from the body_builder return."""
|
||||
|
||||
# Determine if the body already has an output op.
|
||||
block_len = len(entry_block.operations)
|
||||
if block_len > 0:
|
||||
last_op = entry_block.operations[block_len - 1]
|
||||
if isinstance(last_op, hw.OutputOp):
|
||||
# If it does, the return from body_builder must be None.
|
||||
if bb_ret is not None and bb_ret != last_op:
|
||||
raise support.ConnectionError(
|
||||
f"In {cls_name}, cannot return value from body_builder and "
|
||||
"create hw.OutputOp")
|
||||
return
|
||||
|
||||
# If builder didn't create an output op and didn't return anything, this op
|
||||
# mustn't have any outputs.
|
||||
if bb_ret is None:
|
||||
if len(output_ports) == 0:
|
||||
hw.OutputOp([])
|
||||
return
|
||||
raise support.ConnectionError(
|
||||
f"In {cls_name}, must return module output values")
|
||||
|
||||
# Now create the output op depending on the object type returned
|
||||
outputs: list[Value] = list()
|
||||
|
||||
# Only acceptable return is a dict of port, value mappings.
|
||||
if not isinstance(bb_ret, dict):
|
||||
raise support.ConnectionError(
|
||||
f"In {cls_name}, can only return a dict of port, value mappings "
|
||||
"from body_builder.")
|
||||
|
||||
# A dict of `OutputPortName` -> ValueLike must be converted to a list in port
|
||||
# order.
|
||||
unconnected_ports = []
|
||||
for (name, port_type) in output_ports:
|
||||
if name not in bb_ret:
|
||||
unconnected_ports.append(name)
|
||||
outputs.append(None)
|
||||
else:
|
||||
val = support.get_value(bb_ret[name])
|
||||
if val is None:
|
||||
field_type = type(bb_ret[name])
|
||||
raise TypeError(
|
||||
f"In {cls_name}, body_builder return doesn't support type "
|
||||
f"'{field_type}'")
|
||||
if val.type != port_type:
|
||||
if isinstance(port_type, hw.TypeAliasType) and \
|
||||
port_type.inner_type == val.type:
|
||||
val = hw.BitcastOp.create(port_type, val).result
|
||||
else:
|
||||
raise TypeError(
|
||||
f"In {cls_name}, output port '{name}' type ({val.type}) doesn't "
|
||||
f"match declared type ({port_type})")
|
||||
outputs.append(val)
|
||||
bb_ret.pop(name)
|
||||
if len(unconnected_ports) > 0:
|
||||
raise support.UnconnectedSignalError(cls_name, unconnected_ports)
|
||||
if len(bb_ret) > 0:
|
||||
raise support.ConnectionError(
|
||||
f"Could not map the following to output ports in {cls_name}: " +
|
||||
",".join(bb_ret.keys()))
|
||||
|
||||
hw.OutputOp(outputs)
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class HWModuleOp(ModuleLike, HWModuleOp):
|
||||
"""Specialization for the HW module op class."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name,
|
||||
input_ports=[],
|
||||
output_ports=[],
|
||||
*,
|
||||
parameters=[],
|
||||
attributes={},
|
||||
body_builder=None,
|
||||
loc=None,
|
||||
ip=None,
|
||||
):
|
||||
if "comment" not in attributes:
|
||||
attributes["comment"] = StringAttr.get("")
|
||||
super().__init__(name,
|
||||
input_ports,
|
||||
output_ports,
|
||||
parameters=parameters,
|
||||
attributes=attributes,
|
||||
body_builder=body_builder,
|
||||
loc=loc,
|
||||
ip=ip)
|
||||
|
||||
@property
|
||||
def body(self):
|
||||
return self.regions[0]
|
||||
|
||||
@property
|
||||
def entry_block(self):
|
||||
return self.regions[0].blocks[0]
|
||||
|
||||
@property
|
||||
def input_indices(self):
|
||||
indices: dict[int, str] = {}
|
||||
op_names = self.type.input_names
|
||||
for idx, name in enumerate(op_names):
|
||||
indices[name] = idx
|
||||
return indices
|
||||
|
||||
# Support attribute access to block arguments by name
|
||||
def __getattr__(self, name):
|
||||
if name in self.input_indices:
|
||||
index = self.input_indices[name]
|
||||
return self.entry_block.arguments[index]
|
||||
raise AttributeError(f"unknown input port name {name}")
|
||||
|
||||
def inputs(self) -> dict[str:Value]:
|
||||
ret = {}
|
||||
for (name, idx) in self.input_indices.items():
|
||||
ret[name] = self.entry_block.arguments[idx]
|
||||
return ret
|
||||
|
||||
def outputs(self) -> dict[str:Type]:
|
||||
result_names = self.type.output_names
|
||||
result_types = self.type.output_types
|
||||
return dict(zip(result_names, result_types))
|
||||
|
||||
def add_entry_block(self):
|
||||
if not self.is_external:
|
||||
raise IndexError('The module already has an entry block')
|
||||
self.body.blocks.append(*self.type.input_types)
|
||||
return self.body.blocks[0]
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class HWModuleExternOp(ModuleLike, HWModuleExternOp):
|
||||
"""Specialization for the HW module op class."""
|
||||
|
||||
def __init__(
|
||||
self,
|
||||
name,
|
||||
input_ports=[],
|
||||
output_ports=[],
|
||||
*,
|
||||
parameters=[],
|
||||
attributes={},
|
||||
body_builder=None,
|
||||
loc=None,
|
||||
ip=None,
|
||||
):
|
||||
if "comment" not in attributes:
|
||||
attributes["comment"] = StringAttr.get("")
|
||||
super().__init__(name,
|
||||
input_ports,
|
||||
output_ports,
|
||||
parameters=parameters,
|
||||
attributes=attributes,
|
||||
body_builder=body_builder,
|
||||
loc=loc,
|
||||
ip=ip)
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class ConstantOp(ConstantOp):
|
||||
|
||||
@staticmethod
|
||||
def create(data_type, value):
|
||||
return hw.ConstantOp(IntegerAttr.get(data_type, value))
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class BitcastOp(BitcastOp):
|
||||
|
||||
@staticmethod
|
||||
def create(data_type, value):
|
||||
value = support.get_value(value)
|
||||
return hw.BitcastOp(data_type, value)
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class ArrayGetOp(ArrayGetOp):
|
||||
|
||||
@staticmethod
|
||||
def create(array_value, idx):
|
||||
array_value = support.get_value(array_value)
|
||||
array_type = support.get_self_or_inner(array_value.type)
|
||||
if isinstance(idx, int):
|
||||
idx_width = (array_type.size - 1).bit_length()
|
||||
idx_val = ConstantOp.create(IntegerType.get_signless(idx_width),
|
||||
idx).result
|
||||
else:
|
||||
idx_val = support.get_value(idx)
|
||||
return hw.ArrayGetOp(array_value, idx_val)
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class ArraySliceOp(ArraySliceOp):
|
||||
|
||||
@staticmethod
|
||||
def create(array_value, low_index, ret_type):
|
||||
array_value = support.get_value(array_value)
|
||||
array_type = support.get_self_or_inner(array_value.type)
|
||||
if isinstance(low_index, int):
|
||||
idx_width = (array_type.size - 1).bit_length()
|
||||
idx_width = max(1, idx_width) # hw.constant cannot produce i0.
|
||||
idx_val = ConstantOp.create(IntegerType.get_signless(idx_width),
|
||||
low_index).result
|
||||
else:
|
||||
idx_val = support.get_value(low_index)
|
||||
return hw.ArraySliceOp(ret_type, array_value, idx_val)
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class ArrayCreateOp(ArrayCreateOp):
|
||||
|
||||
@staticmethod
|
||||
def create(elements):
|
||||
if not elements:
|
||||
raise ValueError("Cannot 'create' an array of length zero")
|
||||
vals = []
|
||||
type = None
|
||||
for i, arg in enumerate(elements):
|
||||
arg_val = support.get_value(arg)
|
||||
vals.append(arg_val)
|
||||
if type is None:
|
||||
type = arg_val.type
|
||||
elif type != arg_val.type:
|
||||
raise TypeError(
|
||||
f"Argument {i} has a different element type ({arg_val.type}) than the element type of the array ({type})"
|
||||
)
|
||||
return hw.ArrayCreateOp(hw.ArrayType.get(type, len(vals)), vals)
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class ArrayConcatOp(ArrayConcatOp):
|
||||
|
||||
@staticmethod
|
||||
def create(*sub_arrays):
|
||||
vals = []
|
||||
types = []
|
||||
element_type = None
|
||||
for i, array in enumerate(sub_arrays):
|
||||
array_value = support.get_value(array)
|
||||
array_type = support.type_to_pytype(array_value.type)
|
||||
if array_value is None or not isinstance(array_type, hw.ArrayType):
|
||||
raise TypeError(f"Cannot concatenate {array_value}")
|
||||
if element_type is None:
|
||||
element_type = array_type.element_type
|
||||
elif element_type != array_type.element_type:
|
||||
raise TypeError(
|
||||
f"Argument {i} has a different element type ({element_type}) than the element type of the array ({array_type.element_type})"
|
||||
)
|
||||
|
||||
vals.append(array_value)
|
||||
types.append(array_type)
|
||||
|
||||
size = sum(t.size for t in types)
|
||||
combined_type = hw.ArrayType.get(element_type, size)
|
||||
return hw.ArrayConcatOp(combined_type, vals)
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class StructCreateOp(StructCreateOp):
|
||||
|
||||
@staticmethod
|
||||
def create(elements, result_type: Type = None):
|
||||
elem_name_values = [
|
||||
(name, support.get_value(value)) for (name, value) in elements
|
||||
]
|
||||
struct_fields = [(name, value.type) for (name, value) in elem_name_values]
|
||||
struct_type = hw.StructType.get(struct_fields)
|
||||
|
||||
if result_type is None:
|
||||
result_type = struct_type
|
||||
else:
|
||||
result_type_inner = support.get_self_or_inner(result_type)
|
||||
if result_type_inner != struct_type:
|
||||
raise TypeError(
|
||||
f"result type:\n\t{result_type_inner}\nmust match generated struct type:\n\t{struct_type}"
|
||||
)
|
||||
|
||||
return hw.StructCreateOp(result_type,
|
||||
[value for (_, value) in elem_name_values])
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class StructExtractOp(StructExtractOp):
|
||||
|
||||
@staticmethod
|
||||
def create(struct_value, field_name: str):
|
||||
struct_value = support.get_value(struct_value)
|
||||
struct_type = support.get_self_or_inner(struct_value.type)
|
||||
field_type = struct_type.get_field(field_name)
|
||||
return hw.StructExtractOp(field_type, struct_value,
|
||||
StringAttr.get(field_name))
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class TypedeclOp(TypedeclOp):
|
||||
|
||||
@staticmethod
|
||||
def create(sym_name: str, type: Type, verilog_name: str = None):
|
||||
return hw.TypedeclOp(StringAttr.get(sym_name),
|
||||
TypeAttr.get(type),
|
||||
verilogName=verilog_name)
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class TypeScopeOp(TypeScopeOp):
|
||||
|
||||
@staticmethod
|
||||
def create(sym_name: str):
|
||||
op = hw.TypeScopeOp(StringAttr.get(sym_name))
|
||||
op.regions[0].blocks.append()
|
||||
return op
|
||||
|
||||
@property
|
||||
def body(self):
|
||||
return self.regions[0].blocks[0]
|
||||
|
|
|
@ -2,4 +2,89 @@
|
|||
# See https://llvm.org/LICENSE.txt for license information.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
from ..dialects._ods_common import _cext as _ods_cext
|
||||
from ..ir import IntegerAttr, IntegerType
|
||||
from ..support import NamedValueOpView, get_value
|
||||
from ._hwarith_ops_gen import *
|
||||
from ._hwarith_ops_gen import _Dialect
|
||||
|
||||
|
||||
class BinaryOpBuilder(NamedValueOpView):
|
||||
|
||||
def operand_names(self):
|
||||
return ["lhs", "rhs"]
|
||||
|
||||
def result_names(self):
|
||||
return ["result"]
|
||||
|
||||
|
||||
def BinaryOp(base):
|
||||
|
||||
class _Class(base):
|
||||
|
||||
@classmethod
|
||||
def create(cls, lhs=None, rhs=None, result_type=None):
|
||||
return cls([get_value(lhs), get_value(rhs)])
|
||||
|
||||
return _Class
|
||||
|
||||
|
||||
@BinaryOp
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class DivOp(DivOp):
|
||||
pass
|
||||
|
||||
|
||||
@BinaryOp
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class SubOp(SubOp):
|
||||
pass
|
||||
|
||||
|
||||
@BinaryOp
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class AddOp(AddOp):
|
||||
pass
|
||||
|
||||
|
||||
@BinaryOp
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class MulOp(MulOp):
|
||||
pass
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class CastOp(CastOp):
|
||||
|
||||
@classmethod
|
||||
def create(cls, value, result_type):
|
||||
return cls(result_type, value)
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class ICmpOp(ICmpOp):
|
||||
# Predicate constants.
|
||||
|
||||
# `==` and `!=`
|
||||
PRED_EQ = 0b000
|
||||
PRED_NE = 0b001
|
||||
# `<` and `>=`
|
||||
PRED_LT = 0b010
|
||||
PRED_GE = 0b011
|
||||
# `<=` and `>`
|
||||
PRED_LE = 0b100
|
||||
PRED_GT = 0b101
|
||||
|
||||
@classmethod
|
||||
def create(cls, pred, a, b):
|
||||
if isinstance(pred, int):
|
||||
pred = IntegerAttr.get(IntegerType.get_signless(64), pred)
|
||||
return cls(pred, a, b)
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class ConstantOp(ConstantOp):
|
||||
|
||||
@classmethod
|
||||
def create(cls, data_type, value):
|
||||
return cls(IntegerAttr.get(data_type, value))
|
||||
|
|
|
@ -2,5 +2,67 @@
|
|||
# See https://llvm.org/LICENSE.txt for license information.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
from ._msft_ops_gen import *
|
||||
from . import hw, msft
|
||||
from .. import support
|
||||
from .._mlir_libs._circt._msft import *
|
||||
from ..dialects._ods_common import _cext as _ods_cext
|
||||
from ..ir import ArrayAttr
|
||||
from ._msft_ops_gen import *
|
||||
from ._msft_ops_gen import _Dialect
|
||||
from typing import Dict, List, Type
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class DeclPhysicalRegionOp(DeclPhysicalRegionOp):
|
||||
|
||||
def add_bounds(self, bounds):
|
||||
existing_bounds = [b for b in ArrayAttr(self.attributes["bounds"])]
|
||||
existing_bounds.append(bounds)
|
||||
new_bounds = ArrayAttr.get(existing_bounds)
|
||||
self.attributes["bounds"] = new_bounds
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class InstanceHierarchyOp(InstanceHierarchyOp):
|
||||
|
||||
@staticmethod
|
||||
def create(root_mod, instance_name=None):
|
||||
hier = msft.InstanceHierarchyOp(root_mod, instName=instance_name)
|
||||
hier.body.blocks.append()
|
||||
return hier
|
||||
|
||||
@property
|
||||
def top_module_ref(self):
|
||||
return self.attributes["topModuleRef"]
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class DynamicInstanceOp(DynamicInstanceOp):
|
||||
|
||||
@staticmethod
|
||||
def create(name_ref):
|
||||
inst = msft.DynamicInstanceOp(name_ref)
|
||||
inst.body.blocks.append()
|
||||
return inst
|
||||
|
||||
@property
|
||||
def instance_path(self):
|
||||
path = []
|
||||
next = self
|
||||
while isinstance(next, DynamicInstanceOp):
|
||||
path.append(next.attributes["instanceRef"])
|
||||
next = next.operation.parent.opview
|
||||
path.reverse()
|
||||
return ArrayAttr.get(path)
|
||||
|
||||
@property
|
||||
def instanceRef(self):
|
||||
return self.attributes["instanceRef"]
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class PDPhysLocationOp(PDPhysLocationOp):
|
||||
|
||||
@property
|
||||
def loc(self):
|
||||
return msft.PhysLocationAttr(self.attributes["loc"])
|
||||
|
|
|
@ -2,10 +2,14 @@
|
|||
# See https://llvm.org/LICENSE.txt for license information.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
from ._seq_ops_gen import *
|
||||
|
||||
from .seq import CompRegOp
|
||||
from . import hw
|
||||
from .._mlir_libs._circt._seq import *
|
||||
from ..dialects._ods_common import _cext as _ods_cext
|
||||
from ..ir import IntegerType, OpView, StringAttr
|
||||
from ..support import BackedgeBuilder, NamedValueOpView
|
||||
from ._seq_ops_gen import *
|
||||
from ._seq_ops_gen import _Dialect
|
||||
from .seq import CompRegOp
|
||||
|
||||
|
||||
# Create a computational register whose input is the given value, and is clocked
|
||||
|
@ -34,3 +38,135 @@ def reg(value, clock, reset=None, reset_value=None, name=None, sym_name=None):
|
|||
clk=clock,
|
||||
name=name,
|
||||
sym_name=sym_name).data.value
|
||||
|
||||
|
||||
class CompRegLikeBuilder(NamedValueOpView):
|
||||
|
||||
def result_names(self):
|
||||
return ["data"]
|
||||
|
||||
def create_initial_value(self, index, data_type, arg_name):
|
||||
if arg_name == "input":
|
||||
operand_type = data_type
|
||||
else:
|
||||
operand_type = IntegerType.get_signless(1)
|
||||
return BackedgeBuilder.create(operand_type, arg_name, self)
|
||||
|
||||
|
||||
class CompRegLike:
|
||||
|
||||
def __init__(self,
|
||||
data_type,
|
||||
input,
|
||||
clk,
|
||||
clockEnable=None,
|
||||
*,
|
||||
reset=None,
|
||||
reset_value=None,
|
||||
power_on_value=None,
|
||||
name=None,
|
||||
sym_name=None,
|
||||
loc=None,
|
||||
ip=None):
|
||||
operands = [input, clk]
|
||||
results = []
|
||||
attributes = {}
|
||||
results.append(data_type)
|
||||
operand_segment_sizes = [1, 1]
|
||||
if isinstance(self, CompRegOp):
|
||||
if clockEnable is not None:
|
||||
raise Exception("Clock enable not supported on compreg")
|
||||
elif isinstance(self, CompRegClockEnabledOp):
|
||||
if clockEnable is None:
|
||||
raise Exception("Clock enable required on compreg.ce")
|
||||
operands.append(clockEnable)
|
||||
operand_segment_sizes.append(1)
|
||||
else:
|
||||
assert False, "Class not recognized"
|
||||
if reset is not None and reset_value is not None:
|
||||
operands.append(reset)
|
||||
operands.append(reset_value)
|
||||
operand_segment_sizes += [1, 1]
|
||||
else:
|
||||
operand_segment_sizes += [0, 0]
|
||||
operands += [None, None]
|
||||
|
||||
if power_on_value is not None:
|
||||
operands.append(power_on_value)
|
||||
operand_segment_sizes.append(1)
|
||||
else:
|
||||
operands.append(None)
|
||||
operand_segment_sizes.append(0)
|
||||
if name is None:
|
||||
attributes["name"] = StringAttr.get("")
|
||||
else:
|
||||
attributes["name"] = StringAttr.get(name)
|
||||
if sym_name is not None:
|
||||
attributes["inner_sym"] = hw.InnerSymAttr.get(StringAttr.get(sym_name))
|
||||
|
||||
self._ODS_OPERAND_SEGMENTS = operand_segment_sizes
|
||||
|
||||
OpView.__init__(
|
||||
self,
|
||||
self.build_generic(
|
||||
attributes=attributes,
|
||||
results=results,
|
||||
operands=operands,
|
||||
loc=loc,
|
||||
ip=ip,
|
||||
),
|
||||
)
|
||||
|
||||
|
||||
class CompRegBuilder(CompRegLikeBuilder):
|
||||
|
||||
def operand_names(self):
|
||||
return ["input", "clk"]
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class CompRegOp(CompRegLike, CompRegOp):
|
||||
|
||||
@classmethod
|
||||
def create(cls,
|
||||
result_type,
|
||||
reset=None,
|
||||
reset_value=None,
|
||||
name=None,
|
||||
sym_name=None,
|
||||
**kwargs):
|
||||
return CompRegBuilder(cls,
|
||||
result_type,
|
||||
kwargs,
|
||||
reset=reset,
|
||||
reset_value=reset_value,
|
||||
name=name,
|
||||
sym_name=sym_name,
|
||||
needs_result_type=True)
|
||||
|
||||
|
||||
class CompRegClockEnabledBuilder(CompRegLikeBuilder):
|
||||
|
||||
def operand_names(self):
|
||||
return ["input", "clk", "clockEnable"]
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class CompRegClockEnabledOp(CompRegLike, CompRegClockEnabledOp):
|
||||
|
||||
@classmethod
|
||||
def create(cls,
|
||||
result_type,
|
||||
reset=None,
|
||||
reset_value=None,
|
||||
name=None,
|
||||
sym_name=None,
|
||||
**kwargs):
|
||||
return CompRegClockEnabledBuilder(cls,
|
||||
result_type,
|
||||
kwargs,
|
||||
reset=reset,
|
||||
reset_value=reset_value,
|
||||
name=name,
|
||||
sym_name=sym_name,
|
||||
needs_result_type=True)
|
||||
|
|
|
@ -2,5 +2,108 @@
|
|||
# See https://llvm.org/LICENSE.txt for license information.
|
||||
# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
||||
|
||||
from ._sv_ops_gen import *
|
||||
from . import sv, hw
|
||||
from .. import support
|
||||
from .._mlir_libs._circt._sv import *
|
||||
from ..dialects._ods_common import _cext as _ods_cext
|
||||
from ..ir import ArrayAttr, Attribute, FlatSymbolRefAttr, OpView, StringAttr
|
||||
from ._sv_ops_gen import *
|
||||
from ._sv_ops_gen import _Dialect
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class IfDefOp(IfDefOp):
|
||||
|
||||
def __init__(self, cond: Attribute, *, loc=None, ip=None):
|
||||
operands = []
|
||||
results = []
|
||||
attributes = {"cond": cond}
|
||||
regions = 2
|
||||
super().__init__(
|
||||
self.build_generic(attributes=attributes,
|
||||
results=results,
|
||||
operands=operands,
|
||||
successors=None,
|
||||
regions=regions,
|
||||
loc=loc,
|
||||
ip=ip))
|
||||
self.regions[0].blocks.append()
|
||||
self.regions[1].blocks.append()
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class WireOp(WireOp):
|
||||
|
||||
def __init__(self,
|
||||
data_type,
|
||||
name,
|
||||
*,
|
||||
sym_name=None,
|
||||
svAttributes=None,
|
||||
loc=None,
|
||||
ip=None):
|
||||
attributes = {"name": StringAttr.get(name)}
|
||||
if sym_name is not None:
|
||||
attributes["inner_sym"] = hw.InnerSymAttr.get(StringAttr.get(sym_name))
|
||||
if svAttributes is not None:
|
||||
attributes["svAttributes"] = ArrayAttr.get(svAttributes)
|
||||
OpView.__init__(
|
||||
self,
|
||||
self.build_generic(attributes=attributes,
|
||||
results=[data_type],
|
||||
operands=[],
|
||||
successors=None,
|
||||
regions=0,
|
||||
loc=loc,
|
||||
ip=ip))
|
||||
|
||||
@staticmethod
|
||||
def create(data_type, name=None, sym_name=None):
|
||||
if not isinstance(data_type, hw.InOutType):
|
||||
data_type = hw.InOutType.get(data_type)
|
||||
return sv.WireOp(data_type, name, sym_name=sym_name)
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class RegOp(RegOp):
|
||||
|
||||
def __init__(self,
|
||||
data_type,
|
||||
name,
|
||||
*,
|
||||
sym_name=None,
|
||||
svAttributes=None,
|
||||
loc=None,
|
||||
ip=None):
|
||||
attributes = {"name": StringAttr.get(name)}
|
||||
if sym_name is not None:
|
||||
attributes["inner_sym"] = hw.InnerSymAttr.get(StringAttr.get(sym_name))
|
||||
if svAttributes is not None:
|
||||
attributes["svAttributes"] = ArrayAttr.get(svAttributes)
|
||||
OpView.__init__(
|
||||
self,
|
||||
self.build_generic(attributes=attributes,
|
||||
results=[data_type],
|
||||
operands=[],
|
||||
successors=None,
|
||||
regions=0,
|
||||
loc=loc,
|
||||
ip=ip))
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class AssignOp(AssignOp):
|
||||
|
||||
@staticmethod
|
||||
def create(dest, src):
|
||||
return sv.AssignOp(dest=dest, src=src)
|
||||
|
||||
|
||||
@_ods_cext.register_operation(_Dialect, replace=True)
|
||||
class ReadInOutOp(ReadInOutOp):
|
||||
|
||||
@staticmethod
|
||||
def create(value):
|
||||
value = support.get_value(value)
|
||||
type = support.get_self_or_inner(value.type).element_type
|
||||
return sv.ReadInOutOp(value)
|
||||
|
|
|
@ -159,11 +159,8 @@ struct ArrayGetOpConversion : public ConvertOpToLLVMPattern<hw::ArrayGetOp> {
|
|||
rewriter.create<LLVM::StoreOp>(op->getLoc(), adaptor.getInput(), arrPtr);
|
||||
}
|
||||
|
||||
auto arrTy = typeConverter->convertType(op.getInput().getType());
|
||||
auto elemTy = typeConverter->convertType(op.getResult().getType());
|
||||
|
||||
auto zeroC = rewriter.create<LLVM::ConstantOp>(
|
||||
op->getLoc(), IntegerType::get(rewriter.getContext(), 32),
|
||||
rewriter.getI32IntegerAttr(0));
|
||||
auto zextIndex = zextByOne(op->getLoc(), rewriter, op.getIndex());
|
||||
|
||||
// During the ongoing migration to opaque types, use the constructor that
|
||||
|
@ -173,11 +170,11 @@ struct ArrayGetOpConversion : public ConvertOpToLLVMPattern<hw::ArrayGetOp> {
|
|||
if (cast<LLVM::LLVMPointerType>(arrPtr.getType()).isOpaque())
|
||||
gep = rewriter.create<LLVM::GEPOp>(
|
||||
op->getLoc(), LLVM::LLVMPointerType::get(rewriter.getContext()),
|
||||
elemTy, arrPtr, ArrayRef<Value>({zeroC, zextIndex}));
|
||||
arrTy, arrPtr, ArrayRef<LLVM::GEPArg>{0, zextIndex});
|
||||
else
|
||||
gep = rewriter.create<LLVM::GEPOp>(
|
||||
op->getLoc(), LLVM::LLVMPointerType::get(elemTy), arrPtr,
|
||||
ArrayRef<Value>({zeroC, zextIndex}));
|
||||
ArrayRef<LLVM::GEPArg>{0, zextIndex});
|
||||
|
||||
rewriter.replaceOpWithNewOp<LLVM::LoadOp>(op, elemTy, gep);
|
||||
|
||||
|
@ -202,8 +199,6 @@ struct ArraySliceOpConversion
|
|||
auto elemTy = typeConverter->convertType(
|
||||
op.getDst().getType().cast<hw::ArrayType>().getElementType());
|
||||
|
||||
auto zeroC = rewriter.create<LLVM::ConstantOp>(
|
||||
op->getLoc(), rewriter.getI32Type(), rewriter.getI32IntegerAttr(0));
|
||||
auto oneC = rewriter.create<LLVM::ConstantOp>(
|
||||
op->getLoc(), rewriter.getI32Type(), rewriter.getI32IntegerAttr(1));
|
||||
|
||||
|
@ -223,11 +218,11 @@ struct ArraySliceOpConversion
|
|||
if (cast<LLVM::LLVMPointerType>(arrPtr.getType()).isOpaque())
|
||||
gep = rewriter.create<LLVM::GEPOp>(
|
||||
op->getLoc(), LLVM::LLVMPointerType::get(rewriter.getContext()),
|
||||
elemTy, arrPtr, ArrayRef<Value>({zeroC, zextIndex}));
|
||||
dstTy, arrPtr, ArrayRef<LLVM::GEPArg>{0, zextIndex});
|
||||
else
|
||||
gep = rewriter.create<LLVM::GEPOp>(
|
||||
op->getLoc(), LLVM::LLVMPointerType::get(elemTy), arrPtr,
|
||||
ArrayRef<Value>({zeroC, zextIndex}));
|
||||
ArrayRef<LLVM::GEPArg>{0, zextIndex});
|
||||
|
||||
auto cast = rewriter.create<LLVM::BitcastOp>(
|
||||
op->getLoc(), LLVM::LLVMPointerType::get(dstTy), gep);
|
||||
|
|
|
@ -177,7 +177,7 @@ circt::firrtl::detail::replaceWithNewForceability(Forceable op, bool forceable,
|
|||
if (forceable)
|
||||
attributes.push_back(forceableMarker);
|
||||
else {
|
||||
llvm::erase_value(attributes, forceableMarker);
|
||||
llvm::erase(attributes, forceableMarker);
|
||||
assert(attributes.size() != op->getAttrs().size());
|
||||
}
|
||||
|
||||
|
|
|
@ -69,9 +69,9 @@ void NLATable::erase(hw::HierPathOp nla, SymbolTable *symbolTable) {
|
|||
symToOp.erase(nla.getSymNameAttr());
|
||||
for (auto ent : nla.getNamepath())
|
||||
if (auto mod = dyn_cast<FlatSymbolRefAttr>(ent))
|
||||
llvm::erase_value(nodeMap[mod.getAttr()], nla);
|
||||
llvm::erase(nodeMap[mod.getAttr()], nla);
|
||||
else if (auto inr = ent.dyn_cast<hw::InnerRefAttr>())
|
||||
llvm::erase_value(nodeMap[inr.getModule()], nla);
|
||||
llvm::erase(nodeMap[inr.getModule()], nla);
|
||||
if (symbolTable)
|
||||
symbolTable->erase(nla);
|
||||
}
|
||||
|
|
2
llvm
2
llvm
|
@ -1 +1 @@
|
|||
Subproject commit 5f5faf407b42342708ce31a1ca3095ddff10dad8
|
||||
Subproject commit 7ce613fc77af092dd6e9db71ce3747b75bc5616e
|
|
@ -36,18 +36,16 @@ func.func @convertArray(%arg0 : i1, %arg1: !hw.array<2xi32>, %arg2: i32, %arg3:
|
|||
// CHECK-NEXT: %[[ONE:.*]] = llvm.mlir.constant(1 : i32) : i32
|
||||
// CHECK-NEXT: %[[ALLOCA:.*]] = llvm.alloca %[[ONE]] x !llvm.array<2 x i32> {alignment = 4 : i64} : (i32) -> !llvm.ptr<array<2 x i32>>
|
||||
// CHECK-NEXT: llvm.store %[[CAST0]], %[[ALLOCA]] : !llvm.ptr<array<2 x i32>>
|
||||
// CHECK-NEXT: %[[ZERO:.*]] = llvm.mlir.constant(0 : i32) : i32
|
||||
// CHECK-NEXT: %[[ZEXT:.*]] = llvm.zext %arg0 : i1 to i2
|
||||
// CHECK-NEXT: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][%[[ZERO]], %[[ZEXT]]] : (!llvm.ptr<array<2 x i32>>, i32, i2) -> !llvm.ptr<i32>
|
||||
// CHECK-NEXT: %[[GEP:.*]] = llvm.getelementptr %[[ALLOCA]][0, %[[ZEXT]]] : (!llvm.ptr<array<2 x i32>>, i2) -> !llvm.ptr<i32>
|
||||
// CHECK-NEXT: llvm.load %[[GEP]] : !llvm.ptr<i32>
|
||||
%0 = hw.array_get %arg1[%arg0] : !hw.array<2xi32>, i1
|
||||
|
||||
// CHECK-NEXT: %[[ZERO1:.*]] = llvm.mlir.constant(0 : i32) : i32
|
||||
// CHECK-NEXT: %[[ONE4:.*]] = llvm.mlir.constant(1 : i32) : i32
|
||||
// CHECK-NEXT: %[[ALLOCA1:.*]] = llvm.alloca %[[ONE4]] x !llvm.array<2 x i32> {alignment = 4 : i64} : (i32) -> !llvm.ptr<array<2 x i32>>
|
||||
// CHECK-NEXT: llvm.store %[[CAST0]], %[[ALLOCA1]] : !llvm.ptr<array<2 x i32>>
|
||||
// CHECK-NEXT: %[[ZEXT1:.*]] = llvm.zext %arg0 : i1 to i2
|
||||
// CHECK-NEXT: %[[GEP1:.*]] = llvm.getelementptr %[[ALLOCA1]][%[[ZERO1]], %[[ZEXT1]]] : (!llvm.ptr<array<2 x i32>>, i32, i2) -> !llvm.ptr<i32>
|
||||
// CHECK-NEXT: %[[GEP1:.*]] = llvm.getelementptr %[[ALLOCA1]][0, %[[ZEXT1]]] : (!llvm.ptr<array<2 x i32>>, i2) -> !llvm.ptr<i32>
|
||||
// CHECK-NEXT: %[[BITCAST:.*]] = llvm.bitcast %[[GEP1]] : !llvm.ptr<i32> to !llvm.ptr<array<1 x i32>>
|
||||
// CHECK-NEXT: llvm.load %[[LD:.*]] : !llvm.ptr<array<1 x i32>>
|
||||
%1 = hw.array_slice %arg1[%arg0] : (!hw.array<2xi32>) -> !hw.array<1xi32>
|
||||
|
@ -104,9 +102,8 @@ func.func @convertConstArray(%arg0 : i1) {
|
|||
|
||||
// COM: Test: when the array argument is already a load from a pointer,
|
||||
// COM: then don't allocate on the stack again but take that pointer directly as a shortcut
|
||||
// CHECK-NEXT: %[[VAL_4:.*]] = llvm.mlir.constant(0 : i32) : i32
|
||||
// CHECK-NEXT: %[[VAL_5:.*]] = llvm.zext %arg0 : i1 to i2
|
||||
// CHECK-NEXT: %[[VAL_6:.*]] = llvm.getelementptr %[[VAL_2]][%[[VAL_4]], %[[VAL_5]]] : (!llvm.ptr, i32, i2) -> !llvm.ptr, i32
|
||||
// CHECK-NEXT: %[[VAL_6:.*]] = llvm.getelementptr %[[VAL_2]][0, %[[VAL_5]]] : (!llvm.ptr, i2) -> !llvm.ptr, !llvm.array<2 x i32>
|
||||
// CHECK-NEXT: %{{.+}} = llvm.load %[[VAL_6]] : !llvm.ptr -> i32
|
||||
%1 = hw.array_get %0[%arg0] : !hw.array<2xi32>, i1
|
||||
|
||||
|
|
Loading…
Reference in New Issue