1. Jun 11, 2024
  2. Jun 09, 2024
  3. Jun 05, 2024
  4. Jun 03, 2024
  5. Jun 01, 2024
    • Matthew Fernandez's avatar
      translation to SMV · 391cb95a
      Matthew Fernandez authored
      This is based on `murphi2uclid`. But unlike Uclid5 translation, this is much
      more rough. The semantics and structure of SMV are sufficiently different that
      an automatic translation would be more like a compiler than the AST-walking
      strategy employed by the `murphi2*` tools. It does not seem worth undertaking
      something this ambitious until we get some experience in whether this
      translation is useful.
      
      The translation gives up in numerous scenarios. But it should be more usable
      once we implement the ability to ingest partial Murphi models.
      391cb95a
  6. May 19, 2024
  7. May 09, 2024
    • Matthew Fernandez's avatar
      murphi2murphi: fix: use original token when testing for comment begin · b9309d6b
      Matthew Fernandez authored
      a9de733a,
      5dac7295,
      10acb279, and
      cc345ea2 introduced handling of some unicode
      characters that map to ASCII characters involved in starting a comment. These
      would incorrectly be considered as eligible aliases within comment tokens. E.g.
      `÷×` would be treated as validly starting a multi-line comment.
      
      This problem seems somewhat latent in that most sequences that would be confused
      in this way are not valid Murphi substrings anyway. The only one I can come up
      with is:
      
        x := y −-- a comment
         --    ▲▲
         --    │└─ actual start of the comment
         --    └─ unicode subtraction character
         z; -- ◄── conclusion of the subtraction
      
      This would be misinterpreted as the comment starting one character earlier. It
      is unclear whether this is an actual problem because the translation both before
      and after this change is identical; it is only the internal state of
      `murphi2murphi` that differs. Translation of something like this produces
      invalid Murphi source, but it is unclear what the user would want to happen
      here.
      b9309d6b
    • Matthew Fernandez's avatar
      CI: upgrade ARM job to GCC 14 · 176713ce
      Matthew Fernandez authored
      176713ce
    • Matthew Fernandez's avatar
      CI: add GCC 14 job · 452a32b3
      Matthew Fernandez authored
      452a32b3
  8. May 07, 2024
  9. May 06, 2024
  10. May 05, 2024
    • Matthew Fernandez's avatar
      Merge pull request #252 from Smattr/smattr/4bc946d0-5199-4366-9631-98f617b4ee78 · c69f84b3
      Matthew Fernandez authored
      avoid linking libatomic if possible on ARM64
      c69f84b3
    • Matthew Fernandez's avatar
      79265c3d
    • Matthew Fernandez's avatar
      avoid linking libatomic if possible on ARM64 · adba81cd
      Matthew Fernandez authored
      Double-word atomics are used to implement lock-free reference-counted pointers.¹
      Compiler built-ins (the GCC __sync and __atomic built-ins) are used to access
      this functionality. It is up to the compiler how to lower these built-ins, and
      it chooses between emitting inline instructions or calling into the libatomic
      runtime support library.² The implementations in libatomic are typically not
      lock-free – they work by using per-variable-instance mutexes – which negates the
      performance benefits of the lock-free algorithm we are trying to implement. In
      tight code like our scenario, the function call overhead into libatomic is also
      a noticeable factor.
      
      It was observed that on ARM64 GCC lowers these __atomic built-ins into libatomic
      calls. ARM64 has Load-Linked/Store-Conditional (LL/SC) instructions that can be
      used to implement these inline, but GCC has traditionally avoided using these to
      back the atomics.³ While compiler developers were debating the utility of these
      instructions, ARM introduced “Large System Extensions,” adding a new CASP family
      of instructions that more efficiently implements compare-and-swap.
      
      So our aim is to use the CASP instructions where possible. We have the following
      matrix:
      
        ┌──────┬───────────────────────┬───────────────────────┐
        │      │       Clang           │         GCC           │
        ├──────┼───────────────────────┼───────────────────────┤
        │ load │     __atomic          │       __sync          │
        │      │ <armv8.1-a: LL/SC     │ <armv8.1-a: libatomic │
        │      │ ≥armv8.1-a: CASP      │ ≥armv8.1-a: CASP      │
        ├──────┼───────────────────────┼───────────────────────┤
        │ store│     __atomic          │       __sync          │
        │      │ <armv8.1-a: LL/SC     │ <armv8.1-a: libatomic │
        │      │ ≥armv8.1-a: CASP      │ ≥armv8.1-a: CASP      │
        ├──────┼───────────────────────┼───────────────────────┤
        │ CAS  │     __atomic          │       __sync          │
        │      │ <armv8.1-a: libatomic │ <armv8.1-a: libatomic │
        │      │ ≥armv8.1-a: CASP      │ ≥armv8.1-a: CASP      │
        └──────┴───────────────────────┴───────────────────────┘
      
      This seems to result in a near-optimal situation on ≥armv8.1-a. For <armv8.1-a,
      the only way to avoid linking against libatomic seems to be resorting to inline
      assembly which is not worthwhile.
      
      Reported-by: e69d5a347277e5e7cb23518d93266bdac89a4bad
      
      ¹ Specifically “Hazard Pointers” as described in Maged Michael’s “Hazard
        Pointers: Safe Memory Reclamation for Lock-Free Objects” in TPDS 15(8) 2004.
      ² GCC 10.1 introduced a third option that does a runtime check, similar to GNU
        indirect functions (IFUNCs),
        https://community.arm.com/arm-community-blogs/b/tools-software-ides-blog/posts/making-the-most-of-the-arm-architecture-in-gcc-10.
        However, this is not relevant to us.
      ³ See https://gcc.gnu.org/pipermail/gcc-help/2017-June.txt for a lengthy debate
        on this and https://gcc.gnu.org/bugzilla/show_bug.cgi?id=80878 for the
        underlying rationale for avoiding both LL/SC and cmpxchg for backing these
        atomics. As one participant in the first linked discussion accurately
        summarises, “I think what’s happened makes perfect sense at each step of the
        way but has led to an outcome which is crazy.”
      adba81cd
    • Matthew Fernandez's avatar
      apply '-march=native' when running the test suite · 84d70ff1
      Matthew Fernandez authored
      This is preparation for leveraging this to avoid linking against libatomic on
      aarch64.
      84d70ff1
    • Matthew Fernandez's avatar
      rumur: pass '-march=native' to the C compiler when fuzz testing · dbb98b82
      Matthew Fernandez authored
      As discussed in the prior commit, this can avoid the need for linking against
      libatomic.
      dbb98b82
    • Matthew Fernandez's avatar
      rumur-run: apply '-march=native' when testing for libatomic dependency · 5afc797f
      Matthew Fernandez authored
      The value of `-march=…` can be a factor in deciding whether linking against
      libatomic is required. In particular, on aarch64 libatomic is required for <
      armv8.1-a.
      5afc797f
    • Matthew Fernandez's avatar
      work around GCC ≤ 13.2 bug on ARM · 28eb088c
      Matthew Fernandez authored
      Upcoming changes make this branch apply on aarch64 too. Unfortunately as-is it
      triggers a GCC bug. This rephrasing manages to side step the issue.
      
      GCC: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=114310
      28eb088c
  11. Apr 30, 2024
  12. Apr 27, 2024
  13. Apr 26, 2024
    • Matthew Fernandez's avatar
      fix: avoid mixing '__sync_*' and '__atomic_*' built-ins on ref-counted pointers · e6e8572c
      Matthew Fernandez authored
      When operating on reference counted pointers that take up a double-word,
      `refcounted_ptr_peek` was using a single-word read as an optimisation because it
      only needs the first word of the data. Meanwhile the other operations on
      reference counted pointers were using double-word compare-and-swap. On x86-64
      with `-mcx16`, this results in near-optimal code: `CMPXCHG16B` for the
      double-word operations and `MOV` for the single-word read.¹ Similar for x86.
      
      Unfortunately on other platforms, this design can result in non-atomic
      operations. To understand why, note that the compiler has a number of options
      for lowering both the `__sync_*` built-ins and the `__atomic_*` built-ins. Two
      of these options are (1) an inline instruction sequence and (2) a call to a
      libatomic function. A constraint is that its choices must interoperate
      correctly. For example, lowering a 16-bit `__atomic_load` to a `MOV` and a
      16-bit `__atomic_store` to a libatomic call (which is typically implemented with
      a per-instance mutex) would be incorrect. The following interleaving could
      occur, assuming X begins with the value 0x0:
      
        1. Thread A calls `__atomic_store` on X
        2. Thread A’s libatomic call takes a lock on X
        3. Thread A writes 0xad into the first byte of X
        4. Thread B loads both bytes of X in a single instruction
        5. Thread A writes 0xde into the second byte of X
        6. Thread A releases the lock on X
      
      It would have been valid for thread B to read either 0x0 (seeing the value
      before A’s store) or 0xdead (seeing the value after A’s store), but it instead
      saw a torn read of 0x00ad. Because the load and store do not agree on the
      protocol for synchronisation, atomicity can be violated.
      
      Crucially the compiler is only required to maintain this compatibility between
      the _same_ built-ins on the _same_ data type. The `__sync_*` built-ins and the
      `__atomic_*` built-ins are not required to use compatible protocols (and indeed
      they do not on x86-64 with `-mcx16`). And operations on a double-word type are
      not required to use a compatible protocol with operations on a single-word type
      (and indeed they do not on x86-64 _without_ `-mcx16`).
      
      The code in `refcounted_ptr_peek` was violating _both_ of these assumptions. On
      x86-64 without `-mcx16` it resulted in racy code, as it also did on ARM64. We
      could try to detect the narrow scenario wherein it is safe to mix built-ins
      because we know exactly which single instructions they will be lowered to (the
      ideal case on x86-64 described in the first paragraph), but this change
      conservatively switches to a double-word read which we know meets the compiler’s
      assumptions.
      
      ¹ `MOV` is atomic on naturally aligned 8-/16-/32-/64-bit data on x86-64.
      e6e8572c