• Top
    • Documentation
    • Books
    • Recursion-and-induction
    • Boolean-reasoning
    • Projects
    • Debugging
    • Std
    • Proof-automation
      • Gl
      • Witness-cp
      • Ccg
      • Install-not-normalized
      • Rewrite$
      • Removable-runes
      • Efficiency
      • Rewrite-bounds
      • Bash
      • Def-dag-measure
      • Fgl
        • Fgl-rewrite-rules
        • Fgl-function-mode
        • Fgl-object
        • Fgl-solving
        • Fgl-handling-if-then-elses
        • Fgl-getting-bits-from-objects
        • Fgl-primitive-and-meta-rules
        • Fgl-interpreter-overview
        • Fgl-counterexamples
        • Fgl-correctness-of-binding-free-variables
        • Fgl-debugging
        • Fgl-testbenches
        • Def-fgl-boolean-constraint
        • Fgl-stack
        • Fgl-rewrite-tracing
        • Def-fgl-param-thm
        • Def-fgl-thm
        • Fgl-fast-alist-support
        • Advanced-equivalence-checking-with-fgl
          • Solve-lane-by-lane-masked
            • Solve-lane-by-lane-masked+
            • Top-level-equal
            • Solve-lane-by-lane
            • Replace-equal-with-top-level-equal-rec
            • Lookup-previous-stack-frame-binding
            • Monolithic-sat-with-transforms
            • Ipasir-sat-limit100
          • Fgl-array-support
          • Fgl-internals
        • Bdd
        • Remove-hyps
        • Contextual-rewriting
        • Simp
        • Rewrite$-hyps
        • Bash-term-to-dnf
        • Use-trivial-ancestors-check
        • Minimal-runes
        • Clause-processor-tools
        • Fn-is-body
        • Without-subsumption
        • Rewrite-equiv-hint
        • Def-bounds
        • Rewrite$-context
        • Try-gl-concls
        • Hint-utils
      • Macro-libraries
      • ACL2
      • Interfacing-tools
      • Hardware-verification
      • Software-verification
      • Testing-utilities
      • Math
    • Advanced-equivalence-checking-with-fgl

    Solve-lane-by-lane-masked

    Equality check that works around hard SAT/fraiging problems caused by writemasking.

    Signature
    (solve-lane-by-lane-masked x y mask width) → *

    This addresses a problem that sometimes comes up in proving correctness of SIMD operations with writemasking. Suppose an instruction applies function F to each 32-bit lane of a vector, with writemasking; that is, the spec for lane i is mask[i] ? F(src.lanes32[i]) : dst.lanes32[i]. Now, perhaps the implementation applies the same function F, but instead operates on mask[i] ? src.lanes32[i] : 0. Of course this is OK because when mask[i] is 0 we don't care what the function computes. But unfortunately when we pack the lanes together and try to equivalence check spec versus implementation, one of our best tools, fraiging (aka SAT sweeping) doesn't work. This is because there are no equivalent formulas within the computation of the function F: each subformula G within F shows up in the spec as G(src.lanes32[i]) but in the implementation as G(mask[i] ? src.lanes32[i] : 0), which is obviously not equivalent.

    A workaround for this problem is to split the check for each lane into cases according to mask[i] and propagate that assumption into their formulas. That is, when mask[i] is assumed true, replace mask[i] ? src.lanes32[i] : 0 with just src.lanes32[i]. FGL has a special function called fgl-pathcond-fix that can do this: logically it is the identity function, but under FGL it rewrites the input symbolic object to assume the current path condition. That is, for each Boolean formula in the symbolic object, that formula is simplified by replacing any AIG literals known to be true (false) under the path condition with 1 (0). In many cases simply splitting into cases for each lane's corresponding mask bit, specializing each equivalence under both cases, produces a formula that is much easier to solve than the original, especially using fraiging.

    Sometimes this may not work; for a somewhat more aggressive strategy, see solve-lane-by-lane-masked+.

    Definitions and Theorems

    Function: solve-lane-by-lane-masked

    (defun solve-lane-by-lane-masked
           (x y mask width)
           (declare (xargs :guard t))
           (let ((__function__ 'solve-lane-by-lane-masked))
                (declare (ignorable __function__))
                (equal x y)))

    Theorem: solve-lane-by-lane-masked-impl

    (defthm
      solve-lane-by-lane-masked-impl
      (implies
           (and (syntaxp (posp width))
                (check-integerp xintp x)
                (check-integerp yintp y))
           (equal (solve-lane-by-lane-masked x y mask width)
                  (if (and (check-int-endp x-endp x)
                           (check-int-endp y-endp y))
                      (equal x y)
                      (and* (b* ((lane-equiv (equal (loghead width x)
                                                    (loghead width y))))
                                (if (logbitp 0 mask)
                                    (fgl-pathcond-fix lane-equiv)
                                    (fgl-pathcond-fix lane-equiv)))
                            (solve-lane-by-lane-masked (logtail width x)
                                                       (logtail width y)
                                                       (logcdr mask)
                                                       width))))))