From 39b2175db526406931f0ac2bb453c5014378d687 Mon Sep 17 00:00:00 2001 From: ARF1 <5834577+ARF1@users.noreply.github.com> Date: Sun, 29 Mar 2020 00:28:34 +0100 Subject: [PATCH 1/9] Ensure AppVeyor uses python 3.6 --- appveyor.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index 25cb9454c..4b5e4fd38 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -8,7 +8,7 @@ environment: matrix: # Since appveyor is quite slow, we only use a single configuration - - PYTHON: "3.8" + - PYTHON: "3.6" ARCH: "64" CONDA_ENV: testenv From a9b37d93e0f0e7d352f53f1ec28435ca56186acc Mon Sep 17 00:00:00 2001 From: Shan Sikdar Date: Thu, 19 Mar 2020 17:49:40 -0400 Subject: [PATCH 2/9] Merge atomic load/store into regular load/store --- llvmlite/ir/builder.py | 46 +++++++++++------------------------------- 1 file changed, 12 insertions(+), 34 deletions(-) diff --git a/llvmlite/ir/builder.py b/llvmlite/ir/builder.py index bddf102a8..4c15262d9 100644 --- a/llvmlite/ir/builder.py +++ b/llvmlite/ir/builder.py @@ -723,7 +723,7 @@ def alloca(self, typ, size=None, name=''): self._insert(al) return al - def load(self, ptr, name='', align=None): + def load(self, ptr, name='', align=None, atomic=False, ordering=None): """ Load value from pointer, with optional guaranteed alignment: name = *ptr @@ -731,41 +731,16 @@ def load(self, ptr, name='', align=None): if not isinstance(ptr.type, types.PointerType): msg = "cannot load from value of type %s (%r): not a pointer" raise TypeError(msg % (ptr.type, str(ptr))) - ld = instructions.LoadInstr(self.block, ptr, name) - ld.align = align - self._insert(ld) - return ld - - def store(self, value, ptr, align=None): - """ - Store value to pointer, with optional guaranteed alignment: - *ptr = name - """ - if not isinstance(ptr.type, types.PointerType): - msg = "cannot store to value of type %s (%r): not a pointer" - raise TypeError(msg % (ptr.type, str(ptr))) - if ptr.type.pointee != value.type: - raise TypeError("cannot store %s to %s: mismatching types" - % (value.type, ptr.type)) - st = instructions.StoreInstr(self.block, value, ptr) - st.align = align - self._insert(st) - return st + if atomic: + ld = instructions.LoadAtomicInstr(self.block, ptr, ordering, align, name) + else: + ld = instructions.LoadInstr(self.block, ptr, name) + ld.align = align - def load_atomic(self, ptr, ordering, align, name=''): - """ - Load value from pointer, with optional guaranteed alignment: - name = *ptr - """ - if not isinstance(ptr.type, types.PointerType): - msg = "cannot load from value of type %s (%r): not a pointer" - raise TypeError(msg % (ptr.type, str(ptr))) - ld = instructions.LoadAtomicInstr( - self.block, ptr, ordering, align, name) self._insert(ld) return ld - def store_atomic(self, value, ptr, ordering, align): + def store(self, value, ptr, align=None, atomic=False, ordering=None): """ Store value to pointer, with optional guaranteed alignment: *ptr = name @@ -776,8 +751,11 @@ def store_atomic(self, value, ptr, ordering, align): if ptr.type.pointee != value.type: raise TypeError("cannot store %s to %s: mismatching types" % (value.type, ptr.type)) - st = instructions.StoreAtomicInstr( - self.block, value, ptr, ordering, align) + if atomic: + st = instructions.StoreAtomicInstr(self.block, value, ptr, ordering, align) + else: + st = instructions.StoreInstr(self.block, value, ptr) + st.align = align self._insert(st) return st From 01bed88570de93ce9918a351c64357dabc658bf2 Mon Sep 17 00:00:00 2001 From: ARF1 <5834577+ARF1@users.noreply.github.com> Date: Fri, 27 Mar 2020 14:22:50 +0100 Subject: [PATCH 3/9] revert public api change with deprecation notice and api cleanup --- llvmlite/ir/builder.py | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/llvmlite/ir/builder.py b/llvmlite/ir/builder.py index 4c15262d9..5acf96a62 100644 --- a/llvmlite/ir/builder.py +++ b/llvmlite/ir/builder.py @@ -723,7 +723,7 @@ def alloca(self, typ, size=None, name=''): self._insert(al) return al - def load(self, ptr, name='', align=None, atomic=False, ordering=None): + def load(self, ptr, name='', align=None, atomic_ordering=None): """ Load value from pointer, with optional guaranteed alignment: name = *ptr @@ -731,16 +731,15 @@ def load(self, ptr, name='', align=None, atomic=False, ordering=None): if not isinstance(ptr.type, types.PointerType): msg = "cannot load from value of type %s (%r): not a pointer" raise TypeError(msg % (ptr.type, str(ptr))) - if atomic: - ld = instructions.LoadAtomicInstr(self.block, ptr, ordering, align, name) + if atomic_ordering is not None: + ld = instructions.LoadAtomicInstr(self.block, ptr, atomic_ordering, align, name) else: ld = instructions.LoadInstr(self.block, ptr, name) ld.align = align - self._insert(ld) return ld - def store(self, value, ptr, align=None, atomic=False, ordering=None): + def store(self, value, ptr, align=None, atomic_ordering=None): """ Store value to pointer, with optional guaranteed alignment: *ptr = name @@ -751,14 +750,40 @@ def store(self, value, ptr, align=None, atomic=False, ordering=None): if ptr.type.pointee != value.type: raise TypeError("cannot store %s to %s: mismatching types" % (value.type, ptr.type)) - if atomic: - st = instructions.StoreAtomicInstr(self.block, value, ptr, ordering, align) + if atomic_ordering is not None: + st = instructions.StoreAtomicInstr(self.block, value, ptr, atomic_ordering, align) else: st = instructions.StoreInstr(self.block, value, ptr) st.align = align self._insert(st) return st + def load_atomic(self, ptr, ordering, align, name=''): + """ + Load value from pointer, with optional guaranteed alignment: + name = *ptr + + Deprecated. Please use the `atomic_ordering` keyword of load(). + """ + return self.load( + ptr=ptr, + name=name, + align=align, + atomic_ordering=ordering) + + def store_atomic(self, value, ptr, ordering, align): + """ + Store value to pointer, with optional guaranteed alignment: + *ptr = name + + Deprecated. Please use the `atomic_ordering` keyword of store(). + """ + return self.store( + value=value, + ptr=ptr, + align=align, + atomic_ordering=ordering) + # # Terminators APIs # From 82ffe1a2b31d6f502e8c85489bbc4b5d434eefa7 Mon Sep 17 00:00:00 2001 From: ARF1 <5834577+ARF1@users.noreply.github.com> Date: Fri, 27 Mar 2020 14:32:27 +0100 Subject: [PATCH 4/9] push setting of align parameter to load/store instruction --- llvmlite/ir/builder.py | 6 ++---- llvmlite/ir/instructions.py | 7 ++++--- 2 files changed, 6 insertions(+), 7 deletions(-) diff --git a/llvmlite/ir/builder.py b/llvmlite/ir/builder.py index 5acf96a62..1d67c6ac3 100644 --- a/llvmlite/ir/builder.py +++ b/llvmlite/ir/builder.py @@ -734,8 +734,7 @@ def load(self, ptr, name='', align=None, atomic_ordering=None): if atomic_ordering is not None: ld = instructions.LoadAtomicInstr(self.block, ptr, atomic_ordering, align, name) else: - ld = instructions.LoadInstr(self.block, ptr, name) - ld.align = align + ld = instructions.LoadInstr(self.block, ptr, name, align) self._insert(ld) return ld @@ -753,8 +752,7 @@ def store(self, value, ptr, align=None, atomic_ordering=None): if atomic_ordering is not None: st = instructions.StoreAtomicInstr(self.block, value, ptr, atomic_ordering, align) else: - st = instructions.StoreInstr(self.block, value, ptr) - st.align = align + st = instructions.StoreInstr(self.block, value, ptr, align) self._insert(st) return st diff --git a/llvmlite/ir/instructions.py b/llvmlite/ir/instructions.py index 54ec0972e..9ecbf17d7 100644 --- a/llvmlite/ir/instructions.py +++ b/llvmlite/ir/instructions.py @@ -390,10 +390,10 @@ def descr(self, buf): class LoadInstr(Instruction): - def __init__(self, parent, ptr, name=''): + def __init__(self, parent, ptr, name='', align=None): super(LoadInstr, self).__init__(parent, ptr.type.pointee, "load", [ptr], name=name) - self.align = None + self.align = align def descr(self, buf): [val] = self.operands @@ -411,9 +411,10 @@ def descr(self, buf): class StoreInstr(Instruction): - def __init__(self, parent, val, ptr): + def __init__(self, parent, val, ptr, align=None): super(StoreInstr, self).__init__(parent, types.VoidType(), "store", [val, ptr]) + self.align = align def descr(self, buf): val, ptr = self.operands From ddc8e2e53e90a2db71c6f34d08ceb074e04ba6d4 Mon Sep 17 00:00:00 2001 From: ARF1 <5834577+ARF1@users.noreply.github.com> Date: Sat, 28 Mar 2020 20:07:34 +0100 Subject: [PATCH 5/9] merge atomic load/store into non-atomic load/store --- llvmlite/ir/instructions.py | 119 +++++++++++++++++++----------------- 1 file changed, 62 insertions(+), 57 deletions(-) diff --git a/llvmlite/ir/instructions.py b/llvmlite/ir/instructions.py index 9ecbf17d7..5fb83caac 100644 --- a/llvmlite/ir/instructions.py +++ b/llvmlite/ir/instructions.py @@ -389,86 +389,91 @@ def descr(self, buf): class LoadInstr(Instruction): - - def __init__(self, parent, ptr, name='', align=None): + def __init__(self, parent, ptr, name='', align=None, atomic_ordering=None): + if atomic_ordering is not None and align is None: + msg = "atomic load requires the align paramter to be specified" + raise ValueError(msg) super(LoadInstr, self).__init__(parent, ptr.type.pointee, "load", [ptr], name=name) self.align = align + self.atomic_ordering = atomic_ordering def descr(self, buf): [val] = self.operands - if self.align is not None: - align = ', align %d' % (self.align) + if self.atomic_ordering is None: + if self.align is not None: + align = ', align %d' % (self.align) + else: + align = '' + buf.append("load {0}, {1} {2}{3}{4}\n".format( + val.type.pointee, + val.type, + val.get_reference(), + align, + self._stringify_metadata(leading_comma=True), + )) else: - align = '' - buf.append("load {0}, {1} {2}{3}{4}\n".format( - val.type.pointee, - val.type, - val.get_reference(), - align, - self._stringify_metadata(leading_comma=True), - )) + buf.append("load atomic {0}, {1} {2} {3}, align {4}{5}\n".format( + val.type.pointee, + val.type, + val.get_reference(), + self.atomic_ordering, + self.align, + self._stringify_metadata(leading_comma=True), + )) class StoreInstr(Instruction): - def __init__(self, parent, val, ptr, align=None): + def __init__(self, parent, val, ptr, align=None, atomic_ordering=None): + if atomic_ordering is not None and align is None: + msg = "atomic store requires the align paramter to be specified" + raise ValueError(msg) super(StoreInstr, self).__init__(parent, types.VoidType(), "store", [val, ptr]) self.align = align + self.atomic_ordering = atomic_ordering def descr(self, buf): val, ptr = self.operands - if self.align is not None: - align = ', align %d' % (self.align) + if self.atomic_ordering is None: + if self.align is not None: + align = ', align %d' % (self.align) + else: + align = '' + buf.append("store {0} {1}, {2} {3}{4}{5}\n".format( + val.type, + val.get_reference(), + ptr.type, + ptr.get_reference(), + align, + self._stringify_metadata(leading_comma=True), + )) else: - align = '' - buf.append("store {0} {1}, {2} {3}{4}{5}\n".format( - val.type, - val.get_reference(), - ptr.type, - ptr.get_reference(), - align, - self._stringify_metadata(leading_comma=True), - )) - + buf.append("store atomic {0} {1}, {2} {3} {4}, align {5}{6}\n".format( + val.type, + val.get_reference(), + ptr.type, + ptr.get_reference(), + self.atomic_ordering, + self.align, + self._stringify_metadata(leading_comma=True), + )) + + +class LoadAtomicInstr(LoadInstr): + # QUESTION: Can this be removed without prior deprecation? -class LoadAtomicInstr(Instruction): def __init__(self, parent, ptr, ordering, align, name=''): - super(LoadAtomicInstr, self).__init__(parent, ptr.type.pointee, - "load atomic", [ptr], name=name) - self.ordering = ordering - self.align = align + super(LoadAtomicInstr, self).__init__( + parent, ptr, align=align, atomic_ordering=ordering, name=name) - def descr(self, buf): - [val] = self.operands - buf.append("load atomic {0}, {1} {2} {3}, align {4}{5}\n".format( - val.type.pointee, - val.type, - val.get_reference(), - self.ordering, - self.align, - self._stringify_metadata(leading_comma=True), - )) +class StoreAtomicInstr(StoreInstr): + # QUESTION: Can this be removed without prior deprecation? -class StoreAtomicInstr(Instruction): def __init__(self, parent, val, ptr, ordering, align): - super(StoreAtomicInstr, self).__init__(parent, types.VoidType(), - "store atomic", [val, ptr]) - self.ordering = ordering - self.align = align - - def descr(self, buf): - val, ptr = self.operands - buf.append("store atomic {0} {1}, {2} {3} {4}, align {5}{6}\n".format( - val.type, - val.get_reference(), - ptr.type, - ptr.get_reference(), - self.ordering, - self.align, - self._stringify_metadata(leading_comma=True), - )) + super(StoreAtomicInstr, self).__init__( + parent, val, ptr, align=align, atomic_ordering=ordering) class AllocaInstr(Instruction): From e4aa996af7968ff152918f4ce7328384721cbf76 Mon Sep 17 00:00:00 2001 From: ARF1 <5834577+ARF1@users.noreply.github.com> Date: Sat, 28 Mar 2020 21:18:46 +0100 Subject: [PATCH 6/9] deprecation warnings for obsolete functions/classes --- llvmlite/ir/builder.py | 19 +++++++++++-------- llvmlite/ir/instructions.py | 15 ++++++++++----- 2 files changed, 21 insertions(+), 13 deletions(-) diff --git a/llvmlite/ir/builder.py b/llvmlite/ir/builder.py index 1d67c6ac3..29c3ec88d 100644 --- a/llvmlite/ir/builder.py +++ b/llvmlite/ir/builder.py @@ -1,5 +1,6 @@ import contextlib import functools +import warnings from llvmlite.ir import instructions, types, values @@ -731,10 +732,7 @@ def load(self, ptr, name='', align=None, atomic_ordering=None): if not isinstance(ptr.type, types.PointerType): msg = "cannot load from value of type %s (%r): not a pointer" raise TypeError(msg % (ptr.type, str(ptr))) - if atomic_ordering is not None: - ld = instructions.LoadAtomicInstr(self.block, ptr, atomic_ordering, align, name) - else: - ld = instructions.LoadInstr(self.block, ptr, name, align) + ld = instructions.LoadInstr(self.block, ptr, name, align, atomic_ordering) self._insert(ld) return ld @@ -749,10 +747,7 @@ def store(self, value, ptr, align=None, atomic_ordering=None): if ptr.type.pointee != value.type: raise TypeError("cannot store %s to %s: mismatching types" % (value.type, ptr.type)) - if atomic_ordering is not None: - st = instructions.StoreAtomicInstr(self.block, value, ptr, atomic_ordering, align) - else: - st = instructions.StoreInstr(self.block, value, ptr, align) + st = instructions.StoreInstr(self.block, value, ptr, align, atomic_ordering) self._insert(st) return st @@ -763,6 +758,10 @@ def load_atomic(self, ptr, ordering, align, name=''): Deprecated. Please use the `atomic_ordering` keyword of load(). """ + msg = ("load_atomic() is being deprecated. Please use the " + "atomic_ordering parameter of load() instead.") + warnings.warn(msg, DeprecationWarning) + return self.load( ptr=ptr, name=name, @@ -776,6 +775,10 @@ def store_atomic(self, value, ptr, ordering, align): Deprecated. Please use the `atomic_ordering` keyword of store(). """ + msg = ("store_atomic() is being deprecated. Please use the " + "atomic_ordering parameter of store() instead.") + warnings.warn(msg, DeprecationWarning) + return self.store( value=value, ptr=ptr, diff --git a/llvmlite/ir/instructions.py b/llvmlite/ir/instructions.py index 5fb83caac..9144f6d25 100644 --- a/llvmlite/ir/instructions.py +++ b/llvmlite/ir/instructions.py @@ -1,6 +1,7 @@ """ Implementation of LLVM IR instructions. """ +import warnings from llvmlite.ir import types from llvmlite.ir.values import (Block, Function, Value, NamedValue, Constant, @@ -458,20 +459,24 @@ def descr(self, buf): self.align, self._stringify_metadata(leading_comma=True), )) - -class LoadAtomicInstr(LoadInstr): - # QUESTION: Can this be removed without prior deprecation? +class LoadAtomicInstr(LoadInstr): def __init__(self, parent, ptr, ordering, align, name=''): + msg = ("LoadAtomicInstr() is being deprecated. Please use the " + "atomic_ordering parameter of LoadInstr() instead.") + warnings.warn(msg, DeprecationWarning) + super(LoadAtomicInstr, self).__init__( parent, ptr, align=align, atomic_ordering=ordering, name=name) class StoreAtomicInstr(StoreInstr): - # QUESTION: Can this be removed without prior deprecation? - def __init__(self, parent, val, ptr, ordering, align): + msg = ("StoreAtomicInstr() is being deprecated. Please use the " + "atomic_ordering parameter of StoreInstr() instead.") + warnings.warn(msg, DeprecationWarning) + super(StoreAtomicInstr, self).__init__( parent, val, ptr, align=align, atomic_ordering=ordering) From eb502318a40255b8af297dffa55a5b074e6e51bd Mon Sep 17 00:00:00 2001 From: ARF1 <5834577+ARF1@users.noreply.github.com> Date: Sat, 28 Mar 2020 22:50:02 +0100 Subject: [PATCH 7/9] volatile flag for store/load --- docs/source/user-guide/ir/ir-builder.rst | 22 ++++++- llvmlite/ir/builder.py | 12 ++-- llvmlite/ir/instructions.py | 82 +++++++++++------------- llvmlite/tests/test_ir.py | 24 +++++-- 4 files changed, 84 insertions(+), 56 deletions(-) diff --git a/docs/source/user-guide/ir/ir-builder.rst b/docs/source/user-guide/ir/ir-builder.rst index d8c3bc35f..47db21532 100644 --- a/docs/source/user-guide/ir/ir-builder.rst +++ b/docs/source/user-guide/ir/ir-builder.rst @@ -459,26 +459,44 @@ Memory *typ*. If *size* is not given, a stack slot for 1 value is allocated. -* .. method:: IRBuilder.load(ptr, name='', align=None) +* .. method:: IRBuilder.load(ptr, name='', align=None, atomic_ordering=None, volatile=False) Load value from pointer *ptr*. If *align* is passed, it should be a Python integer specifying the guaranteed pointer alignment. + + If *volatile* is truthy, the load is marked as volatile. -* .. method:: IRBuilder.store(value, ptr, align=None) + If *atomic_ordering* and *align* are specified, the load is marked as + atomic. + +* .. method:: IRBuilder.store(value, ptr, align=None, atomic_ordering=None, volatile=False) Store *value* to pointer *ptr*. If *align* is passed, it should be a Python integer specifying the guaranteed pointer alignment. + + If *volatile* is truthy, the load is marked as volatile. + + If *atomic_ordering* and *align* are specified, the load is marked as + atomic. * .. method:: IRBuilder.load_atomic(ptr, ordering, align, name='') + .. deprecated:: 0.33.0 + + Use :func:`IRBuilder.load` with parameter `atomic_ordering` instead. + Load value from pointer *ptr* as an atomic operation with the given *ordering*. *align* must be a Python integer specifying the guaranteed pointer alignment. * .. method:: IRBuilder.store_atomic(value, ptr, ordering, align) + .. deprecated:: 0.33.0 + + Use :func:`IRBuilder.store` with parameter `atomic_ordering` instead. + Store *value* to pointer *ptr* as an atomic operation with the given *ordering*. *align* must be a Python integer specifying the guaranteed pointer alignment. diff --git a/llvmlite/ir/builder.py b/llvmlite/ir/builder.py index 29c3ec88d..e51a65413 100644 --- a/llvmlite/ir/builder.py +++ b/llvmlite/ir/builder.py @@ -724,7 +724,8 @@ def alloca(self, typ, size=None, name=''): self._insert(al) return al - def load(self, ptr, name='', align=None, atomic_ordering=None): + def load(self, ptr, name='', align=None, atomic_ordering=None, + volatile=False): """ Load value from pointer, with optional guaranteed alignment: name = *ptr @@ -732,11 +733,13 @@ def load(self, ptr, name='', align=None, atomic_ordering=None): if not isinstance(ptr.type, types.PointerType): msg = "cannot load from value of type %s (%r): not a pointer" raise TypeError(msg % (ptr.type, str(ptr))) - ld = instructions.LoadInstr(self.block, ptr, name, align, atomic_ordering) + ld = instructions.LoadInstr(self.block, ptr, name, align, + atomic_ordering, volatile) self._insert(ld) return ld - def store(self, value, ptr, align=None, atomic_ordering=None): + def store(self, value, ptr, align=None, atomic_ordering=None, + volatile=False): """ Store value to pointer, with optional guaranteed alignment: *ptr = name @@ -747,7 +750,8 @@ def store(self, value, ptr, align=None, atomic_ordering=None): if ptr.type.pointee != value.type: raise TypeError("cannot store %s to %s: mismatching types" % (value.type, ptr.type)) - st = instructions.StoreInstr(self.block, value, ptr, align, atomic_ordering) + st = instructions.StoreInstr(self.block, value, ptr, align, + atomic_ordering, volatile) self._insert(st) return st diff --git a/llvmlite/ir/instructions.py b/llvmlite/ir/instructions.py index 9144f6d25..b0ef31164 100644 --- a/llvmlite/ir/instructions.py +++ b/llvmlite/ir/instructions.py @@ -390,7 +390,8 @@ def descr(self, buf): class LoadInstr(Instruction): - def __init__(self, parent, ptr, name='', align=None, atomic_ordering=None): + def __init__(self, parent, ptr, name='', align=None, atomic_ordering=None, + volatile=False): if atomic_ordering is not None and align is None: msg = "atomic load requires the align paramter to be specified" raise ValueError(msg) @@ -398,34 +399,30 @@ def __init__(self, parent, ptr, name='', align=None, atomic_ordering=None): [ptr], name=name) self.align = align self.atomic_ordering = atomic_ordering + self.volatile = volatile def descr(self, buf): [val] = self.operands - if self.atomic_ordering is None: - if self.align is not None: - align = ', align %d' % (self.align) - else: - align = '' - buf.append("load {0}, {1} {2}{3}{4}\n".format( - val.type.pointee, - val.type, - val.get_reference(), - align, - self._stringify_metadata(leading_comma=True), - )) - else: - buf.append("load atomic {0}, {1} {2} {3}, align {4}{5}\n".format( - val.type.pointee, - val.type, - val.get_reference(), - self.atomic_ordering, - self.align, - self._stringify_metadata(leading_comma=True), - )) + + flags = [] + if self.atomic_ordering is not None: + flags.append('atomic') + if self.volatile: + flags.append('volatile') + + opname = ' '.join(['load'] + flags) + ordering = ('' if self.atomic_ordering is None + else f' {self.atomic_ordering}') + align = '' if self.align is None else f', align {self.align}' + metadata = self._stringify_metadata(leading_comma=True) + + buf.append(f"{opname} {val.type.pointee}, {val.type} " + f"{val.get_reference()}{ordering}{align}{metadata}\n") class StoreInstr(Instruction): - def __init__(self, parent, val, ptr, align=None, atomic_ordering=None): + def __init__(self, parent, val, ptr, align=None, atomic_ordering=None, + volatile=False): if atomic_ordering is not None and align is None: msg = "atomic store requires the align paramter to be specified" raise ValueError(msg) @@ -433,32 +430,25 @@ def __init__(self, parent, val, ptr, align=None, atomic_ordering=None): [val, ptr]) self.align = align self.atomic_ordering = atomic_ordering + self.volatile = volatile def descr(self, buf): val, ptr = self.operands - if self.atomic_ordering is None: - if self.align is not None: - align = ', align %d' % (self.align) - else: - align = '' - buf.append("store {0} {1}, {2} {3}{4}{5}\n".format( - val.type, - val.get_reference(), - ptr.type, - ptr.get_reference(), - align, - self._stringify_metadata(leading_comma=True), - )) - else: - buf.append("store atomic {0} {1}, {2} {3} {4}, align {5}{6}\n".format( - val.type, - val.get_reference(), - ptr.type, - ptr.get_reference(), - self.atomic_ordering, - self.align, - self._stringify_metadata(leading_comma=True), - )) + + flags = [] + if self.atomic_ordering is not None: + flags.append('atomic') + if self.volatile: + flags.append('volatile') + + opname = ' '.join(['store'] + flags) + ordering = ('' if self.atomic_ordering is None + else f' {self.atomic_ordering}') + align = '' if self.align is None else f', align {self.align}' + metadata = self._stringify_metadata(leading_comma=True) + + buf.append(f"{opname} {val.type} {val.get_reference()}, {ptr.type} " + f"{ptr.get_reference()}{ordering}{align}{metadata}\n") class LoadAtomicInstr(LoadInstr): diff --git a/llvmlite/tests/test_ir.py b/llvmlite/tests/test_ir.py index 155510096..3b205c699 100644 --- a/llvmlite/tests/test_ir.py +++ b/llvmlite/tests/test_ir.py @@ -805,11 +805,23 @@ def test_mem_ops(self): self.assertEqual(h.type, ir.VoidType()) i = builder.load(c, 'i', align=1) self.assertEqual(i.type, int32) - # Atomics - j = builder.store_atomic(b, c, ordering="seq_cst", align=4) + # Volatile + j = builder.store(b, c, align=1, volatile=True) self.assertEqual(j.type, ir.VoidType()) - k = builder.load_atomic(c, ordering="seq_cst", align=4, name='k') + k = builder.load(c, 'k', align=1, volatile=True) self.assertEqual(k.type, int32) + # Atomics + l = builder.store(b, c, atomic_ordering="seq_cst", align=4) + self.assertEqual(l.type, ir.VoidType()) + m = builder.load(c, atomic_ordering="seq_cst", align=4, name='m') + self.assertEqual(m.type, int32) + # Atomics Volatile + o = builder.store(b, c, atomic_ordering="seq_cst", + align=4, volatile=True) + self.assertEqual(o.type, ir.VoidType()) + p = builder.load(c, atomic_ordering="seq_cst", + align=4, name='p', volatile=True) + self.assertEqual(p.type, int32) # Not pointer types with self.assertRaises(TypeError): builder.store(b, a) @@ -830,8 +842,12 @@ def test_mem_ops(self): %"g" = load i32, i32* %"c" store i32 %".2", i32* %"c", align 1 %"i" = load i32, i32* %"c", align 1 + store volatile i32 %".2", i32* %"c", align 1 + %"k" = load volatile i32, i32* %"c", align 1 store atomic i32 %".2", i32* %"c" seq_cst, align 4 - %"k" = load atomic i32, i32* %"c" seq_cst, align 4 + %"m" = load atomic i32, i32* %"c" seq_cst, align 4 + store atomic volatile i32 %".2", i32* %"c" seq_cst, align 4 + %"p" = load atomic volatile i32, i32* %"c" seq_cst, align 4 """) def test_gep(self): From 15c8193fc1a6580c6a68c28d179125197dda99eb Mon Sep 17 00:00:00 2001 From: ARF1 <5834577+ARF1@users.noreply.github.com> Date: Sun, 29 Mar 2020 10:36:02 +0200 Subject: [PATCH 8/9] add sync_scope parameter for store/load --- docs/source/user-guide/ir/ir-builder.rst | 8 ++-- llvmlite/ir/builder.py | 12 +++--- llvmlite/ir/instructions.py | 52 ++++++++++++++++-------- llvmlite/tests/test_ir.py | 18 ++++++++ 4 files changed, 64 insertions(+), 26 deletions(-) diff --git a/docs/source/user-guide/ir/ir-builder.rst b/docs/source/user-guide/ir/ir-builder.rst index 47db21532..78b067ec2 100644 --- a/docs/source/user-guide/ir/ir-builder.rst +++ b/docs/source/user-guide/ir/ir-builder.rst @@ -459,7 +459,7 @@ Memory *typ*. If *size* is not given, a stack slot for 1 value is allocated. -* .. method:: IRBuilder.load(ptr, name='', align=None, atomic_ordering=None, volatile=False) +* .. method:: IRBuilder.load(ptr, name='', align=None, volatile=False, atomic_ordering=None, sync_scope=None) Load value from pointer *ptr*. If *align* is passed, it should be a Python integer specifying the guaranteed pointer @@ -468,9 +468,9 @@ Memory If *volatile* is truthy, the load is marked as volatile. If *atomic_ordering* and *align* are specified, the load is marked as - atomic. + atomic. For atomic load a *sync_scope* may optionally be specified. -* .. method:: IRBuilder.store(value, ptr, align=None, atomic_ordering=None, volatile=False) +* .. method:: IRBuilder.store(value, ptr, align=None, volatile=False, atomic_ordering=None, sync_scope=None) Store *value* to pointer *ptr*. If *align* is passed, it should be a Python integer specifying the guaranteed pointer @@ -479,7 +479,7 @@ Memory If *volatile* is truthy, the load is marked as volatile. If *atomic_ordering* and *align* are specified, the load is marked as - atomic. + atomic. For atomic store a *sync_scope* may optionally be specified. * .. method:: IRBuilder.load_atomic(ptr, ordering, align, name='') diff --git a/llvmlite/ir/builder.py b/llvmlite/ir/builder.py index e51a65413..68cc1cf94 100644 --- a/llvmlite/ir/builder.py +++ b/llvmlite/ir/builder.py @@ -724,8 +724,8 @@ def alloca(self, typ, size=None, name=''): self._insert(al) return al - def load(self, ptr, name='', align=None, atomic_ordering=None, - volatile=False): + def load(self, ptr, name='', align=None, volatile=False, + atomic_ordering=None, sync_scope=None): """ Load value from pointer, with optional guaranteed alignment: name = *ptr @@ -734,12 +734,12 @@ def load(self, ptr, name='', align=None, atomic_ordering=None, msg = "cannot load from value of type %s (%r): not a pointer" raise TypeError(msg % (ptr.type, str(ptr))) ld = instructions.LoadInstr(self.block, ptr, name, align, - atomic_ordering, volatile) + volatile, atomic_ordering, sync_scope) self._insert(ld) return ld - def store(self, value, ptr, align=None, atomic_ordering=None, - volatile=False): + def store(self, value, ptr, align=None, volatile=False, + atomic_ordering=None, sync_scope=None): """ Store value to pointer, with optional guaranteed alignment: *ptr = name @@ -751,7 +751,7 @@ def store(self, value, ptr, align=None, atomic_ordering=None, raise TypeError("cannot store %s to %s: mismatching types" % (value.type, ptr.type)) st = instructions.StoreInstr(self.block, value, ptr, align, - atomic_ordering, volatile) + volatile, atomic_ordering, sync_scope) self._insert(st) return st diff --git a/llvmlite/ir/instructions.py b/llvmlite/ir/instructions.py index b0ef31164..038a31286 100644 --- a/llvmlite/ir/instructions.py +++ b/llvmlite/ir/instructions.py @@ -390,15 +390,20 @@ def descr(self, buf): class LoadInstr(Instruction): - def __init__(self, parent, ptr, name='', align=None, atomic_ordering=None, - volatile=False): + def __init__(self, parent, ptr, name='', align=None, volatile=False, + atomic_ordering=None, sync_scope=None): if atomic_ordering is not None and align is None: - msg = "atomic load requires the align paramter to be specified" + msg = "atomic load requires the align parameter to be specified" + raise ValueError(msg) + if sync_scope is not None and atomic_ordering is None: + msg = ("sync_scope may only be specified in combination with " + "atomic_ordering") raise ValueError(msg) super(LoadInstr, self).__init__(parent, ptr.type.pointee, "load", [ptr], name=name) self.align = align self.atomic_ordering = atomic_ordering + self.sync_scope = sync_scope self.volatile = volatile def descr(self, buf): @@ -409,27 +414,37 @@ def descr(self, buf): flags.append('atomic') if self.volatile: flags.append('volatile') + flags = ' '.join([''] + flags) + + atomic = [] + if self.atomic_ordering is not None: + atomic.append(self.atomic_ordering) + if self.sync_scope is not None: + atomic.append(f'syncscope("self.sync_scope")') + atomic_params = " ".join([''] + atomic) - opname = ' '.join(['load'] + flags) - ordering = ('' if self.atomic_ordering is None - else f' {self.atomic_ordering}') align = '' if self.align is None else f', align {self.align}' metadata = self._stringify_metadata(leading_comma=True) - buf.append(f"{opname} {val.type.pointee}, {val.type} " - f"{val.get_reference()}{ordering}{align}{metadata}\n") + buf.append(f"load{flags} {val.type.pointee}, {val.type} " + f"{val.get_reference()}{atomic_params}{align}{metadata}\n") class StoreInstr(Instruction): - def __init__(self, parent, val, ptr, align=None, atomic_ordering=None, - volatile=False): + def __init__(self, parent, val, ptr, align=None, volatile=False, + atomic_ordering=None, sync_scope=None): if atomic_ordering is not None and align is None: - msg = "atomic store requires the align paramter to be specified" + msg = "atomic store requires the align parameter to be specified" + raise ValueError(msg) + if sync_scope is not None and atomic_ordering is None: + msg = ("sync_scope may only be specified in combination with " + "atomic_ordering") raise ValueError(msg) super(StoreInstr, self).__init__(parent, types.VoidType(), "store", [val, ptr]) self.align = align self.atomic_ordering = atomic_ordering + self.sync_scope = sync_scope self.volatile = volatile def descr(self, buf): @@ -440,15 +455,20 @@ def descr(self, buf): flags.append('atomic') if self.volatile: flags.append('volatile') + flags = ' '.join([''] + flags) + + atomic = [] + if self.atomic_ordering is not None: + atomic.append(self.atomic_ordering) + if self.sync_scope is not None: + atomic.append(f'syncscope("self.sync_scope")') + atomic_params = " ".join([''] + atomic) - opname = ' '.join(['store'] + flags) - ordering = ('' if self.atomic_ordering is None - else f' {self.atomic_ordering}') align = '' if self.align is None else f', align {self.align}' metadata = self._stringify_metadata(leading_comma=True) - buf.append(f"{opname} {val.type} {val.get_reference()}, {ptr.type} " - f"{ptr.get_reference()}{ordering}{align}{metadata}\n") + buf.append(f"store{flags} {val.type} {val.get_reference()}, {ptr.type}" + f" {ptr.get_reference()}{atomic_params}{align}{metadata}\n") class LoadAtomicInstr(LoadInstr): diff --git a/llvmlite/tests/test_ir.py b/llvmlite/tests/test_ir.py index 3b205c699..7ab57d7a3 100644 --- a/llvmlite/tests/test_ir.py +++ b/llvmlite/tests/test_ir.py @@ -832,6 +832,24 @@ def test_mem_ops(self): builder.store(b, e) self.assertEqual(str(cm.exception), "cannot store i32 to double*: mismatching types") + # atomic store without align + with self.assertRaises(ValueError) as cm: + builder.store(b, c, atomic_ordering="seq_cst") + self.assertIn('requires the align parameter', str(cm.exception)) + # atomic load without align + with self.assertRaises(ValueError) as cm: + builder.load(c, atomic_ordering="seq_cst", name='m') + self.assertIn('requires the align parameter', str(cm.exception)) + # store with sync_scope with missing atomic_ordering + with self.assertRaises(ValueError) as cm: + builder.store(b, c, sync_scope="test_scope") + self.assertIn('may only be specified in combination with ' + 'atomic_ordering', str(cm.exception)) + # load with sync_scope with missing atomic_ordering + with self.assertRaises(ValueError) as cm: + builder.load(c, sync_scope="test_scope") + self.assertIn('may only be specified in combination with ' + 'atomic_ordering', str(cm.exception)) self.check_block(block, """\ my_block: %"c" = alloca i32 From fa96c90d75e29090032b5b3ae99d86ca80219096 Mon Sep 17 00:00:00 2001 From: ARF1 <5834577+ARF1@users.noreply.github.com> Date: Sun, 29 Mar 2020 11:33:35 +0200 Subject: [PATCH 9/9] add test for sync_scope & fix sync_scope --- llvmlite/ir/instructions.py | 8 ++++---- llvmlite/tests/test_ir.py | 15 ++++++++++++++- 2 files changed, 18 insertions(+), 5 deletions(-) diff --git a/llvmlite/ir/instructions.py b/llvmlite/ir/instructions.py index 038a31286..fc41bba54 100644 --- a/llvmlite/ir/instructions.py +++ b/llvmlite/ir/instructions.py @@ -418,9 +418,9 @@ def descr(self, buf): atomic = [] if self.atomic_ordering is not None: - atomic.append(self.atomic_ordering) if self.sync_scope is not None: - atomic.append(f'syncscope("self.sync_scope")') + atomic.append(f'syncscope("{self.sync_scope}")') + atomic.append(self.atomic_ordering) atomic_params = " ".join([''] + atomic) align = '' if self.align is None else f', align {self.align}' @@ -459,9 +459,9 @@ def descr(self, buf): atomic = [] if self.atomic_ordering is not None: - atomic.append(self.atomic_ordering) if self.sync_scope is not None: - atomic.append(f'syncscope("self.sync_scope")') + atomic.append(f'syncscope("{self.sync_scope}")') + atomic.append(self.atomic_ordering) atomic_params = " ".join([''] + atomic) align = '' if self.align is None else f', align {self.align}' diff --git a/llvmlite/tests/test_ir.py b/llvmlite/tests/test_ir.py index 7ab57d7a3..b848b6777 100644 --- a/llvmlite/tests/test_ir.py +++ b/llvmlite/tests/test_ir.py @@ -822,6 +822,13 @@ def test_mem_ops(self): p = builder.load(c, atomic_ordering="seq_cst", align=4, name='p', volatile=True) self.assertEqual(p.type, int32) + # Atomics Volatile with syncscope + q = builder.store(b, c, atomic_ordering="seq_cst", + align=4, volatile=True, sync_scope='test_scope') + self.assertEqual(q.type, ir.VoidType()) + r = builder.load(c, atomic_ordering="seq_cst", align=4, name='r', + volatile=True, sync_scope='test_scope') + self.assertEqual(r.type, int32) # Not pointer types with self.assertRaises(TypeError): builder.store(b, a) @@ -850,7 +857,9 @@ def test_mem_ops(self): builder.load(c, sync_scope="test_scope") self.assertIn('may only be specified in combination with ' 'atomic_ordering', str(cm.exception)) - self.check_block(block, """\ + self.check_block( + block, + """\ my_block: %"c" = alloca i32 %"d" = alloca i32, i32 42 @@ -866,6 +875,10 @@ def test_mem_ops(self): %"m" = load atomic i32, i32* %"c" seq_cst, align 4 store atomic volatile i32 %".2", i32* %"c" seq_cst, align 4 %"p" = load atomic volatile i32, i32* %"c" seq_cst, align 4 + store atomic volatile i32 %".2", i32* %"c" """ + """syncscope("test_scope") seq_cst, align 4""" """ + %"r" = load atomic volatile i32, i32* %"c" """ + """syncscope("test_scope") seq_cst, align 4""" """ """) def test_gep(self):