Skip to content

Commit bb3306e

Browse files
authored
[mypyc] Small improvements to developer docs (#9714)
Document tagged integers and some other updates.
1 parent 2695e95 commit bb3306e

File tree

2 files changed

+46
-22
lines changed

2 files changed

+46
-22
lines changed

mypyc/doc/dev-intro.md

Lines changed: 37 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -231,11 +231,25 @@ Installing a released version of mypy using `pip` (which is compiled)
231231
and using `dmypy` (mypy daemon) is a much, much faster way to type
232232
check mypyc during development.
233233

234-
## Overview of Generated C
234+
## Value Representation
235+
236+
Mypyc uses a tagged pointer representation for values of type `int`
237+
(`CPyTagged`), `char` for booleans, and C structs for tuples. For most
238+
other objects mypyc uses the CPython `PyObject *`.
239+
240+
Python integers that fit in 31/63 bits (depending on whether we are on
241+
a 32-bit or 64-bit platform) are represented as C integers
242+
(`CPyTagged`) shifted left by 1. Integers that don't fit in this
243+
representation are represented as pointers to a `PyObject *` (this is
244+
always a Python `int` object) with the least significant bit
245+
set. Tagged integer operations are defined in `mypyc/lib-rt/int_ops.c`
246+
and `mypyc/lib-rt/CPy.h`.
235247

236-
Mypyc uses a tagged pointer representation for integers, `char` for
237-
booleans, and C structs for tuples. For most other objects mypyc uses
238-
the CPython `PyObject *`.
248+
There are also low-level integer types, such as `int32` (see
249+
`mypyc.ir.rtypes`), that don't use the tagged representation. These
250+
types are not exposed to users, but they are used in generated code.
251+
252+
## Overview of Generated C
239253

240254
Mypyc compiles a function into two functions, a native function and
241255
a wrapper function:
@@ -261,10 +275,8 @@ insert a runtime type check (an unbox or a cast operation), since
261275
Python lists can contain arbitrary objects.
262276

263277
The generated code uses various helpers defined in
264-
`mypyc/lib-rt/CPy.h`. The header must only contain static functions,
265-
since it is included in many files. `mypyc/lib-rt/CPy.c` contains
266-
definitions that must only occur once, but really most of `CPy.h`
267-
should be moved into it.
278+
`mypyc/lib-rt/CPy.h`. The implementations are in various `.c` files
279+
under `mypyc/lib-rt`.
268280

269281
## Inspecting Generated C
270282

@@ -298,10 +310,10 @@ also write tests that test the generated IR, however.
298310
### Tests that compile and run code
299311

300312
Test cases that compile and run code are located in
301-
`test-data/run*.test` and the test runner is in `mypyc.test.test_run`.
302-
The code to compile comes after `[case test<name>]`. The code gets
303-
saved into the file `native.py`, and it gets compiled into the module
304-
`native`.
313+
`mypyc/test-data/run*.test` and the test runner is in
314+
`mypyc.test.test_run`. The code to compile comes after `[case
315+
test<name>]`. The code gets saved into the file `native.py`, and it
316+
gets compiled into the module `native`.
305317

306318
Each test case uses a non-compiled Python driver that imports the
307319
`native` module and typically calls some compiled functions. Some
@@ -312,8 +324,10 @@ driver just calls each module-level function that is prefixed with
312324
`test_` and reports any uncaught exceptions as failures. (Failure to
313325
build or a segfault also count as failures.) `testStringOps` in
314326
`mypyc/test-data/run-strings.test` is an example of a test that uses
315-
the default driver. You should usually use the default driver. It's
316-
the simplest way to write most tests.
327+
the default driver.
328+
329+
You should usually use the default driver (don't include
330+
`driver.py`). It's the simplest way to write most tests.
317331

318332
Here's an example test case that uses the default driver:
319333

@@ -412,23 +426,22 @@ If you add an operation that compiles into a lot of C code, you may
412426
also want to add a C helper function for the operation to make the
413427
generated code smaller. Here is how to do this:
414428

415-
* Add the operation to `mypyc/lib-rt/CPy.h`. Usually defining a static
416-
function is the right thing to do, but feel free to also define
417-
inline functions for very simple and performance-critical
418-
operations. We avoid macros since they are error-prone.
429+
* Declare the operation in `mypyc/lib-rt/CPy.h`. We avoid macros, and
430+
we generally avoid inline functions to make it easier to target
431+
additional backends in the future.
419432

420433
* Consider adding a unit test for your C helper in `mypyc/lib-rt/test_capi.cc`.
421434
We use
422435
[Google Test](https://github.com/google/googletest) for writing
423436
tests in C++. The framework is included in the repository under the
424437
directory `googletest/`. The C unit tests are run as part of the
425-
pytest test suite (`test_c_unit_tests`).
438+
pytest test suite (`test_c_unit_test`).
426439

427440
### Adding a Specialized Primitive Operation
428441

429442
Mypyc speeds up operations on primitive types such as `list` and `int`
430443
by having primitive operations specialized for specific types. These
431-
operations are defined in `mypyc.primitives` (and
444+
operations are declared in `mypyc.primitives` (and
432445
`mypyc/lib-rt/CPy.h`). For example, `mypyc.primitives.list_ops`
433446
contains primitives that target list objects.
434447

@@ -487,7 +500,7 @@ operations, and so on. You likely also want to add some faster,
487500
specialized primitive operations for the type (see Adding a
488501
Specialized Primitive Operation above for how to do this).
489502

490-
Add a test case to `mypyc/test-data/run.test` to test compilation and
503+
Add a test case to `mypyc/test-data/run*.test` to test compilation and
491504
running compiled code. Ideas for things to test:
492505

493506
* Test using the type as an argument.
@@ -523,7 +536,9 @@ about how to do this.
523536

524537
* Feel free to open GitHub issues with questions if you need help when
525538
contributing, or ask questions in existing issues. Note that we only
526-
support contributors. Mypyc is not (yet) an end-user product.
539+
support contributors. Mypyc is not (yet) an end-user product. You
540+
can also ask questions in our Gitter chat
541+
(https://gitter.im/mypyc-dev/community).
527542

528543
## Undocumented Workflows
529544

mypyc/lib-rt/mypyc_util.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,15 @@
3131
// Here just for consistency
3232
#define CPy_XDECREF(p) Py_XDECREF(p)
3333

34+
// Tagged integer -- our representation of Python 'int' objects.
35+
// Small enough integers are represented as unboxed integers (shifted
36+
// left by 1); larger integers (larger than 63 bits on a 64-bit
37+
// platform) are stored as a tagged pointer (PyObject *)
38+
// representing a Python int object, with the lowest bit set.
39+
// Tagged integers are always normalized. A small integer *must not*
40+
// have the tag bit set.
3441
typedef size_t CPyTagged;
42+
3543
typedef size_t CPyPtr;
3644

3745
#define CPY_INT_BITS (CHAR_BIT * sizeof(CPyTagged))
@@ -42,6 +50,7 @@ typedef size_t CPyPtr;
4250

4351
typedef PyObject CPyModule;
4452

53+
// Tag bit used for long integers
4554
#define CPY_INT_TAG 1
4655

4756
typedef void (*CPyVTableItem)(void);

0 commit comments

Comments
 (0)