Revert "[mypyc] Add LoadLiteral and use tables to construct and store literals (#10040)"

This reverts commit 7ec1455821373ee394afc824f18c53bff1b6923b.
diff --git a/mypyc/analysis/dataflow.py b/mypyc/analysis/dataflow.py
index 17f6d33..d130e48 100644
--- a/mypyc/analysis/dataflow.py
+++ b/mypyc/analysis/dataflow.py
@@ -7,7 +7,7 @@
 from mypyc.ir.ops import (
     Value, ControlOp,
     BasicBlock, OpVisitor, Assign, Integer, LoadErrorValue, RegisterOp, Goto, Branch, Return, Call,
-    Box, Unbox, Cast, Op, Unreachable, TupleGet, TupleSet, GetAttr, SetAttr, LoadLiteral,
+    Box, Unbox, Cast, Op, Unreachable, TupleGet, TupleSet, GetAttr, SetAttr,
     LoadStatic, InitStatic, MethodCall, RaiseStandardError, CallC, LoadGlobal,
     Truncate, IntOp, LoadMem, GetElementPtr, LoadAddress, ComparisonOp, SetMem
 )
@@ -165,9 +165,6 @@
     def visit_load_error_value(self, op: LoadErrorValue) -> GenAndKill:
         return self.visit_register_op(op)
 
-    def visit_load_literal(self, op: LoadLiteral) -> GenAndKill:
-        return self.visit_register_op(op)
-
     def visit_get_attr(self, op: GetAttr) -> GenAndKill:
         return self.visit_register_op(op)
 
diff --git a/mypyc/codegen/cstring.py b/mypyc/codegen/cstring.py
index 15c8538..4fdb279 100644
--- a/mypyc/codegen/cstring.py
+++ b/mypyc/codegen/cstring.py
@@ -18,13 +18,10 @@
 octal digits.
 """
 
-from typing import List
 import string
+from typing import Tuple
 
-from typing_extensions import Final
-
-
-CHAR_MAP = ['\\{:03o}'.format(i) for i in range(256)]  # type: Final
+CHAR_MAP = ['\\{:03o}'.format(i) for i in range(256)]
 
 # It is safe to use string.printable as it always uses the C locale.
 for c in string.printable:
@@ -41,33 +38,12 @@
 CHAR_MAP[ord('?')] = r'\?'
 
 
-def encode_bytes_as_c_string(b: bytes) -> str:
-    """Produce contents of a C string literal for a byte string, without quotes."""
+def encode_as_c_string(s: str) -> Tuple[str, int]:
+    """Produce a quoted C string literal and its size, for a UTF-8 string."""
+    return encode_bytes_as_c_string(s.encode('utf-8'))
+
+
+def encode_bytes_as_c_string(b: bytes) -> Tuple[str, int]:
+    """Produce a quoted C string literal and its size, for a byte string."""
     escaped = ''.join([CHAR_MAP[i] for i in b])
-    return escaped
-
-
-def c_string_initializer(components: List[bytes]) -> str:
-    """Create initializer for a C char[] variable from a list of fragments.
-
-    For example, if components is [b'foo', b'bar'], the result would be
-    '"foobar"', which could then be used like this to initialize 's':
-
-        const char s[] = "foobar";
-
-    If the result is long, split it into multiple lines.
-    """
-    res = []
-    current = ''
-    for c in components:
-        enc = encode_bytes_as_c_string(c)
-        if not current or len(current) + len(enc) < 70:
-            current += enc
-        else:
-            res.append('"%s"' % current)
-            current = enc
-    if current:
-        res.append('"%s"' % current)
-    if len(res) > 1:
-        res.insert(0, '')
-    return '\n    '.join(res)
+    return '"{}"'.format(escaped), len(b)
diff --git a/mypyc/codegen/emit.py b/mypyc/codegen/emit.py
index 82d17c6..6199262 100644
--- a/mypyc/codegen/emit.py
+++ b/mypyc/codegen/emit.py
@@ -20,7 +20,6 @@
 from mypyc.ir.class_ir import ClassIR, all_concrete_classes
 from mypyc.namegen import NameGenerator, exported_name
 from mypyc.sametype import is_same_type
-from mypyc.codegen.literals import Literals
 
 
 class HeaderDeclaration:
@@ -85,8 +84,6 @@
         # The declaration contains the body of the struct.
         self.declarations = OrderedDict()  # type: Dict[str, HeaderDeclaration]
 
-        self.literals = Literals()
-
 
 class Emitter:
     """Helper for C code generation."""
diff --git a/mypyc/codegen/emitfunc.py b/mypyc/codegen/emitfunc.py
index 538a672..c8b6334 100644
--- a/mypyc/codegen/emitfunc.py
+++ b/mypyc/codegen/emitfunc.py
@@ -12,11 +12,11 @@
     LoadStatic, InitStatic, TupleGet, TupleSet, Call, IncRef, DecRef, Box, Cast, Unbox,
     BasicBlock, Value, MethodCall, Unreachable, NAMESPACE_STATIC, NAMESPACE_TYPE, NAMESPACE_MODULE,
     RaiseStandardError, CallC, LoadGlobal, Truncate, IntOp, LoadMem, GetElementPtr,
-    LoadAddress, ComparisonOp, SetMem, Register, LoadLiteral
+    LoadAddress, ComparisonOp, SetMem, Register
 )
 from mypyc.ir.rtypes import (
     RType, RTuple, is_tagged, is_int32_rprimitive, is_int64_rprimitive, RStruct,
-    is_pointer_rprimitive, is_int_rprimitive
+    is_pointer_rprimitive
 )
 from mypyc.ir.func_ir import FuncIR, FuncDecl, FUNC_STATICMETHOD, FUNC_CLASSMETHOD, all_values
 from mypyc.ir.class_ir import ClassIR
@@ -96,7 +96,6 @@
         self.declarations = declarations
         self.source_path = source_path
         self.module_name = module_name
-        self.literals = emitter.context.literals
 
     def temp_name(self) -> str:
         return self.emitter.temp_name()
@@ -174,19 +173,6 @@
             self.emit_line('%s = %s;' % (self.reg(op),
                                          self.c_error_value(op.type)))
 
-    def visit_load_literal(self, op: LoadLiteral) -> None:
-        index = self.literals.literal_index(op.value)
-        s = repr(op.value)
-        if not any(x in s for x in ('/*', '*/', '\0')):
-            ann = ' /* %s */' % s
-        else:
-            ann = ''
-        if not is_int_rprimitive(op.type):
-            self.emit_line('%s = CPyStatics[%d];%s' % (self.reg(op), index, ann))
-        else:
-            self.emit_line('%s = (CPyTagged)CPyStatics[%d] | 1;%s' % (
-                self.reg(op), index, ann))
-
     def get_attr_expr(self, obj: str, op: Union[GetAttr, SetAttr], decl_cl: ClassIR) -> str:
         """Generate attribute accessor for normal (non-property) access.
 
diff --git a/mypyc/codegen/emitmodule.py b/mypyc/codegen/emitmodule.py
index 9f149e7..48ae169 100644
--- a/mypyc/codegen/emitmodule.py
+++ b/mypyc/codegen/emitmodule.py
@@ -23,11 +23,10 @@
 from mypyc.irbuild.prepare import load_type_map
 from mypyc.irbuild.mapper import Mapper
 from mypyc.common import (
-    PREFIX, TOP_LEVEL_NAME, MODULE_PREFIX, RUNTIME_C_FILES, USE_FASTCALL,
+    PREFIX, TOP_LEVEL_NAME, INT_PREFIX, MODULE_PREFIX, RUNTIME_C_FILES, USE_FASTCALL,
     USE_VECTORCALL, shared_lib_name,
 )
-from mypyc.codegen.cstring import c_string_initializer
-from mypyc.codegen.literals import Literals
+from mypyc.codegen.cstring import encode_as_c_string, encode_bytes_as_c_string
 from mypyc.codegen.emit import EmitterContext, Emitter, HeaderDeclaration
 from mypyc.codegen.emitfunc import generate_native_function, native_function_header
 from mypyc.codegen.emitclass import generate_class_type_decl, generate_class
@@ -35,7 +34,7 @@
     generate_wrapper_function, wrapper_function_header,
     generate_legacy_wrapper_function, legacy_wrapper_function_header,
 )
-from mypyc.ir.ops import DeserMaps, LoadLiteral
+from mypyc.ir.ops import LiteralsMap, DeserMaps
 from mypyc.ir.rtypes import RType, RTuple
 from mypyc.ir.func_ir import FuncIR
 from mypyc.ir.class_ir import ClassIR
@@ -287,8 +286,9 @@
         if not group_modules:
             ctext[group_name] = []
             continue
+        literals = mapper.literals[group_name]
         generator = GroupGenerator(
-            group_modules, source_paths,
+            literals, group_modules, source_paths,
             group_name, mapper.group_map, names,
             compiler_options
         )
@@ -447,6 +447,7 @@
 
 class GroupGenerator:
     def __init__(self,
+                 literals: LiteralsMap,
                  modules: List[Tuple[str, ModuleIR]],
                  source_paths: Dict[str, str],
                  group_name: Optional[str],
@@ -460,6 +461,7 @@
         one .c file per module if in multi_file mode.)
 
         Arguments:
+            literals: The literals declared in this group
             modules: (name, ir) pairs for each module in the group
             source_paths: Map from module names to source file paths
             group_name: The name of the group (or None if this is single-module compilation)
@@ -468,6 +470,7 @@
             multi_file: Whether to put each module in its own source file regardless
                         of group structure.
         """
+        self.literals = literals
         self.modules = modules
         self.source_paths = source_paths
         self.context = EmitterContext(names, group_name, group_map)
@@ -492,11 +495,6 @@
         file_contents = []
         multi_file = self.use_shared_lib and self.multi_file
 
-        # Collect all literal refs in IR.
-        for _, module in self.modules:
-            for fn in module.functions:
-                collect_literals(fn, self.context.literals)
-
         base_emitter = Emitter(self.context)
         # Optionally just include the runtime library c files to
         # reduce the number of compiler invocations needed
@@ -507,7 +505,12 @@
         base_emitter.emit_line('#include "__native_internal{}.h"'.format(self.short_group_suffix))
         emitter = base_emitter
 
-        self.generate_literal_tables()
+        for (_, literal), identifier in self.literals.items():
+            if isinstance(literal, int):
+                symbol = emitter.static_name(identifier, None)
+                self.declare_global('CPyTagged ', symbol)
+            else:
+                self.declare_static_pyobject(identifier, emitter)
 
         for module_name, module in self.modules:
             if multi_file:
@@ -618,32 +621,6 @@
              ''.join(ext_declarations.fragments)),
         ]
 
-    def generate_literal_tables(self) -> None:
-        """Generate tables containing descriptions of Python literals to construct.
-
-        We will store the constructed literals in a single array that contains
-        literals of all types. This way we can refer to an arbitrary literal by
-        its index.
-        """
-        literals = self.context.literals
-        # During module initialization we store all the constructed objects here
-        self.declare_global('PyObject *[%d]' % literals.num_literals(), 'CPyStatics')
-        # Descriptions of str literals
-        init_str = c_string_initializer(literals.encoded_str_values())
-        self.declare_global('const char []', 'CPyLit_Str', initializer=init_str)
-        # Descriptions of bytes literals
-        init_bytes = c_string_initializer(literals.encoded_bytes_values())
-        self.declare_global('const char []', 'CPyLit_Bytes', initializer=init_bytes)
-        # Descriptions of int literals
-        init_int = c_string_initializer(literals.encoded_int_values())
-        self.declare_global('const char []', 'CPyLit_Int', initializer=init_int)
-        # Descriptions of float literals
-        init_floats = c_array_initializer(literals.encoded_float_values())
-        self.declare_global('const double []', 'CPyLit_Float', initializer=init_floats)
-        # Descriptions of complex literals
-        init_complex = c_array_initializer(literals.encoded_complex_values())
-        self.declare_global('const double []', 'CPyLit_Complex', initializer=init_complex)
-
     def generate_export_table(self, decl_emitter: Emitter, code_emitter: Emitter) -> None:
         """Generate the declaration and definition of the group's export struct.
 
@@ -816,10 +793,46 @@
         for symbol, fixup in self.simple_inits:
             emitter.emit_line('{} = {};'.format(symbol, fixup))
 
-        values = 'CPyLit_Str, CPyLit_Bytes, CPyLit_Int, CPyLit_Float, CPyLit_Complex'
-        emitter.emit_lines('if (CPyStatics_Initialize(CPyStatics, {}) < 0) {{'.format(values),
-                           'return -1;',
-                           '}')
+        for (_, literal), identifier in self.literals.items():
+            symbol = emitter.static_name(identifier, None)
+            if isinstance(literal, int):
+                actual_symbol = symbol
+                symbol = INT_PREFIX + symbol
+                emitter.emit_line(
+                    'PyObject * {} = PyLong_FromString(\"{}\", NULL, 10);'.format(
+                        symbol, str(literal))
+                )
+            elif isinstance(literal, float):
+                emitter.emit_line(
+                    '{} = PyFloat_FromDouble({});'.format(symbol, str(literal))
+                )
+            elif isinstance(literal, complex):
+                emitter.emit_line(
+                    '{} = PyComplex_FromDoubles({}, {});'.format(
+                        symbol, str(literal.real), str(literal.imag))
+                )
+            elif isinstance(literal, str):
+                emitter.emit_line(
+                    '{} = PyUnicode_FromStringAndSize({}, {});'.format(
+                        symbol, *encode_as_c_string(literal))
+                )
+            elif isinstance(literal, bytes):
+                emitter.emit_line(
+                    '{} = PyBytes_FromStringAndSize({}, {});'.format(
+                        symbol, *encode_bytes_as_c_string(literal))
+                )
+            else:
+                assert False, ('Literals must be integers, floating point numbers, or strings,',
+                               'but the provided literal is of type {}'.format(type(literal)))
+            emitter.emit_lines('if (unlikely({} == NULL))'.format(symbol),
+                               '    return -1;')
+            # Ints have an unboxed representation.
+            if isinstance(literal, int):
+                emitter.emit_line(
+                    '{} = CPyTagged_FromObject({});'.format(actual_symbol, symbol)
+                )
+            elif isinstance(literal, str):
+                emitter.emit_line('PyUnicode_InternInPlace(&{});'.format(symbol))
 
         emitter.emit_lines(
             'is_initialized = 1;',
@@ -961,19 +974,13 @@
     def declare_global(self, type_spaced: str, name: str,
                        *,
                        initializer: Optional[str] = None) -> None:
-        if '[' not in type_spaced:
-            base = '{}{}'.format(type_spaced, name)
-        else:
-            a, b = type_spaced.split('[', 1)
-            base = '{}{}[{}'.format(a, name, b)
-
         if not initializer:
             defn = None
         else:
-            defn = ['{} = {};'.format(base, initializer)]
+            defn = ['{}{} = {};'.format(type_spaced, name, initializer)]
         if name not in self.context.declarations:
             self.context.declarations[name] = HeaderDeclaration(
-                '{};'.format(base),
+                '{}{};'.format(type_spaced, name),
                 defn=defn,
             )
 
@@ -1073,46 +1080,3 @@
         # TODO: Support fastcall for __init__.
         return USE_FASTCALL and fn.name != '__init__'
     return USE_FASTCALL
-
-
-def collect_literals(fn: FuncIR, literals: Literals) -> None:
-    """Store all Python literal object refs in fn.
-
-    Collecting literals must happen only after we have the final IR.
-    This way we won't include literals that have been optimized away.
-    """
-    for block in fn.blocks:
-        for op in block.ops:
-            if isinstance(op, LoadLiteral):
-                literals.record_literal(op.value)
-
-
-def c_array_initializer(components: List[str]) -> str:
-    """Construct an initializer for a C array variable.
-
-    Components are C expressions valid in an initializer.
-
-    For example, if components are ["1", "2"], the result
-    would be "{1, 2}", which can be used like this:
-
-        int a[] = {1, 2};
-
-    If the result is long, split it into multiple lines.
-    """
-    res = []
-    current = []  # type: List[str]
-    cur_len = 0
-    for c in components:
-        if not current or cur_len + 2 + len(c) < 70:
-            current.append(c)
-            cur_len += len(c) + 2
-        else:
-            res.append(', '.join(current))
-            current = [c]
-            cur_len = len(c)
-    if not res:
-        # Result fits on a single line
-        return '{%s}' % ', '.join(current)
-    # Multi-line result
-    res.append(', '.join(current))
-    return '{\n    ' + ',\n    '.join(res) + '\n}'
diff --git a/mypyc/codegen/literals.py b/mypyc/codegen/literals.py
deleted file mode 100644
index a7b5967..0000000
--- a/mypyc/codegen/literals.py
+++ /dev/null
@@ -1,190 +0,0 @@
-from typing import Dict, List, Union
-
-
-class Literals:
-    """Collection of literal values used in a compilation group and related helpers."""
-
-    def __init__(self) -> None:
-        # Each dict maps value to literal index (0, 1, ...)
-        self.str_literals = {}  # type: Dict[str, int]
-        self.bytes_literals = {}  # type: Dict[bytes, int]
-        self.int_literals = {}  # type: Dict[int, int]
-        self.float_literals = {}  # type: Dict[float, int]
-        self.complex_literals = {}  # type: Dict[complex, int]
-
-    def record_literal(self, value: Union[str, bytes, int, float, complex]) -> None:
-        """Ensure that the literal value is available in generated code."""
-        if isinstance(value, str):
-            str_literals = self.str_literals
-            if value not in str_literals:
-                str_literals[value] = len(str_literals)
-        elif isinstance(value, bytes):
-            bytes_literals = self.bytes_literals
-            if value not in bytes_literals:
-                bytes_literals[value] = len(bytes_literals)
-        elif isinstance(value, int):
-            int_literals = self.int_literals
-            if value not in int_literals:
-                int_literals[value] = len(int_literals)
-        elif isinstance(value, float):
-            float_literals = self.float_literals
-            if value not in float_literals:
-                float_literals[value] = len(float_literals)
-        elif isinstance(value, complex):
-            complex_literals = self.complex_literals
-            if value not in complex_literals:
-                complex_literals[value] = len(complex_literals)
-        else:
-            assert False, 'invalid literal: %r' % value
-
-    def literal_index(self, value: Union[str, bytes, int, float, complex]) -> int:
-        """Return the index to the literals array for given value."""
-        # The array contains first all str values, followed by bytes values, etc.
-        if isinstance(value, str):
-            return self.str_literals[value]
-        n = len(self.str_literals)
-        if isinstance(value, bytes):
-            return n + self.bytes_literals[value]
-        n += len(self.bytes_literals)
-        if isinstance(value, int):
-            return n + self.int_literals[value]
-        n += len(self.int_literals)
-        if isinstance(value, float):
-            return n + self.float_literals[value]
-        n += len(self.float_literals)
-        if isinstance(value, complex):
-            return n + self.complex_literals[value]
-        assert False, 'invalid literal: %r' % value
-
-    def num_literals(self) -> int:
-        return (len(self.str_literals) + len(self.bytes_literals) + len(self.int_literals) +
-                len(self.float_literals) + len(self.complex_literals))
-
-    # The following methods return the C encodings of literal values
-    # of different types
-
-    def encoded_str_values(self) -> List[bytes]:
-        return encode_str_values(self.str_literals)
-
-    def encoded_int_values(self) -> List[bytes]:
-        return encode_int_values(self.int_literals)
-
-    def encoded_bytes_values(self) -> List[bytes]:
-        return encode_bytes_values(self.bytes_literals)
-
-    def encoded_float_values(self) -> List[str]:
-        return encode_float_values(self.float_literals)
-
-    def encoded_complex_values(self) -> List[str]:
-        return encode_complex_values(self.complex_literals)
-
-
-def encode_str_values(values: Dict[str, int]) -> List[bytes]:
-    value_by_index = {}
-    for value, index in values.items():
-        value_by_index[index] = value
-    result = []
-    num = len(values)
-    result.append(format_int(num))
-    for i in range(num):
-        value = value_by_index[i]
-        c_literal = format_str_literal(value)
-        result.append(c_literal)
-    return result
-
-
-def encode_bytes_values(values: Dict[bytes, int]) -> List[bytes]:
-    value_by_index = {}
-    for value, index in values.items():
-        value_by_index[index] = value
-    result = []
-    num = len(values)
-    result.append(format_int(num))
-    for i in range(num):
-        value = value_by_index[i]
-        result.append(format_int(len(value)))
-        result.append(value)
-    return result
-
-
-def format_int(n: int) -> bytes:
-    """Format an integer using a variable-length binary encoding."""
-    if n < 128:
-        a = [n]
-    else:
-        a = []
-        while n > 0:
-            a.insert(0, n & 0x7f)
-            n >>= 7
-        for i in range(len(a) - 1):
-            # If the highest bit is set, more 7-bit digits follow
-            a[i] |= 0x80
-    return bytes(a)
-
-
-def format_str_literal(s: str) -> bytes:
-    utf8 = s.encode('utf-8')
-    return format_int(len(utf8)) + utf8
-
-
-def encode_int_values(values: Dict[int, int]) -> List[bytes]:
-    """Encode int values into C string fragments.
-
-    Values are stored in base 10 and separated by 0 bytes.
-    """
-    value_by_index = {}
-    for value, index in values.items():
-        value_by_index[index] = value
-    result = []
-    num = len(values)
-    result.append(format_int(num))
-    for i in range(num):
-        value = value_by_index[i]
-        result.append(b'%d\0' % value)
-    return result
-
-
-def float_to_c(x: float) -> str:
-    """Return C literal representation of a float value."""
-    s = str(x)
-    if s == 'inf':
-        return 'INFINITY'
-    elif s == '-inf':
-        return '-INFINITY'
-    return s
-
-
-def encode_float_values(values: Dict[float, int]) -> List[str]:
-    """Encode float values into a C array values.
-
-    The result contains the number of values followed by individual values.
-    """
-    value_by_index = {}
-    for value, index in values.items():
-        value_by_index[index] = value
-    result = []
-    num = len(values)
-    result.append(str(num))
-    for i in range(num):
-        value = value_by_index[i]
-        result.append(float_to_c(value))
-    return result
-
-
-def encode_complex_values(values: Dict[complex, int]) -> List[str]:
-    """Encode float values into a C array values.
-
-    The result contains the number of values followed by pairs of doubles
-    representing complex numbers.
-    """
-    value_by_index = {}
-    for value, index in values.items():
-        value_by_index[index] = value
-    result = []
-    num = len(values)
-    result.append(str(num))
-    for i in range(num):
-        value = value_by_index[i]
-        result.append(float_to_c(value.real))
-        result.append(float_to_c(value.imag))
-    return result
diff --git a/mypyc/common.py b/mypyc/common.py
index fdb07f2..7c06372 100644
--- a/mypyc/common.py
+++ b/mypyc/common.py
@@ -19,6 +19,7 @@
 LAMBDA_NAME = '__mypyc_lambda__'  # type: Final
 PROPSET_PREFIX = '__mypyc_setter__'  # type: Final
 SELF_NAME = '__mypyc_self__'  # type: Final
+INT_PREFIX = '__tmp_literal_int_'  # type: Final
 
 # Max short int we accept as a literal is based on 32-bit platforms,
 # so that we can just always emit the same code.
diff --git a/mypyc/ir/ops.py b/mypyc/ir/ops.py
index 567ee59..107a2e5 100644
--- a/mypyc/ir/ops.py
+++ b/mypyc/ir/ops.py
@@ -14,7 +14,7 @@
     List, Sequence, Dict, Generic, TypeVar, Optional, NamedTuple, Tuple, Union
 )
 
-from typing_extensions import Final, TYPE_CHECKING
+from typing_extensions import Final, Type, TYPE_CHECKING
 from mypy_extensions import trait
 
 from mypyc.ir.rtypes import (
@@ -143,7 +143,7 @@
 
 
 class Integer(Value):
-    """Short integer literal.
+    """Integer literal.
 
     Integer literals are treated as constant values and are generally
     not included in data flow analyses and such, unlike Register and
@@ -494,36 +494,6 @@
         return visitor.visit_load_error_value(self)
 
 
-class LoadLiteral(RegisterOp):
-    """Load a Python literal object (dest = 'foo' / b'foo' / ...).
-
-    This is used to load a static PyObject * value corresponding to
-    a literal of one of the supported types.
-
-    NOTE: For int literals, both int_rprimitive (CPyTagged) and
-          object_primitive (PyObject *) are supported as types. However,
-          when using int_rprimitive, the value must *not* be small enough
-          to fit in an unboxed integer.
-
-    NOTE: You can use this to load boxed (Python) int objects. Use
-          Integer to load unboxed, tagged integers or fixed-width,
-          low-level integers.
-    """
-
-    error_kind = ERR_NEVER
-    is_borrowed = True
-
-    def __init__(self, value: Union[str, bytes, int, float, complex], rtype: RType) -> None:
-        self.value = value
-        self.type = rtype
-
-    def sources(self) -> List[Value]:
-        return []
-
-    def accept(self, visitor: 'OpVisitor[T]') -> T:
-        return visitor.visit_load_literal(self)
-
-
 class GetAttr(RegisterOp):
     """obj.attr (for a native object)"""
 
@@ -870,12 +840,7 @@
 
 
 class LoadGlobal(RegisterOp):
-    """Load a low-level global variable/pointer.
-
-    Note that can't be used to directly load Python module-level
-    global variable, since they are stored in a globals dictionary
-    and accessed using dictionary operations.
-    """
+    """Load a global variable/pointer."""
 
     error_kind = ERR_NEVER
     is_borrowed = True
@@ -1160,10 +1125,6 @@
         raise NotImplementedError
 
     @abstractmethod
-    def visit_load_literal(self, op: LoadLiteral) -> T:
-        raise NotImplementedError
-
-    @abstractmethod
     def visit_get_attr(self, op: GetAttr) -> T:
         raise NotImplementedError
 
@@ -1254,7 +1215,7 @@
         raise NotImplementedError
 
 
-# TODO: Should the following definition live somewhere else?
+# TODO: Should the following definitions live somewhere else?
 
 # We do a three-pass deserialization scheme in order to resolve name
 # references.
@@ -1280,3 +1241,5 @@
 # compilation but so far it is not hooked up to anything.)
 DeserMaps = NamedTuple('DeserMaps',
                        [('classes', Dict[str, 'ClassIR']), ('functions', Dict[str, 'FuncIR'])])
+
+LiteralsMap = Dict[Tuple[Type[object], Union[int, float, str, bytes, complex]], str]
diff --git a/mypyc/ir/pprint.py b/mypyc/ir/pprint.py
index c7c750a..046f903 100644
--- a/mypyc/ir/pprint.py
+++ b/mypyc/ir/pprint.py
@@ -9,7 +9,7 @@
     Goto, Branch, Return, Unreachable, Assign, Integer, LoadErrorValue, GetAttr, SetAttr,
     LoadStatic, InitStatic, TupleGet, TupleSet, IncRef, DecRef, Call, MethodCall, Cast, Box, Unbox,
     RaiseStandardError, CallC, Truncate, LoadGlobal, IntOp, ComparisonOp, LoadMem, SetMem,
-    GetElementPtr, LoadAddress, Register, Value, OpVisitor, BasicBlock, ControlOp, LoadLiteral
+    GetElementPtr, LoadAddress, Register, Value, OpVisitor, BasicBlock, ControlOp
 )
 from mypyc.ir.func_ir import FuncIR, all_values_full
 from mypyc.ir.module_ir import ModuleIRs
@@ -59,14 +59,6 @@
     def visit_load_error_value(self, op: LoadErrorValue) -> str:
         return self.format('%r = <error> :: %s', op, op.type)
 
-    def visit_load_literal(self, op: LoadLiteral) -> str:
-        prefix = ''
-        # For values that have a potential unboxed representation, make
-        # it explicit that this is a Python object.
-        if isinstance(op.value, int):
-            prefix = 'object '
-        return self.format('%r = %s%s', op, prefix, repr(op.value))
-
     def visit_get_attr(self, op: GetAttr) -> str:
         return self.format('%r = %r.%s', op, op.obj, op.attr)
 
diff --git a/mypyc/irbuild/builder.py b/mypyc/irbuild/builder.py
index ef4fb79..190e852 100644
--- a/mypyc/irbuild/builder.py
+++ b/mypyc/irbuild/builder.py
@@ -191,11 +191,11 @@
     def py_get_attr(self, obj: Value, attr: str, line: int) -> Value:
         return self.builder.py_get_attr(obj, attr, line)
 
-    def load_str(self, value: str) -> Value:
-        return self.builder.load_str(value)
+    def load_static_unicode(self, value: str) -> Value:
+        return self.builder.load_static_unicode(value)
 
-    def load_int(self, value: int) -> Value:
-        return self.builder.load_int(value)
+    def load_static_int(self, value: int) -> Value:
+        return self.builder.load_static_int(value)
 
     def unary_op(self, lreg: Value, expr_op: str, line: int) -> Value:
         return self.builder.unary_op(lreg, expr_op, line)
@@ -283,7 +283,7 @@
     def add_to_non_ext_dict(self, non_ext: NonExtClassInfo,
                             key: str, val: Value, line: int) -> None:
         # Add an attribute entry into the class dict of a non-extension class.
-        key_unicode = self.load_str(key)
+        key_unicode = self.load_static_unicode(key)
         self.call_c(dict_set_item_op, [non_ext.dict, key_unicode, val], line)
 
     def gen_import(self, id: str, line: int) -> None:
@@ -295,7 +295,7 @@
         self.add_bool_branch(comparison, out, needs_import)
 
         self.activate_block(needs_import)
-        value = self.call_c(import_op, [self.load_str(id)], line)
+        value = self.call_c(import_op, [self.load_static_unicode(id)], line)
         self.add(InitStatic(value, id, namespace=NAMESPACE_MODULE))
         self.goto_and_activate(out)
 
@@ -378,13 +378,13 @@
         elif isinstance(val, int):
             # TODO: take care of negative integer initializers
             # (probably easier to fix this in mypy itself).
-            return self.builder.load_int(val)
+            return self.builder.load_static_int(val)
         elif isinstance(val, float):
-            return self.builder.load_float(val)
+            return self.builder.load_static_float(val)
         elif isinstance(val, str):
-            return self.builder.load_str(val)
+            return self.builder.load_static_unicode(val)
         elif isinstance(val, bytes):
-            return self.builder.load_bytes(val)
+            return self.builder.load_static_bytes(val)
         else:
             assert False, "Unsupported final literal value"
 
@@ -419,7 +419,7 @@
                     return self.lookup(symbol)
             elif lvalue.kind == GDEF:
                 globals_dict = self.load_globals_dict()
-                name = self.load_str(lvalue.name)
+                name = self.load_static_unicode(lvalue.name)
                 return AssignmentTargetIndex(globals_dict, name)
             else:
                 assert False, lvalue.kind
@@ -484,7 +484,7 @@
                 rvalue_reg = self.coerce(rvalue_reg, target.type, line)
                 self.add(SetAttr(target.obj, target.attr, rvalue_reg, line))
             else:
-                key = self.load_str(target.attr)
+                key = self.load_static_unicode(target.attr)
                 boxed_reg = self.builder.box(rvalue_reg)
                 self.call_c(py_setattr_op, [target.obj, key, boxed_reg], line)
         elif isinstance(target, AssignmentTargetIndex):
@@ -519,7 +519,7 @@
         values = []
         for i in range(len(target.items)):
             item = target.items[i]
-            index = self.builder.load_int(i)
+            index = self.builder.load_static_int(i)
             if is_list_rprimitive(rvalue.type):
                 item_value = self.call_c(list_get_item_unsafe_op, [rvalue, index], line)
             else:
@@ -1074,7 +1074,7 @@
 
     def load_global_str(self, name: str, line: int) -> Value:
         _globals = self.load_globals_dict()
-        reg = self.load_str(name)
+        reg = self.load_static_unicode(name)
         return self.call_c(dict_get_item_op, [_globals, reg], line)
 
     def load_globals_dict(self) -> Value:
diff --git a/mypyc/irbuild/classdef.py b/mypyc/irbuild/classdef.py
index b708255..88d49b2 100644
--- a/mypyc/irbuild/classdef.py
+++ b/mypyc/irbuild/classdef.py
@@ -123,7 +123,7 @@
             typ = builder.load_native_type_object(cdef.fullname)
             value = builder.accept(stmt.rvalue)
             builder.call_c(
-                py_setattr_op, [typ, builder.load_str(lvalue.name), value], stmt.line)
+                py_setattr_op, [typ, builder.load_static_unicode(lvalue.name), value], stmt.line)
             if builder.non_function_scope() and stmt.is_final_def:
                 builder.init_final_static(lvalue, value, cdef.name)
         elif isinstance(stmt, ExpressionStmt) and isinstance(stmt.expr, StrExpr):
@@ -150,7 +150,7 @@
         builder.call_c(dict_set_item_op,
                        [
                            builder.load_globals_dict(),
-                           builder.load_str(cdef.name),
+                           builder.load_static_unicode(cdef.name),
                            non_ext_class
                        ], cdef.line)
 
@@ -166,7 +166,7 @@
         tp_bases = builder.new_tuple(bases, cdef.line)
     else:
         tp_bases = builder.add(LoadErrorValue(object_rprimitive, is_borrowed=True))
-    modname = builder.load_str(builder.module_name)
+    modname = builder.load_static_unicode(builder.module_name)
     template = builder.add(LoadStatic(object_rprimitive, cdef.name + "_template",
                                    builder.module_name, NAMESPACE_TYPE))
     # Create the class
@@ -181,7 +181,7 @@
                      FuncSignature([], bool_rprimitive)), [], -1))
     # Populate a '__mypyc_attrs__' field containing the list of attrs
     builder.call_c(py_setattr_op, [
-        tp, builder.load_str('__mypyc_attrs__'),
+        tp, builder.load_static_unicode('__mypyc_attrs__'),
         create_mypyc_attrs_tuple(builder, builder.mapper.type_to_ir[cdef.info], cdef.line)],
         cdef.line)
 
@@ -192,7 +192,7 @@
     builder.call_c(dict_set_item_op,
                 [
                     builder.load_globals_dict(),
-                    builder.load_str(cdef.name),
+                    builder.load_static_unicode(cdef.name),
                     tp,
                 ], cdef.line)
 
@@ -242,7 +242,7 @@
     # Check if the metaclass defines a __prepare__ method, and if so, call it.
     has_prepare = builder.call_c(py_hasattr_op,
                                 [metaclass,
-                                builder.load_str('__prepare__')], cdef.line)
+                                builder.load_static_unicode('__prepare__')], cdef.line)
 
     non_ext_dict = Register(dict_rprimitive)
 
@@ -250,7 +250,7 @@
     builder.add_bool_branch(has_prepare, true_block, false_block)
 
     builder.activate_block(true_block)
-    cls_name = builder.load_str(cdef.name)
+    cls_name = builder.load_static_unicode(cdef.name)
     prepare_meth = builder.py_get_attr(metaclass, '__prepare__', cdef.line)
     prepare_dict = builder.py_call(prepare_meth, [cls_name, bases], cdef.line)
     builder.assign(non_ext_dict, prepare_dict, cdef.line)
@@ -277,7 +277,7 @@
     # We populate __annotations__ because dataclasses uses it to determine
     # which attributes to compute on.
     # TODO: Maybe generate more precise types for annotations
-    key = builder.load_str(lvalue.name)
+    key = builder.load_static_unicode(lvalue.name)
     typ = builder.add(LoadAddress(type_object_op.type, type_object_op.src, stmt.line))
     builder.call_c(dict_set_item_op, [non_ext.anns, key, typ], stmt.line)
 
@@ -389,7 +389,7 @@
                        ir: ClassIR,
                        non_ext: NonExtClassInfo,
                        line: int) -> Value:
-    cls_name = builder.load_str(ir.name)
+    cls_name = builder.load_static_unicode(ir.name)
 
     finish_non_ext_dict(builder, non_ext, line)
 
@@ -432,14 +432,14 @@
     attrs = [name for ancestor in ir.mro for name in ancestor.attributes]
     if ir.inherits_python:
         attrs.append('__dict__')
-    items = [builder.load_str(attr) for attr in attrs]
+    items = [builder.load_static_unicode(attr) for attr in attrs]
     return builder.new_tuple(items, line)
 
 
 def finish_non_ext_dict(builder: IRBuilder, non_ext: NonExtClassInfo, line: int) -> None:
     # Add __annotations__ to the class dict.
     builder.call_c(dict_set_item_op,
-                [non_ext.dict, builder.load_str('__annotations__'),
+                [non_ext.dict, builder.load_static_unicode('__annotations__'),
                 non_ext.anns], -1)
 
     # We add a __doc__ attribute so if the non-extension class is decorated with the
@@ -447,9 +447,9 @@
     # https://github.com/python/cpython/blob/3.7/Lib/dataclasses.py#L957
     filler_doc_str = 'mypyc filler docstring'
     builder.add_to_non_ext_dict(
-        non_ext, '__doc__', builder.load_str(filler_doc_str), line)
+        non_ext, '__doc__', builder.load_static_unicode(filler_doc_str), line)
     builder.add_to_non_ext_dict(
-        non_ext, '__module__', builder.load_str(builder.module_name), line)
+        non_ext, '__module__', builder.load_static_unicode(builder.module_name), line)
 
 
 def dataclass_finalize(
diff --git a/mypyc/irbuild/expression.py b/mypyc/irbuild/expression.py
index 19f8aa2..8b671ad 100644
--- a/mypyc/irbuild/expression.py
+++ b/mypyc/irbuild/expression.py
@@ -95,7 +95,7 @@
             # instead load the module separately on each access.
             mod_dict = builder.call_c(get_module_dict_op, [], expr.line)
             obj = builder.call_c(dict_get_item_op,
-                                 [mod_dict, builder.load_str(expr.node.fullname)],
+                                 [mod_dict, builder.load_static_unicode(expr.node.fullname)],
                                  expr.line)
             return obj
         else:
@@ -124,7 +124,7 @@
     if isinstance(typ, TupleType) and typ.partial_fallback.type.is_named_tuple:
         fields = typ.partial_fallback.type.metadata['namedtuple']['fields']
         if expr.name in fields:
-            index = builder.builder.load_int(fields.index(expr.name))
+            index = builder.builder.load_static_int(fields.index(expr.name))
             return builder.gen_method_call(obj, '__getitem__', [index], rtype, expr.line)
     return builder.builder.get_attr(obj, expr.name, rtype, expr.line)
 
@@ -383,13 +383,13 @@
         if index.begin_index:
             begin = builder.accept(index.begin_index)
         else:
-            begin = builder.load_int(0)
+            begin = builder.load_static_int(0)
         if index.end_index:
             end = builder.accept(index.end_index)
         else:
             # Replace missing end index with the largest short integer
             # (a sequence can't be longer).
-            end = builder.load_int(MAX_SHORT_INT)
+            end = builder.load_static_int(MAX_SHORT_INT)
         candidates = [list_slice_op, tuple_slice_op, str_slice_op]
         return builder.builder.matching_call_c(candidates, [base, begin, end], index.line)
 
@@ -520,24 +520,24 @@
 
 
 def transform_int_expr(builder: IRBuilder, expr: IntExpr) -> Value:
-    return builder.builder.load_int(expr.value)
+    return builder.builder.load_static_int(expr.value)
 
 
 def transform_float_expr(builder: IRBuilder, expr: FloatExpr) -> Value:
-    return builder.builder.load_float(expr.value)
+    return builder.builder.load_static_float(expr.value)
 
 
 def transform_complex_expr(builder: IRBuilder, expr: ComplexExpr) -> Value:
-    return builder.builder.load_complex(expr.value)
+    return builder.builder.load_static_complex(expr.value)
 
 
 def transform_str_expr(builder: IRBuilder, expr: StrExpr) -> Value:
-    return builder.load_str(expr.value)
+    return builder.load_static_unicode(expr.value)
 
 
 def transform_bytes_expr(builder: IRBuilder, expr: BytesExpr) -> Value:
     value = bytes(expr.value, 'utf8').decode('unicode-escape').encode('raw-unicode-escape')
-    return builder.builder.load_bytes(value)
+    return builder.builder.load_static_bytes(value)
 
 
 def transform_ellipsis(builder: IRBuilder, o: EllipsisExpr) -> Value:
diff --git a/mypyc/irbuild/function.py b/mypyc/irbuild/function.py
index 0e76067..53bdbcf 100644
--- a/mypyc/irbuild/function.py
+++ b/mypyc/irbuild/function.py
@@ -96,7 +96,7 @@
         # Set the callable object representing the decorated function as a global.
         builder.call_c(dict_set_item_op,
                     [builder.load_globals_dict(),
-                    builder.load_str(dec.func.name), decorated_func],
+                    builder.load_static_unicode(dec.func.name), decorated_func],
                     decorated_func.line)
 
     builder.functions.append(func_ir)
@@ -361,7 +361,7 @@
         builder.call_c(py_setattr_op,
                     [
                         typ,
-                        builder.load_str(name),
+                        builder.load_static_unicode(name),
                         decorated_func
                     ],
                     fdef.line)
diff --git a/mypyc/irbuild/ll_builder.py b/mypyc/irbuild/ll_builder.py
index c2e8e76..8466e4f 100644
--- a/mypyc/irbuild/ll_builder.py
+++ b/mypyc/irbuild/ll_builder.py
@@ -18,8 +18,8 @@
 
 from mypyc.ir.ops import (
     BasicBlock, Op, Integer, Value, Register, Assign, Branch, Goto, Call, Box, Unbox, Cast,
-    GetAttr, LoadStatic, MethodCall, CallC, Truncate, LoadLiteral,
-    RaiseStandardError, Unreachable, LoadErrorValue,
+    GetAttr, LoadStatic, MethodCall, CallC, Truncate,
+    RaiseStandardError, Unreachable, LoadErrorValue, LoadGlobal,
     NAMESPACE_TYPE, NAMESPACE_MODULE, NAMESPACE_STATIC, IntOp, GetElementPtr,
     LoadMem, ComparisonOp, LoadAddress, TupleGet, SetMem, ERR_NEVER, ERR_FALSE
 )
@@ -34,7 +34,8 @@
 from mypyc.ir.func_ir import FuncDecl, FuncSignature
 from mypyc.ir.class_ir import ClassIR, all_concrete_classes
 from mypyc.common import (
-    FAST_ISINSTANCE_MAX_SUBCLASSES, MAX_LITERAL_SHORT_INT, PLATFORM_SIZE
+    FAST_ISINSTANCE_MAX_SUBCLASSES, MAX_LITERAL_SHORT_INT,
+    STATIC_PREFIX, PLATFORM_SIZE
 )
 from mypyc.primitives.registry import (
     method_call_ops, CFunctionDescription, function_ops,
@@ -190,7 +191,7 @@
 
         Prefer get_attr() which generates optimized code for native classes.
         """
-        key = self.load_str(attr)
+        key = self.load_static_unicode(attr)
         return self.call_c(py_getattr_op, [obj, key], line)
 
     # isinstance() checks
@@ -261,7 +262,7 @@
                 pos_arg_values.append(value)
             elif kind == ARG_NAMED:
                 assert name is not None
-                key = self.load_str(name)
+                key = self.load_static_unicode(name)
                 kw_arg_key_value_pairs.append((key, value))
             elif kind == ARG_STAR:
                 star_arg_values.append(value)
@@ -297,7 +298,7 @@
                        arg_names: Optional[Sequence[Optional[str]]]) -> Value:
         """Call a Python method (non-native and slow)."""
         if (arg_kinds is None) or all(kind == ARG_POS for kind in arg_kinds):
-            method_name_reg = self.load_str(method_name)
+            method_name_reg = self.load_static_unicode(method_name)
             return self.call_c(py_method_call_op, [obj, method_name_reg] + arg_values, line)
         else:
             method = self.py_get_attr(obj, method_name, line)
@@ -348,7 +349,7 @@
                 items = [args[i] for i in lst]
                 output_arg = self.new_tuple(items, line)
             elif arg.kind == ARG_STAR2:
-                dict_entries = [(self.load_str(cast(str, arg_names[i])), args[i])
+                dict_entries = [(self.load_static_unicode(cast(str, arg_names[i])), args[i])
                                 for i in lst]
                 output_arg = self.make_dict(dict_entries, line)
             elif not lst:
@@ -447,32 +448,40 @@
         """Load Python None value (type: object_rprimitive)."""
         return self.add(LoadAddress(none_object_op.type, none_object_op.src, line=-1))
 
-    def load_int(self, value: int) -> Value:
-        """Load a tagged (Python) integer literal value."""
+    def literal_static_name(self, value: Union[int, float, complex, str, bytes]) -> str:
+        return STATIC_PREFIX + self.mapper.literal_static_name(self.current_module, value)
+
+    def load_static_int(self, value: int) -> Value:
+        """Loads a static integer Python 'int' object into a register."""
         if abs(value) > MAX_LITERAL_SHORT_INT:
-            return self.add(LoadLiteral(value, int_rprimitive))
+            identifier = self.literal_static_name(value)
+            return self.add(LoadGlobal(int_rprimitive, identifier, ann=value))
         else:
             return Integer(value)
 
-    def load_float(self, value: float) -> Value:
-        """Load a float literal value."""
-        return self.add(LoadLiteral(value, float_rprimitive))
+    def load_static_float(self, value: float) -> Value:
+        """Loads a static float value into a register."""
+        identifier = self.literal_static_name(value)
+        return self.add(LoadGlobal(float_rprimitive, identifier, ann=value))
 
-    def load_str(self, value: str) -> Value:
-        """Load a str literal value.
+    def load_static_bytes(self, value: bytes) -> Value:
+        """Loads a static bytes value into a register."""
+        identifier = self.literal_static_name(value)
+        return self.add(LoadGlobal(object_rprimitive, identifier, ann=value))
 
-        This is useful for more than just str literals; for example, method calls
+    def load_static_complex(self, value: complex) -> Value:
+        """Loads a static complex value into a register."""
+        identifier = self.literal_static_name(value)
+        return self.add(LoadGlobal(object_rprimitive, identifier, ann=value))
+
+    def load_static_unicode(self, value: str) -> Value:
+        """Loads a static unicode value into a register.
+
+        This is useful for more than just unicode literals; for example, method calls
         also require a PyObject * form for the name of the method.
         """
-        return self.add(LoadLiteral(value, str_rprimitive))
-
-    def load_bytes(self, value: bytes) -> Value:
-        """Load a bytes literal value."""
-        return self.add(LoadLiteral(value, object_rprimitive))
-
-    def load_complex(self, value: complex) -> Value:
-        """Load a complex literal value."""
-        return self.add(LoadLiteral(value, object_rprimitive))
+        identifier = self.literal_static_name(value)
+        return self.add(LoadGlobal(str_rprimitive, identifier, ann=value))
 
     def load_static_checked(self, typ: RType, identifier: str, module_name: Optional[str] = None,
                             namespace: str = NAMESPACE_STATIC,
diff --git a/mypyc/irbuild/mapper.py b/mypyc/irbuild/mapper.py
index 5b2521d..7cc6689 100644
--- a/mypyc/irbuild/mapper.py
+++ b/mypyc/irbuild/mapper.py
@@ -1,6 +1,7 @@
 """Maintain a mapping from mypy concepts to IR/compiled concepts."""
 
-from typing import Dict, Optional
+from typing import Dict, Optional, Union
+from mypy.ordered_dict import OrderedDict
 
 from mypy.nodes import FuncDef, TypeInfo, SymbolNode, ARG_STAR, ARG_STAR2
 from mypy.types import (
@@ -9,6 +10,7 @@
     get_proper_type
 )
 
+from mypyc.ir.ops import LiteralsMap
 from mypyc.ir.rtypes import (
     RType, RUnion, RTuple, RInstance, object_rprimitive, dict_rprimitive, tuple_rprimitive,
     none_rprimitive, int_rprimitive, float_rprimitive, str_rprimitive, bool_rprimitive,
@@ -32,6 +34,12 @@
         self.group_map = group_map
         self.type_to_ir = {}  # type: Dict[TypeInfo, ClassIR]
         self.func_to_decl = {}  # type: Dict[SymbolNode, FuncDecl]
+        # LiteralsMap maps literal values to a static name. Each
+        # compilation group has its own LiteralsMap. (Since they can't
+        # share literals.)
+        self.literals = {
+            v: OrderedDict() for v in group_map.values()
+        }  # type: Dict[Optional[str], LiteralsMap]
 
     def type_to_rtype(self, typ: Optional[Type]) -> RType:
         if typ is None:
@@ -140,3 +148,19 @@
         if fdef.name in ('__eq__', '__ne__', '__lt__', '__gt__', '__le__', '__ge__'):
             ret = object_rprimitive
         return FuncSignature(args, ret)
+
+    def literal_static_name(self, module: str,
+                            value: Union[int, float, complex, str, bytes]) -> str:
+        # Literals are shared between modules in a compilation group
+        # but not outside the group.
+        literals = self.literals[self.group_map.get(module)]
+
+        # Include type to distinguish between 1 and 1.0, and so on.
+        key = (type(value), value)
+        if key not in literals:
+            if isinstance(value, str):
+                prefix = 'unicode_'
+            else:
+                prefix = type(value).__name__ + '_'
+            literals[key] = prefix + str(len(literals))
+        return literals[key]
diff --git a/mypyc/irbuild/statement.py b/mypyc/irbuild/statement.py
index 06d5cca..269e354 100644
--- a/mypyc/irbuild/statement.py
+++ b/mypyc/irbuild/statement.py
@@ -156,10 +156,10 @@
         mod_dict = builder.call_c(get_module_dict_op, [], node.line)
         # Get top-level module/package object.
         obj = builder.call_c(dict_get_item_op,
-                             [mod_dict, builder.load_str(base)], node.line)
+                             [mod_dict, builder.load_static_unicode(base)], node.line)
 
         builder.gen_method_call(
-            globals, '__setitem__', [builder.load_str(name), obj],
+            globals, '__setitem__', [builder.load_static_unicode(name), obj],
             result_type=None, line=node.line)
 
 
@@ -193,7 +193,7 @@
         as_name = maybe_as_name or name
         obj = builder.py_get_attr(module, name, node.line)
         builder.gen_method_call(
-            globals, '__setitem__', [builder.load_str(as_name), obj],
+            globals, '__setitem__', [builder.load_static_unicode(as_name), obj],
             result_type=None, line=node.line)
 
 
@@ -663,7 +663,7 @@
             line=line
         )
     elif isinstance(target, AssignmentTargetAttr):
-        key = builder.load_str(target.attr)
+        key = builder.load_static_unicode(target.attr)
         builder.call_c(py_delattr_op, [target.obj, key], line)
     elif isinstance(target, AssignmentTargetRegister):
         # Delete a local by assigning an error value to it, which will
diff --git a/mypyc/lib-rt/CPy.h b/mypyc/lib-rt/CPy.h
index a69836a..9d0ec6e 100644
--- a/mypyc/lib-rt/CPy.h
+++ b/mypyc/lib-rt/CPy.h
@@ -522,8 +522,6 @@
                                        CPyArg_Parser *parser, ...);
 
 int CPySequence_CheckUnpackCount(PyObject *sequence, Py_ssize_t expected);
-int CPyStatics_Initialize(PyObject **statics, const char *strings, const char *bytestrings,
-                          const char *ints, const double *floats, const double *complex_numbers);
 
 
 #ifdef __cplusplus
diff --git a/mypyc/lib-rt/misc_ops.c b/mypyc/lib-rt/misc_ops.c
index bc51dea..5d6aa63 100644
--- a/mypyc/lib-rt/misc_ops.c
+++ b/mypyc/lib-rt/misc_ops.c
@@ -509,90 +509,3 @@
     }
     return 0;
 }
-
-// Parse an integer (size_t) encoded as a variable-length binary sequence.
-static const char *parse_int(const char *s, size_t *len) {
-    ssize_t n = 0;
-    while ((unsigned char)*s >= 0x80) {
-        n = (n << 7) + (*s & 0x7f);
-        s++;
-    }
-    n = (n << 7) | *s++;
-    *len = n;
-    return s;
-}
-
-// Initialize static constant array of literal values
-int CPyStatics_Initialize(PyObject **statics,
-                          const char *strings,
-                          const char *bytestrings,
-                          const char *ints,
-                          const double *floats,
-                          const double *complex_numbers) {
-    if (strings) {
-        size_t num;
-        strings = parse_int(strings, &num);
-        while (num-- > 0) {
-            size_t len;
-            strings = parse_int(strings, &len);
-            PyObject *obj = PyUnicode_FromStringAndSize(strings, len);
-            if (obj == NULL) {
-                return -1;
-            }
-            PyUnicode_InternInPlace(&obj);
-            *statics++ = obj;
-            strings += len;
-        }
-    }
-    if (bytestrings) {
-        size_t num;
-        bytestrings = parse_int(bytestrings, &num);
-        while (num-- > 0) {
-            size_t len;
-            bytestrings = parse_int(bytestrings, &len);
-            PyObject *obj = PyBytes_FromStringAndSize(bytestrings, len);
-            if (obj == NULL) {
-                return -1;
-            }
-            *statics++ = obj;
-            bytestrings += len;
-        }
-    }
-    if (ints) {
-        size_t num;
-        ints = parse_int(ints, &num);
-        while (num-- > 0) {
-            char *end;
-            PyObject *obj = PyLong_FromString(ints, &end, 10);
-            if (obj == NULL) {
-                return -1;
-            }
-            ints = end;
-            ints++;
-            *statics++ = obj;
-        }
-    }
-    if (floats) {
-        size_t num = (size_t)*floats++;
-        while (num-- > 0) {
-            PyObject *obj = PyFloat_FromDouble(*floats++);
-            if (obj == NULL) {
-                return -1;
-            }
-            *statics++ = obj;
-        }
-    }
-    if (complex_numbers) {
-        size_t num = (size_t)*complex_numbers++;
-        while (num-- > 0) {
-            double real = *complex_numbers++;
-            double imag = *complex_numbers++;
-            PyObject *obj = PyComplex_FromDoubles(real, imag);
-            if (obj == NULL) {
-                return -1;
-            }
-            *statics++ = obj;
-        }
-    }
-    return 0;
-}
diff --git a/mypyc/test-data/analysis.test b/mypyc/test-data/analysis.test
index efa7fd0..3e12b52 100644
--- a/mypyc/test-data/analysis.test
+++ b/mypyc/test-data/analysis.test
@@ -548,7 +548,7 @@
 L2:
     r1 = CPy_CatchError()
     r2 = builtins :: module
-    r3 = 'Exception'
+    r3 = load_global CPyStatic_unicode_1 :: static  ('Exception')
     r4 = CPyObject_GetAttr(r2, r3)
     if is_error(r4) goto L8 (error at lol:4) else goto L3
 L3:
@@ -605,4 +605,3 @@
 (10, 1)  {r8}                    {}
 (11, 0)  {}                      {r9}
 (11, 1)  {r9}                    {}
-
diff --git a/mypyc/test-data/exceptions.test b/mypyc/test-data/exceptions.test
index ba21969..a1925e4 100644
--- a/mypyc/test-data/exceptions.test
+++ b/mypyc/test-data/exceptions.test
@@ -187,7 +187,7 @@
 L0:
 L1:
     r0 = builtins :: module
-    r1 = 'object'
+    r1 = load_global CPyStatic_unicode_1 :: static  ('object')
     r2 = CPyObject_GetAttr(r0, r1)
     if is_error(r2) goto L3 (error at g:3) else goto L2
 L2:
@@ -196,9 +196,9 @@
     if is_error(r3) goto L3 (error at g:3) else goto L10
 L3:
     r4 = CPy_CatchError()
-    r5 = 'weeee'
+    r5 = load_global CPyStatic_unicode_2 :: static  ('weeee')
     r6 = builtins :: module
-    r7 = 'print'
+    r7 = load_global CPyStatic_unicode_3 :: static  ('print')
     r8 = CPyObject_GetAttr(r6, r7)
     if is_error(r8) goto L6 (error at g:5) else goto L4
 L4:
@@ -253,7 +253,7 @@
 L0:
 L1:
     r0 = builtins :: module
-    r1 = 'print'
+    r1 = load_global CPyStatic_unicode_1 :: static  ('print')
     r2 = CPyObject_GetAttr(r0, r1)
     if is_error(r2) goto L5 (error at a:3) else goto L2
 L2:
@@ -261,7 +261,7 @@
     dec_ref r2
     if is_error(r3) goto L5 (error at a:3) else goto L20
 L3:
-    r4 = 'hi'
+    r4 = load_global CPyStatic_unicode_2 :: static  ('hi')
     inc_ref r4
     r5 = r4
 L4:
@@ -274,9 +274,9 @@
     r9 = CPy_CatchError()
     r7 = r9
 L6:
-    r10 = 'goodbye!'
+    r10 = load_global CPyStatic_unicode_3 :: static  ('goodbye!')
     r11 = builtins :: module
-    r12 = 'print'
+    r12 = load_global CPyStatic_unicode_1 :: static  ('print')
     r13 = CPyObject_GetAttr(r11, r12)
     if is_error(r13) goto L13 (error at a:6) else goto L7
 L7:
@@ -352,7 +352,7 @@
     r3 :: str
 L0:
 L1:
-    r0 = 'foo'
+    r0 = load_global CPyStatic_unicode_3 :: static  ('foo')
     r1 = CPyObject_GetAttr(x, r0)
     if is_error(r1) goto L3 (error at lol:4) else goto L2
 L2:
@@ -360,7 +360,7 @@
     goto L4
 L3:
     r2 = CPy_CatchError()
-    r3 = ''
+    r3 = load_global CPyStatic_unicode_4 :: static
     CPy_RestoreExcInfo(r2)
     dec_ref r2
     inc_ref r3
@@ -394,12 +394,12 @@
     r1 = <error> :: object
     b = r1
 L1:
-    r2 = 'foo'
+    r2 = load_global CPyStatic_unicode_3 :: static  ('foo')
     r3 = CPyObject_GetAttr(x, r2)
     if is_error(r3) goto L4 (error at lol:4) else goto L15
 L2:
     a = r3
-    r4 = 'bar'
+    r4 = load_global CPyStatic_unicode_4 :: static  ('bar')
     r5 = CPyObject_GetAttr(x, r4)
     if is_error(r5) goto L4 (error at lol:5) else goto L16
 L3:
@@ -469,13 +469,13 @@
 L0:
     r0 = <error> :: str
     v = r0
-    r1 = 'a'
+    r1 = load_global CPyStatic_unicode_1 :: static  ('a')
     inc_ref r1
     u = r1
 L1:
     if b goto L10 else goto L11 :: bool
 L2:
-    r2 = 'b'
+    r2 = load_global CPyStatic_unicode_2 :: static  ('b')
     inc_ref r2
     v = r2
     r3 = v == u
@@ -483,7 +483,7 @@
     if r4 goto L11 else goto L1 :: bool
 L3:
     r5 = builtins :: module
-    r6 = 'print'
+    r6 = load_global CPyStatic_unicode_3 :: static  ('print')
     r7 = CPyObject_GetAttr(r5, r6)
     if is_error(r7) goto L12 (error at f:7) else goto L4
 L4:
diff --git a/mypyc/test-data/fixtures/ir.py b/mypyc/test-data/fixtures/ir.py
index bb85a41..09bd0aa 100644
--- a/mypyc/test-data/fixtures/ir.py
+++ b/mypyc/test-data/fixtures/ir.py
@@ -90,7 +90,6 @@
     def __sub__(self, n: complex) -> complex: pass
     def __mul__(self, n: complex) -> complex: pass
     def __truediv__(self, n: complex) -> complex: pass
-    def __neg__(self) -> complex: pass
 
 class bytes:
     def __init__(self, x: object) -> None: pass
diff --git a/mypyc/test-data/irbuild-any.test b/mypyc/test-data/irbuild-any.test
index c2badd4..8c07aeb 100644
--- a/mypyc/test-data/irbuild-any.test
+++ b/mypyc/test-data/irbuild-any.test
@@ -62,7 +62,7 @@
     a = r4
     r5 = unbox(int, a)
     n = r5
-    r6 = 'a'
+    r6 = load_global CPyStatic_unicode_6 :: static  ('a')
     r7 = box(int, n)
     r8 = PyObject_SetAttr(a, r6, r7)
     r9 = r8 >= 0 :: signed
diff --git a/mypyc/test-data/irbuild-basic.test b/mypyc/test-data/irbuild-basic.test
index 184984e..e853fda 100644
--- a/mypyc/test-data/irbuild-basic.test
+++ b/mypyc/test-data/irbuild-basic.test
@@ -683,7 +683,7 @@
     r5 :: int
 L0:
     r0 = testmodule :: module
-    r1 = 'factorial'
+    r1 = load_global CPyStatic_unicode_2 :: static  ('factorial')
     r2 = CPyObject_GetAttr(r0, r1)
     r3 = box(int, x)
     r4 = PyObject_CallFunctionObjArgs(r2, r3, 0)
@@ -707,7 +707,7 @@
     r5 :: int
 L0:
     r0 = __main__.globals :: static
-    r1 = 'g'
+    r1 = load_global CPyStatic_unicode_2 :: static  ('g')
     r2 = CPyDict_GetItem(r0, r1)
     r3 = box(int, x)
     r4 = PyObject_CallFunctionObjArgs(r2, r3, 0)
@@ -726,7 +726,7 @@
     r2, r3, r4 :: object
 L0:
     r0 = builtins :: module
-    r1 = 'print'
+    r1 = load_global CPyStatic_unicode_1 :: static  ('print')
     r2 = CPyObject_GetAttr(r0, r1)
     r3 = box(short_int, 10)
     r4 = PyObject_CallFunctionObjArgs(r2, r3, 0)
@@ -744,7 +744,7 @@
     r2, r3, r4 :: object
 L0:
     r0 = builtins :: module
-    r1 = 'print'
+    r1 = load_global CPyStatic_unicode_1 :: static  ('print')
     r2 = CPyObject_GetAttr(r0, r1)
     r3 = box(short_int, 10)
     r4 = PyObject_CallFunctionObjArgs(r2, r3, 0)
@@ -758,9 +758,9 @@
 def f():
     r0, x, r1 :: str
 L0:
-    r0 = 'some string'
+    r0 = load_global CPyStatic_unicode_1 :: static  ('some string')
     x = r0
-    r1 = 'some other string'
+    r1 = load_global CPyStatic_unicode_2 :: static  ('some other string')
     return r1
 
 [case testBytesLiteral]
@@ -771,9 +771,9 @@
 def f():
     r0, x, r1 :: object
 L0:
-    r0 = b'\xf0'
+    r0 = load_global CPyStatic_bytes_1 :: static  (b'\xf0')
     x = r0
-    r1 = b'1234'
+    r1 = load_global CPyStatic_bytes_2 :: static  (b'1234')
     return r1
 
 [case testPyMethodCall1]
@@ -791,11 +791,11 @@
     r4 :: object
     r5 :: int
 L0:
-    r0 = 'pop'
+    r0 = load_global CPyStatic_unicode_3 :: static  ('pop')
     r1 = CPyObject_CallMethodObjArgs(x, r0, 0)
     r2 = unbox(int, r1)
     y = r2
-    r3 = 'pop'
+    r3 = load_global CPyStatic_unicode_3 :: static  ('pop')
     r4 = CPyObject_CallMethodObjArgs(x, r3, 0)
     r5 = unbox(int, r4)
     return r5
@@ -1018,11 +1018,11 @@
     r5 :: object
     r6 :: float
 L0:
-    r0 = 1.0
+    r0 = load_global CPyStatic_float_1 :: static  (1.0)
     f1 = r0
-    r1 = 2.0
+    r1 = load_global CPyStatic_float_2 :: static  (2.0)
     f2 = r1
-    r2 = 3.0
+    r2 = load_global CPyStatic_float_3 :: static  (3.0)
     f3 = r2
     r3 = PyNumber_Multiply(f1, f2)
     r4 = cast(float, r3)
@@ -1039,8 +1039,8 @@
     r1 :: float
     r2 :: object
 L0:
-    r0 = 5j
-    r1 = 1.0
+    r0 = load_global CPyStatic_complex_1 :: static  (5j)
+    r1 = load_global CPyStatic_float_2 :: static  (1.0)
     r2 = PyNumber_Add(r0, r1)
     return r2
 
@@ -1060,13 +1060,13 @@
 L0:
     a_62_bit = 9223372036854775804
     max_62_bit = 9223372036854775806
-    r0 = object 4611686018427387904
+    r0 = load_global CPyStatic_int_1 :: static  (4611686018427387904)
     b_63_bit = r0
-    r1 = object 9223372036854775806
+    r1 = load_global CPyStatic_int_2 :: static  (9223372036854775806)
     c_63_bit = r1
-    r2 = object 9223372036854775807
+    r2 = load_global CPyStatic_int_3 :: static  (9223372036854775807)
     max_63_bit = r2
-    r3 = object 9223372036854775808
+    r3 = load_global CPyStatic_int_4 :: static  (9223372036854775808)
     d_64_bit = r3
     max_32_bit = 4294967294
     max_31_bit = 2147483646
@@ -1086,19 +1086,19 @@
 def big_int():
     r0, a_62_bit, r1, max_62_bit, r2, b_63_bit, r3, c_63_bit, r4, max_63_bit, r5, d_64_bit, r6, max_32_bit, max_31_bit :: int
 L0:
-    r0 = object 4611686018427387902
+    r0 = load_global CPyStatic_int_1 :: static  (4611686018427387902)
     a_62_bit = r0
-    r1 = object 4611686018427387903
+    r1 = load_global CPyStatic_int_2 :: static  (4611686018427387903)
     max_62_bit = r1
-    r2 = object 4611686018427387904
+    r2 = load_global CPyStatic_int_3 :: static  (4611686018427387904)
     b_63_bit = r2
-    r3 = object 9223372036854775806
+    r3 = load_global CPyStatic_int_4 :: static  (9223372036854775806)
     c_63_bit = r3
-    r4 = object 9223372036854775807
+    r4 = load_global CPyStatic_int_5 :: static  (9223372036854775807)
     max_63_bit = r4
-    r5 = object 9223372036854775808
+    r5 = load_global CPyStatic_int_6 :: static  (9223372036854775808)
     d_64_bit = r5
-    r6 = object 2147483647
+    r6 = load_global CPyStatic_int_7 :: static  (2147483647)
     max_32_bit = r6
     max_31_bit = 2147483646
     return 1
@@ -1165,7 +1165,7 @@
 def return_float():
     r0 :: float
 L0:
-    r0 = 5.0
+    r0 = load_global CPyStatic_float_3 :: static  (5.0)
     return r0
 def return_callable_type():
     r0 :: dict
@@ -1173,7 +1173,7 @@
     r2 :: object
 L0:
     r0 = __main__.globals :: static
-    r1 = 'return_float'
+    r1 = load_global CPyStatic_unicode_4 :: static  ('return_float')
     r2 = CPyDict_GetItem(r0, r1)
     return r2
 def call_callable_type():
@@ -1209,7 +1209,7 @@
     r6 :: int
 L0:
     r0 = load_address PyLong_Type
-    r1 = 'base'
+    r1 = load_global CPyStatic_unicode_3 :: static  ('base')
     r2 = PyTuple_Pack(1, x)
     r3 = box(short_int, 4)
     r4 = CPyDict_Build(1, r1, r3)
@@ -1235,18 +1235,18 @@
     r15 :: dict
     r16 :: object
 L0:
-    r0 = 'insert'
+    r0 = load_global CPyStatic_unicode_4 :: static  ('insert')
     r1 = CPyObject_GetAttr(xs, r0)
-    r2 = 'x'
+    r2 = load_global CPyStatic_unicode_5 :: static  ('x')
     r3 = box(short_int, 0)
     r4 = PyTuple_Pack(1, r3)
     r5 = box(int, first)
     r6 = CPyDict_Build(1, r2, r5)
     r7 = PyObject_Call(r1, r4, r6)
-    r8 = 'insert'
+    r8 = load_global CPyStatic_unicode_4 :: static  ('insert')
     r9 = CPyObject_GetAttr(xs, r8)
-    r10 = 'x'
-    r11 = 'i'
+    r10 = load_global CPyStatic_unicode_5 :: static  ('x')
+    r11 = load_global CPyStatic_unicode_6 :: static  ('i')
     r12 = PyTuple_Pack(0)
     r13 = box(int, second)
     r14 = box(short_int, 2)
@@ -1417,7 +1417,7 @@
     r2, r3 :: object
 L0:
     r0 = builtins :: module
-    r1 = 'Exception'
+    r1 = load_global CPyStatic_unicode_1 :: static  ('Exception')
     r2 = CPyObject_GetAttr(r0, r1)
     r3 = PyObject_CallFunctionObjArgs(r2, 0)
     CPy_Raise(r3)
@@ -1428,7 +1428,7 @@
     r2 :: object
 L0:
     r0 = builtins :: module
-    r1 = 'Exception'
+    r1 = load_global CPyStatic_unicode_1 :: static  ('Exception')
     r2 = CPyObject_GetAttr(r0, r1)
     CPy_Raise(r2)
     unreachable
@@ -1450,11 +1450,11 @@
     r6, r7, r8 :: object
 L0:
     r0 = __main__.globals :: static
-    r1 = 'x'
+    r1 = load_global CPyStatic_unicode_1 :: static  ('x')
     r2 = CPyDict_GetItem(r0, r1)
     r3 = unbox(int, r2)
     r4 = builtins :: module
-    r5 = 'print'
+    r5 = load_global CPyStatic_unicode_2 :: static  ('print')
     r6 = CPyObject_GetAttr(r4, r5)
     r7 = box(int, r3)
     r8 = PyObject_CallFunctionObjArgs(r6, r7, 0)
@@ -1482,21 +1482,21 @@
     r2 = r0 != r1
     if r2 goto L2 else goto L1 :: bool
 L1:
-    r3 = 'builtins'
+    r3 = load_global CPyStatic_unicode_0 :: static  ('builtins')
     r4 = PyImport_Import(r3)
     builtins = r4 :: module
 L2:
     r5 = __main__.globals :: static
-    r6 = 'x'
+    r6 = load_global CPyStatic_unicode_1 :: static  ('x')
     r7 = box(short_int, 2)
     r8 = CPyDict_SetItem(r5, r6, r7)
     r9 = r8 >= 0 :: signed
     r10 = __main__.globals :: static
-    r11 = 'x'
+    r11 = load_global CPyStatic_unicode_1 :: static  ('x')
     r12 = CPyDict_GetItem(r10, r11)
     r13 = unbox(int, r12)
     r14 = builtins :: module
-    r15 = 'print'
+    r15 = load_global CPyStatic_unicode_2 :: static  ('print')
     r16 = CPyObject_GetAttr(r14, r15)
     r17 = box(int, r13)
     r18 = PyObject_CallFunctionObjArgs(r16, r17, 0)
@@ -1520,7 +1520,7 @@
     r5 :: str
 L0:
     r0 = m :: module
-    r1 = 'f'
+    r1 = load_global CPyStatic_unicode_2 :: static  ('f')
     r2 = CPyObject_GetAttr(r0, r1)
     r3 = box(short_int, 2)
     r4 = PyObject_CallFunctionObjArgs(r2, r3, 0)
@@ -1628,9 +1628,9 @@
     r2 :: str
     r3 :: None
 L0:
-    r0 = 'a'
+    r0 = load_global CPyStatic_unicode_1 :: static  ('a')
     r1 = f(0, r0)
-    r2 = 'b'
+    r2 = load_global CPyStatic_unicode_2 :: static  ('b')
     r3 = f(2, r2)
     return 1
 
@@ -1655,9 +1655,9 @@
     r2 :: str
     r3 :: None
 L0:
-    r0 = 'a'
+    r0 = load_global CPyStatic_unicode_4 :: static  ('a')
     r1 = a.f(0, r0)
-    r2 = 'b'
+    r2 = load_global CPyStatic_unicode_5 :: static  ('b')
     r3 = a.f(2, r2)
     return 1
 
@@ -1690,7 +1690,7 @@
 L0:
     r0 = (2, 4, 6)
     r1 = __main__.globals :: static
-    r2 = 'f'
+    r2 = load_global CPyStatic_unicode_3 :: static  ('f')
     r3 = CPyDict_GetItem(r1, r2)
     r4 = PyList_New(0)
     r5 = box(tuple[int, int, int], r0)
@@ -1716,7 +1716,7 @@
 L0:
     r0 = (4, 6)
     r1 = __main__.globals :: static
-    r2 = 'f'
+    r2 = load_global CPyStatic_unicode_3 :: static  ('f')
     r3 = CPyDict_GetItem(r1, r2)
     r4 = PyList_New(1)
     r5 = box(short_int, 2)
@@ -1759,15 +1759,15 @@
     r14 :: object
     r15 :: tuple[int, int, int]
 L0:
-    r0 = 'a'
-    r1 = 'b'
-    r2 = 'c'
+    r0 = load_global CPyStatic_unicode_3 :: static  ('a')
+    r1 = load_global CPyStatic_unicode_4 :: static  ('b')
+    r2 = load_global CPyStatic_unicode_5 :: static  ('c')
     r3 = box(short_int, 2)
     r4 = box(short_int, 4)
     r5 = box(short_int, 6)
     r6 = CPyDict_Build(3, r0, r3, r1, r4, r2, r5)
     r7 = __main__.globals :: static
-    r8 = 'f'
+    r8 = load_global CPyStatic_unicode_6 :: static  ('f')
     r9 = CPyDict_GetItem(r7, r8)
     r10 = PyTuple_Pack(0)
     r11 = PyDict_New()
@@ -1789,13 +1789,13 @@
     r13 :: object
     r14 :: tuple[int, int, int]
 L0:
-    r0 = 'b'
-    r1 = 'c'
+    r0 = load_global CPyStatic_unicode_4 :: static  ('b')
+    r1 = load_global CPyStatic_unicode_5 :: static  ('c')
     r2 = box(short_int, 4)
     r3 = box(short_int, 6)
     r4 = CPyDict_Build(2, r0, r2, r1, r3)
     r5 = __main__.globals :: static
-    r6 = 'f'
+    r6 = load_global CPyStatic_unicode_6 :: static  ('f')
     r7 = CPyDict_GetItem(r5, r6)
     r8 = box(short_int, 2)
     r9 = PyTuple_Pack(1, r8)
@@ -1824,7 +1824,7 @@
 L2:
     if is_error(z) goto L3 else goto L4
 L3:
-    r0 = 'test'
+    r0 = load_global CPyStatic_unicode_1 :: static  ('test')
     z = r0
 L4:
     return 1
@@ -1863,7 +1863,7 @@
 L2:
     if is_error(z) goto L3 else goto L4
 L3:
-    r0 = 'test'
+    r0 = load_global CPyStatic_unicode_4 :: static  ('test')
     z = r0
 L4:
     return 1
@@ -2566,7 +2566,7 @@
     r2 = r0 != r1
     if r2 goto L2 else goto L1 :: bool
 L1:
-    r3 = 'builtins'
+    r3 = load_global CPyStatic_unicode_0 :: static  ('builtins')
     r4 = PyImport_Import(r3)
     builtins = r4 :: module
 L2:
@@ -2575,76 +2575,76 @@
     r7 = r5 != r6
     if r7 goto L4 else goto L3 :: bool
 L3:
-    r8 = 'typing'
+    r8 = load_global CPyStatic_unicode_1 :: static  ('typing')
     r9 = PyImport_Import(r8)
     typing = r9 :: module
 L4:
     r10 = typing :: module
     r11 = __main__.globals :: static
-    r12 = 'List'
+    r12 = load_global CPyStatic_unicode_2 :: static  ('List')
     r13 = CPyObject_GetAttr(r10, r12)
-    r14 = 'List'
+    r14 = load_global CPyStatic_unicode_2 :: static  ('List')
     r15 = CPyDict_SetItem(r11, r14, r13)
     r16 = r15 >= 0 :: signed
-    r17 = 'NewType'
+    r17 = load_global CPyStatic_unicode_3 :: static  ('NewType')
     r18 = CPyObject_GetAttr(r10, r17)
-    r19 = 'NewType'
+    r19 = load_global CPyStatic_unicode_3 :: static  ('NewType')
     r20 = CPyDict_SetItem(r11, r19, r18)
     r21 = r20 >= 0 :: signed
-    r22 = 'NamedTuple'
+    r22 = load_global CPyStatic_unicode_4 :: static  ('NamedTuple')
     r23 = CPyObject_GetAttr(r10, r22)
-    r24 = 'NamedTuple'
+    r24 = load_global CPyStatic_unicode_4 :: static  ('NamedTuple')
     r25 = CPyDict_SetItem(r11, r24, r23)
     r26 = r25 >= 0 :: signed
-    r27 = 'Lol'
-    r28 = 'a'
+    r27 = load_global CPyStatic_unicode_5 :: static  ('Lol')
+    r28 = load_global CPyStatic_unicode_6 :: static  ('a')
     r29 = load_address PyLong_Type
     r30 = (r28, r29)
     r31 = box(tuple[str, object], r30)
-    r32 = 'b'
+    r32 = load_global CPyStatic_unicode_7 :: static  ('b')
     r33 = load_address PyUnicode_Type
     r34 = (r32, r33)
     r35 = box(tuple[str, object], r34)
     r36 = (r31, r35)
     r37 = box(tuple[object, object], r36)
     r38 = __main__.globals :: static
-    r39 = 'NamedTuple'
+    r39 = load_global CPyStatic_unicode_4 :: static  ('NamedTuple')
     r40 = CPyDict_GetItem(r38, r39)
     r41 = PyObject_CallFunctionObjArgs(r40, r27, r37, 0)
     r42 = __main__.globals :: static
-    r43 = 'Lol'
+    r43 = load_global CPyStatic_unicode_5 :: static  ('Lol')
     r44 = CPyDict_SetItem(r42, r43, r41)
     r45 = r44 >= 0 :: signed
-    r46 = ''
+    r46 = load_global CPyStatic_unicode_8 :: static
     r47 = __main__.globals :: static
-    r48 = 'Lol'
+    r48 = load_global CPyStatic_unicode_5 :: static  ('Lol')
     r49 = CPyDict_GetItem(r47, r48)
     r50 = box(short_int, 2)
     r51 = PyObject_CallFunctionObjArgs(r49, r50, r46, 0)
     r52 = cast(tuple, r51)
     r53 = __main__.globals :: static
-    r54 = 'x'
+    r54 = load_global CPyStatic_unicode_9 :: static  ('x')
     r55 = CPyDict_SetItem(r53, r54, r52)
     r56 = r55 >= 0 :: signed
     r57 = __main__.globals :: static
-    r58 = 'List'
+    r58 = load_global CPyStatic_unicode_2 :: static  ('List')
     r59 = CPyDict_GetItem(r57, r58)
     r60 = load_address PyLong_Type
     r61 = PyObject_GetItem(r59, r60)
     r62 = __main__.globals :: static
-    r63 = 'Foo'
+    r63 = load_global CPyStatic_unicode_10 :: static  ('Foo')
     r64 = CPyDict_SetItem(r62, r63, r61)
     r65 = r64 >= 0 :: signed
-    r66 = 'Bar'
+    r66 = load_global CPyStatic_unicode_11 :: static  ('Bar')
     r67 = __main__.globals :: static
-    r68 = 'Foo'
+    r68 = load_global CPyStatic_unicode_10 :: static  ('Foo')
     r69 = CPyDict_GetItem(r67, r68)
     r70 = __main__.globals :: static
-    r71 = 'NewType'
+    r71 = load_global CPyStatic_unicode_3 :: static  ('NewType')
     r72 = CPyDict_GetItem(r70, r71)
     r73 = PyObject_CallFunctionObjArgs(r72, r66, r69, 0)
     r74 = __main__.globals :: static
-    r75 = 'Bar'
+    r75 = load_global CPyStatic_unicode_11 :: static  ('Bar')
     r76 = CPyDict_SetItem(r74, r75, r73)
     r77 = r76 >= 0 :: signed
     r78 = PyList_New(3)
@@ -2659,11 +2659,11 @@
     r85 = r83 + WORD_SIZE*2
     set_mem r85, r81, r78 :: builtins.object*
     r86 = __main__.globals :: static
-    r87 = 'Bar'
+    r87 = load_global CPyStatic_unicode_11 :: static  ('Bar')
     r88 = CPyDict_GetItem(r86, r87)
     r89 = PyObject_CallFunctionObjArgs(r88, r78, 0)
     r90 = __main__.globals :: static
-    r91 = 'y'
+    r91 = load_global CPyStatic_unicode_12 :: static  ('y')
     r92 = CPyDict_SetItem(r90, r91, r89)
     r93 = r92 >= 0 :: signed
     return 1
@@ -2825,16 +2825,16 @@
     r0 = __mypyc_self__.__mypyc_env__
     r1 = r0.g
     g = r1
-    r2 = 'Entering'
+    r2 = load_global CPyStatic_unicode_3 :: static  ('Entering')
     r3 = builtins :: module
-    r4 = 'print'
+    r4 = load_global CPyStatic_unicode_4 :: static  ('print')
     r5 = CPyObject_GetAttr(r3, r4)
     r6 = PyObject_CallFunctionObjArgs(r5, r2, 0)
     r7 = r0.f
     r8 = PyObject_CallFunctionObjArgs(r7, 0)
-    r9 = 'Exited'
+    r9 = load_global CPyStatic_unicode_5 :: static  ('Exited')
     r10 = builtins :: module
-    r11 = 'print'
+    r11 = load_global CPyStatic_unicode_4 :: static  ('print')
     r12 = CPyObject_GetAttr(r10, r11)
     r13 = PyObject_CallFunctionObjArgs(r12, r9, 0)
     return 1
@@ -2882,16 +2882,16 @@
     r0 = __mypyc_self__.__mypyc_env__
     r1 = r0.g
     g = r1
-    r2 = '---'
+    r2 = load_global CPyStatic_unicode_6 :: static  ('---')
     r3 = builtins :: module
-    r4 = 'print'
+    r4 = load_global CPyStatic_unicode_4 :: static  ('print')
     r5 = CPyObject_GetAttr(r3, r4)
     r6 = PyObject_CallFunctionObjArgs(r5, r2, 0)
     r7 = r0.f
     r8 = PyObject_CallFunctionObjArgs(r7, 0)
-    r9 = '---'
+    r9 = load_global CPyStatic_unicode_6 :: static  ('---')
     r10 = builtins :: module
-    r11 = 'print'
+    r11 = load_global CPyStatic_unicode_4 :: static  ('print')
     r12 = CPyObject_GetAttr(r10, r11)
     r13 = PyObject_CallFunctionObjArgs(r12, r9, 0)
     return 1
@@ -2935,9 +2935,9 @@
     r0 = __mypyc_self__.__mypyc_env__
     r1 = r0.d
     d = r1
-    r2 = 'd'
+    r2 = load_global CPyStatic_unicode_7 :: static  ('d')
     r3 = builtins :: module
-    r4 = 'print'
+    r4 = load_global CPyStatic_unicode_4 :: static  ('print')
     r5 = CPyObject_GetAttr(r3, r4)
     r6 = PyObject_CallFunctionObjArgs(r5, r2, 0)
     return 1
@@ -2961,17 +2961,17 @@
     r1 = __mypyc_d_decorator_helper_____mypyc_c_decorator_helper___obj()
     r1.__mypyc_env__ = r0; r2 = is_error
     r3 = __main__.globals :: static
-    r4 = 'b'
+    r4 = load_global CPyStatic_unicode_8 :: static  ('b')
     r5 = CPyDict_GetItem(r3, r4)
     r6 = PyObject_CallFunctionObjArgs(r5, r1, 0)
     r7 = __main__.globals :: static
-    r8 = 'a'
+    r8 = load_global CPyStatic_unicode_9 :: static  ('a')
     r9 = CPyDict_GetItem(r7, r8)
     r10 = PyObject_CallFunctionObjArgs(r9, r6, 0)
     r0.d = r10; r11 = is_error
-    r12 = 'c'
+    r12 = load_global CPyStatic_unicode_10 :: static  ('c')
     r13 = builtins :: module
-    r14 = 'print'
+    r14 = load_global CPyStatic_unicode_4 :: static  ('print')
     r15 = CPyObject_GetAttr(r13, r14)
     r16 = PyObject_CallFunctionObjArgs(r15, r12, 0)
     r17 = r0.d
@@ -3010,7 +3010,7 @@
     r2 = r0 != r1
     if r2 goto L2 else goto L1 :: bool
 L1:
-    r3 = 'builtins'
+    r3 = load_global CPyStatic_unicode_0 :: static  ('builtins')
     r4 = PyImport_Import(r3)
     builtins = r4 :: module
 L2:
@@ -3019,30 +3019,30 @@
     r7 = r5 != r6
     if r7 goto L4 else goto L3 :: bool
 L3:
-    r8 = 'typing'
+    r8 = load_global CPyStatic_unicode_1 :: static  ('typing')
     r9 = PyImport_Import(r8)
     typing = r9 :: module
 L4:
     r10 = typing :: module
     r11 = __main__.globals :: static
-    r12 = 'Callable'
+    r12 = load_global CPyStatic_unicode_2 :: static  ('Callable')
     r13 = CPyObject_GetAttr(r10, r12)
-    r14 = 'Callable'
+    r14 = load_global CPyStatic_unicode_2 :: static  ('Callable')
     r15 = CPyDict_SetItem(r11, r14, r13)
     r16 = r15 >= 0 :: signed
     r17 = __main__.globals :: static
-    r18 = '__mypyc_c_decorator_helper__'
+    r18 = load_global CPyStatic_unicode_11 :: static  ('__mypyc_c_decorator_helper__')
     r19 = CPyDict_GetItem(r17, r18)
     r20 = __main__.globals :: static
-    r21 = 'b'
+    r21 = load_global CPyStatic_unicode_8 :: static  ('b')
     r22 = CPyDict_GetItem(r20, r21)
     r23 = PyObject_CallFunctionObjArgs(r22, r19, 0)
     r24 = __main__.globals :: static
-    r25 = 'a'
+    r25 = load_global CPyStatic_unicode_9 :: static  ('a')
     r26 = CPyDict_GetItem(r24, r25)
     r27 = PyObject_CallFunctionObjArgs(r26, r23, 0)
     r28 = __main__.globals :: static
-    r29 = 'c'
+    r29 = load_global CPyStatic_unicode_10 :: static  ('c')
     r30 = CPyDict_SetItem(r28, r29, r27)
     r31 = r30 >= 0 :: signed
     return 1
@@ -3087,16 +3087,16 @@
     r0 = __mypyc_self__.__mypyc_env__
     r1 = r0.g
     g = r1
-    r2 = 'Entering'
+    r2 = load_global CPyStatic_unicode_3 :: static  ('Entering')
     r3 = builtins :: module
-    r4 = 'print'
+    r4 = load_global CPyStatic_unicode_4 :: static  ('print')
     r5 = CPyObject_GetAttr(r3, r4)
     r6 = PyObject_CallFunctionObjArgs(r5, r2, 0)
     r7 = r0.f
     r8 = PyObject_CallFunctionObjArgs(r7, 0)
-    r9 = 'Exited'
+    r9 = load_global CPyStatic_unicode_5 :: static  ('Exited')
     r10 = builtins :: module
-    r11 = 'print'
+    r11 = load_global CPyStatic_unicode_4 :: static  ('print')
     r12 = CPyObject_GetAttr(r10, r11)
     r13 = PyObject_CallFunctionObjArgs(r12, r9, 0)
     return 1
@@ -3135,7 +3135,7 @@
     r2 = r0 != r1
     if r2 goto L2 else goto L1 :: bool
 L1:
-    r3 = 'builtins'
+    r3 = load_global CPyStatic_unicode_0 :: static  ('builtins')
     r4 = PyImport_Import(r3)
     builtins = r4 :: module
 L2:
@@ -3144,15 +3144,15 @@
     r7 = r5 != r6
     if r7 goto L4 else goto L3 :: bool
 L3:
-    r8 = 'typing'
+    r8 = load_global CPyStatic_unicode_1 :: static  ('typing')
     r9 = PyImport_Import(r8)
     typing = r9 :: module
 L4:
     r10 = typing :: module
     r11 = __main__.globals :: static
-    r12 = 'Callable'
+    r12 = load_global CPyStatic_unicode_2 :: static  ('Callable')
     r13 = CPyObject_GetAttr(r10, r12)
-    r14 = 'Callable'
+    r14 = load_global CPyStatic_unicode_2 :: static  ('Callable')
     r15 = CPyDict_SetItem(r11, r14, r13)
     r16 = r15 >= 0 :: signed
     return 1
@@ -3266,8 +3266,8 @@
     r3 :: bit
     r4 :: object
 L0:
-    r0 = 'x'
-    r1 = '5'
+    r0 = load_global CPyStatic_unicode_5 :: static  ('x')
+    r1 = load_global CPyStatic_unicode_6 :: static  ('5')
     r2 = PyObject_SetAttr(x, r0, r1)
     r3 = r2 >= 0 :: signed
     r4 = box(None, 1)
@@ -3314,10 +3314,10 @@
 L0:
     if a goto L1 else goto L2 :: bool
 L1:
-    r0 = 'x'
+    r0 = load_global CPyStatic_unicode_3 :: static  ('x')
     return r0
 L2:
-    r1 = 'y'
+    r1 = load_global CPyStatic_unicode_4 :: static  ('y')
     return r1
 L3:
     unreachable
@@ -3507,7 +3507,7 @@
     r2, r3, r4 :: object
 L0:
     r0 = builtins :: module
-    r1 = 'reveal_type'
+    r1 = load_global CPyStatic_unicode_1 :: static  ('reveal_type')
     r2 = CPyObject_GetAttr(r0, r1)
     r3 = box(int, x)
     r4 = PyObject_CallFunctionObjArgs(r2, r3, 0)
@@ -3610,20 +3610,20 @@
     r3 = r1 != r2
     if r3 goto L2 else goto L1 :: bool
 L1:
-    r4 = 'p.m'
+    r4 = load_global CPyStatic_unicode_1 :: static  ('p.m')
     r5 = PyImport_Import(r4)
     p.m = r5 :: module
 L2:
     r6 = PyImport_GetModuleDict()
-    r7 = 'p'
+    r7 = load_global CPyStatic_unicode_2 :: static  ('p')
     r8 = CPyDict_GetItem(r6, r7)
-    r9 = 'p'
+    r9 = load_global CPyStatic_unicode_2 :: static  ('p')
     r10 = CPyDict_SetItem(r0, r9, r8)
     r11 = r10 >= 0 :: signed
     r12 = PyImport_GetModuleDict()
-    r13 = 'p'
+    r13 = load_global CPyStatic_unicode_2 :: static  ('p')
     r14 = CPyDict_GetItem(r12, r13)
-    r15 = 'x'
+    r15 = load_global CPyStatic_unicode_3 :: static  ('x')
     r16 = CPyObject_GetAttr(r14, r15)
     r17 = unbox(int, r16)
     return r17
diff --git a/mypyc/test-data/irbuild-classes.test b/mypyc/test-data/irbuild-classes.test
index 278b8c4..505a499 100644
--- a/mypyc/test-data/irbuild-classes.test
+++ b/mypyc/test-data/irbuild-classes.test
@@ -83,7 +83,7 @@
     r0 :: str
     r1 :: int
 L0:
-    r0 = 'hi'
+    r0 = load_global CPyStatic_unicode_4 :: static  ('hi')
     r1 = a.f(2, r0)
     return 1
 
@@ -370,7 +370,7 @@
     r2 = r0 != r1
     if r2 goto L2 else goto L1 :: bool
 L1:
-    r3 = 'builtins'
+    r3 = load_global CPyStatic_unicode_0 :: static  ('builtins')
     r4 = PyImport_Import(r3)
     builtins = r4 :: module
 L2:
@@ -379,20 +379,20 @@
     r7 = r5 != r6
     if r7 goto L4 else goto L3 :: bool
 L3:
-    r8 = 'typing'
+    r8 = load_global CPyStatic_unicode_1 :: static  ('typing')
     r9 = PyImport_Import(r8)
     typing = r9 :: module
 L4:
     r10 = typing :: module
     r11 = __main__.globals :: static
-    r12 = 'TypeVar'
+    r12 = load_global CPyStatic_unicode_2 :: static  ('TypeVar')
     r13 = CPyObject_GetAttr(r10, r12)
-    r14 = 'TypeVar'
+    r14 = load_global CPyStatic_unicode_2 :: static  ('TypeVar')
     r15 = CPyDict_SetItem(r11, r14, r13)
     r16 = r15 >= 0 :: signed
-    r17 = 'Generic'
+    r17 = load_global CPyStatic_unicode_3 :: static  ('Generic')
     r18 = CPyObject_GetAttr(r10, r17)
-    r19 = 'Generic'
+    r19 = load_global CPyStatic_unicode_3 :: static  ('Generic')
     r20 = CPyDict_SetItem(r11, r19, r18)
     r21 = r20 >= 0 :: signed
     r22 = mypy_extensions :: module
@@ -400,75 +400,75 @@
     r24 = r22 != r23
     if r24 goto L6 else goto L5 :: bool
 L5:
-    r25 = 'mypy_extensions'
+    r25 = load_global CPyStatic_unicode_4 :: static  ('mypy_extensions')
     r26 = PyImport_Import(r25)
     mypy_extensions = r26 :: module
 L6:
     r27 = mypy_extensions :: module
     r28 = __main__.globals :: static
-    r29 = 'trait'
+    r29 = load_global CPyStatic_unicode_5 :: static  ('trait')
     r30 = CPyObject_GetAttr(r27, r29)
-    r31 = 'trait'
+    r31 = load_global CPyStatic_unicode_5 :: static  ('trait')
     r32 = CPyDict_SetItem(r28, r31, r30)
     r33 = r32 >= 0 :: signed
-    r34 = 'T'
+    r34 = load_global CPyStatic_unicode_6 :: static  ('T')
     r35 = __main__.globals :: static
-    r36 = 'TypeVar'
+    r36 = load_global CPyStatic_unicode_2 :: static  ('TypeVar')
     r37 = CPyDict_GetItem(r35, r36)
     r38 = PyObject_CallFunctionObjArgs(r37, r34, 0)
     r39 = __main__.globals :: static
-    r40 = 'T'
+    r40 = load_global CPyStatic_unicode_6 :: static  ('T')
     r41 = CPyDict_SetItem(r39, r40, r38)
     r42 = r41 >= 0 :: signed
     r43 = <error> :: object
-    r44 = '__main__'
+    r44 = load_global CPyStatic_unicode_7 :: static  ('__main__')
     r45 = __main__.C_template :: type
     r46 = CPyType_FromTemplate(r45, r43, r44)
     r47 = C_trait_vtable_setup()
-    r48 = '__mypyc_attrs__'
+    r48 = load_global CPyStatic_unicode_8 :: static  ('__mypyc_attrs__')
     r49 = PyTuple_Pack(0)
     r50 = PyObject_SetAttr(r46, r48, r49)
     r51 = r50 >= 0 :: signed
     __main__.C = r46 :: type
     r52 = __main__.globals :: static
-    r53 = 'C'
+    r53 = load_global CPyStatic_unicode_9 :: static  ('C')
     r54 = CPyDict_SetItem(r52, r53, r46)
     r55 = r54 >= 0 :: signed
     r56 = <error> :: object
-    r57 = '__main__'
+    r57 = load_global CPyStatic_unicode_7 :: static  ('__main__')
     r58 = __main__.S_template :: type
     r59 = CPyType_FromTemplate(r58, r56, r57)
-    r60 = '__mypyc_attrs__'
+    r60 = load_global CPyStatic_unicode_8 :: static  ('__mypyc_attrs__')
     r61 = PyTuple_Pack(0)
     r62 = PyObject_SetAttr(r59, r60, r61)
     r63 = r62 >= 0 :: signed
     __main__.S = r59 :: type
     r64 = __main__.globals :: static
-    r65 = 'S'
+    r65 = load_global CPyStatic_unicode_10 :: static  ('S')
     r66 = CPyDict_SetItem(r64, r65, r59)
     r67 = r66 >= 0 :: signed
     r68 = __main__.C :: type
     r69 = __main__.S :: type
     r70 = __main__.globals :: static
-    r71 = 'Generic'
+    r71 = load_global CPyStatic_unicode_3 :: static  ('Generic')
     r72 = CPyDict_GetItem(r70, r71)
     r73 = __main__.globals :: static
-    r74 = 'T'
+    r74 = load_global CPyStatic_unicode_6 :: static  ('T')
     r75 = CPyDict_GetItem(r73, r74)
     r76 = PyObject_GetItem(r72, r75)
     r77 = PyTuple_Pack(3, r68, r69, r76)
-    r78 = '__main__'
+    r78 = load_global CPyStatic_unicode_7 :: static  ('__main__')
     r79 = __main__.D_template :: type
     r80 = CPyType_FromTemplate(r79, r77, r78)
     r81 = D_trait_vtable_setup()
-    r82 = '__mypyc_attrs__'
-    r83 = '__dict__'
+    r82 = load_global CPyStatic_unicode_8 :: static  ('__mypyc_attrs__')
+    r83 = load_global CPyStatic_unicode_11 :: static  ('__dict__')
     r84 = PyTuple_Pack(1, r83)
     r85 = PyObject_SetAttr(r80, r82, r84)
     r86 = r85 >= 0 :: signed
     __main__.D = r80 :: type
     r87 = __main__.globals :: static
-    r88 = 'D'
+    r88 = load_global CPyStatic_unicode_12 :: static  ('D')
     r89 = CPyDict_SetItem(r87, r88, r80)
     r90 = r89 >= 0 :: signed
     return 1
@@ -792,7 +792,7 @@
     r3 :: int
 L0:
     r0 = __main__.A :: type
-    r1 = 'x'
+    r1 = load_global CPyStatic_unicode_6 :: static  ('x')
     r2 = CPyObject_GetAttr(r0, r1)
     r3 = unbox(int, r2)
     return r3
@@ -958,7 +958,7 @@
     r1 :: object
     r2 :: bool
 L0:
-    r0 = '__ne__'
+    r0 = load_global CPyStatic_unicode_1 :: static  ('__ne__')
     r1 = CPyObject_CallMethodObjArgs(a, r0, b, 0)
     r2 = unbox(bool, r1)
     return r2
@@ -1029,7 +1029,7 @@
 L0:
     __mypyc_self__.x = 20; r0 = is_error
     r1 = __main__.globals :: static
-    r2 = 'LOL'
+    r2 = load_global CPyStatic_unicode_9 :: static  ('LOL')
     r3 = CPyDict_GetItem(r1, r2)
     r4 = cast(str, r3)
     __mypyc_self__.y = r4; r5 = is_error
diff --git a/mypyc/test-data/irbuild-dict.test b/mypyc/test-data/irbuild-dict.test
index 5a127ff..ba0c7a8 100644
--- a/mypyc/test-data/irbuild-dict.test
+++ b/mypyc/test-data/irbuild-dict.test
@@ -52,7 +52,7 @@
     r1, r2 :: object
     r3, d :: dict
 L0:
-    r0 = ''
+    r0 = load_global CPyStatic_unicode_1 :: static
     r1 = box(short_int, 2)
     r2 = box(short_int, 4)
     r3 = CPyDict_Build(2, r1, r2, r0, x)
@@ -194,7 +194,7 @@
     r6 :: int32
     r7 :: bit
 L0:
-    r0 = 'z'
+    r0 = load_global CPyStatic_unicode_3 :: static  ('z')
     r1 = box(short_int, 4)
     r2 = CPyDict_Build(1, x, r1)
     r3 = CPyDict_UpdateInDisplay(r2, y)
diff --git a/mypyc/test-data/irbuild-nested.test b/mypyc/test-data/irbuild-nested.test
index c5de7d6..d531a03 100644
--- a/mypyc/test-data/irbuild-nested.test
+++ b/mypyc/test-data/irbuild-nested.test
@@ -93,7 +93,7 @@
     r1 = r0.__mypyc_env__
     r2 = r0.second
     second = r2
-    r3 = 'b.first.second: nested function'
+    r3 = load_global CPyStatic_unicode_3 :: static  ('b.first.second: nested function')
     return r3
 def first_b_obj.__get__(__mypyc_self__, instance, owner):
     __mypyc_self__, instance, owner, r0 :: object
@@ -163,7 +163,7 @@
     r0 = __mypyc_self__.__mypyc_env__
     r1 = r0.inner
     inner = r1
-    r2 = '!'
+    r2 = load_global CPyStatic_unicode_4 :: static  ('!')
     r3 = PyUnicode_Concat(s, r2)
     return r3
 def c(num):
@@ -202,7 +202,7 @@
     r0 = __mypyc_self__.__mypyc_env__
     r1 = r0.inner
     inner = r1
-    r2 = '?'
+    r2 = load_global CPyStatic_unicode_5 :: static  ('?')
     r3 = PyUnicode_Concat(s, r2)
     return r3
 def d(num):
@@ -220,12 +220,12 @@
     r1 = inner_d_obj()
     r1.__mypyc_env__ = r0; r2 = is_error
     r0.inner = r1; r3 = is_error
-    r4 = 'one'
+    r4 = load_global CPyStatic_unicode_6 :: static  ('one')
     r5 = r0.inner
     r6 = PyObject_CallFunctionObjArgs(r5, r4, 0)
     r7 = cast(str, r6)
     a = r7
-    r8 = 'two'
+    r8 = load_global CPyStatic_unicode_7 :: static  ('two')
     r9 = r0.inner
     r10 = PyObject_CallFunctionObjArgs(r9, r8, 0)
     r11 = cast(str, r10)
@@ -234,17 +234,17 @@
 def inner():
     r0 :: str
 L0:
-    r0 = 'inner: normal function'
+    r0 = load_global CPyStatic_unicode_8 :: static  ('inner: normal function')
     return r0
 def first():
     r0 :: str
 L0:
-    r0 = 'first: normal function'
+    r0 = load_global CPyStatic_unicode_9 :: static  ('first: normal function')
     return r0
 def second():
     r0 :: str
 L0:
-    r0 = 'second: normal function'
+    r0 = load_global CPyStatic_unicode_10 :: static  ('second: normal function')
     return r0
 
 [case testFreeVars]
@@ -384,7 +384,7 @@
     r0 = __mypyc_self__.__mypyc_env__
     r1 = r0.inner
     inner = r1
-    r2 = 'f.inner: first definition'
+    r2 = load_global CPyStatic_unicode_3 :: static  ('f.inner: first definition')
     return r2
 def inner_c_obj_0.__get__(__mypyc_self__, instance, owner):
     __mypyc_self__, instance, owner, r0 :: object
@@ -408,7 +408,7 @@
     r0 = __mypyc_self__.__mypyc_env__
     r1 = r0.inner
     inner = r1
-    r2 = 'f.inner: second definition'
+    r2 = load_global CPyStatic_unicode_4 :: static  ('f.inner: second definition')
     return r2
 def c(flag):
     flag :: bool
@@ -565,7 +565,7 @@
     r0 = __mypyc_self__.__mypyc_env__
     r1 = r0.inner
     inner = r1
-    r2 = 'f.inner: first definition'
+    r2 = load_global CPyStatic_unicode_1 :: static  ('f.inner: first definition')
     return r2
 def inner_f_obj_0.__get__(__mypyc_self__, instance, owner):
     __mypyc_self__, instance, owner, r0 :: object
@@ -589,7 +589,7 @@
     r0 = __mypyc_self__.__mypyc_env__
     r1 = r0.inner
     inner = r1
-    r2 = 'f.inner: second definition'
+    r2 = load_global CPyStatic_unicode_2 :: static  ('f.inner: second definition')
     return r2
 def f(flag):
     flag :: bool
diff --git a/mypyc/test-data/irbuild-optional.test b/mypyc/test-data/irbuild-optional.test
index ab7890f..20a9ce3 100644
--- a/mypyc/test-data/irbuild-optional.test
+++ b/mypyc/test-data/irbuild-optional.test
@@ -341,7 +341,7 @@
     r1 :: int32
     r2 :: bit
 L0:
-    r0 = 'a'
+    r0 = load_global CPyStatic_unicode_5 :: static  ('a')
     r1 = PyObject_SetAttr(o, r0, s)
     r2 = r1 >= 0 :: signed
     return 1
@@ -471,7 +471,7 @@
     goto L3
 L2:
     r7 = o
-    r8 = 'x'
+    r8 = load_global CPyStatic_unicode_7 :: static  ('x')
     r9 = CPyObject_GetAttr(r7, r8)
     r10 = unbox(int, r9)
     r6 = r10
@@ -502,7 +502,7 @@
     goto L3
 L2:
     r7 = o
-    r8 = 'x'
+    r8 = load_global CPyStatic_unicode_7 :: static  ('x')
     r9 = CPyObject_GetAttr(r7, r8)
     r10 = unbox(int, r9)
     r6 = r10
@@ -530,9 +530,8 @@
     r2, r3 :: object
 L0:
     r0 = o
-    r1 = 'x'
+    r1 = load_global CPyStatic_unicode_6 :: static  ('x')
     r2 = CPyObject_GetAttr(r0, r1)
     r3 = r2
 L1:
     return 1
-
diff --git a/mypyc/test-data/irbuild-statements.test b/mypyc/test-data/irbuild-statements.test
index de8521d..490da2a 100644
--- a/mypyc/test-data/irbuild-statements.test
+++ b/mypyc/test-data/irbuild-statements.test
@@ -737,7 +737,7 @@
     if r5 goto L3 else goto L2 :: bool
 L2:
     r6 = builtins :: module
-    r7 = 'AssertionError'
+    r7 = load_global CPyStatic_unicode_3 :: static  ('AssertionError')
     r8 = CPyObject_GetAttr(r6, r7)
     r9 = PyObject_CallFunctionObjArgs(r8, s, 0)
     CPy_Raise(r9)
@@ -841,13 +841,13 @@
     r6 :: int32
     r7 :: bit
 L0:
-    r0 = 'one'
-    r1 = 'two'
+    r0 = load_global CPyStatic_unicode_1 :: static  ('one')
+    r1 = load_global CPyStatic_unicode_2 :: static  ('two')
     r2 = box(short_int, 2)
     r3 = box(short_int, 4)
     r4 = CPyDict_Build(2, r0, r2, r1, r3)
     d = r4
-    r5 = 'one'
+    r5 = load_global CPyStatic_unicode_1 :: static  ('one')
     r6 = PyObject_DelItem(d, r5)
     r7 = r6 >= 0 :: signed
     return 1
@@ -861,18 +861,18 @@
     r13 :: int32
     r14 :: bit
 L0:
-    r0 = 'one'
-    r1 = 'two'
-    r2 = 'three'
-    r3 = 'four'
+    r0 = load_global CPyStatic_unicode_1 :: static  ('one')
+    r1 = load_global CPyStatic_unicode_2 :: static  ('two')
+    r2 = load_global CPyStatic_unicode_3 :: static  ('three')
+    r3 = load_global CPyStatic_unicode_4 :: static  ('four')
     r4 = box(short_int, 2)
     r5 = box(short_int, 4)
     r6 = box(short_int, 6)
     r7 = box(short_int, 8)
     r8 = CPyDict_Build(4, r0, r4, r1, r5, r2, r6, r3, r7)
     d = r8
-    r9 = 'one'
-    r10 = 'four'
+    r9 = load_global CPyStatic_unicode_1 :: static  ('one')
+    r10 = load_global CPyStatic_unicode_4 :: static  ('four')
     r11 = PyObject_DelItem(d, r9)
     r12 = r11 >= 0 :: signed
     r13 = PyObject_DelItem(d, r10)
@@ -907,7 +907,7 @@
 L0:
     r0 = Dummy(2, 4)
     dummy = r0
-    r1 = 'x'
+    r1 = load_global CPyStatic_unicode_3 :: static  ('x')
     r2 = PyObject_DelAttr(dummy, r1)
     r3 = r2 >= 0 :: signed
     return 1
@@ -922,10 +922,10 @@
 L0:
     r0 = Dummy(2, 4)
     dummy = r0
-    r1 = 'x'
+    r1 = load_global CPyStatic_unicode_3 :: static  ('x')
     r2 = PyObject_DelAttr(dummy, r1)
     r3 = r2 >= 0 :: signed
-    r4 = 'y'
+    r4 = load_global CPyStatic_unicode_4 :: static  ('y')
     r5 = PyObject_DelAttr(dummy, r4)
     r6 = r5 >= 0 :: signed
     return 1
diff --git a/mypyc/test-data/irbuild-try.test b/mypyc/test-data/irbuild-try.test
index d1119c5..7d68040 100644
--- a/mypyc/test-data/irbuild-try.test
+++ b/mypyc/test-data/irbuild-try.test
@@ -18,15 +18,15 @@
 L0:
 L1:
     r0 = builtins :: module
-    r1 = 'object'
+    r1 = load_global CPyStatic_unicode_1 :: static  ('object')
     r2 = CPyObject_GetAttr(r0, r1)
     r3 = PyObject_CallFunctionObjArgs(r2, 0)
     goto L5
 L2: (handler for L1)
     r4 = CPy_CatchError()
-    r5 = 'weeee'
+    r5 = load_global CPyStatic_unicode_2 :: static  ('weeee')
     r6 = builtins :: module
-    r7 = 'print'
+    r7 = load_global CPyStatic_unicode_3 :: static  ('print')
     r8 = CPyObject_GetAttr(r6, r7)
     r9 = PyObject_CallFunctionObjArgs(r8, r5, 0)
 L3:
@@ -66,20 +66,20 @@
     if b goto L2 else goto L3 :: bool
 L2:
     r0 = builtins :: module
-    r1 = 'object'
+    r1 = load_global CPyStatic_unicode_1 :: static  ('object')
     r2 = CPyObject_GetAttr(r0, r1)
     r3 = PyObject_CallFunctionObjArgs(r2, 0)
     goto L4
 L3:
-    r4 = 'hi'
+    r4 = load_global CPyStatic_unicode_2 :: static  ('hi')
     r5 = PyObject_Str(r4)
 L4:
     goto L8
 L5: (handler for L1, L2, L3, L4)
     r6 = CPy_CatchError()
-    r7 = 'weeee'
+    r7 = load_global CPyStatic_unicode_3 :: static  ('weeee')
     r8 = builtins :: module
-    r9 = 'print'
+    r9 = load_global CPyStatic_unicode_4 :: static  ('print')
     r10 = CPyObject_GetAttr(r8, r9)
     r11 = PyObject_CallFunctionObjArgs(r10, r7, 0)
 L6:
@@ -129,30 +129,30 @@
     r27 :: bit
 L0:
 L1:
-    r0 = 'a'
+    r0 = load_global CPyStatic_unicode_1 :: static  ('a')
     r1 = builtins :: module
-    r2 = 'print'
+    r2 = load_global CPyStatic_unicode_2 :: static  ('print')
     r3 = CPyObject_GetAttr(r1, r2)
     r4 = PyObject_CallFunctionObjArgs(r3, r0, 0)
 L2:
     r5 = builtins :: module
-    r6 = 'object'
+    r6 = load_global CPyStatic_unicode_3 :: static  ('object')
     r7 = CPyObject_GetAttr(r5, r6)
     r8 = PyObject_CallFunctionObjArgs(r7, 0)
     goto L8
 L3: (handler for L2)
     r9 = CPy_CatchError()
     r10 = builtins :: module
-    r11 = 'AttributeError'
+    r11 = load_global CPyStatic_unicode_4 :: static  ('AttributeError')
     r12 = CPyObject_GetAttr(r10, r11)
     r13 = CPy_ExceptionMatches(r12)
     if r13 goto L4 else goto L5 :: bool
 L4:
     r14 = CPy_GetExcValue()
     e = r14
-    r15 = 'b'
+    r15 = load_global CPyStatic_unicode_5 :: static  ('b')
     r16 = builtins :: module
-    r17 = 'print'
+    r17 = load_global CPyStatic_unicode_2 :: static  ('print')
     r18 = CPyObject_GetAttr(r16, r17)
     r19 = PyObject_CallFunctionObjArgs(r18, r15, e, 0)
     goto L6
@@ -170,9 +170,9 @@
     goto L12
 L9: (handler for L1, L6, L7, L8)
     r21 = CPy_CatchError()
-    r22 = 'weeee'
+    r22 = load_global CPyStatic_unicode_6 :: static  ('weeee')
     r23 = builtins :: module
-    r24 = 'print'
+    r24 = load_global CPyStatic_unicode_2 :: static  ('print')
     r25 = CPyObject_GetAttr(r23, r24)
     r26 = PyObject_CallFunctionObjArgs(r25, r22, 0)
 L10:
@@ -218,27 +218,27 @@
 L2: (handler for L1)
     r0 = CPy_CatchError()
     r1 = builtins :: module
-    r2 = 'KeyError'
+    r2 = load_global CPyStatic_unicode_1 :: static  ('KeyError')
     r3 = CPyObject_GetAttr(r1, r2)
     r4 = CPy_ExceptionMatches(r3)
     if r4 goto L3 else goto L4 :: bool
 L3:
-    r5 = 'weeee'
+    r5 = load_global CPyStatic_unicode_2 :: static  ('weeee')
     r6 = builtins :: module
-    r7 = 'print'
+    r7 = load_global CPyStatic_unicode_3 :: static  ('print')
     r8 = CPyObject_GetAttr(r6, r7)
     r9 = PyObject_CallFunctionObjArgs(r8, r5, 0)
     goto L7
 L4:
     r10 = builtins :: module
-    r11 = 'IndexError'
+    r11 = load_global CPyStatic_unicode_4 :: static  ('IndexError')
     r12 = CPyObject_GetAttr(r10, r11)
     r13 = CPy_ExceptionMatches(r12)
     if r13 goto L5 else goto L6 :: bool
 L5:
-    r14 = 'yo'
+    r14 = load_global CPyStatic_unicode_5 :: static  ('yo')
     r15 = builtins :: module
-    r16 = 'print'
+    r16 = load_global CPyStatic_unicode_3 :: static  ('print')
     r17 = CPyObject_GetAttr(r15, r16)
     r18 = PyObject_CallFunctionObjArgs(r17, r14, 0)
     goto L7
@@ -279,9 +279,9 @@
 L1:
     if b goto L2 else goto L3 :: bool
 L2:
-    r0 = 'hi'
+    r0 = load_global CPyStatic_unicode_1 :: static  ('hi')
     r1 = builtins :: module
-    r2 = 'Exception'
+    r2 = load_global CPyStatic_unicode_2 :: static  ('Exception')
     r3 = CPyObject_GetAttr(r1, r2)
     r4 = PyObject_CallFunctionObjArgs(r3, r0, 0)
     CPy_Raise(r4)
@@ -296,9 +296,9 @@
     r7 = CPy_CatchError()
     r6 = r7
 L7:
-    r8 = 'finally'
+    r8 = load_global CPyStatic_unicode_3 :: static  ('finally')
     r9 = builtins :: module
-    r10 = 'print'
+    r10 = load_global CPyStatic_unicode_4 :: static  ('print')
     r11 = CPyObject_GetAttr(r9, r10)
     r12 = PyObject_CallFunctionObjArgs(r11, r8, 0)
     if is_error(r6) goto L9 else goto L8
@@ -347,18 +347,18 @@
 L0:
     r0 = PyObject_CallFunctionObjArgs(x, 0)
     r1 = PyObject_Type(r0)
-    r2 = '__exit__'
+    r2 = load_global CPyStatic_unicode_3 :: static  ('__exit__')
     r3 = CPyObject_GetAttr(r1, r2)
-    r4 = '__enter__'
+    r4 = load_global CPyStatic_unicode_4 :: static  ('__enter__')
     r5 = CPyObject_GetAttr(r1, r4)
     r6 = PyObject_CallFunctionObjArgs(r5, r0, 0)
     r7 = 1
 L1:
 L2:
     y = r6
-    r8 = 'hello'
+    r8 = load_global CPyStatic_unicode_5 :: static  ('hello')
     r9 = builtins :: module
-    r10 = 'print'
+    r10 = load_global CPyStatic_unicode_6 :: static  ('print')
     r11 = CPyObject_GetAttr(r9, r10)
     r12 = PyObject_CallFunctionObjArgs(r11, r8, 0)
     goto L8
@@ -415,4 +415,3 @@
     unreachable
 L20:
     return 1
-
diff --git a/mypyc/test-data/refcount.test b/mypyc/test-data/refcount.test
index 804e1da..7134529 100644
--- a/mypyc/test-data/refcount.test
+++ b/mypyc/test-data/refcount.test
@@ -661,7 +661,7 @@
 def f():
     r0 :: str
 L0:
-    r0 = 'some string'
+    r0 = load_global CPyStatic_unicode_1 :: static  ('some string')
     inc_ref r0
     return r0
 
@@ -680,7 +680,7 @@
     r6 :: int
 L0:
     r0 = load_address PyLong_Type
-    r1 = 'base'
+    r1 = load_global CPyStatic_unicode_1 :: static  ('base')
     r2 = PyTuple_Pack(1, x)
     r3 = box(short_int, 4)
     r4 = CPyDict_Build(1, r1, r3)
diff --git a/mypyc/test-data/run-misc.test b/mypyc/test-data/run-misc.test
index cc9ef44..cdfa7da 100644
--- a/mypyc/test-data/run-misc.test
+++ b/mypyc/test-data/run-misc.test
@@ -1014,43 +1014,3 @@
 
 assert foo(None) == None
 assert foo([1, 2, 3]) == ((1, 2, 3), [1, 2, 3])
-
-[case testAllLiterals]
-# Test having all sorts of literals in a single file
-
-def test_str() -> None:
-    assert '' == eval("''")
-    assert len('foo bar' + str()) == 7
-    assert 'foo bar' == eval("'foo bar'")
-    assert 'foo\u1245\0bar' == eval("'foo' + chr(0x1245) + chr(0) + 'bar'")
-    assert 'foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345' == eval("'foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345'")
-    assert 'Zoobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar123' == eval("'Zoobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar123'")
-
-def test_bytes() -> None:
-    assert b'' == eval("b''")
-    assert b'foo bar' == eval("b'foo bar'")
-    assert b'\xafde' == eval(r"b'\xafde'")
-    assert b'foo\xde\0bar' == eval("b'foo' + bytes([0xde, 0]) + b'bar'")
-    assert b'foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345' == eval("b'foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345foobar12345'")
-
-def test_int() -> None:
-    assert 2875872359823758923758923759 == eval('2875872359823758923758923759')
-    assert -552875872359823758923758923759 == eval('-552875872359823758923758923759')
-
-def test_float() -> None:
-    assert 1.5 == eval('1.5')
-    assert -3.75 == eval('-3.75')
-    assert 2.5e10 == eval('2.5e10')
-    assert 2.5e50 == eval('2.5e50')
-    assert 2.5e1000 == eval('2.5e1000')
-    assert -2.5e1000 == eval('-2.5e1000')
-
-def test_complex() -> None:
-    assert 1.5j == eval('1.5j')
-    assert 1.5j + 2.5 == eval('2.5 + 1.5j')
-    assert -3.75j == eval('-3.75j')
-    assert 2.5e10j == eval('2.5e10j')
-    assert 2.5e50j == eval('2.5e50j')
-    assert 2.5e1000j == eval('2.5e1000j')
-    assert 2.5e1000j + 3.5e2000 == eval('3.5e2000 + 2.5e1000j')
-    assert -2.5e1000j == eval('-2.5e1000j')
diff --git a/mypyc/test-data/run-primitives.test b/mypyc/test-data/run-primitives.test
index 9611c0c..450480d 100644
--- a/mypyc/test-data/run-primitives.test
+++ b/mypyc/test-data/run-primitives.test
@@ -241,7 +241,7 @@
     return int(x)
 
 def get_complex() -> complex:
-    return 5.2j + 3.5 + 1j
+    return 5.0j + 3.0
 
 [file driver.py]
 from native import assign_and_return_float_sum, from_int, to_int, get_complex
@@ -253,7 +253,7 @@
 assert str(from_int(10)) == '10.0'
 assert str(to_int(3.14)) == '3'
 assert str(to_int(3)) == '3'
-assert get_complex() == 3.5 + 6.2j
+assert get_complex() == 3+5j
 
 [case testBytes]
 def f(x: bytes) -> bytes:
diff --git a/mypyc/test/test_literals.py b/mypyc/test/test_literals.py
deleted file mode 100644
index a9a6c51..0000000
--- a/mypyc/test/test_literals.py
+++ /dev/null
@@ -1,14 +0,0 @@
-"""Test code geneneration for literals."""
-
-import unittest
-
-from mypyc.codegen.literals import format_str_literal
-
-
-class TestLiterals(unittest.TestCase):
-    def test_format_str_literal(self) -> None:
-        assert format_str_literal('') == b'\x00'
-        assert format_str_literal('xyz') == b'\x03xyz'
-        assert format_str_literal('x' * 127) == b'\x7f' + b'x' * 127
-        assert format_str_literal('x' * 128) == b'\x81\x00' + b'x' * 128
-        assert format_str_literal('x' * 131) == b'\x81\x03' + b'x' * 131