Bump LLVM to 7ce613fc77af092dd6e9db71ce3747b75bc5616e (#6342)

This commit is contained in:
Fabian Schuiki 2023-10-26 13:53:12 -07:00 committed by GitHub
parent 58662f4415
commit 34c320f474
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
23 changed files with 1363 additions and 1346 deletions

View File

@ -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

View File

@ -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(

View File

@ -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

View File

@ -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]

View File

@ -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)

View File

@ -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]

View File

@ -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))

View File

@ -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"])

View File

@ -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)

View File

@ -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)

View File

@ -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

View File

@ -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]

View File

@ -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)

View File

@ -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]

View File

@ -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))

View File

@ -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"])

View File

@ -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)

View File

@ -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)

View File

@ -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);

View File

@ -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());
}

View File

@ -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

@ -1 +1 @@
Subproject commit 5f5faf407b42342708ce31a1ca3095ddff10dad8
Subproject commit 7ce613fc77af092dd6e9db71ce3747b75bc5616e

View File

@ -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