mlir.dialects._emitc_ops_gen ============================ .. py:module:: mlir.dialects._emitc_ops_gen Attributes ---------- .. autoapisummary:: mlir.dialects._emitc_ops_gen._ods_ir Classes ------- .. autoapisummary:: mlir.dialects._emitc_ops_gen._Dialect mlir.dialects._emitc_ops_gen.AddOp mlir.dialects._emitc_ops_gen.ApplyOp mlir.dialects._emitc_ops_gen.AssignOp mlir.dialects._emitc_ops_gen.BitwiseAndOp mlir.dialects._emitc_ops_gen.BitwiseLeftShiftOp mlir.dialects._emitc_ops_gen.BitwiseNotOp mlir.dialects._emitc_ops_gen.BitwiseOrOp mlir.dialects._emitc_ops_gen.BitwiseRightShiftOp mlir.dialects._emitc_ops_gen.BitwiseXorOp mlir.dialects._emitc_ops_gen.CallOp mlir.dialects._emitc_ops_gen.CallOpaqueOp mlir.dialects._emitc_ops_gen.CastOp mlir.dialects._emitc_ops_gen.ClassOp mlir.dialects._emitc_ops_gen.CmpOp mlir.dialects._emitc_ops_gen.ConditionalOp mlir.dialects._emitc_ops_gen.ConstantOp mlir.dialects._emitc_ops_gen.DeclareFuncOp mlir.dialects._emitc_ops_gen.DivOp mlir.dialects._emitc_ops_gen.DoOp mlir.dialects._emitc_ops_gen.ExpressionOp mlir.dialects._emitc_ops_gen.FieldOp mlir.dialects._emitc_ops_gen.FileOp mlir.dialects._emitc_ops_gen.ForOp mlir.dialects._emitc_ops_gen.FuncOp mlir.dialects._emitc_ops_gen.GetFieldOp mlir.dialects._emitc_ops_gen.GetGlobalOp mlir.dialects._emitc_ops_gen.GlobalOp mlir.dialects._emitc_ops_gen.IfOp mlir.dialects._emitc_ops_gen.IncludeOp mlir.dialects._emitc_ops_gen.LiteralOp mlir.dialects._emitc_ops_gen.LoadOp mlir.dialects._emitc_ops_gen.LogicalAndOp mlir.dialects._emitc_ops_gen.LogicalNotOp mlir.dialects._emitc_ops_gen.LogicalOrOp mlir.dialects._emitc_ops_gen.MemberOfPtrOp mlir.dialects._emitc_ops_gen.MemberOp mlir.dialects._emitc_ops_gen.MulOp mlir.dialects._emitc_ops_gen.RemOp mlir.dialects._emitc_ops_gen.ReturnOp mlir.dialects._emitc_ops_gen.SubOp mlir.dialects._emitc_ops_gen.SubscriptOp mlir.dialects._emitc_ops_gen.SwitchOp mlir.dialects._emitc_ops_gen.UnaryMinusOp mlir.dialects._emitc_ops_gen.UnaryPlusOp mlir.dialects._emitc_ops_gen.VariableOp mlir.dialects._emitc_ops_gen.VerbatimOp mlir.dialects._emitc_ops_gen.YieldOp Functions --------- .. autoapisummary:: mlir.dialects._emitc_ops_gen.add mlir.dialects._emitc_ops_gen.apply mlir.dialects._emitc_ops_gen.assign mlir.dialects._emitc_ops_gen.bitwise_and mlir.dialects._emitc_ops_gen.bitwise_left_shift mlir.dialects._emitc_ops_gen.bitwise_not mlir.dialects._emitc_ops_gen.bitwise_or mlir.dialects._emitc_ops_gen.bitwise_right_shift mlir.dialects._emitc_ops_gen.bitwise_xor mlir.dialects._emitc_ops_gen.call mlir.dialects._emitc_ops_gen.call_opaque mlir.dialects._emitc_ops_gen.cast mlir.dialects._emitc_ops_gen.class_ mlir.dialects._emitc_ops_gen.cmp mlir.dialects._emitc_ops_gen.conditional mlir.dialects._emitc_ops_gen.constant mlir.dialects._emitc_ops_gen.declare_func mlir.dialects._emitc_ops_gen.div mlir.dialects._emitc_ops_gen.do mlir.dialects._emitc_ops_gen.expression mlir.dialects._emitc_ops_gen.field mlir.dialects._emitc_ops_gen.file mlir.dialects._emitc_ops_gen.for_ mlir.dialects._emitc_ops_gen.func mlir.dialects._emitc_ops_gen.get_field mlir.dialects._emitc_ops_gen.get_global mlir.dialects._emitc_ops_gen.global_ mlir.dialects._emitc_ops_gen.if_ mlir.dialects._emitc_ops_gen.include mlir.dialects._emitc_ops_gen.literal mlir.dialects._emitc_ops_gen.load mlir.dialects._emitc_ops_gen.logical_and mlir.dialects._emitc_ops_gen.logical_not mlir.dialects._emitc_ops_gen.logical_or mlir.dialects._emitc_ops_gen.member_of_ptr mlir.dialects._emitc_ops_gen.member mlir.dialects._emitc_ops_gen.mul mlir.dialects._emitc_ops_gen.rem mlir.dialects._emitc_ops_gen.return_ mlir.dialects._emitc_ops_gen.sub mlir.dialects._emitc_ops_gen.subscript mlir.dialects._emitc_ops_gen.switch mlir.dialects._emitc_ops_gen.unary_minus mlir.dialects._emitc_ops_gen.unary_plus mlir.dialects._emitc_ops_gen.variable mlir.dialects._emitc_ops_gen.verbatim mlir.dialects._emitc_ops_gen.yield_ Module Contents --------------- .. py:data:: _ods_ir .. py:class:: _Dialect(descriptor: object) Bases: :py:obj:`_ods_ir` .. py:attribute:: DIALECT_NAMESPACE :value: 'emitc' .. py:class:: AddOp(result, lhs, rhs, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` With the ``emitc.add`` operation the arithmetic operator + (addition) can be applied. Example: .. code:: mlir // Custom form of the addition operation. %0 = emitc.add %arg0, %arg1 : (i32, i32) -> i32 %1 = emitc.add %arg2, %arg3 : (!emitc.ptr, i32) -> !emitc.ptr .. code:: c++ // Code emitted for the operations above. int32_t v5 = v1 + v2; float* v6 = v3 + v4; .. py:attribute:: OPERATION_NAME :value: 'emitc.add' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: lhs() -> _ods_ir .. py:method:: rhs() -> _ods_ir .. py:function:: add(result, lhs, rhs, *, loc=None, ip=None) -> _ods_ir .. py:class:: ApplyOp(result, applicableOperator, operand, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` With the ``emitc.apply`` operation the operators & (address of) and * (contents of) can be applied to a single operand. Example: .. code:: mlir // Custom form of applying the & operator. %0 = emitc.apply "&"(%arg0) : (!emitc.lvalue) -> !emitc.ptr // Generic form of the same operation. %0 = "emitc.apply"(%arg0) {applicableOperator = "&"} : (!emitc.lvalue) -> !emitc.ptr .. py:attribute:: OPERATION_NAME :value: 'emitc.apply' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: operand() -> _ods_ir .. py:method:: applicableOperator() -> _ods_ir .. py:method:: result() -> _ods_ir Shortcut to get an op result if it has only one (throws an error otherwise). .. py:function:: apply(result, applicable_operator, operand, *, loc=None, ip=None) -> _ods_ir .. py:class:: AssignOp(var, value, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` The ``emitc.assign`` operation stores an SSA value to the location designated by an EmitC variable. This operation doesn't return any value. The assigned value must be of the same type as the variable being assigned. The operation is emitted as a C/C++ '=' operator. Example: .. code:: mlir // Integer variable %0 = "emitc.variable"(){value = 42 : i32} : () -> !emitc.lvalue %1 = emitc.call_opaque "foo"() : () -> (i32) // Assign emitted as `... = ...;` "emitc.assign"(%0, %1) : (!emitc.lvalue, i32) -> () .. py:attribute:: OPERATION_NAME :value: 'emitc.assign' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: var() -> _ods_ir .. py:method:: value() -> _ods_ir .. py:function:: assign(var, value, *, loc=None, ip=None) -> AssignOp .. py:class:: BitwiseAndOp(result, lhs, rhs, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` With the ``emitc.bitwise_and`` operation the bitwise operator & (and) can be applied. Example: .. code:: mlir %0 = emitc.bitwise_and %arg0, %arg1 : (i32, i32) -> i32 .. code:: c++ // Code emitted for the operation above. int32_t v3 = v1 & v2; .. py:attribute:: OPERATION_NAME :value: 'emitc.bitwise_and' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: lhs() -> _ods_ir .. py:method:: rhs() -> _ods_ir .. py:function:: bitwise_and(result, lhs, rhs, *, loc=None, ip=None) -> _ods_ir .. py:class:: BitwiseLeftShiftOp(result, lhs, rhs, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` With the ``emitc.bitwise_left_shift`` operation the bitwise operator << (left shift) can be applied. Example: .. code:: mlir %0 = emitc.bitwise_left_shift %arg0, %arg1 : (i32, i32) -> i32 .. code:: c++ // Code emitted for the operation above. int32_t v3 = v1 << v2; .. py:attribute:: OPERATION_NAME :value: 'emitc.bitwise_left_shift' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: lhs() -> _ods_ir .. py:method:: rhs() -> _ods_ir .. py:function:: bitwise_left_shift(result, lhs, rhs, *, loc=None, ip=None) -> _ods_ir .. py:class:: BitwiseNotOp(result, _gen_arg_0, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` With the ``emitc.bitwise_not`` operation the bitwise operator ~ (not) can be applied. Example: .. code:: mlir %0 = emitc.bitwise_not %arg0 : (i32) -> i32 .. code:: c++ // Code emitted for the operation above. int32_t v2 = ~v1; .. py:attribute:: OPERATION_NAME :value: 'emitc.bitwise_not' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:function:: bitwise_not(result, _gen_arg_0, *, loc=None, ip=None) -> _ods_ir .. py:class:: BitwiseOrOp(result, lhs, rhs, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` With the ``emitc.bitwise_or`` operation the bitwise operator | (or) can be applied. Example: .. code:: mlir %0 = emitc.bitwise_or %arg0, %arg1 : (i32, i32) -> i32 .. code:: c++ // Code emitted for the operation above. int32_t v3 = v1 | v2; .. py:attribute:: OPERATION_NAME :value: 'emitc.bitwise_or' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: lhs() -> _ods_ir .. py:method:: rhs() -> _ods_ir .. py:function:: bitwise_or(result, lhs, rhs, *, loc=None, ip=None) -> _ods_ir .. py:class:: BitwiseRightShiftOp(result, lhs, rhs, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` With the ``emitc.bitwise_right_shift`` operation the bitwise operator >> (right shift) can be applied. Example: .. code:: mlir %0 = emitc.bitwise_right_shift %arg0, %arg1 : (i32, i32) -> i32 .. code:: c++ // Code emitted for the operation above. int32_t v3 = v1 >> v2; .. py:attribute:: OPERATION_NAME :value: 'emitc.bitwise_right_shift' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: lhs() -> _ods_ir .. py:method:: rhs() -> _ods_ir .. py:function:: bitwise_right_shift(result, lhs, rhs, *, loc=None, ip=None) -> _ods_ir .. py:class:: BitwiseXorOp(result, lhs, rhs, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` With the ``emitc.bitwise_xor`` operation the bitwise operator ^ (xor) can be applied. Example: .. code:: mlir %0 = emitc.bitwise_xor %arg0, %arg1 : (i32, i32) -> i32 .. code:: c++ // Code emitted for the operation above. int32_t v3 = v1 ^ v2; .. py:attribute:: OPERATION_NAME :value: 'emitc.bitwise_xor' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: lhs() -> _ods_ir .. py:method:: rhs() -> _ods_ir .. py:function:: bitwise_xor(result, lhs, rhs, *, loc=None, ip=None) -> _ods_ir .. py:class:: CallOp(result, callee, operands_, *, arg_attrs=None, res_attrs=None, loc=None, ip=None) Bases: :py:obj:`_ods_ir` The ``emitc.call`` operation represents a direct call to an ``emitc.func`` that is within the same symbol scope as the call. The operands and result type of the call must match the specified function type. The callee is encoded as a symbol reference attribute named "callee". Example: .. code:: mlir %2 = emitc.call @my_add(%0, %1) : (f32, f32) -> f32 .. py:attribute:: OPERATION_NAME :value: 'emitc.call' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: operands_() -> _ods_ir .. py:method:: callee() -> _ods_ir .. py:method:: arg_attrs() -> Optional[_ods_ir] .. py:method:: res_attrs() -> Optional[_ods_ir] .. py:function:: call(result, callee, operands_, *, arg_attrs=None, res_attrs=None, loc=None, ip=None) -> Union[_ods_ir, _ods_ir, CallOp] .. py:class:: CallOpaqueOp(result, callee, operands_, *, args=None, template_args=None, loc=None, ip=None) Bases: :py:obj:`_ods_ir` The ``emitc.call_opaque`` operation represents a C++ function call. The callee can be an arbitrary non-empty string. The call allows specifying order of operands and attributes in the call as follows: * integer value of index type refers to an operand; * attribute which will get lowered to constant value in call; Example: .. code:: mlir // Custom form defining a call to `foo()`. %0 = emitc.call_opaque "foo" () : () -> i32 // Generic form of the same operation. %0 = "emitc.call_opaque"() {callee = "foo"} : () -> i32 .. py:attribute:: OPERATION_NAME :value: 'emitc.call_opaque' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: operands_() -> _ods_ir .. py:method:: callee() -> _ods_ir .. py:method:: args() -> Optional[_ods_ir] .. py:method:: template_args() -> Optional[_ods_ir] .. py:function:: call_opaque(result, callee, operands_, *, args=None, template_args=None, loc=None, ip=None) -> Union[_ods_ir, _ods_ir, CallOpaqueOp] .. py:class:: CastOp(dest, source, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` The ``emitc.cast`` operation performs an explicit type conversion and is emitted as a C-style cast expression. It can be applied to integer, float, index and EmitC types. Example: .. code:: mlir // Cast from `int32_t` to `float` %0 = emitc.cast %arg0: i32 to f32 // Cast from `void` to `int32_t` pointer %1 = emitc.cast %arg1 : !emitc.ptr> to !emitc.ptr .. py:attribute:: OPERATION_NAME :value: 'emitc.cast' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: source() -> _ods_ir .. py:method:: dest() -> _ods_ir .. py:function:: cast(dest, source, *, loc=None, ip=None) -> _ods_ir .. py:class:: ClassOp(sym_name, *, final_specifier=None, loc=None, ip=None) Bases: :py:obj:`_ods_ir` The ``emitc.class`` operation defines a C++ class, acting as a container for its data fields (``emitc.field``) and methods (``emitc.func``). It creates a distinct scope, isolating its contents from the surrounding MLIR region, similar to how C++ classes encapsulate their internals. Example: .. code:: mlir emitc.class @modelClass { emitc.field @fieldName0 : !emitc.array<1xf32> = {emitc.opaque = "input_tensor"} emitc.func @execute() { %0 = "emitc.constant"() <{value = 0 : index}> : () -> !emitc.size_t %1 = get_field @fieldName0 : !emitc.array<1xf32> %2 = subscript %1[%0] : (!emitc.array<1xf32>, !emitc.size_t) -> !emitc.lvalue return } } // Class with a final specifer emitc.class final @modelClass { emitc.field @fieldName0 : !emitc.array<1xf32> = {emitc.opaque = "input_tensor"} emitc.func @execute() { %0 = "emitc.constant"() <{value = 0 : index}> : () -> !emitc.size_t %1 = get_field @fieldName0 : !emitc.array<1xf32> %2 = subscript %1[%0] : (!emitc.array<1xf32>, !emitc.size_t) -> !emitc.lvalue return } } .. py:attribute:: OPERATION_NAME :value: 'emitc.class' .. py:attribute:: _ODS_REGIONS :value: (1, True) .. py:method:: sym_name() -> _ods_ir .. py:method:: final_specifier() -> bool .. py:method:: body() -> _ods_ir .. py:function:: class_(sym_name, *, final_specifier=None, loc=None, ip=None) -> ClassOp .. py:class:: CmpOp(result, predicate, lhs, rhs, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` With the ``emitc.cmp`` operation the comparison operators ==, !=, <, <=, >, >=, <=> can be applied. Its first argument is an attribute that defines the comparison operator: * equal to (mnemonic: ``"eq"``; integer value: ``0``) * not equal to (mnemonic: ``"ne"``; integer value: ``1``) * less than (mnemonic: ``"lt"``; integer value: ``2``) * less than or equal to (mnemonic: ``"le"``; integer value: ``3``) * greater than (mnemonic: ``"gt"``; integer value: ``4``) * greater than or equal to (mnemonic: ``"ge"``; integer value: ``5``) * three-way-comparison (mnemonic: ``"three_way"``; integer value: ``6``) Example: .. code:: mlir // Custom form of the cmp operation. %0 = emitc.cmp eq, %arg0, %arg1 : (i32, i32) -> i1 %1 = emitc.cmp lt, %arg2, %arg3 : ( !emitc.opaque<"std::valarray">, !emitc.opaque<"std::valarray"> ) -> !emitc.opaque<"std::valarray"> .. code:: c++ // Code emitted for the operations above. bool v5 = v1 == v2; std::valarray v6 = v3 < v4; .. py:attribute:: OPERATION_NAME :value: 'emitc.cmp' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: lhs() -> _ods_ir .. py:method:: rhs() -> _ods_ir .. py:method:: predicate() -> _ods_ir .. py:function:: cmp(result, predicate, lhs, rhs, *, loc=None, ip=None) -> _ods_ir .. py:class:: ConditionalOp(result, condition, true_value, false_value, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` With the ``emitc.conditional`` operation the ternary conditional operator can be applied. Example: .. code:: mlir %0 = emitc.cmp gt, %arg0, %arg1 : (i32, i32) -> i1 %c0 = "emitc.constant"() {value = 10 : i32} : () -> i32 %c1 = "emitc.constant"() {value = 11 : i32} : () -> i32 %1 = emitc.conditional %0, %c0, %c1 : i32 .. code:: c++ // Code emitted for the operations above. bool v3 = v1 > v2; int32_t v4 = 10; int32_t v5 = 11; int32_t v6 = v3 ? v4 : v5; .. py:attribute:: OPERATION_NAME :value: 'emitc.conditional' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: condition() -> _ods_ir .. py:method:: true_value() -> _ods_ir .. py:method:: false_value() -> _ods_ir .. py:method:: result() -> _ods_ir Shortcut to get an op result if it has only one (throws an error otherwise). .. py:function:: conditional(result, condition, true_value, false_value, *, loc=None, ip=None) -> _ods_ir .. py:class:: ConstantOp(result, value, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` The ``emitc.constant`` operation produces an SSA value equal to some constant specified by an attribute. This can be used to form simple integer and floating point constants, as well as more exotic things like tensor constants. The ``emitc.constant`` operation also supports the EmitC opaque attribute and the EmitC opaque type. Since folding is supported, it should not be used with pointers. Example: .. code:: mlir // Integer constant %0 = "emitc.constant"(){value = 42 : i32} : () -> i32 // Constant emitted as `char = CHAR_MIN;` %1 = "emitc.constant"() {value = #emitc.opaque<"CHAR_MIN">} : () -> !emitc.opaque<"char"> .. py:attribute:: OPERATION_NAME :value: 'emitc.constant' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: value() -> _ods_ir .. py:function:: constant(result, value, *, loc=None, ip=None) -> _ods_ir .. py:class:: DeclareFuncOp(sym_name, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` The ``emitc.declare_func`` operation allows to insert a function declaration for an ``emitc.func`` at a specific position. The operation only requires the "callee" of the ``emitc.func`` to be specified as an attribute. Example: .. code:: mlir emitc.declare_func @bar emitc.func @foo(%arg0: i32) -> i32 { %0 = emitc.call @bar(%arg0) : (i32) -> (i32) emitc.return %0 : i32 } emitc.func @bar(%arg0: i32) -> i32 { emitc.return %arg0 : i32 } .. code:: c++ // Code emitted for the operations above. int32_t bar(int32_t v1); int32_t foo(int32_t v1) { int32_t v2 = bar(v1); return v2; } int32_t bar(int32_t v1) { return v1; } .. py:attribute:: OPERATION_NAME :value: 'emitc.declare_func' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: sym_name() -> _ods_ir .. py:function:: declare_func(sym_name, *, loc=None, ip=None) -> DeclareFuncOp .. py:class:: DivOp(result, _gen_arg_0, _gen_arg_1, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` With the ``emitc.div`` operation the arithmetic operator / (division) can be applied. Example: .. code:: mlir // Custom form of the division operation. %0 = emitc.div %arg0, %arg1 : (i32, i32) -> i32 %1 = emitc.div %arg2, %arg3 : (f32, f32) -> f32 .. code:: c++ // Code emitted for the operations above. int32_t v5 = v1 / v2; float v6 = v3 / v4; .. py:attribute:: OPERATION_NAME :value: 'emitc.div' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:function:: div(result, _gen_arg_0, _gen_arg_1, *, loc=None, ip=None) -> _ods_ir .. py:class:: DoOp(*, loc=None, ip=None) Bases: :py:obj:`_ods_ir` The ``emitc.do`` operation represents a C/C++ do-while loop construct that repeatedly executes a body region as long as a condition region evaluates to true. The operation has two regions: #. A body region that contains the loop body #. A condition region that must yield a boolean value (i1) The condition is evaluated before each iteration as follows: * The condition region must contain exactly one block with: #. An ``emitc.expression`` operation producing an i1 value #. An ``emitc.yield`` passing through the expression result * The expression's body contains the actual condition logic The body region is executed before the first evaluation of the condition. Thus, there is a guarantee that the loop will be executed at least once. The loop terminates when the condition yields false. The canonical structure of ``emitc.do`` is: .. code:: mlir emitc.do { // Body region (no terminator required). // Loop body operations... } while { // Condition region (must yield i1) %condition = emitc.expression : () -> i1 { // Condition computation... %result = ... : i1 // Last operation must produce i1 emitc.yield %result : i1 } // Forward expression result emitc.yield %condition : i1 } Example: .. code:: mlir emitc.func @do_example() { %counter = "emitc.variable"() <{value = 0 : i32}> : () -> !emitc.lvalue %end = emitc.literal "10" : i32 %step = emitc.literal "1" : i32 emitc.do { // Print current value %val = emitc.load %counter : !emitc.lvalue emitc.verbatim "printf(\"%d\\n\", {});" args %val : i32 // Increment counter %new_val = emitc.add %val, %step : (i32, i32) -> i32 "emitc.assign"(%counter, %new_val) : (!emitc.lvalue, i32) -> () } while { %condition = emitc.expression %counter, %end : (!emitc.lvalue, i32) -> i1 { %current = emitc.load %counter : !emitc.lvalue %cmp_res = emitc.cmp lt, %current, %end : (i32, i32) -> i1 emitc.yield %cmp_res : i1 } emitc.yield %condition : i1 } return } .. code:: c++ // Code emitted for the operation above. void do_example() { int32_t v1 = 0; do { int32_t v2 = v1; printf("%d\n", v2); int32_t v3 = v2 + 1; v1 = v3; } while (v1 < 10); return; } .. py:attribute:: OPERATION_NAME :value: 'emitc.do' .. py:attribute:: _ODS_REGIONS :value: (2, True) .. py:method:: bodyRegion() -> _ods_ir .. py:method:: conditionRegion() -> _ods_ir .. py:function:: do(*, loc=None, ip=None) -> DoOp .. py:class:: ExpressionOp(result, defs, *, do_not_inline=None, loc=None, ip=None) Bases: :py:obj:`_ods_ir` The ``emitc.expression`` operation returns a single SSA value which is yielded by its single-basic-block region. The operation takes zero or more input operands that are passed as block arguments to the region. As the operation is to be emitted as a C expression, the operations within its body must form a single Def-Use tree, or a DAG trivially expandable to one, i.e. a DAG where each operation with side effects is only reachable once from the expression root. Input operands can be of both value types (``EmitCType``) and lvalue types (``EmitC_LValueType``). Example: .. code:: mlir %r = emitc.expression %a, %b, %c : (i32, i32, i32) -> i32 { %0 = emitc.call_opaque "foo"(%a) : (i32) -> i32 %1 = emitc.add %b, %c : (i32, i32) -> i32 %2 = emitc.mul %0, %1 : (i32, i32) -> i32 emitc.yield %2 : i32 } May be emitted as: .. code:: c++ int32_t v4 = foo(v1) * (v2 + v3); When specified, the optional ``noinline`` indicates that the expression is to be emitted as seen above, i.e. as the rhs of an EmitC SSA value definition. Otherwise, the expression may be emitted inline, i.e. directly at its use. .. py:attribute:: OPERATION_NAME :value: 'emitc.expression' .. py:attribute:: _ODS_REGIONS :value: (1, True) .. py:method:: defs() -> _ods_ir .. py:method:: do_not_inline() -> bool .. py:method:: result() -> _ods_ir Shortcut to get an op result if it has only one (throws an error otherwise). .. py:method:: region() -> _ods_ir .. py:function:: expression(result, defs, *, do_not_inline=None, loc=None, ip=None) -> _ods_ir .. py:class:: FieldOp(sym_name, type_, *, initial_value=None, loc=None, ip=None) Bases: :py:obj:`_ods_ir` The ``emitc.field`` operation declares a named field within an ``emitc.class`` operation. The field's type must be an EmitC type. Example: .. code:: mlir // Example with an attribute: emitc.field @fieldName0 : !emitc.array<1xf32> {emitc.opaque = "another_feature"} // Example with no attribute: emitc.field @fieldName0 : !emitc.array<1xf32> // Example with an initial value: emitc.field @fieldName0 : !emitc.array<1xf32> = dense<0.0> // Example with an initial value and attributes: emitc.field @fieldName0 : !emitc.array<1xf32> = dense<0.0> { emitc.opaque = "input_tensor"} .. py:attribute:: OPERATION_NAME :value: 'emitc.field' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: sym_name() -> _ods_ir .. py:method:: type_() -> _ods_ir .. py:method:: initial_value() -> Optional[_ods_ir] .. py:function:: field(sym_name, type_, *, initial_value=None, loc=None, ip=None) -> FieldOp .. py:class:: FileOp(id, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` A ``file`` represents a single C/C++ file. ``mlir-translate`` ignores the body of all ``emitc.file`` ops unless the ``-file-id=id`` flag is used. With that flag, all ``emitc.file`` ops with matching id are emitted. Example: .. code:: mlir emitc.file "main" { emitc.func @func_one() { emitc.return } } .. py:attribute:: OPERATION_NAME :value: 'emitc.file' .. py:attribute:: _ODS_REGIONS :value: (1, True) .. py:method:: id() -> _ods_ir .. py:method:: bodyRegion() -> _ods_ir .. py:function:: file(id, *, loc=None, ip=None) -> FileOp .. py:class:: ForOp(lowerBound, upperBound, step, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` The ``emitc.for`` operation represents a C loop of the following form: .. code:: c++ for (T i = lb; i < ub; i += step) { /* ... */ } // where T is typeof(lb) The operation takes 3 SSA values as operands that represent the lower bound, upper bound and step respectively, and defines an SSA value for its induction variable. It has one region capturing the loop body. The induction variable is represented as an argument of this region. This SSA value is a signless integer, or an index. The step is a value of same type. This operation has no result. The body region must contain exactly one block that terminates with ``emitc.yield``. Calling ForOp::build will create such a region and insert the terminator implicitly if none is defined, so will the parsing even in cases when it is absent from the custom format. For example: .. code:: mlir // Index case. emitc.for %iv = %lb to %ub step %step { ... // body } ... // Integer case. emitc.for %iv_32 = %lb_32 to %ub_32 step %step_32 : i32 { ... // body } .. py:attribute:: OPERATION_NAME :value: 'emitc.for' .. py:attribute:: _ODS_REGIONS :value: (1, True) .. py:method:: lowerBound() -> _ods_ir .. py:method:: upperBound() -> _ods_ir .. py:method:: step() -> _ods_ir .. py:method:: region() -> _ods_ir .. py:function:: for_(lower_bound, upper_bound, step, *, loc=None, ip=None) -> ForOp .. py:class:: FuncOp(sym_name, function_type, *, specifiers=None, arg_attrs=None, res_attrs=None, loc=None, ip=None) Bases: :py:obj:`_ods_ir` Operations within the function cannot implicitly capture values defined outside of the function, i.e. Functions are ``IsolatedFromAbove``. All external references must use function arguments or attributes that establish a symbolic connection (e.g. symbols referenced by name via a string attribute like SymbolRefAttr). While the MLIR textual form provides a nice inline syntax for function arguments, they are internally represented as “block arguments” to the first block in the region. Only dialect attribute names may be specified in the attribute dictionaries for function arguments, results, or the function itself. Example: .. code:: mlir // A function with no results: emitc.func @foo(%arg0 : i32) { emitc.call_opaque "bar" (%arg0) : (i32) -> () emitc.return } // A function with its argument as single result: emitc.func @foo(%arg0 : i32) -> i32 { emitc.return %arg0 : i32 } // A function with specifiers attribute: emitc.func @example_specifiers_fn_attr() -> i32 attributes {specifiers = ["static","inline"]} { %0 = emitc.call_opaque "foo" (): () -> i32 emitc.return %0 : i32 } // An external function definition: emitc.func private @extern_func(i32) attributes {specifiers = ["extern"]} .. py:attribute:: OPERATION_NAME :value: 'emitc.func' .. py:attribute:: _ODS_REGIONS :value: (1, True) .. py:method:: sym_name() -> _ods_ir .. py:method:: function_type() -> _ods_ir .. py:method:: specifiers() -> Optional[_ods_ir] .. py:method:: arg_attrs() -> Optional[_ods_ir] .. py:method:: res_attrs() -> Optional[_ods_ir] .. py:method:: body() -> _ods_ir .. py:function:: func(sym_name, function_type, *, specifiers=None, arg_attrs=None, res_attrs=None, loc=None, ip=None) -> FuncOp .. py:class:: GetFieldOp(result, field_name, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` The ``emitc.get_field`` operation retrieves the lvalue of a named field from a given class instance. Example: .. code:: mlir %0 = get_field @fieldName0 : !emitc.array<1xf32> .. py:attribute:: OPERATION_NAME :value: 'emitc.get_field' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: field_name() -> _ods_ir .. py:method:: result() -> _ods_ir Shortcut to get an op result if it has only one (throws an error otherwise). .. py:function:: get_field(result, field_name, *, loc=None, ip=None) -> _ods_ir .. py:class:: GetGlobalOp(result, name, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` The ``emitc.get_global`` operation retrieves the lvalue of a named global variable. If the global variable is marked constant, assigning to that lvalue is undefined. Example: .. code:: mlir %x = emitc.get_global @foo : !emitc.array<2xf32> %y = emitc.get_global @bar : !emitc.lvalue .. py:attribute:: OPERATION_NAME :value: 'emitc.get_global' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: name() -> _ods_ir Returns the fully qualified name of the operation. .. py:method:: result() -> _ods_ir Shortcut to get an op result if it has only one (throws an error otherwise). .. py:function:: get_global(result, name, *, loc=None, ip=None) -> _ods_ir .. py:class:: GlobalOp(sym_name, type_, *, initial_value=None, extern_specifier=None, static_specifier=None, const_specifier=None, loc=None, ip=None) Bases: :py:obj:`_ods_ir` The ``emitc.global`` operation declares or defines a named global variable. The backing memory for the variable is allocated statically and described by the variable's type, which must be an EmitC type. Optionally, an ``initial_value`` can be provided. Internal linkage can be specified using the ``static_specifier`` unit attribute and external linkage can be specified using the ``extern_specifier`` unit attribute. Note that the default linkage without those two keywords depends on whether the target is C or C++ and whether the global variable is ``const``. The global variable can also be marked constant using the ``const_specifier`` unit attribute. Writing to such constant global variables is undefined. The global variable can be accessed by using the ``emitc.get_global`` to retrieve the value for the global variable. Example: .. code:: mlir // Global variable with an initial value. emitc.global @x : !emitc.array<2xf32> = dense<0.0> // Global variable with an initial values. emitc.global @x : !emitc.array<3xi32> = dense<[0, 1, 2]> // Global variable with an opaque initial value. emitc.global @x : !emitc.opaque<"char"> = #emitc.opaque<"CHAR_MIN"> // External global variable emitc.global extern @x : !emitc.array<2xf32> // Constant global variable with internal linkage emitc.global static const @x : i32 = 0 .. py:attribute:: OPERATION_NAME :value: 'emitc.global' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: sym_name() -> _ods_ir .. py:method:: type_() -> _ods_ir .. py:method:: initial_value() -> Optional[_ods_ir] .. py:method:: extern_specifier() -> bool .. py:method:: static_specifier() -> bool .. py:method:: const_specifier() -> bool .. py:function:: global_(sym_name, type_, *, initial_value=None, extern_specifier=None, static_specifier=None, const_specifier=None, loc=None, ip=None) -> GlobalOp .. py:class:: IfOp(condition, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` The ``emitc.if`` operation represents an if-then-else construct for conditionally executing two regions of code. The operand to an if operation is a boolean value. For example: .. code:: mlir emitc.if %b { ... } else { ... } The "then" region has exactly 1 block. The "else" region may have 0 or 1 blocks. The blocks are always terminated with ``emitc.yield``, which can be left out to be inserted implicitly. This operation doesn't produce any results. .. py:attribute:: OPERATION_NAME :value: 'emitc.if' .. py:attribute:: _ODS_REGIONS :value: (2, True) .. py:method:: condition() -> _ods_ir .. py:method:: thenRegion() -> _ods_ir .. py:method:: elseRegion() -> _ods_ir .. py:function:: if_(condition, *, loc=None, ip=None) -> IfOp .. py:class:: IncludeOp(include, *, is_standard_include=None, loc=None, ip=None) Bases: :py:obj:`_ods_ir` The ``emitc.include`` operation allows to define a source file inclusion via the ``#include`` directive. Example: .. code:: mlir // Custom form defining the inclusion of ``. emitc.include <"myheader.h"> // Generic form of the same operation. "emitc.include" (){include = "myheader.h", is_standard_include} : () -> () // Custom form defining the inclusion of `"myheader"`. emitc.include "myheader.h" // Generic form of the same operation. "emitc.include" (){include = "myheader.h"} : () -> () .. py:attribute:: OPERATION_NAME :value: 'emitc.include' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: include() -> _ods_ir .. py:method:: is_standard_include() -> bool .. py:function:: include(include, *, is_standard_include=None, loc=None, ip=None) -> IncludeOp .. py:class:: LiteralOp(result, value, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` The ``emitc.literal`` operation produces an SSA value equal to some constant specified by an attribute. Example: .. code:: mlir %p0 = emitc.literal "M_PI" : f32 %1 = "emitc.add" (%arg0, %p0) : (f32, f32) -> f32 .. code:: c++ // Code emitted for the operation above. float v2 = v1 + M_PI; .. py:attribute:: OPERATION_NAME :value: 'emitc.literal' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: value() -> _ods_ir .. py:method:: result() -> _ods_ir Shortcut to get an op result if it has only one (throws an error otherwise). .. py:function:: literal(result, value, *, loc=None, ip=None) -> _ods_ir .. py:class:: LoadOp(result, operand, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` This operation loads the content of a modifiable lvalue into an SSA value. Modifications of the lvalue executed after the load are not observable on the produced value. Example: .. code:: mlir %1 = emitc.load %0 : !emitc.lvalue .. code:: c++ // Code emitted for the operation above. int32_t v2 = v1; .. py:attribute:: OPERATION_NAME :value: 'emitc.load' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: operand() -> _ods_ir .. py:method:: result() -> _ods_ir Shortcut to get an op result if it has only one (throws an error otherwise). .. py:function:: load(result, operand, *, loc=None, ip=None) -> _ods_ir .. py:class:: LogicalAndOp(result, lhs, rhs, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` With the ``emitc.logical_and`` operation the logical operator && (and) can be applied. Example: .. code:: mlir %0 = emitc.logical_and %arg0, %arg1 : i32, i32 .. code:: c++ // Code emitted for the operation above. bool v3 = v1 && v2; .. py:attribute:: OPERATION_NAME :value: 'emitc.logical_and' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: lhs() -> _ods_ir .. py:method:: rhs() -> _ods_ir .. py:function:: logical_and(result, lhs, rhs, *, loc=None, ip=None) -> _ods_ir .. py:class:: LogicalNotOp(result, _gen_arg_0, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` With the ``emitc.logical_not`` operation the logical operator ! (negation) can be applied. Example: .. code:: mlir %0 = emitc.logical_not %arg0 : i32 .. code:: c++ // Code emitted for the operation above. bool v2 = !v1; .. py:attribute:: OPERATION_NAME :value: 'emitc.logical_not' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:function:: logical_not(result, _gen_arg_0, *, loc=None, ip=None) -> _ods_ir .. py:class:: LogicalOrOp(result, lhs, rhs, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` With the ``emitc.logical_or`` operation the logical operator || (inclusive or) can be applied. Example: .. code:: mlir %0 = emitc.logical_or %arg0, %arg1 : i32, i32 .. code:: c++ // Code emitted for the operation above. bool v3 = v1 || v2; .. py:attribute:: OPERATION_NAME :value: 'emitc.logical_or' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: lhs() -> _ods_ir .. py:method:: rhs() -> _ods_ir .. py:function:: logical_or(result, lhs, rhs, *, loc=None, ip=None) -> _ods_ir .. py:class:: MemberOfPtrOp(result, member, operand, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` With the ``emitc.member_of_ptr`` operation the member access operator ``->`` can be applied. Example: .. code:: mlir %0 = "emitc.member_of_ptr" (%arg0) {member = "a"} : (!emitc.lvalue>>) -> !emitc.lvalue %1 = "emitc.member_of_ptr" (%arg0) {member = "b"} : (!emitc.lvalue>>) -> !emitc.array<2xi32> .. py:attribute:: OPERATION_NAME :value: 'emitc.member_of_ptr' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: operand() -> _ods_ir .. py:method:: member() -> _ods_ir .. py:function:: member_of_ptr(result, member, operand, *, loc=None, ip=None) -> _ods_ir .. py:class:: MemberOp(result, member, operand, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` With the ``emitc.member`` operation the member access operator ``.`` can be applied. Example: .. code:: mlir %0 = "emitc.member" (%arg0) {member = "a"} : (!emitc.lvalue>) -> !emitc.lvalue %1 = "emitc.member" (%arg0) {member = "b"} : (!emitc.lvalue>) -> !emitc.array<2xi32> .. py:attribute:: OPERATION_NAME :value: 'emitc.member' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: operand() -> _ods_ir .. py:method:: member() -> _ods_ir .. py:function:: member(result, member, operand, *, loc=None, ip=None) -> _ods_ir .. py:class:: MulOp(result, _gen_arg_0, _gen_arg_1, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` With the ``emitc.mul`` operation the arithmetic operator * (multiplication) can be applied. Example: .. code:: mlir // Custom form of the multiplication operation. %0 = emitc.mul %arg0, %arg1 : (i32, i32) -> i32 %1 = emitc.mul %arg2, %arg3 : (f32, f32) -> f32 .. code:: c++ // Code emitted for the operations above. int32_t v5 = v1 * v2; float v6 = v3 * v4; .. py:attribute:: OPERATION_NAME :value: 'emitc.mul' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:function:: mul(result, _gen_arg_0, _gen_arg_1, *, loc=None, ip=None) -> _ods_ir .. py:class:: RemOp(result, _gen_arg_0, _gen_arg_1, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` With the ``emitc.rem`` operation the arithmetic operator % (remainder) can be applied. Example: .. code:: mlir // Custom form of the remainder operation. %0 = emitc.rem %arg0, %arg1 : (i32, i32) -> i32 .. code:: c++ // Code emitted for the operation above. int32_t v5 = v1 % v2; .. py:attribute:: OPERATION_NAME :value: 'emitc.rem' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:function:: rem(result, _gen_arg_0, _gen_arg_1, *, loc=None, ip=None) -> _ods_ir .. py:class:: ReturnOp(*, operand=None, loc=None, ip=None) Bases: :py:obj:`_ods_ir` The ``emitc.return`` operation represents a return operation within a function. The operation takes zero or exactly one operand and produces no results. The operand number and type must match the signature of the function that contains the operation. Example: .. code:: mlir emitc.func @foo() -> (i32) { ... emitc.return %0 : i32 } .. py:attribute:: OPERATION_NAME :value: 'emitc.return' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: operand() -> Optional[_ods_ir] .. py:function:: return_(*, operand=None, loc=None, ip=None) -> ReturnOp .. py:class:: SubOp(result, lhs, rhs, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` With the ``emitc.sub`` operation the arithmetic operator - (subtraction) can be applied. Example: .. code:: mlir // Custom form of the substraction operation. %0 = emitc.sub %arg0, %arg1 : (i32, i32) -> i32 %1 = emitc.sub %arg2, %arg3 : (!emitc.ptr, i32) -> !emitc.ptr %2 = emitc.sub %arg4, %arg5 : (!emitc.ptr, !emitc.ptr) -> !emitc.ptrdiff_t .. code:: c++ // Code emitted for the operations above. int32_t v7 = v1 - v2; float* v8 = v3 - v4; ptrdiff_t v9 = v5 - v6; .. py:attribute:: OPERATION_NAME :value: 'emitc.sub' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: lhs() -> _ods_ir .. py:method:: rhs() -> _ods_ir .. py:function:: sub(result, lhs, rhs, *, loc=None, ip=None) -> _ods_ir .. py:class:: SubscriptOp(result, value, indices, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` With the ``emitc.subscript`` operation the subscript operator ``[]`` can be applied to variables or arguments of array, pointer and opaque type. Example: .. code:: mlir %i = index.constant 1 %j = index.constant 7 %0 = emitc.subscript %arg0[%i, %j] : (!emitc.array<4x8xf32>, index, index) -> !emitc.lvalue %1 = emitc.subscript %arg1[%i] : (!emitc.ptr, index) -> !emitc.lvalue .. py:attribute:: OPERATION_NAME :value: 'emitc.subscript' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: value() -> _ods_ir .. py:method:: indices() -> _ods_ir .. py:method:: result() -> _ods_ir Shortcut to get an op result if it has only one (throws an error otherwise). .. py:function:: subscript(result, value, indices, *, loc=None, ip=None) -> _ods_ir .. py:class:: SwitchOp(arg, cases, num_caseRegions, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` The ``emitc.switch`` is a control-flow operation that branches to one of the given regions based on the values of the argument and the cases. The operand to a switch operation is a opaque, integral or pointer wide types. The operation always has a "default" region and any number of case regions denoted by integer constants. Control-flow transfers to the case region whose constant value equals the value of the argument. If the argument does not equal any of the case values, control-flow transfer to the "default" region. The operation does not return any value. Moreover, case regions must be explicitly terminated using the ``emitc.yield`` operation. Default region is yielded implicitly. Example: .. code:: mlir // Example: emitc.switch %0 : i32 case 2 { %1 = emitc.call_opaque "func_b" () : () -> i32 emitc.yield } case 5 { %2 = emitc.call_opaque "func_a" () : () -> i32 emitc.yield } default { %3 = "emitc.constant"(){value = 42.0 : f32} : () -> f32 emitc.call_opaque "func2" (%3) : (f32) -> () } .. code:: c++ // Code emitted for the operations above. switch (v1) { case 2: { int32_t v2 = func_b(); break; } case 5: { int32_t v3 = func_a(); break; } default: { float v4 = 4.200000000e+01f; func2(v4); break; } } .. py:attribute:: OPERATION_NAME :value: 'emitc.switch' .. py:attribute:: _ODS_REGIONS :value: (1, False) .. py:method:: arg() -> _ods_ir .. py:method:: cases() -> _ods_ir .. py:method:: defaultRegion() -> _ods_ir .. py:method:: caseRegions() -> _ods_ir .. py:function:: switch(arg, cases, num_case_regions, *, loc=None, ip=None) -> SwitchOp .. py:class:: UnaryMinusOp(result, _gen_arg_0, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` With the ``emitc.unary_minus`` operation the unary operator - (minus) can be applied. Example: .. code:: mlir %0 = emitc.unary_minus %arg0 : (i32) -> i32 .. code:: c++ // Code emitted for the operation above. int32_t v2 = -v1; .. py:attribute:: OPERATION_NAME :value: 'emitc.unary_minus' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:function:: unary_minus(result, _gen_arg_0, *, loc=None, ip=None) -> _ods_ir .. py:class:: UnaryPlusOp(result, _gen_arg_0, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` With the ``emitc.unary_plus`` operation the unary operator + (plus) can be applied. Example: .. code:: mlir %0 = emitc.unary_plus %arg0 : (i32) -> i32 .. code:: c++ // Code emitted for the operation above. int32_t v2 = +v1; .. py:attribute:: OPERATION_NAME :value: 'emitc.unary_plus' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:function:: unary_plus(result, _gen_arg_0, *, loc=None, ip=None) -> _ods_ir .. py:class:: VariableOp(result, value, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` The ``emitc.variable`` operation produces an SSA value equal to some value specified by an attribute. This can be used to form simple integer and floating point variables, as well as more exotic things like tensor variables. The ``emitc.variable`` operation also supports the EmitC opaque attribute and the EmitC opaque type. If further supports the EmitC pointer type, whereas folding is not supported. The ``emitc.variable`` is emitted as a C/C++ local variable. Example: .. code:: mlir // Integer variable %0 = "emitc.variable"(){value = 42 : i32} : () -> !emitc.lvalue // Variable emitted as `int32_t* = NULL;` %1 = "emitc.variable"() {value = #emitc.opaque<"NULL">} : () -> !emitc.lvalue>> Since folding is not supported, it can be used with pointers. As an example, it is valid to create pointers to ``variable`` operations by using ``apply`` operations and pass these to a ``call`` operation. .. code:: mlir %0 = "emitc.variable"() {value = 0 : i32} : () -> !emitc.lvalue %1 = "emitc.variable"() {value = 0 : i32} : () -> !emitc.lvalue %2 = emitc.apply "&"(%0) : (!emitc.lvalue) -> !emitc.ptr %3 = emitc.apply "&"(%1) : (!emitc.lvalue) -> !emitc.ptr emitc.call_opaque "write"(%2, %3) : (!emitc.ptr, !emitc.ptr) -> () .. py:attribute:: OPERATION_NAME :value: 'emitc.variable' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: value() -> _ods_ir .. py:function:: variable(result, value, *, loc=None, ip=None) -> _ods_ir .. py:class:: VerbatimOp(value, fmtArgs, *, loc=None, ip=None) Bases: :py:obj:`_ods_ir` The ``emitc.verbatim`` operation produces no results and the value is emitted as is followed by a line break ('\n' character) during translation. Note: Use with caution. This operation can have arbitrary effects on the semantics of the emitted code. Use semantically more meaningful operations whenever possible. Additionally this op is *NOT* intended to be used to inject large snippets of code. This operation can be used in situations where a more suitable operation is not yet implemented in the dialect or where preprocessor directives interfere with the structure of the code. One example of this is to declare the linkage of external symbols to make the generated code usable in both C and C++ contexts: .. code:: c++ #ifdef __cplusplus extern "C" { #endif ... #ifdef __cplusplus } #endif If the ``emitc.verbatim`` op has operands, then the ``value`` is interpreted as format string, where ``{}`` is a placeholder for an operand in their order. For example, ``emitc.verbatim "#pragma my src={} dst={}" %src, %dest : i32, i32`` would be emitted as ``#pragma my src=a dst=b`` if ``%src`` became ``a`` and ``%dest`` became ``b`` in the C code. ``{{`` in the format string is interpreted as a single ``{`` and doesn't introduce a placeholder. Example: .. code:: mlir emitc.verbatim "typedef float f32;" emitc.verbatim "#pragma my var={} property" args %arg : f32 .. code:: c++ // Code emitted for the operation above. typedef float f32; #pragma my var=v1 property .. py:attribute:: OPERATION_NAME :value: 'emitc.verbatim' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: fmtArgs() -> _ods_ir .. py:method:: value() -> _ods_ir .. py:function:: verbatim(value, fmt_args, *, loc=None, ip=None) -> VerbatimOp .. py:class:: YieldOp(*, result=None, loc=None, ip=None) Bases: :py:obj:`_ods_ir` The ``emitc.yield`` terminates its parent EmitC op's region, optionally yielding an SSA value. The semantics of how the values are yielded is defined by the parent operation. If ``emitc.yield`` has an operand, the operand must match the parent operation's result. If the parent operation defines no values, then the ``emitc.yield`` may be left out in the custom syntax and the builders will insert one implicitly. Otherwise, it has to be present in the syntax to indicate which value is yielded. .. py:attribute:: OPERATION_NAME :value: 'emitc.yield' .. py:attribute:: _ODS_REGIONS :value: (0, True) .. py:method:: result() -> Optional[_ods_ir] Shortcut to get an op result if it has only one (throws an error otherwise). .. py:function:: yield_(*, result=None, loc=None, ip=None) -> YieldOp