From 35f91aef68ca3d1f0d8686232be01abe331b73ef Mon Sep 17 00:00:00 2001 From: mwojcik Date: Wed, 23 Feb 2022 15:22:28 +0800 Subject: [PATCH 1/5] flake: fix substituters --- flake.nix | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/flake.nix b/flake.nix index 502b8ecbe..b0f2d2331 100644 --- a/flake.nix +++ b/flake.nix @@ -504,8 +504,8 @@ }; nixConfig = { - binaryCachePublicKeys = ["nixbld.m-labs.hk-1:5aSRVA5b320xbNvu30tqxVPXpld73bhtOeH6uAjRyHc="]; - binaryCaches = ["https://nixbld.m-labs.hk" "https://cache.nixos.org"]; + extra-trusted-public-keys = "nixbld.m-labs.hk-1:5aSRVA5b320xbNvu30tqxVPXpld73bhtOeH6uAjRyHc="; + extra-substituters = "https://nixbld.m-labs.hk"; sandboxPaths = ["/opt"]; }; } From c000af9985abe60acf0fb419147ce9ac98621170 Mon Sep 17 00:00:00 2001 From: mwojcik Date: Wed, 23 Feb 2022 15:30:16 +0800 Subject: [PATCH 2/5] flake: extra-sandbox-paths too --- flake.nix | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/flake.nix b/flake.nix index b0f2d2331..7d796bbf5 100644 --- a/flake.nix +++ b/flake.nix @@ -506,6 +506,6 @@ nixConfig = { extra-trusted-public-keys = "nixbld.m-labs.hk-1:5aSRVA5b320xbNvu30tqxVPXpld73bhtOeH6uAjRyHc="; extra-substituters = "https://nixbld.m-labs.hk"; - sandboxPaths = ["/opt"]; + extra-sandbox-paths = "/opt"; }; } From 2d6215158fe3bfe06a3837e07d07447189ed0388 Mon Sep 17 00:00:00 2001 From: Michael Birtwell Date: Tue, 22 Feb 2022 10:47:29 +0000 Subject: [PATCH 3/5] Fix try/finally:while:try compilation When we have a trys inside a loop then we want to make sure any finallys are executed by break and continue inside this try. But this shouldn't pull finallys defined outside the loop in to the loop. This change resets the `outer_final` attribute when visiting for and while loops so that this doesn't happen. Signed-off-by: Michael Birtwell --- artiq/compiler/transforms/artiq_ir_generator.py | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index 9062b6806..8b9355894 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -468,6 +468,7 @@ class ARTIQIRGenerator(algorithm.Visitor): self.append(ir.BranchIf(cond, if_true, tail), block=head) def visit_While(self, node): + old_outer_final, self.outer_final = self.outer_final, None try: head = self.add_block("while.head") self.append(ir.Branch(head)) @@ -487,6 +488,7 @@ class ARTIQIRGenerator(algorithm.Visitor): finally: self.break_target = old_break self.continue_target = old_continue + self.outer_final = old_outer_final if any(node.orelse): else_tail = self.add_block("while.else") @@ -561,6 +563,7 @@ class ARTIQIRGenerator(algorithm.Visitor): assert False def visit_ForT(self, node): + old_outer_final, self.outer_final = self.outer_final, None try: iterable = self.visit(node.iter) length = self.iterable_len(iterable) @@ -598,6 +601,7 @@ class ARTIQIRGenerator(algorithm.Visitor): finally: self.break_target = old_break self.continue_target = old_continue + self.outer_final = old_outer_final if any(node.orelse): else_tail = self.add_block("for.else") @@ -783,8 +787,18 @@ class ARTIQIRGenerator(algorithm.Visitor): old_unwind, self.unwind_target = self.unwind_target, final_dispatcher if any(node.finalbody): + # if we have a while:try/finally continue must execute finally + # before continuing the while redirect = final_branch elif self.outer_final is not None: + # If we have while:try/finally:try then we need to execute that finally + # before the continuing the while + # If we have try/finally:while:try then we should just continue the + # while without having to execute the finally until later + # If we have try/finally:while:try/finally:try we should execute + # one but not the other + # This is achieved by reseting self.outer_final in while and for + # loops redirect = self.outer_final else: redirect = lambda dest, proxy: proxy.append(ir.Branch(dest)) From 1b80746f4892efa768b55004018249af85edfe7a Mon Sep 17 00:00:00 2001 From: Michael Birtwell Date: Tue, 22 Feb 2022 16:49:11 +0000 Subject: [PATCH 4/5] Remove `outer_final` We don't need to know whether there's a outer finally block that's already implicit in the current break and continue target. Signed-off-by: Michael Birtwell --- .../compiler/transforms/artiq_ir_generator.py | 24 +---------- .../try_finally_while_try_finally_break.py | 42 +++++++++++++++++++ .../try_loop/try_finally_while_try_reraise.py | 42 +++++++++++++++++++ .../try_loop/try_finally_while_try_return.py | 29 +++++++++++++ 4 files changed, 115 insertions(+), 22 deletions(-) create mode 100644 artiq/test/lit/try_loop/try_finally_while_try_finally_break.py create mode 100644 artiq/test/lit/try_loop/try_finally_while_try_reraise.py create mode 100644 artiq/test/lit/try_loop/try_finally_while_try_return.py diff --git a/artiq/compiler/transforms/artiq_ir_generator.py b/artiq/compiler/transforms/artiq_ir_generator.py index 8b9355894..4a3d9fbbc 100644 --- a/artiq/compiler/transforms/artiq_ir_generator.py +++ b/artiq/compiler/transforms/artiq_ir_generator.py @@ -113,7 +113,6 @@ class ARTIQIRGenerator(algorithm.Visitor): self.return_target = None self.unwind_target = None self.catch_clauses = [] - self.outer_final = None self.final_branch = None self.function_map = dict() self.variable_map = dict() @@ -468,7 +467,6 @@ class ARTIQIRGenerator(algorithm.Visitor): self.append(ir.BranchIf(cond, if_true, tail), block=head) def visit_While(self, node): - old_outer_final, self.outer_final = self.outer_final, None try: head = self.add_block("while.head") self.append(ir.Branch(head)) @@ -488,7 +486,6 @@ class ARTIQIRGenerator(algorithm.Visitor): finally: self.break_target = old_break self.continue_target = old_continue - self.outer_final = old_outer_final if any(node.orelse): else_tail = self.add_block("while.else") @@ -563,7 +560,6 @@ class ARTIQIRGenerator(algorithm.Visitor): assert False def visit_ForT(self, node): - old_outer_final, self.outer_final = self.outer_final, None try: iterable = self.visit(node.iter) length = self.iterable_len(iterable) @@ -601,7 +597,6 @@ class ARTIQIRGenerator(algorithm.Visitor): finally: self.break_target = old_break self.continue_target = old_continue - self.outer_final = old_outer_final if any(node.orelse): else_tail = self.add_block("for.else") @@ -710,9 +705,7 @@ class ARTIQIRGenerator(algorithm.Visitor): value = return_action.append(ir.GetLocal(self.current_private_env, "$return")) return_action.append(ir.Return(value)) final_branch(return_action, return_proxy) - - old_outer_final, self.outer_final = self.outer_final, final_branch - elif self.outer_final is None: + else: landingpad.has_cleanup = False # we should propagate the clauses to nested try catch blocks @@ -777,7 +770,7 @@ class ARTIQIRGenerator(algorithm.Visitor): self.continue_target = old_continue self.return_target = old_return - if any(node.finalbody) or self.outer_final is not None: + if any(node.finalbody): # create new unwind target for cleanup final_dispatcher = self.add_block("try.final.dispatch") final_landingpad = ir.LandingPad(cleanup) @@ -790,16 +783,6 @@ class ARTIQIRGenerator(algorithm.Visitor): # if we have a while:try/finally continue must execute finally # before continuing the while redirect = final_branch - elif self.outer_final is not None: - # If we have while:try/finally:try then we need to execute that finally - # before the continuing the while - # If we have try/finally:while:try then we should just continue the - # while without having to execute the finally until later - # If we have try/finally:while:try/finally:try we should execute - # one but not the other - # This is achieved by reseting self.outer_final in while and for - # loops - redirect = self.outer_final else: redirect = lambda dest, proxy: proxy.append(ir.Branch(dest)) @@ -860,7 +843,6 @@ class ARTIQIRGenerator(algorithm.Visitor): if any(node.finalbody): # Finalize and continue after try statement. - self.outer_final = old_outer_final self.unwind_target = old_unwind # Exception path finalizer_reraise = self.add_block("finally.resume") @@ -910,8 +892,6 @@ class ARTIQIRGenerator(algorithm.Visitor): block.append(ir.SetLocal(final_state, "$cont", tail)) block.append(ir.Branch(finalizer)) else: - if self.outer_final is not None: - self.unwind_target = old_unwind self.current_block = tail = self.add_block("try.tail") if not body.is_terminated(): body.append(ir.Branch(tail)) diff --git a/artiq/test/lit/try_loop/try_finally_while_try_finally_break.py b/artiq/test/lit/try_loop/try_finally_while_try_finally_break.py new file mode 100644 index 000000000..c66d88ceb --- /dev/null +++ b/artiq/test/lit/try_loop/try_finally_while_try_finally_break.py @@ -0,0 +1,42 @@ +# RUN: %python -m artiq.compiler.testbench.jit %s >%t +# RUN: OutputCheck %s --file-to-check=%t +# REQUIRES: exceptions + +def run(): + loop = 0 + print("start") + try: + while True: + print("loop") + try: + if loop == 0: + loop += 1 + continue + func() + break + except RuntimeError: + print("except") + return False + finally: + print("finally2") + print("after-while") + finally: + print("finally1") + print("exit") + return True + + +def func(): + print("func") + +# CHECK-L: start +# CHECK-NEXT-L: loop +# CHECK-NEXT-L: finally2 +# CHECK-NEXT-L: loop +# CHECK-NEXT-L: func +# CHECK-NEXT-L: finally2 +# CHECK-NEXT-L: after-while +# CHECK-NEXT-L: finally1 +# CHECK-NEXT-L: exit + +run() diff --git a/artiq/test/lit/try_loop/try_finally_while_try_reraise.py b/artiq/test/lit/try_loop/try_finally_while_try_reraise.py new file mode 100644 index 000000000..f7c6db84f --- /dev/null +++ b/artiq/test/lit/try_loop/try_finally_while_try_reraise.py @@ -0,0 +1,42 @@ +# RUN: %python -m artiq.compiler.testbench.jit %s >%t +# RUN: OutputCheck %s --file-to-check=%t +# REQUIRES: exceptions + +def run(): + print("start") + try: + try: + while True: + print("loop") + try: + print("try") + func() + print("unreachable") + return True + except RuntimeError: + print("except1") + raise + print("unreachable") + finally: + print("finally1") + print("unreachable") + return False + except RuntimeError: + print("except2") + raise + finally: + print("finally2") + return True + + +def func(): + raise RuntimeError("Test") + +# CHECK-L: start +# CHECK-NEXT-L: loop +# CHECK-NEXT-L: try +# CHECK-NEXT-L: except1 +# CHECK-NEXT-L: finally1 +# CHECK-NEXT-L: except2 +# CHECK-NEXT-L: finally2 +run() diff --git a/artiq/test/lit/try_loop/try_finally_while_try_return.py b/artiq/test/lit/try_loop/try_finally_while_try_return.py new file mode 100644 index 000000000..92a547f02 --- /dev/null +++ b/artiq/test/lit/try_loop/try_finally_while_try_return.py @@ -0,0 +1,29 @@ +# RUN: %python -m artiq.compiler.testbench.jit %s >%t +# RUN: OutputCheck %s --file-to-check=%t +# REQUIRES: exceptions + +def run(): + try: + while True: + try: + print("try") + func() + return True + except RuntimeError: + print("except") + return False + print("unreachable") + finally: + print("finally") + print("unreachable") + return False + + +def func(): + pass + +# CHECK-L: try +# CHECK-NOT-L: except +# CHECK-NOT-L: unreachable +# CHECK-L: finally +run() From 2b918ac6f726c9ecc1143584ed72ef10bd1cbd01 Mon Sep 17 00:00:00 2001 From: Sebastien Bourdeauducq Date: Fri, 25 Feb 2022 19:01:14 +0800 Subject: [PATCH 5/5] coredevice: merge pcf8574a into i2c --- artiq/coredevice/i2c.py | 43 ++++++++++++++++++++++++ artiq/coredevice/pcf8574a.py | 47 --------------------------- doc/manual/core_drivers_reference.rst | 7 ---- 3 files changed, 43 insertions(+), 54 deletions(-) delete mode 100644 artiq/coredevice/pcf8574a.py diff --git a/artiq/coredevice/i2c.py b/artiq/coredevice/i2c.py index 61be474e4..3608f4dc8 100644 --- a/artiq/coredevice/i2c.py +++ b/artiq/coredevice/i2c.py @@ -207,3 +207,46 @@ class TCA6424A: self._write24(0x8c, 0) # set all directions to output self._write24(0x84, outputs_le) # set levels + +class PCF8574A: + """Driver for the PCF8574 I2C remote 8-bit I/O expander. + + I2C transactions not real-time, and are performed by the CPU without + involving RTIO. + """ + def __init__(self, dmgr, busno=0, address=0x7c, core_device="core"): + self.core = dmgr.get(core_device) + self.busno = busno + self.address = address + + @kernel + def set(self, data): + """Drive data on the quasi-bidirectional pins. + + :param data: Pin data. High bits are weakly driven high + (and thus inputs), low bits are strongly driven low. + """ + i2c_start(self.busno) + try: + if not i2c_write(self.busno, self.address): + raise I2CError("PCF8574A failed to ack address") + if not i2c_write(self.busno, data): + raise I2CError("PCF8574A failed to ack data") + finally: + i2c_stop(self.busno) + + @kernel + def get(self): + """Retrieve quasi-bidirectional pin input data. + + :return: Pin data + """ + i2c_start(self.busno) + ret = 0 + try: + if not i2c_write(self.busno, self.address | 1): + raise I2CError("PCF8574A failed to ack address") + ret = i2c_read(self.busno, False) + finally: + i2c_stop(self.busno) + return ret diff --git a/artiq/coredevice/pcf8574a.py b/artiq/coredevice/pcf8574a.py deleted file mode 100644 index ed11cc311..000000000 --- a/artiq/coredevice/pcf8574a.py +++ /dev/null @@ -1,47 +0,0 @@ -from artiq.experiment import kernel -from artiq.coredevice.i2c import ( - i2c_start, i2c_write, i2c_read, i2c_stop, I2CError) - - -class PCF8574A: - """Driver for the PCF8574 I2C remote 8-bit I/O expander. - - I2C transactions not real-time, and are performed by the CPU without - involving RTIO. - """ - def __init__(self, dmgr, busno=0, address=0x7c, core_device="core"): - self.core = dmgr.get(core_device) - self.busno = busno - self.address = address - - @kernel - def set(self, data): - """Drive data on the quasi-bidirectional pins. - - :param data: Pin data. High bits are weakly driven high - (and thus inputs), low bits are strongly driven low. - """ - i2c_start(self.busno) - try: - if not i2c_write(self.busno, self.address): - raise I2CError("PCF8574A failed to ack address") - if not i2c_write(self.busno, data): - raise I2CError("PCF8574A failed to ack data") - finally: - i2c_stop(self.busno) - - @kernel - def get(self): - """Retrieve quasi-bidirectional pin input data. - - :return: Pin data - """ - i2c_start(self.busno) - ret = 0 - try: - if not i2c_write(self.busno, self.address | 1): - raise I2CError("PCF8574A failed to ack address") - ret = i2c_read(self.busno, False) - finally: - i2c_stop(self.busno) - return ret diff --git a/doc/manual/core_drivers_reference.rst b/doc/manual/core_drivers_reference.rst index 0fc5a8e8f..175039862 100644 --- a/doc/manual/core_drivers_reference.rst +++ b/doc/manual/core_drivers_reference.rst @@ -65,13 +65,6 @@ Digital I/O drivers .. automodule:: artiq.coredevice.i2c :members: -:mod:`artiq.coredevice.pcf8574a` module -+++++++++++++++++++++++++++++++++++++++ - -.. automodule:: artiq.coredevice.pcf8574a - :members: - - RF generation drivers ---------------------