# CIRCT

Circuit IR Compilers and Tools

# Interop Dialect

Provides interoperability between backends and tools This dialect defines the interop dialect which defines operations and interfaces necessary to provide interoperability between backends and and external tools without the need of writing custom pairwise interop solutions.

## Operation definition

### interop.procedural.alloc (::circt::interop::ProceduralAllocOp)

represents persistent state to be allocated

Syntax:

operation ::= interop.procedural.alloc $interopMechanism ( : qualified(type($states))^ )? attr-dict


The interop.procedural.alloc operation returns a variadic list of values that represent persistent state, i.e., state that has to persist across multiple executions of the interop.procedural.update operation. For example, it can be lowered to C++ class fields that are persistent across multiple calls of a member function, or to global simulator state that persists over simulation cycles, etc.

Additionally, it has an attribute that specifies the interop mechanism under which the state types are valid. This is necessary to allow bridging patterns to map the types to valid types in the other interop mechanism, e.g., to an opaque pointer, if it does not support the same types.

#### Attributes:

AttributeMLIR TypeDescription
interopMechanism::InteropMechanismAttrinterface through which interoperability is achieved

#### Results:

ResultDescription
statesany type

### interop.procedural.dealloc (::circt::interop::ProceduralDeallocOp)

performs some deallocation logic before the state is released

Syntax:

operation ::= interop.procedural.dealloc $interopMechanism ($states^ : qualified(type($states)) )? attr-dict-with-keyword$deallocRegion


The interop.procedural.dealloc operation shall be executed right before the state requested by the interop.procedural.alloc operation is released. This allows the instance to do some cleanup, e.g., when the state type was a pointer and the instance performed some malloc.

Structurally the operation is the same as the interop.procedural.update operation, but without input and output values. The state is also passed by value.

Traits: NoTerminator, SingleBlock

#### Attributes:

AttributeMLIR TypeDescription
interopMechanism::InteropMechanismAttrinterface through which interoperability is achieved

#### Operands:

OperandDescription
statesany type

### interop.procedural.init (::circt::interop::ProceduralInitOp)

computes the initial values for the allocated state

Syntax:

operation ::= interop.procedural.init $interopMechanism ($states^ : qualified(type($states)) )? attr-dict-with-keyword$initRegion


The interop.procedural.init operation takes the variadic list of states from the interop.procedural.alloc operation as operands and has a body with a interop.return operation that has a variadic list of operands that matches the types of the states and represent the initial values to be assigned to the state values. The assignment will be inserted by the container-side lowering of the interop operations. The operation also has an interop mechanism attribute to allow bridging patterns to map the types to valid types in another interop mechanism and to wrap the operations in the body in a way to make them executable in the other interop mechanism, e.g., wrap them in a extern "C" function to make it callable from C or LLVM IR.

Traits: SingleBlock

#### Attributes:

AttributeMLIR TypeDescription
interopMechanism::InteropMechanismAttrinterface through which interoperability is achieved

#### Operands:

OperandDescription
statesany type

### interop.procedural.update (::circt::interop::ProceduralUpdateOp)

takes some persistent state and inputs to compute some results

Syntax:

operation ::= interop.procedural.update $interopMechanism (   [$states^ ] )? ( ( $inputs^ ) )? : ([ qualified(type($states))^ ])? functional-type($inputs,$outputs)
attr-dict-with-keyword $updateRegion  The interop.procedural.update operation has an interop mechanism attribute to allow bridging patterns to map the types to valid types in another interop mechanism and to wrap the operations in the body in a way to make them executable using the other interop mechanism. It takes the state values returned by the interop.procedural.allocas operands and passes them on to the body via block arguments using pass-by-value semantics. In addition to the state values, it also takes a variadic list of inputs and also passes them on to the body. The interop.return inside the body then returns the result values after doing some computation inside the body. If the state needs to be mutated, it has to be a pointer type. Traits: AttrSizedOperandSegments, SingleBlock #### Attributes: AttributeMLIR TypeDescription interopMechanism::InteropMechanismAttrinterface through which interoperability is achieved #### Operands: OperandDescription statesany type inputsany type #### Results: ResultDescription outputsany type ### interop.return (::circt::interop::ReturnOp) a return operation Syntax: operation ::= interop.return attr-dict ($returnValues^ : type(\$returnValues))?


The interop.return operation lists the computed initial values when inside the init operation or the computed results when inside the update operation.

Traits: HasParent<ProceduralInitOp, ProceduralUpdateOp>, ReturnLike, Terminator

#### Operands:

OperandDescription
returnValuesany type