Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
[mypyc] Use C99 compound literals for undefined tuple values
This simplified things a bit. All the C compilers we care about should
support this.

This will make things easier once we support more types represented as
C structs.

I expect this to have no measurable impact on performance.
  • Loading branch information
JukkaL committed Jun 16, 2023
commit c61ab04d4665ef4a3fb16711d4594215b90afa2e
35 changes: 13 additions & 22 deletions mypyc/codegen/emit.py
Original file line number Diff line number Diff line change
Expand Up @@ -345,12 +345,6 @@ def tuple_c_declaration(self, rtuple: RTuple) -> list[str]:
result.append(f"{self.ctype_spaced(typ)}f{i};")
i += 1
result.append(f"}} {rtuple.struct_name};")
values = self.tuple_undefined_value_helper(rtuple)
result.append(
"static {} {} = {{ {} }};".format(
self.ctype(rtuple), self.tuple_undefined_value(rtuple), "".join(values)
)
)
result.append("#endif")
result.append("")

Expand Down Expand Up @@ -470,23 +464,20 @@ def tuple_undefined_check_cond(
return check

def tuple_undefined_value(self, rtuple: RTuple) -> str:
return "tuple_undefined_" + rtuple.unique_id
"""Undefined tuple value suitable in an expression."""
return f"({rtuple.struct_name}) {self.c_initializer_undefined_value(rtuple)}"

def tuple_undefined_value_helper(self, rtuple: RTuple) -> list[str]:
res = []
# see tuple_c_declaration()
if len(rtuple.types) == 0:
return [self.c_undefined_value(int_rprimitive)]
for item in rtuple.types:
if not isinstance(item, RTuple):
res.append(self.c_undefined_value(item))
else:
sub_list = self.tuple_undefined_value_helper(item)
res.append("{ ")
res.extend(sub_list)
res.append(" }")
res.append(", ")
return res[:-1]
def c_initializer_undefined_value(self, rtype: RType) -> str:
"""Undefined value represented in a form suitable for variable initialization."""
if isinstance(rtype, RTuple):
if not rtype.types:
# Empty tuples contain a flag so that they can still indicate
# error values.
return f"{{ {int_rprimitive.c_undefined} }}"
items = ", ".join([self.c_initializer_undefined_value(t) for t in rtype.types])
return f"{{ {items} }}"
else:
return self.c_undefined_value(rtype)

# Higher-level operations

Expand Down
8 changes: 2 additions & 6 deletions mypyc/codegen/emitmodule.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@
from mypyc.ir.func_ir import FuncIR
from mypyc.ir.module_ir import ModuleIR, ModuleIRs, deserialize_modules
from mypyc.ir.ops import DeserMaps, LoadLiteral
from mypyc.ir.rtypes import RTuple, RType
from mypyc.ir.rtypes import RType
from mypyc.irbuild.main import build_ir
from mypyc.irbuild.mapper import Mapper
from mypyc.irbuild.prepare import load_type_map
Expand Down Expand Up @@ -1052,11 +1052,7 @@ def declare_finals(
def final_definition(self, module: str, name: str, typ: RType, emitter: Emitter) -> str:
static_name = emitter.static_name(name, module)
# Here we rely on the fact that undefined value and error value are always the same
if isinstance(typ, RTuple):
# We need to inline because initializer must be static
undefined = "{{ {} }}".format("".join(emitter.tuple_undefined_value_helper(typ)))
else:
undefined = emitter.c_undefined_value(typ)
undefined = emitter.c_initializer_undefined_value(typ)
return f"{emitter.ctype_spaced(typ)}{static_name} = {undefined};"

def declare_static_pyobject(self, identifier: str, emitter: Emitter) -> None:
Expand Down
3 changes: 0 additions & 3 deletions mypyc/lib-rt/CPy.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,6 @@ typedef struct tuple_T3OOO {
PyObject *f1;
PyObject *f2;
} tuple_T3OOO;
static tuple_T3OOO tuple_undefined_T3OOO = { NULL, NULL, NULL };
#endif

// Our return tuple wrapper for dictionary iteration helper.
Expand All @@ -52,7 +51,6 @@ typedef struct tuple_T3CIO {
CPyTagged f1; // Last dict offset
PyObject *f2; // Next dictionary key or value
} tuple_T3CIO;
static tuple_T3CIO tuple_undefined_T3CIO = { 2, CPY_INT_TAG, NULL };
#endif

// Same as above but for both key and value.
Expand All @@ -64,7 +62,6 @@ typedef struct tuple_T4CIOO {
PyObject *f2; // Next dictionary key
PyObject *f3; // Next dictionary value
} tuple_T4CIOO;
static tuple_T4CIOO tuple_undefined_T4CIOO = { 2, CPY_INT_TAG, NULL, NULL };
#endif


Expand Down
20 changes: 19 additions & 1 deletion mypyc/test/test_emit.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

from mypyc.codegen.emit import Emitter, EmitterContext
from mypyc.ir.ops import BasicBlock, Register, Value
from mypyc.ir.rtypes import int_rprimitive
from mypyc.ir.rtypes import RTuple, bool_rprimitive, int_rprimitive, str_rprimitive
from mypyc.namegen import NameGenerator


Expand Down Expand Up @@ -49,3 +49,21 @@ def test_emit_line(self) -> None:
CPyStatics[1]; /* [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20,
21, 22, 23, 24, 25, 26, 27, 28, 29] */\n"""
)

def test_emit_undefined_value_for_simple_type(self) -> None:
emitter = Emitter(self.context, {})
assert emitter.c_undefined_value(int_rprimitive) == "CPY_INT_TAG"
assert emitter.c_undefined_value(str_rprimitive) == "NULL"
assert emitter.c_undefined_value(bool_rprimitive) == "2"

def test_emit_undefined_value_for_tuple(self) -> None:
emitter = Emitter(self.context, {})
assert (
emitter.c_undefined_value(RTuple([str_rprimitive, int_rprimitive, bool_rprimitive]))
== "(tuple_T3OIC) { NULL, CPY_INT_TAG, 2 }"
)
assert emitter.c_undefined_value(RTuple([str_rprimitive])) == "(tuple_T1O) { NULL }"
assert (
emitter.c_undefined_value(RTuple([RTuple([str_rprimitive]), bool_rprimitive]))
== "(tuple_T2T1OC) { { NULL }, 2 }"
)