@@ -1572,4 +1572,120 @@ def EmitC_SwitchOp : EmitC_Op<"switch", [RecursiveMemoryEffects,
15721572 let hasVerifier = 1;
15731573}
15741574
1575+ def EmitC_ClassOp : EmitC_Op<"class", [AutomaticAllocationScope,
1576+ IsolatedFromAbove, OpAsmOpInterface]> {
1577+ let summary =
1578+ "Represents a C++ class definition, encapsulating fields and methods.";
1579+
1580+ let description = [{
1581+ The `emitc.class` operation defines a C++ class, acting as a container
1582+ for its data fields (`emitc.variable`) and methods (`emitc.func`).
1583+ It creates a distinct scope, isolating its contents from the surrounding
1584+ MLIR region, similar to how C++ classes encapsulate their internals.
1585+
1586+ Example:
1587+ ```mlir
1588+ emitc.class @MyModelClass {
1589+ emitc.field @another_feature : !emitc.lvalue<!emitc.ptr<f32>>
1590+ emitc.field @some_feature : !emitc.lvalue<!emitc.ptr<f32>>
1591+ emitc.field @output_0 : !emitc.lvalue<!emitc.ptr<f32>>
1592+
1593+ emitc.func @main() attributes {tf.entry_function = {inputs = "serving_default_another_feature:0,serving_default_some_feature:0", outputs = "PartitionedCall:0"}, tf_saved_model.exported_names = ["serving_default"]} {
1594+ %c0 = "emitc.constant"() <{value = 0 : index}> : () -> !emitc.size_t
1595+
1596+ %some_ptr = emitc.get_field %self : @MyModelClass, @some_feature -> !emitc.ptr<f32>
1597+ %another_ptr = emitc.get_field %self : @MyModelClass, @another_feature -> !emitc.ptr<f32>
1598+ %output_ptr = emitc.get_field %self : @MyModelClass, @output_0 -> !emitc.ptr<f32>
1599+
1600+ %v1 = subscript %some_ptr[%c0] : (!emitc.ptr<f32>, !emitc.size_t) -> !emitc.lvalue<f32>
1601+ %v1_val = load %v1 : !emitc.lvalue<f32> -> f32
1602+
1603+ %v2 = subscript %another_ptr[%c0] : (!emitc.ptr<f32>, !emitc.size_t) -> !emitc.lvalue<f32>
1604+ %v2_val = load %v2 : !emitc.lvalue<f32> -> f32
1605+
1606+ %v3_val = add %v1_val, %v2_val : (f32, f32) -> f32
1607+
1608+ %output_lvalue = subscript %output_ptr[%c0] : (!emitc.ptr<f32>, !emitc.size_t) -> !emitc.lvalue<f32>
1609+ assign %v3_val, %output_lvalue : (f32, !emitc.lvalue<f32>) -> ()
1610+
1611+ return
1612+ }
1613+ }
1614+ }
1615+
1616+ ```
1617+ }];
1618+
1619+ let arguments = (ins SymbolNameAttr:$sym_name);
1620+
1621+ let regions = (region AnyRegion:$body);
1622+
1623+ let builders = [];
1624+
1625+ let extraClassDeclaration = [{
1626+ // Returns the body block containing class members and methods.
1627+ Block &getBlock();
1628+ }];
1629+
1630+ let hasCustomAssemblyFormat = 1;
1631+
1632+ let assemblyFormat = "`class` $sym_name attr-dict-with-keyword $body";
1633+ }
1634+
1635+ def EmitC_FieldOp : EmitC_Op<"field", [Symbol]> {
1636+ let summary = "A field within a class";
1637+ let description = [{
1638+ The `emitc.field` operation declares a named field within an `emitc.class`
1639+ operation. The field's type must be an EmitC type. An optional initial value can be provided.
1640+
1641+ Example with initial values:
1642+
1643+ ```mlir
1644+ emitc.class @MyModelClass {
1645+ emitc.field @another_feature : !emitc.lvalue<!emitc.ptr<f32>> = #emitc.value<0.0> : !emitc.f32
1646+ emitc.field @some_feature : !emitc.lvalue<!emitc.ptr<f32>> = #emitc.value<1.0> : !emitc.f32
1647+ emitc.field @output_0 : !emitc.lvalue<!emitc.ptr<f32>>
1648+ }
1649+ ```
1650+ Example without initial value:
1651+ ```mlir
1652+ emitc.class @MyModelClass {
1653+ emitc.field @another_feature : !emitc.lvalue<!emitc.ptr<f32>>
1654+ }
1655+ ```
1656+ }];
1657+
1658+ let arguments = (ins SymbolNameAttr:$sym_name, TypeAttr:$type,
1659+ OptionalAttr<AnyAttr>:$initial_value);
1660+
1661+ let assemblyFormat = "$sym_name `:` $type (`=` $initial_value^)? attr-dict";
1662+
1663+ let hasVerifier = 1;
1664+ }
1665+
1666+ def EmitC_GetFieldOp
1667+ : EmitC_Op<"get_field", [Pure, DeclareOpInterfaceMethods<
1668+ SymbolUserOpInterface>]> {
1669+ let summary = "Obtain access to a field within a class instance";
1670+ let description = [{
1671+ The `emitc.get_field` operation retrieves the lvalue of a
1672+ named field from a given class instance.
1673+
1674+ Example:
1675+
1676+ ```mlir
1677+ %some_ptr = emitc.get_field %self : @MyModelClass, @some_feature -> !emitc.ptr<f32>
1678+ %another_ptr = emitc.get_field %self : @MyModelClass, @another_feature -> !emitc.ptr<f32>
1679+ %output_ptr = emitc.get_field %self : @MyModelClass, @output_0 -> !emitc.ptr<f32>
1680+ ```
1681+ }];
1682+
1683+ let arguments = (ins AnyTypeOf<[EmitC_LValueType, EmitC_PointerType]>:$base,
1684+ FlatSymbolRefAttr:$class_name, FlatSymbolRefAttr:$field_name);
1685+
1686+ let results = (outs AnyTypeOf<[EmitC_LValueType, EmitC_PointerType]>:$result);
1687+ let assemblyFormat = "$base `:` type($base) $class_name `,` $field_name `->` "
1688+ "type($result) attr-dict";
1689+ }
1690+
15751691#endif // MLIR_DIALECT_EMITC_IR_EMITC
0 commit comments