|  | # Lowering IREEPyDM to IREE | 
|  |  | 
|  | At the top-level, a program expressed in IREEPyDM ("PyDM") can be lowered to | 
|  | IREE via the overall conversion pass `-convert-iree-pydm-to-iree`; however, | 
|  | additional steps are needed to link a runtime library, etc. | 
|  |  | 
|  | This document provides application notes for how the conversion is | 
|  | implemented. | 
|  |  | 
|  | ## Type Conversion | 
|  |  | 
|  | Generally, types in PyDM map 1:1 with IREE types in a way which facilitates | 
|  | a direct conversion. | 
|  |  | 
|  | ## `object` and `object<type>` records | 
|  |  | 
|  | Objects map to IREE variant lists (`!iree.list<?>`) of N elements, where the | 
|  | elements are laid out as: | 
|  |  | 
|  | * [0]: Type Code - i32 representing the type code of the object. | 
|  | * [1] (optional): Data corresponding to the type. | 
|  | * [2] (optional): i64 TypeID - if the `id()` function has been evaluated for | 
|  | this object, then this element will contain the unique id. | 
|  |  | 
|  | ### Type Codes | 
|  |  | 
|  | The special type code `0` means "not assigned", which is distinct from `None`. | 
|  | Other built-in types correspond to the `BuiltinTypeCode` enum in the dialect. | 
|  |  | 
|  | The following specifies the contents of the `data` field (1) of the object | 
|  | record, per type code: | 
|  |  | 
|  | * `None`: No contents | 
|  | * `Tuple`: An `!iree.list` of objects | 
|  | * `List`: An `!iree.list` of objects | 
|  | * `Str`: TODO: needs to be a union of i8/i16/i32 codepoint array | 
|  | * `Bytes`: TODO: should be a memory buffer of some kind | 
|  | * `ExceptionResult`: TODO: should hold a boxed exception of some kind | 
|  | * `Type`: An object representing the type | 
|  | * `Bool`: Implementation defined `iree_vm_value_type_t` field (typically | 
|  | `iree_vm_value_type_t.i8`). | 
|  | * `Integer`: Implementation defined `iree_vm_value_type_t` field (typically | 
|  | `iree_vm_value_type_t.i32`). | 
|  | * `Real`: Implementation defined `iree_vm_value_type_t` field (typically | 
|  | `iree_vm_value_type_t.f32`). | 
|  | * `Complex`: TODO | 
|  | * `Integer1` / `UInteger1`: `iree_vm_value_type_t.i8` | 
|  | * `Integer2` / `UInteger2`: `iree_vm_value_type_t.i16` | 
|  | * `Integer4` / `UInteger4`: `iree_vm_value_type_t.i32 | 
|  | * `Integer8` / `UInteger8`: `iree_vm_value_type_t.i64 | 
|  | * `Float2` : `iree_vm_value_type_t.i16` with bit value of an IEEE FP16 | 
|  | * `Float4` : `iree_vm_value_type_t.f32` | 
|  | * `Float8` : `iree_vm_value_type_t.f64` | 
|  | * `BFloat2` : `iree_vm_value_type_t.i16` with bit value of a BFloat16 (thanks | 
|  | Google). | 
|  | * `Complex4` : TODO | 
|  | * `Complex8` : TODO | 
|  | * `Object` (and custom): An object record, as described here | 
|  |  | 
|  | ### Mutability | 
|  |  | 
|  | The VM enforces no immutability constraints on the object records here (i.e. | 
|  | they are just lists). If the compiler believes that it can recycle an object, | 
|  | it is free to resize it appropriately and re-assign its contents. In this | 
|  | way, things like closure cells and free variable cells can just be | 
|  | allocated object records that that compiler completely reassigns the contents | 
|  | of on assignment. | 
|  |  | 
|  | ## Unboxed values | 
|  |  | 
|  | All values can exist in the program unboxed and will have a VM IR type which | 
|  | corresponds to their runtime variant form (i.e. `!iree.list`, `i32`, etc). | 
|  |  | 
|  | ## `!iree_pydm.exception_result` | 
|  |  | 
|  | The `exception_result` type is returned from every PyDM function indicating | 
|  | whether the call completed successfully or in an error state. We encode it as | 
|  | a signed `i32` value at runtime, where: | 
|  |  | 
|  | * `0` : indicates normal termination. | 
|  | * `<0` : signals one of a predefined list of primitive exception types | 
|  | which do not contain any detail (i.e. `ValueException` analog). | 
|  | * `>0` : is an index into a global exception lookup table with slots | 
|  | corresponding to logical threads of execution. | 
|  |  | 
|  | ### Pre-defined exception codes: | 
|  |  | 
|  | * `-1` : `StopIteration` - Standard exception which indicates exhaustion of | 
|  | an iterator. | 
|  | * `-2` : `StopAsyncIteration` - Standard exception which indicates exhaustion | 
|  | of an async iterator. | 
|  | * `-3` : `RuntimeError` - general catch-all failure exception class. | 
|  | * `-4` : `ValueError` | 
|  | * `-5` : `NotImplementedError` | 
|  | * `-6` : `KeyError` | 
|  | * `-7` : `IndexError` | 
|  | * `-8` : `AttributeError` | 
|  | * `-9` : `TypeError` | 
|  | * `-10` : `UnboundLocalError` | 
|  |  | 
|  | These pre-defined exception codes are allocated when the compiler has a need | 
|  | to raise or interoperate with an exception category. |