We are currently solving the following issue within our repository. Here is the issue text:
--- BEGIN ISSUE ---
A reference count handling bug
https://groups.google.com/a/continuum.io/forum/?utm_medium=email&utm_source=footer#!msg/numba-users/8yKajxuVJ10/CqaZXGA_AwAJ


--- END ISSUE ---

Below are some code segments, each from a relevant file. One or more of these files may contain bugs.
--- BEGIN FILES ---
Path: `numba/runtime/atomicops.py`
Content:
```
1 from __future__ import print_function, absolute_import, division
2 
3 import re
4 from collections import defaultdict, deque
5 
6 from numba.config import MACHINE_BITS
7 from numba import cgutils
8 from llvmlite import ir, binding as llvm
9 
10 # Flag to enable debug print in NRT_incref and NRT_decref
11 _debug_print = False
12 
13 _word_type = ir.IntType(MACHINE_BITS)
14 _pointer_type = ir.PointerType(ir.IntType(8))
15 
16 _meminfo_struct_type = ir.LiteralStructType([
17     _word_type,     # size_t refct
18     _pointer_type,  # dtor_function dtor
19     _pointer_type,  # void *dtor_info
20     _pointer_type,  # void *data
21     _word_type,     # size_t size
22     ])
23 
24 
25 incref_decref_ty = ir.FunctionType(ir.VoidType(), [_pointer_type])
26 meminfo_data_ty = ir.FunctionType(_pointer_type, [_pointer_type])
27 
28 
29 def _define_nrt_meminfo_data(module):
30     """
31     Implement NRT_MemInfo_data_fast in the module.  This allows LLVM
32     to inline lookup of the data pointer.
33     """
34     fn = module.get_or_insert_function(meminfo_data_ty,
35                                        name="NRT_MemInfo_data_fast")
36     builder = ir.IRBuilder(fn.append_basic_block())
37     [ptr] = fn.args
38     struct_ptr = builder.bitcast(ptr, _meminfo_struct_type.as_pointer())
39     data_ptr = builder.load(cgutils.gep(builder, struct_ptr, 0, 3))
40     builder.ret(data_ptr)
41 
42 
43 def _define_nrt_incref(module, atomic_incr):
44     """
45     Implement NRT_incref in the module
46     """
47     fn_incref = module.get_or_insert_function(incref_decref_ty,
48                                               name="NRT_incref")
49     builder = ir.IRBuilder(fn_incref.append_basic_block())
50     [ptr] = fn_incref.args
51     is_null = builder.icmp_unsigned("==", ptr, cgutils.get_null_value(ptr.type))
52     with cgutils.if_unlikely(builder, is_null):
53         builder.ret_void()
54 
55     if _debug_print:
56         cgutils.printf(builder, "*** NRT_Incref %zu [%p]\n", builder.load(ptr),
57                        ptr)
58     builder.call(atomic_incr, [builder.bitcast(ptr, atomic_incr.args[0].type)])
59     builder.ret_void()
60 
61 
62 def _define_nrt_decref(module, atomic_decr):
63     """
64     Implement NRT_decref in the module
65     """
66     fn_decref = module.get_or_insert_function(incref_decref_ty,
67                                               name="NRT_decref")
68     calldtor = module.add_function(ir.FunctionType(ir.VoidType(), [_pointer_type]),
69                                    name="NRT_MemInfo_call_dtor")
70 
71     builder = ir.IRBuilder(fn_decref.append_basic_block())
72     [ptr] = fn_decref.args
73     is_null = builder.icmp_unsigned("==", ptr, cgutils.get_null_value(ptr.type))
74     with cgutils.if_unlikely(builder, is_null):
75         builder.ret_void()
76 
77     if _debug_print:
78         cgutils.printf(builder, "*** NRT_Decref %zu [%p]\n", builder.load(ptr),
79                        ptr)
80     newrefct = builder.call(atomic_decr,
81                             [builder.bitcast(ptr, atomic_decr.args[0].type)])
82 
83     refct_eq_0 = builder.icmp_unsigned("==", newrefct,
84                                        ir.Constant(newrefct.type, 0))
85     with cgutils.if_unlikely(builder, refct_eq_0):
86         builder.call(calldtor, [ptr])
87     builder.ret_void()
88 
89 
90 # Set this to True to measure the overhead of atomic refcounts compared
91 # to non-atomic.
92 _disable_atomicity = 0
93 
94 
95 def _define_atomic_inc_dec(module, op, ordering):
96     """Define a llvm function for atomic increment/decrement to the given module
97     Argument ``op`` is the operation "add"/"sub".  Argument ``ordering`` is
98     the memory ordering.  The generated function returns the new value.
99     """
100     ftype = ir.FunctionType(_word_type, [_word_type.as_pointer()])
101     fn_atomic = ir.Function(module, ftype, name="nrt_atomic_{0}".format(op))
102 
103     [ptr] = fn_atomic.args
104     bb = fn_atomic.append_basic_block()
105     builder = ir.IRBuilder(bb)
106     ONE = ir.Constant(_word_type, 1)
107     if not _disable_atomicity:
108         oldval = builder.atomic_rmw(op, ptr, ONE, ordering=ordering)
109         # Perform the operation on the old value so that we can pretend returning
110         # the "new" value.
111         res = getattr(builder, op)(oldval, ONE)
112         builder.ret(res)
113     else:
114         oldval = builder.load(ptr)
115         newval = getattr(builder, op)(oldval, ONE)
116         builder.store(newval, ptr)
117         builder.ret(oldval)
118 
119     return fn_atomic
120 
121 
122 def _define_atomic_cas(module, ordering):
123     """Define a llvm function for atomic compare-and-swap.
124     The generated function is a direct wrapper of the LLVM cmpxchg with the
125     difference that the a int indicate success (1) or failure (0) is returned
126     and the last argument is a output pointer for storing the old value.
127 
128     Note
129     ----
130     On failure, the generated function behaves like an atomic load.  The loaded
131     value is stored to the last argument.
132     """
133     ftype = ir.FunctionType(ir.IntType(32), [_word_type.as_pointer(),
134                                              _word_type, _word_type,
135                                              _word_type.as_pointer()])
136     fn_cas = ir.Function(module, ftype, name="nrt_atomic_cas")
137 
138     [ptr, cmp, repl, oldptr] = fn_cas.args
139     bb = fn_cas.append_basic_block()
140     builder = ir.IRBuilder(bb)
141     outtup = builder.cmpxchg(ptr, cmp, repl, ordering=ordering)
142     old, ok = cgutils.unpack_tuple(builder, outtup, 2)
143     builder.store(old, oldptr)
144     builder.ret(builder.zext(ok, ftype.return_type))
145 
146     return fn_cas
147 
148 
149 def create_nrt_module(ctx):
150     """
151     Create an IR module defining the LLVM NRT functions.
152     A (IR module, library) tuple is returned.
153     """
154     codegen = ctx.codegen()
155     library = codegen.create_library("nrt")
156 
157     # Implement LLVM module with atomic ops
158     ir_mod = library.create_ir_module("nrt_module")
159 
160     atomic_inc = _define_atomic_inc_dec(ir_mod, "add", ordering='monotonic')
161     atomic_dec = _define_atomic_inc_dec(ir_mod, "sub", ordering='monotonic')
162     _define_atomic_cas(ir_mod, ordering='monotonic')
163 
164     _define_nrt_meminfo_data(ir_mod)
165     _define_nrt_incref(ir_mod, atomic_inc)
166     _define_nrt_decref(ir_mod, atomic_dec)
167 
168     return ir_mod, library
169 
170 
171 def compile_nrt_functions(ctx):
172     """
173     Compile all LLVM NRT functions and return a library containing them.
174     The library is created using the given target context.
175     """
176     ir_mod, library = create_nrt_module(ctx)
177 
178     library.add_ir_module(ir_mod)
179     library.finalize()
180 
181     return library
182 
183 
184 _regex_incref = re.compile(r'\s*call void @NRT_incref\((.*)\)')
185 _regex_decref = re.compile(r'\s*call void @NRT_decref\((.*)\)')
186 _regex_bb = re.compile(r'([-a-zA-Z$._][-a-zA-Z$._0-9]*:)|^define')
187 
188 
189 def remove_redundant_nrt_refct(ll_module):
190     """
191     Remove redundant reference count operations from the
192     `llvmlite.binding.ModuleRef`. This parses the ll_module as a string and
193     line by line to remove the unnecessary nrt refct pairs within each block.
194     Decref calls are moved after the last incref call in the block to avoid
195     temporarily decref'ing to zero (which can happen due to hidden decref from
196     alias).
197     """
198     # Note: As soon as we have better utility in analyzing materialized LLVM
199     #       module in llvmlite, we can redo this without so much string
200     #       processing.
201 
202     def _extract_functions(module):
203         cur = []
204         for line in str(module).splitlines():
205             if line.startswith('define'):
206                 # start of function
207                 assert not cur
208                 cur.append(line)
209             elif line.startswith('}'):
210                 # end of function
211                 assert cur
212                 cur.append(line)
213                 yield True, cur
214                 cur = []
215             elif cur:
216                 cur.append(line)
217             else:
218                 yield False, [line]
219 
220     def _process_function(func_lines):
221         out = []
222         for is_bb, bb_lines in _extract_basic_blocks(func_lines):
223             if is_bb and bb_lines:
224                 bb_lines = _process_basic_block(bb_lines)
225             out += bb_lines
226         return out
227 
228     def _extract_basic_blocks(func_lines):
229         assert func_lines[0].startswith('define')
230         assert func_lines[-1].startswith('}')
231         yield False, [func_lines[0]]
232 
233         cur = []
234         for ln in func_lines[1:-1]:
235             m = _regex_bb.match(ln)
236             if m is not None:
237                 # line is a basic block separator
238                 yield True, cur
239                 cur = []
240                 yield False, [ln]
241             elif ln:
242                 cur.append(ln)
243 
244         yield True, cur
245         yield False, [func_lines[-1]]
246 
247     def _process_basic_block(bb_lines):
248         bb_lines = _move_decref_after_all_increfs(bb_lines)
249         bb_lines = _prune_redundant_refct_ops(bb_lines)
250         return bb_lines
251 
252     def _examine_refct_op(bb_lines):
253         for num, ln in enumerate(bb_lines):
254             m = _regex_incref.match(ln)
255             if m is not None:
256                 yield num, m.group(1), None
257                 continue
258 
259             m = _regex_decref.match(ln)
260             if m is not None:
261                 yield num, None, m.group(1)
262                 continue
263 
264             yield ln, None, None
265 
266     def _prune_redundant_refct_ops(bb_lines):
267         incref_map = defaultdict(deque)
268         decref_map = defaultdict(deque)
269         for num, incref_var, decref_var in _examine_refct_op(bb_lines):
270             assert not (incref_var and decref_var)
271             if incref_var:
272                 incref_map[incref_var].append(num)
273             elif decref_var:
274                 decref_map[decref_var].append(num)
275 
276         to_remove = set()
277         for var, decops in decref_map.items():
278             incops = incref_map[var]
279             ct = min(len(incops), len(decops))
280             for _ in range(ct):
281                 to_remove.add(incops.pop())
282                 to_remove.add(decops.popleft())
283 
284         return [ln for num, ln in enumerate(bb_lines)
285                 if num not in to_remove]
286 
287     def _move_decref_after_all_increfs(bb_lines):
288         # find last incref
289         last_pos = 0
290         for pos, ln in enumerate(bb_lines):
291             if _regex_incref.match(ln) is not None:
292                 last_pos = pos + 1
293 
294         # find decrefs before last_pos
295         decrefs = []
296         head = []
297         for ln in bb_lines[:last_pos]:
298             if _regex_decref.match(ln) is not None:
299                 decrefs.append(ln)
300             else:
301                 head.append(ln)
302 
303         # insert decrefs at last_pos
304         return head + decrefs + bb_lines[last_pos:]
305 
306     # Early escape if NRT_incref is not used
307     try:
308         ll_module.get_function('NRT_incref')
309     except NameError:
310         return ll_module
311 
312     processed = []
313 
314     for is_func, lines in _extract_functions(ll_module):
315         if is_func:
316             lines = _process_function(lines)
317 
318         processed += lines
319 
320     newll = '\n'.join(processed)
321     return llvm.parse_assembly(newll)
322
```
--- END FILES ---

Please first localize the bug based on the issue statement, and then generate a patch according to the `git diff` format fenced by three backticks.

Here is an example:

```diff
diff --git a/examples/server_async.py b/examples/server_async.py
--- a/examples/server_async.py
+++ b/examples/server_async.py
@@ -313,4 +313,4 @@
 
 
 if __name__ == "__main__":
-    asyncio.run(run_async_server("."), debug=True)
+    asyncio.run(run_async_server(), debug=True)
diff --git a/examples/server_sync.py b/examples/server_sync.py
--- a/examples/server_sync.py
+++ b/examples/server_sync.py
@@ -313,5 +313,5 @@
 
 
 if __name__ == "__main__":
-    server = run_sync_server(".")
+    server = run_sync_server()
     server.shutdown()

```

diff --git a/numba/runtime/atomicops.py b/numba/runtime/atomicops.py
--- a/numba/runtime/atomicops.py
+++ b/numba/runtime/atomicops.py
@@ -245,7 +245,7 @@
         yield False, [func_lines[-1]]
 
     def _process_basic_block(bb_lines):
-        bb_lines = _move_decref_after_all_increfs(bb_lines)
+        bb_lines = _move_and_group_decref_after_all_increfs(bb_lines)
         bb_lines = _prune_redundant_refct_ops(bb_lines)
         return bb_lines
 
@@ -284,12 +284,20 @@
         return [ln for num, ln in enumerate(bb_lines)
                 if num not in to_remove]
 
-    def _move_decref_after_all_increfs(bb_lines):
+    def _move_and_group_decref_after_all_increfs(bb_lines):
         # find last incref
-        last_pos = 0
+        last_incref_pos = 0
         for pos, ln in enumerate(bb_lines):
             if _regex_incref.match(ln) is not None:
-                last_pos = pos + 1
+                last_incref_pos = pos + 1
+
+        # find last decref
+        last_decref_pos = 0
+        for pos, ln in enumerate(bb_lines):
+            if _regex_decref.match(ln) is not None:
+                last_decref_pos = pos + 1
+
+        last_pos = max(last_incref_pos, last_decref_pos)
 
         # find decrefs before last_pos
         decrefs = []
@@ -303,6 +311,7 @@
         # insert decrefs at last_pos
         return head + decrefs + bb_lines[last_pos:]
 
+
     # Early escape if NRT_incref is not used
     try:
         ll_module.get_function('NRT_incref')

{"golden_diff": "diff --git a/numba/runtime/atomicops.py b/numba/runtime/atomicops.py\n--- a/numba/runtime/atomicops.py\n+++ b/numba/runtime/atomicops.py\n@@ -245,7 +245,7 @@\n         yield False, [func_lines[-1]]\n \n     def _process_basic_block(bb_lines):\n-        bb_lines = _move_decref_after_all_increfs(bb_lines)\n+        bb_lines = _move_and_group_decref_after_all_increfs(bb_lines)\n         bb_lines = _prune_redundant_refct_ops(bb_lines)\n         return bb_lines\n \n@@ -284,12 +284,20 @@\n         return [ln for num, ln in enumerate(bb_lines)\n                 if num not in to_remove]\n \n-    def _move_decref_after_all_increfs(bb_lines):\n+    def _move_and_group_decref_after_all_increfs(bb_lines):\n         # find last incref\n-        last_pos = 0\n+        last_incref_pos = 0\n         for pos, ln in enumerate(bb_lines):\n             if _regex_incref.match(ln) is not None:\n-                last_pos = pos + 1\n+                last_incref_pos = pos + 1\n+\n+        # find last decref\n+        last_decref_pos = 0\n+        for pos, ln in enumerate(bb_lines):\n+            if _regex_decref.match(ln) is not None:\n+                last_decref_pos = pos + 1\n+\n+        last_pos = max(last_incref_pos, last_decref_pos)\n \n         # find decrefs before last_pos\n         decrefs = []\n@@ -303,6 +311,7 @@\n         # insert decrefs at last_pos\n         return head + decrefs + bb_lines[last_pos:]\n \n+\n     # Early escape if NRT_incref is not used\n     try:\n         ll_module.get_function('NRT_incref')\n", "issue": "A reference count handling bug\nhttps://groups.google.com/a/continuum.io/forum/?utm_medium=email&utm_source=footer#!msg/numba-users/8yKajxuVJ10/CqaZXGA_AwAJ\n\n", "before_files": [{"content": "from __future__ import print_function, absolute_import, division\n\nimport re\nfrom collections import defaultdict, deque\n\nfrom numba.config import MACHINE_BITS\nfrom numba import cgutils\nfrom llvmlite import ir, binding as llvm\n\n# Flag to enable debug print in NRT_incref and NRT_decref\n_debug_print = False\n\n_word_type = ir.IntType(MACHINE_BITS)\n_pointer_type = ir.PointerType(ir.IntType(8))\n\n_meminfo_struct_type = ir.LiteralStructType([\n    _word_type,     # size_t refct\n    _pointer_type,  # dtor_function dtor\n    _pointer_type,  # void *dtor_info\n    _pointer_type,  # void *data\n    _word_type,     # size_t size\n    ])\n\n\nincref_decref_ty = ir.FunctionType(ir.VoidType(), [_pointer_type])\nmeminfo_data_ty = ir.FunctionType(_pointer_type, [_pointer_type])\n\n\ndef _define_nrt_meminfo_data(module):\n    \"\"\"\n    Implement NRT_MemInfo_data_fast in the module.  This allows LLVM\n    to inline lookup of the data pointer.\n    \"\"\"\n    fn = module.get_or_insert_function(meminfo_data_ty,\n                                       name=\"NRT_MemInfo_data_fast\")\n    builder = ir.IRBuilder(fn.append_basic_block())\n    [ptr] = fn.args\n    struct_ptr = builder.bitcast(ptr, _meminfo_struct_type.as_pointer())\n    data_ptr = builder.load(cgutils.gep(builder, struct_ptr, 0, 3))\n    builder.ret(data_ptr)\n\n\ndef _define_nrt_incref(module, atomic_incr):\n    \"\"\"\n    Implement NRT_incref in the module\n    \"\"\"\n    fn_incref = module.get_or_insert_function(incref_decref_ty,\n                                              name=\"NRT_incref\")\n    builder = ir.IRBuilder(fn_incref.append_basic_block())\n    [ptr] = fn_incref.args\n    is_null = builder.icmp_unsigned(\"==\", ptr, cgutils.get_null_value(ptr.type))\n    with cgutils.if_unlikely(builder, is_null):\n        builder.ret_void()\n\n    if _debug_print:\n        cgutils.printf(builder, \"*** NRT_Incref %zu [%p]\\n\", builder.load(ptr),\n                       ptr)\n    builder.call(atomic_incr, [builder.bitcast(ptr, atomic_incr.args[0].type)])\n    builder.ret_void()\n\n\ndef _define_nrt_decref(module, atomic_decr):\n    \"\"\"\n    Implement NRT_decref in the module\n    \"\"\"\n    fn_decref = module.get_or_insert_function(incref_decref_ty,\n                                              name=\"NRT_decref\")\n    calldtor = module.add_function(ir.FunctionType(ir.VoidType(), [_pointer_type]),\n                                   name=\"NRT_MemInfo_call_dtor\")\n\n    builder = ir.IRBuilder(fn_decref.append_basic_block())\n    [ptr] = fn_decref.args\n    is_null = builder.icmp_unsigned(\"==\", ptr, cgutils.get_null_value(ptr.type))\n    with cgutils.if_unlikely(builder, is_null):\n        builder.ret_void()\n\n    if _debug_print:\n        cgutils.printf(builder, \"*** NRT_Decref %zu [%p]\\n\", builder.load(ptr),\n                       ptr)\n    newrefct = builder.call(atomic_decr,\n                            [builder.bitcast(ptr, atomic_decr.args[0].type)])\n\n    refct_eq_0 = builder.icmp_unsigned(\"==\", newrefct,\n                                       ir.Constant(newrefct.type, 0))\n    with cgutils.if_unlikely(builder, refct_eq_0):\n        builder.call(calldtor, [ptr])\n    builder.ret_void()\n\n\n# Set this to True to measure the overhead of atomic refcounts compared\n# to non-atomic.\n_disable_atomicity = 0\n\n\ndef _define_atomic_inc_dec(module, op, ordering):\n    \"\"\"Define a llvm function for atomic increment/decrement to the given module\n    Argument ``op`` is the operation \"add\"/\"sub\".  Argument ``ordering`` is\n    the memory ordering.  The generated function returns the new value.\n    \"\"\"\n    ftype = ir.FunctionType(_word_type, [_word_type.as_pointer()])\n    fn_atomic = ir.Function(module, ftype, name=\"nrt_atomic_{0}\".format(op))\n\n    [ptr] = fn_atomic.args\n    bb = fn_atomic.append_basic_block()\n    builder = ir.IRBuilder(bb)\n    ONE = ir.Constant(_word_type, 1)\n    if not _disable_atomicity:\n        oldval = builder.atomic_rmw(op, ptr, ONE, ordering=ordering)\n        # Perform the operation on the old value so that we can pretend returning\n        # the \"new\" value.\n        res = getattr(builder, op)(oldval, ONE)\n        builder.ret(res)\n    else:\n        oldval = builder.load(ptr)\n        newval = getattr(builder, op)(oldval, ONE)\n        builder.store(newval, ptr)\n        builder.ret(oldval)\n\n    return fn_atomic\n\n\ndef _define_atomic_cas(module, ordering):\n    \"\"\"Define a llvm function for atomic compare-and-swap.\n    The generated function is a direct wrapper of the LLVM cmpxchg with the\n    difference that the a int indicate success (1) or failure (0) is returned\n    and the last argument is a output pointer for storing the old value.\n\n    Note\n    ----\n    On failure, the generated function behaves like an atomic load.  The loaded\n    value is stored to the last argument.\n    \"\"\"\n    ftype = ir.FunctionType(ir.IntType(32), [_word_type.as_pointer(),\n                                             _word_type, _word_type,\n                                             _word_type.as_pointer()])\n    fn_cas = ir.Function(module, ftype, name=\"nrt_atomic_cas\")\n\n    [ptr, cmp, repl, oldptr] = fn_cas.args\n    bb = fn_cas.append_basic_block()\n    builder = ir.IRBuilder(bb)\n    outtup = builder.cmpxchg(ptr, cmp, repl, ordering=ordering)\n    old, ok = cgutils.unpack_tuple(builder, outtup, 2)\n    builder.store(old, oldptr)\n    builder.ret(builder.zext(ok, ftype.return_type))\n\n    return fn_cas\n\n\ndef create_nrt_module(ctx):\n    \"\"\"\n    Create an IR module defining the LLVM NRT functions.\n    A (IR module, library) tuple is returned.\n    \"\"\"\n    codegen = ctx.codegen()\n    library = codegen.create_library(\"nrt\")\n\n    # Implement LLVM module with atomic ops\n    ir_mod = library.create_ir_module(\"nrt_module\")\n\n    atomic_inc = _define_atomic_inc_dec(ir_mod, \"add\", ordering='monotonic')\n    atomic_dec = _define_atomic_inc_dec(ir_mod, \"sub\", ordering='monotonic')\n    _define_atomic_cas(ir_mod, ordering='monotonic')\n\n    _define_nrt_meminfo_data(ir_mod)\n    _define_nrt_incref(ir_mod, atomic_inc)\n    _define_nrt_decref(ir_mod, atomic_dec)\n\n    return ir_mod, library\n\n\ndef compile_nrt_functions(ctx):\n    \"\"\"\n    Compile all LLVM NRT functions and return a library containing them.\n    The library is created using the given target context.\n    \"\"\"\n    ir_mod, library = create_nrt_module(ctx)\n\n    library.add_ir_module(ir_mod)\n    library.finalize()\n\n    return library\n\n\n_regex_incref = re.compile(r'\\s*call void @NRT_incref\\((.*)\\)')\n_regex_decref = re.compile(r'\\s*call void @NRT_decref\\((.*)\\)')\n_regex_bb = re.compile(r'([-a-zA-Z$._][-a-zA-Z$._0-9]*:)|^define')\n\n\ndef remove_redundant_nrt_refct(ll_module):\n    \"\"\"\n    Remove redundant reference count operations from the\n    `llvmlite.binding.ModuleRef`. This parses the ll_module as a string and\n    line by line to remove the unnecessary nrt refct pairs within each block.\n    Decref calls are moved after the last incref call in the block to avoid\n    temporarily decref'ing to zero (which can happen due to hidden decref from\n    alias).\n    \"\"\"\n    # Note: As soon as we have better utility in analyzing materialized LLVM\n    #       module in llvmlite, we can redo this without so much string\n    #       processing.\n\n    def _extract_functions(module):\n        cur = []\n        for line in str(module).splitlines():\n            if line.startswith('define'):\n                # start of function\n                assert not cur\n                cur.append(line)\n            elif line.startswith('}'):\n                # end of function\n                assert cur\n                cur.append(line)\n                yield True, cur\n                cur = []\n            elif cur:\n                cur.append(line)\n            else:\n                yield False, [line]\n\n    def _process_function(func_lines):\n        out = []\n        for is_bb, bb_lines in _extract_basic_blocks(func_lines):\n            if is_bb and bb_lines:\n                bb_lines = _process_basic_block(bb_lines)\n            out += bb_lines\n        return out\n\n    def _extract_basic_blocks(func_lines):\n        assert func_lines[0].startswith('define')\n        assert func_lines[-1].startswith('}')\n        yield False, [func_lines[0]]\n\n        cur = []\n        for ln in func_lines[1:-1]:\n            m = _regex_bb.match(ln)\n            if m is not None:\n                # line is a basic block separator\n                yield True, cur\n                cur = []\n                yield False, [ln]\n            elif ln:\n                cur.append(ln)\n\n        yield True, cur\n        yield False, [func_lines[-1]]\n\n    def _process_basic_block(bb_lines):\n        bb_lines = _move_decref_after_all_increfs(bb_lines)\n        bb_lines = _prune_redundant_refct_ops(bb_lines)\n        return bb_lines\n\n    def _examine_refct_op(bb_lines):\n        for num, ln in enumerate(bb_lines):\n            m = _regex_incref.match(ln)\n            if m is not None:\n                yield num, m.group(1), None\n                continue\n\n            m = _regex_decref.match(ln)\n            if m is not None:\n                yield num, None, m.group(1)\n                continue\n\n            yield ln, None, None\n\n    def _prune_redundant_refct_ops(bb_lines):\n        incref_map = defaultdict(deque)\n        decref_map = defaultdict(deque)\n        for num, incref_var, decref_var in _examine_refct_op(bb_lines):\n            assert not (incref_var and decref_var)\n            if incref_var:\n                incref_map[incref_var].append(num)\n            elif decref_var:\n                decref_map[decref_var].append(num)\n\n        to_remove = set()\n        for var, decops in decref_map.items():\n            incops = incref_map[var]\n            ct = min(len(incops), len(decops))\n            for _ in range(ct):\n                to_remove.add(incops.pop())\n                to_remove.add(decops.popleft())\n\n        return [ln for num, ln in enumerate(bb_lines)\n                if num not in to_remove]\n\n    def _move_decref_after_all_increfs(bb_lines):\n        # find last incref\n        last_pos = 0\n        for pos, ln in enumerate(bb_lines):\n            if _regex_incref.match(ln) is not None:\n                last_pos = pos + 1\n\n        # find decrefs before last_pos\n        decrefs = []\n        head = []\n        for ln in bb_lines[:last_pos]:\n            if _regex_decref.match(ln) is not None:\n                decrefs.append(ln)\n            else:\n                head.append(ln)\n\n        # insert decrefs at last_pos\n        return head + decrefs + bb_lines[last_pos:]\n\n    # Early escape if NRT_incref is not used\n    try:\n        ll_module.get_function('NRT_incref')\n    except NameError:\n        return ll_module\n\n    processed = []\n\n    for is_func, lines in _extract_functions(ll_module):\n        if is_func:\n            lines = _process_function(lines)\n\n        processed += lines\n\n    newll = '\\n'.join(processed)\n    return llvm.parse_assembly(newll)\n", "path": "numba/runtime/atomicops.py"}], "after_files": [{"content": "from __future__ import print_function, absolute_import, division\n\nimport re\nfrom collections import defaultdict, deque\n\nfrom numba.config import MACHINE_BITS\nfrom numba import cgutils\nfrom llvmlite import ir, binding as llvm\n\n# Flag to enable debug print in NRT_incref and NRT_decref\n_debug_print = False\n\n_word_type = ir.IntType(MACHINE_BITS)\n_pointer_type = ir.PointerType(ir.IntType(8))\n\n_meminfo_struct_type = ir.LiteralStructType([\n    _word_type,     # size_t refct\n    _pointer_type,  # dtor_function dtor\n    _pointer_type,  # void *dtor_info\n    _pointer_type,  # void *data\n    _word_type,     # size_t size\n    ])\n\n\nincref_decref_ty = ir.FunctionType(ir.VoidType(), [_pointer_type])\nmeminfo_data_ty = ir.FunctionType(_pointer_type, [_pointer_type])\n\n\ndef _define_nrt_meminfo_data(module):\n    \"\"\"\n    Implement NRT_MemInfo_data_fast in the module.  This allows LLVM\n    to inline lookup of the data pointer.\n    \"\"\"\n    fn = module.get_or_insert_function(meminfo_data_ty,\n                                       name=\"NRT_MemInfo_data_fast\")\n    builder = ir.IRBuilder(fn.append_basic_block())\n    [ptr] = fn.args\n    struct_ptr = builder.bitcast(ptr, _meminfo_struct_type.as_pointer())\n    data_ptr = builder.load(cgutils.gep(builder, struct_ptr, 0, 3))\n    builder.ret(data_ptr)\n\n\ndef _define_nrt_incref(module, atomic_incr):\n    \"\"\"\n    Implement NRT_incref in the module\n    \"\"\"\n    fn_incref = module.get_or_insert_function(incref_decref_ty,\n                                              name=\"NRT_incref\")\n    builder = ir.IRBuilder(fn_incref.append_basic_block())\n    [ptr] = fn_incref.args\n    is_null = builder.icmp_unsigned(\"==\", ptr, cgutils.get_null_value(ptr.type))\n    with cgutils.if_unlikely(builder, is_null):\n        builder.ret_void()\n\n    if _debug_print:\n        cgutils.printf(builder, \"*** NRT_Incref %zu [%p]\\n\", builder.load(ptr),\n                       ptr)\n    builder.call(atomic_incr, [builder.bitcast(ptr, atomic_incr.args[0].type)])\n    builder.ret_void()\n\n\ndef _define_nrt_decref(module, atomic_decr):\n    \"\"\"\n    Implement NRT_decref in the module\n    \"\"\"\n    fn_decref = module.get_or_insert_function(incref_decref_ty,\n                                              name=\"NRT_decref\")\n    calldtor = module.add_function(ir.FunctionType(ir.VoidType(), [_pointer_type]),\n                                   name=\"NRT_MemInfo_call_dtor\")\n\n    builder = ir.IRBuilder(fn_decref.append_basic_block())\n    [ptr] = fn_decref.args\n    is_null = builder.icmp_unsigned(\"==\", ptr, cgutils.get_null_value(ptr.type))\n    with cgutils.if_unlikely(builder, is_null):\n        builder.ret_void()\n\n    if _debug_print:\n        cgutils.printf(builder, \"*** NRT_Decref %zu [%p]\\n\", builder.load(ptr),\n                       ptr)\n    newrefct = builder.call(atomic_decr,\n                            [builder.bitcast(ptr, atomic_decr.args[0].type)])\n\n    refct_eq_0 = builder.icmp_unsigned(\"==\", newrefct,\n                                       ir.Constant(newrefct.type, 0))\n    with cgutils.if_unlikely(builder, refct_eq_0):\n        builder.call(calldtor, [ptr])\n    builder.ret_void()\n\n\n# Set this to True to measure the overhead of atomic refcounts compared\n# to non-atomic.\n_disable_atomicity = 0\n\n\ndef _define_atomic_inc_dec(module, op, ordering):\n    \"\"\"Define a llvm function for atomic increment/decrement to the given module\n    Argument ``op`` is the operation \"add\"/\"sub\".  Argument ``ordering`` is\n    the memory ordering.  The generated function returns the new value.\n    \"\"\"\n    ftype = ir.FunctionType(_word_type, [_word_type.as_pointer()])\n    fn_atomic = ir.Function(module, ftype, name=\"nrt_atomic_{0}\".format(op))\n\n    [ptr] = fn_atomic.args\n    bb = fn_atomic.append_basic_block()\n    builder = ir.IRBuilder(bb)\n    ONE = ir.Constant(_word_type, 1)\n    if not _disable_atomicity:\n        oldval = builder.atomic_rmw(op, ptr, ONE, ordering=ordering)\n        # Perform the operation on the old value so that we can pretend returning\n        # the \"new\" value.\n        res = getattr(builder, op)(oldval, ONE)\n        builder.ret(res)\n    else:\n        oldval = builder.load(ptr)\n        newval = getattr(builder, op)(oldval, ONE)\n        builder.store(newval, ptr)\n        builder.ret(oldval)\n\n    return fn_atomic\n\n\ndef _define_atomic_cas(module, ordering):\n    \"\"\"Define a llvm function for atomic compare-and-swap.\n    The generated function is a direct wrapper of the LLVM cmpxchg with the\n    difference that the a int indicate success (1) or failure (0) is returned\n    and the last argument is a output pointer for storing the old value.\n\n    Note\n    ----\n    On failure, the generated function behaves like an atomic load.  The loaded\n    value is stored to the last argument.\n    \"\"\"\n    ftype = ir.FunctionType(ir.IntType(32), [_word_type.as_pointer(),\n                                             _word_type, _word_type,\n                                             _word_type.as_pointer()])\n    fn_cas = ir.Function(module, ftype, name=\"nrt_atomic_cas\")\n\n    [ptr, cmp, repl, oldptr] = fn_cas.args\n    bb = fn_cas.append_basic_block()\n    builder = ir.IRBuilder(bb)\n    outtup = builder.cmpxchg(ptr, cmp, repl, ordering=ordering)\n    old, ok = cgutils.unpack_tuple(builder, outtup, 2)\n    builder.store(old, oldptr)\n    builder.ret(builder.zext(ok, ftype.return_type))\n\n    return fn_cas\n\n\ndef create_nrt_module(ctx):\n    \"\"\"\n    Create an IR module defining the LLVM NRT functions.\n    A (IR module, library) tuple is returned.\n    \"\"\"\n    codegen = ctx.codegen()\n    library = codegen.create_library(\"nrt\")\n\n    # Implement LLVM module with atomic ops\n    ir_mod = library.create_ir_module(\"nrt_module\")\n\n    atomic_inc = _define_atomic_inc_dec(ir_mod, \"add\", ordering='monotonic')\n    atomic_dec = _define_atomic_inc_dec(ir_mod, \"sub\", ordering='monotonic')\n    _define_atomic_cas(ir_mod, ordering='monotonic')\n\n    _define_nrt_meminfo_data(ir_mod)\n    _define_nrt_incref(ir_mod, atomic_inc)\n    _define_nrt_decref(ir_mod, atomic_dec)\n\n    return ir_mod, library\n\n\ndef compile_nrt_functions(ctx):\n    \"\"\"\n    Compile all LLVM NRT functions and return a library containing them.\n    The library is created using the given target context.\n    \"\"\"\n    ir_mod, library = create_nrt_module(ctx)\n\n    library.add_ir_module(ir_mod)\n    library.finalize()\n\n    return library\n\n\n_regex_incref = re.compile(r'\\s*call void @NRT_incref\\((.*)\\)')\n_regex_decref = re.compile(r'\\s*call void @NRT_decref\\((.*)\\)')\n_regex_bb = re.compile(r'([-a-zA-Z$._][-a-zA-Z$._0-9]*:)|^define')\n\n\ndef remove_redundant_nrt_refct(ll_module):\n    \"\"\"\n    Remove redundant reference count operations from the\n    `llvmlite.binding.ModuleRef`. This parses the ll_module as a string and\n    line by line to remove the unnecessary nrt refct pairs within each block.\n    Decref calls are moved after the last incref call in the block to avoid\n    temporarily decref'ing to zero (which can happen due to hidden decref from\n    alias).\n    \"\"\"\n    # Note: As soon as we have better utility in analyzing materialized LLVM\n    #       module in llvmlite, we can redo this without so much string\n    #       processing.\n\n    def _extract_functions(module):\n        cur = []\n        for line in str(module).splitlines():\n            if line.startswith('define'):\n                # start of function\n                assert not cur\n                cur.append(line)\n            elif line.startswith('}'):\n                # end of function\n                assert cur\n                cur.append(line)\n                yield True, cur\n                cur = []\n            elif cur:\n                cur.append(line)\n            else:\n                yield False, [line]\n\n    def _process_function(func_lines):\n        out = []\n        for is_bb, bb_lines in _extract_basic_blocks(func_lines):\n            if is_bb and bb_lines:\n                bb_lines = _process_basic_block(bb_lines)\n            out += bb_lines\n        return out\n\n    def _extract_basic_blocks(func_lines):\n        assert func_lines[0].startswith('define')\n        assert func_lines[-1].startswith('}')\n        yield False, [func_lines[0]]\n\n        cur = []\n        for ln in func_lines[1:-1]:\n            m = _regex_bb.match(ln)\n            if m is not None:\n                # line is a basic block separator\n                yield True, cur\n                cur = []\n                yield False, [ln]\n            elif ln:\n                cur.append(ln)\n\n        yield True, cur\n        yield False, [func_lines[-1]]\n\n    def _process_basic_block(bb_lines):\n        bb_lines = _move_and_group_decref_after_all_increfs(bb_lines)\n        bb_lines = _prune_redundant_refct_ops(bb_lines)\n        return bb_lines\n\n    def _examine_refct_op(bb_lines):\n        for num, ln in enumerate(bb_lines):\n            m = _regex_incref.match(ln)\n            if m is not None:\n                yield num, m.group(1), None\n                continue\n\n            m = _regex_decref.match(ln)\n            if m is not None:\n                yield num, None, m.group(1)\n                continue\n\n            yield ln, None, None\n\n    def _prune_redundant_refct_ops(bb_lines):\n        incref_map = defaultdict(deque)\n        decref_map = defaultdict(deque)\n        for num, incref_var, decref_var in _examine_refct_op(bb_lines):\n            assert not (incref_var and decref_var)\n            if incref_var:\n                incref_map[incref_var].append(num)\n            elif decref_var:\n                decref_map[decref_var].append(num)\n\n        to_remove = set()\n        for var, decops in decref_map.items():\n            incops = incref_map[var]\n            ct = min(len(incops), len(decops))\n            for _ in range(ct):\n                to_remove.add(incops.pop())\n                to_remove.add(decops.popleft())\n\n        return [ln for num, ln in enumerate(bb_lines)\n                if num not in to_remove]\n\n    def _move_and_group_decref_after_all_increfs(bb_lines):\n        # find last incref\n        last_incref_pos = 0\n        for pos, ln in enumerate(bb_lines):\n            if _regex_incref.match(ln) is not None:\n                last_incref_pos = pos + 1\n\n        # find last decref\n        last_decref_pos = 0\n        for pos, ln in enumerate(bb_lines):\n            if _regex_decref.match(ln) is not None:\n                last_decref_pos = pos + 1\n\n        last_pos = max(last_incref_pos, last_decref_pos)\n\n        # find decrefs before last_pos\n        decrefs = []\n        head = []\n        for ln in bb_lines[:last_pos]:\n            if _regex_decref.match(ln) is not None:\n                decrefs.append(ln)\n            else:\n                head.append(ln)\n\n        # insert decrefs at last_pos\n        return head + decrefs + bb_lines[last_pos:]\n\n\n    # Early escape if NRT_incref is not used\n    try:\n        ll_module.get_function('NRT_incref')\n    except NameError:\n        return ll_module\n\n    processed = []\n\n    for is_func, lines in _extract_functions(ll_module):\n        if is_func:\n            lines = _process_function(lines)\n\n        processed += lines\n\n    newll = '\\n'.join(processed)\n    return llvm.parse_assembly(newll)\n", "path": "numba/runtime/atomicops.py"}]}