; -- Simplification Rules --

(define-rule bv-ite-equal-children ((c (_ BitVec 1)) (x ?BitVec)) (bvite c x x) x)
(define-rule bv-ite-const-children-1 (
    (c (_ BitVec 1))
  )
  (bvite c (@bv 0 1) (@bv 1 1))
  (bvnot c))
(define-rule bv-ite-const-children-2 (
    (c (_ BitVec 1))
  )
  (bvite c (@bv 1 1) (@bv 0 1))
  c)
(define-rule bv-ite-equal-cond-1 (
    (c0 (_ BitVec 1))
    (t0 ?BitVec)
    (e0 ?BitVec)
    (e1 ?BitVec)
  )
  (bvite c0 (bvite c0 t0 e0) e1)
  (bvite c0 t0 e1))
(define-rule bv-ite-equal-cond-2 (
    (c0 (_ BitVec 1))
    (t0 ?BitVec)
    (t1 ?BitVec)
    (e1 ?BitVec)
  )
  (bvite c0 t0 (bvite c0 t1 e1))
  (bvite c0 t0 e1))
(define-rule bv-ite-equal-cond-3 (
    (c0 (_ BitVec 1))
    (t0 ?BitVec)
    (e0 ?BitVec)
    (t1 ?BitVec)
    (e1 ?BitVec)
  )
  (bvite c0 (bvite c0 t0 e0) (bvite c0 t1 e1))
  (bvite c0 t0 e1))
(define-rule bv-ite-merge-then-if (
    (c0 (_ BitVec 1))
    (c1 (_ BitVec 1))
    (t1 ?BitVec)
    (e1 ?BitVec)
  )
  (bvite c0 (bvite c1 t1 e1) t1)
  (bvite (bvand c0 (bvnot c1)) e1 t1))
(define-rule bv-ite-merge-else-if (
    (c0 (_ BitVec 1))
    (c1 (_ BitVec 1))
    (t1 ?BitVec)
    (e1 ?BitVec)
  )
  (bvite c0 (bvite c1 t1 e1) e1)
  (bvite (bvand c0 c1) t1 e1))
(define-rule bv-ite-merge-then-else (
    (c0 (_ BitVec 1))
    (c1 (_ BitVec 1))
    (t0 ?BitVec)
    (e1 ?BitVec)
  )
  (bvite c0 t0 (bvite c1 t0 e1))
  (bvite (bvand (bvnot c0) (bvnot c1)) e1 t0))
(define-rule bv-ite-merge-else-else (
    (c0 (_ BitVec 1))
    (c1 (_ BitVec 1))
    (t1 ?BitVec)
    (t0 ?BitVec)
  )
  (bvite c0 t0 (bvite c1 t1 t0))
  (bvite (bvand (bvnot c0) c1) t1 t0))


(define-rule bv-shl-by-const-0
  ((x ?BitVec) (sz Int))
  (bvshl x (@bv 0 sz))
  x)
(define-cond-rule bv-shl-by-const-1
  ((x ?BitVec) (amount Int) (sz Int) (en Int))
  (def (n (@bvsize x)))
  (and (< amount n) (= en (- n (+ 1 amount))))
  (bvshl x (@bv amount sz))
  (concat (extract en 0 x) (@bv 0 amount)))
(define-cond-rule bv-shl-by-const-2
  ((x ?BitVec) (amount Int) (sz Int) (w Int))
  (and (>= amount (@bvsize x)) (< amount (int.pow2 (@bvsize x))) (= w (@bvsize x)))
  (bvshl x (@bv amount sz))
  (@bv 0 w))
(define-rule bv-lshr-by-const-0
  ((x ?BitVec) (sz Int))
  (bvlshr x (@bv 0 sz))
  x)
(define-cond-rule bv-lshr-by-const-1
  ((x ?BitVec) (amount Int) (sz Int) (nm1 Int))
  (def (n (@bvsize x)))
  (and (< amount n) (= nm1 (- n 1)))
  (bvlshr x (@bv amount sz))
  (concat (@bv 0 amount) (extract nm1 amount x)))
(define-cond-rule bv-lshr-by-const-2
  ((x ?BitVec) (amount Int) (sz Int))
  (and (>= amount (@bvsize x)) (< amount (int.pow2 (@bvsize x))))
  (bvlshr x (@bv amount sz))
  (@bv 0 sz))
(define-rule bv-ashr-by-const-0
  ((x ?BitVec) (sz Int))
  (bvashr x (@bv 0 sz))
  x)
(define-cond-rule bv-ashr-by-const-1
  ((x ?BitVec) (amount Int) (sz Int) (nm1 Int))
  (def (n (@bvsize x)))
  (and (< amount n) (= nm1 (- n 1)))
  (bvashr x (@bv amount sz))
  (concat
    (repeat amount (extract nm1 nm1 x))
    (extract nm1 amount x)
  ))
(define-cond-rule bv-ashr-by-const-2
  ((x ?BitVec) (amount Int) (sz Int) (nm1 Int) (rn Int))
  (and (>= amount (@bvsize x)) (= nm1 (- (@bvsize x) 1)) (= rn (@bvsize x)))
  (bvashr x (@bv amount sz))
  (repeat rn (extract nm1 nm1 x)))

; AndOrXorConcatPullUp
(define-cond-rule bv-and-concat-pullup
  ((xs ?BitVec :list) (ws ?BitVec :list) (y ?BitVec)
   (z ?BitVec) (ys ?BitVec :list)
   (nxm1 Int) (ny Int) (nym1 Int))
  (def
    (nx (@bvsize (concat z y ys)))
  )
  (and (= ny (@bvsize y)) (= nxm1 (- nx 1)) (= nym1 (- (@bvsize y) 1)))
  (bvand xs (concat ys z y) ws)
  (concat
    (bvand (extract nxm1 ny (bvand xs ws)) (concat ys z))
    (bvand (extract nym1 0 (bvand xs ws)) y)
  ))
(define-cond-rule bv-or-concat-pullup
  ((xs ?BitVec :list) (ws ?BitVec :list) (y ?BitVec)
   (z ?BitVec) (ys ?BitVec :list)
   (nxm1 Int) (ny Int) (nym1 Int))
  (def
    (nx (@bvsize (concat z y ys)))
  )
  (and (= ny (@bvsize y)) (= nxm1 (- nx 1)) (= nym1 (- (@bvsize y) 1)))
  (bvor xs (concat ys z y) ws)
  (concat
    (bvor (extract nxm1 ny (bvor xs ws)) (concat ys z))
    (bvor (extract nym1 0 (bvor xs ws)) y)
  ))
(define-cond-rule bv-xor-concat-pullup
  ((xs ?BitVec :list) (ws ?BitVec :list) (y ?BitVec)
   (z ?BitVec) (ys ?BitVec :list)
   (nxm1 Int) (ny Int) (nym1 Int))
  (def
    (nx (@bvsize (concat z y ys)))
  )
  (and (= ny (@bvsize y)) (= nxm1 (- nx 1)) (= nym1 (- (@bvsize y) 1)))
  (bvxor xs (concat ys z y) ws)
  (concat
    (bvxor (extract nxm1 ny (bvxor xs ws)) (concat ys z))
    (bvxor (extract nym1 0 (bvxor xs ws)) y)
  ))


(define-cond-rule bv-and-concat-pullup2
  ((xs ?BitVec :list) (ws ?BitVec :list) (y ?BitVec)
   (z ?BitVec) (ys ?BitVec :list)
   (nxm1 Int) (ny Int) (nym1 Int))
  (def
    (s (@bvsize (concat z y ys)))
    (sy (- s (@bvsize z)))
  )
  (and (= ny sy) (= nxm1 (- s 1)) (= nym1 (- sy 1)))
  (bvand xs (concat z y ys) ws)
  (concat
    (bvand (extract nxm1 ny (bvand xs ws)) z)
    (bvand (extract nym1 0 (bvand xs ws)) (concat y ys))
  ))
(define-cond-rule bv-or-concat-pullup2
  ((xs ?BitVec :list) (ws ?BitVec :list) (y ?BitVec)
   (z ?BitVec) (ys ?BitVec :list)
   (nxm1 Int) (ny Int) (nym1 Int))
  (def
    (s (@bvsize (concat z y ys)))
    (sy (- s (@bvsize z)))
  )
  (and (= ny sy) (= nxm1 (- s 1)) (= nym1 (- sy 1)))
  (bvor xs (concat z y ys) ws)
  (concat
    (bvor (extract nxm1 ny (bvor xs ws)) z)
    (bvor (extract nym1 0 (bvor xs ws)) (concat y ys))
  ))
(define-cond-rule bv-xor-concat-pullup2
  ((xs ?BitVec :list) (ws ?BitVec :list) (y ?BitVec)
   (z ?BitVec) (ys ?BitVec :list)
   (nxm1 Int) (ny Int) (nym1 Int))
  (def
    (s (@bvsize (concat z y ys)))
    (sy (- s (@bvsize z)))
  )
  (and (= ny sy) (= nxm1 (- s 1)) (= nym1 (- sy 1)))
  (bvxor xs (concat z y ys) ws)
  (concat
    (bvxor (extract nxm1 ny (bvxor xs ws)) z)
    (bvxor (extract nym1 0 (bvxor xs ws)) (concat y ys))
  ))

(define-cond-rule bv-and-concat-pullup3
  ((xs ?BitVec :list) (ws ?BitVec :list) (y ?BitVec)
   (z ?BitVec) (u ?BitVec)
   (nxm1 Int) (nyu Int) (nyum1 Int) (nu Int) (num1 Int))
  (def
    (su (@bvsize u))
    (sy (@bvsize y))
    (s (+ su sy (@bvsize z)))
  )
  (and (= nxm1 (- s 1)) (= nyu (+ sy su)) (= nyum1 (- (+ sy su) 1)) (= nu su) (= num1 (- su 1)))
  (bvand xs (concat z y u) ws)
  (concat
    (bvand (extract nxm1 nyu (bvand xs ws)) z)
    (bvand (extract nyum1 nu (bvand xs ws)) y)
    (bvand (extract num1 0 (bvand xs ws)) u)
  ))
(define-cond-rule bv-or-concat-pullup3
  ((xs ?BitVec :list) (ws ?BitVec :list) (y ?BitVec)
   (z ?BitVec) (u ?BitVec)
   (nxm1 Int) (nyu Int) (nyum1 Int) (nu Int) (num1 Int))
  (def
    (su (@bvsize u))
    (sy (@bvsize y))
    (s (+ su sy (@bvsize z)))
  )
  (and (= nxm1 (- s 1)) (= nyu (+ sy su)) (= nyum1 (- (+ sy su) 1)) (= nu su) (= num1 (- su 1)))
  (bvor xs (concat z y u) ws)
  (concat
    (bvor (extract nxm1 nyu (bvor xs ws)) z)
    (bvor (extract nyum1 nu (bvor xs ws)) y)
    (bvor (extract num1 0 (bvor xs ws)) u)
  ))
(define-cond-rule bv-xor-concat-pullup3
  ((xs ?BitVec :list) (ws ?BitVec :list) (y ?BitVec)
   (z ?BitVec) (u ?BitVec)
   (nxm1 Int) (nyu Int) (nyum1 Int) (nu Int) (num1 Int))
  (def
    (su (@bvsize u))
    (sy (@bvsize y))
    (s (+ su sy (@bvsize z)))
  )
  (and (= nxm1 (- s 1)) (= nyu (+ sy su)) (= nyum1 (- (+ sy su) 1)) (= nu su) (= num1 (- su 1)))
  (bvxor xs (concat z y u) ws)
  (concat
    (bvxor (extract nxm1 nyu (bvxor xs ws)) z)
    (bvxor (extract nyum1 nu (bvxor xs ws)) y)
    (bvxor (extract num1 0 (bvxor xs ws)) u)
  ))

(define-cond-rule bv-xor-duplicate ((x ?BitVec) (w Int))
  (= w (@bvsize x))
  (bvxor x x) 
  (@bv 0 w))

(define-cond-rule bv-xor-ones ((xs ?BitVec :list) (zs ?BitVec :list) (n Int) (w Int))
  (= n (- (int.pow2 w) 1))
  (bvxor xs (@bv n w) zs)
  (bvnot (bvxor xs zs)))

(define-rule bv-xor-not ((x ?BitVec) (y ?BitVec))
  (bvxor (bvnot x) (bvnot y)) (bvxor x y))
(define-rule bv-not-idemp ((x ?BitVec))
  (bvnot (bvnot x)) x)

(define-rule bv-ult-zero-1
  ((x ?BitVec) (n Int))
  (bvult (@bv 0 n) x)
  (not (= x (@bv 0 n))))
(define-rule bv-ult-zero-2
  ((x ?BitVec) (n Int))
  (bvult x (@bv 0 n))
  false)
(define-rule bv-ult-self ((x ?BitVec)) (bvult x x) false)
(define-rule bv-lt-self ((x ?BitVec)) (bvslt x x) false)
(define-rule bv-ule-self ((x ?BitVec)) (bvule x x) true)
(define-rule bv-ule-zero
  ((x ?BitVec) (n Int))
  (bvule x (@bv 0 n))
  (= x (@bv 0 n)))
(define-rule bv-zero-ule
  ((x ?BitVec) (n Int))
  (bvule (@bv 0 n) x)
  true)
(define-rule bv-sle-self ((x ?BitVec)) (bvsle x x) true)

(define-cond-rule bv-ule-max ((x ?BitVec) (n Int) (w Int))
  (and (= w (@bvsize x)) (= n (- (int.pow2 (@bvsize x)) 1)))
  (bvule x (@bv n w)) true)
(define-rule bv-not-ult ((x ?BitVec) (y ?BitVec))
  (not (bvult x y))
  (bvule y x))

(define-cond-rule bv-mult-pow2-1
  ((xs ?BitVec :list) (ys ?BitVec :list) (z ?BitVec) (size Int) (n Int) (exponent Int) (u Int))
  (def (e (int.log2 n)))
  (and (int.ispow2 n) (= exponent e) (= u (- (- size e) 1)))
  (bvmul xs z (@bv n size) ys)
  (concat
    (extract u 0 (bvmul xs z ys))
    (@bv 0 exponent)))
(define-cond-rule bv-mult-pow2-2
  ((xs ?BitVec :list) (ys ?BitVec :list) (z ?BitVec) (size Int) (n Int) (exponent Int) (u Int))
  (def (ns (- (int.pow2 size) n)) (e (int.log2 ns)))
  (and (int.ispow2 ns) (= exponent e) (= u (- (- size e) 1)))
  (bvmul xs z (@bv n size) ys)
  (concat
    (extract u 0 (bvneg (bvmul xs z ys)))
    (@bv 0 exponent)))
(define-cond-rule bv-mult-pow2-2b
  ((z ?BitVec) (size Int) (n Int) (exponent Int) (u Int))
  (def (ns (- (int.pow2 size) n)) (e (int.log2 ns)))
  (and (int.ispow2 ns) (= exponent e) (= u (- (- size e) 1)))
  (bvmul z (@bv n size))
  (concat
    (extract u 0 (bvneg z))
    (@bv 0 exponent)))

; If the bit-vectors multiplied have enough leading zeros,
; we can determine that the top bits of the multiplication
; are zero and not compute them. Only apply for large bitwidths
; as this can interfere with other mult normalization rewrites such
; as flattening.
(define-cond-rule bv-extract-mult-leading-bit
  (
    (high Int) (low Int)
    (x1i Int) (x1in Int) (x2 ?BitVec)
    (y1i Int) (y1in Int) (y2 ?BitVec)
    (w Int)
  )
  (def
    (n (+ x1in (@bvsize x2)))
    ; length(n) = log2(n) + 1, so we subtract 1 to compensate
    (x0n (ite (= x1i 0) x1in (- x1in (+ 1 (int.log2 x1i)))))
    (y0n (ite (= y1i 0) y1in (- y1in (+ 1 (int.log2 y1i)))))
  )
  (and (> n 64) (<= (- (* 2 n) (+ x0n y0n)) low) (= w (+ 1 (- high low))))
  (extract high low (bvmul
    (concat (@bv x1i x1in) x2)
    (concat (@bv y1i y1in) y2)))
  (@bv 0 w))

; (a udiv 2^k) ==> 0_k a[n-1: k]
(define-cond-rule bv-udiv-pow2-not-one
  ((x ?BitVec) (v Int) (n Int) (power Int) (nm1 Int))
  (and (int.ispow2 v) (> v 1) (= power (int.log2 v)) (= nm1 (- n 1)))
  (bvudiv x (@bv v n))
  (concat (@bv 0 power) (extract nm1 power x)))

(define-rule bv-udiv-zero
  ((x ?BitVec) (n Int))
  (bvudiv x (@bv 0 n))
  (bvnot (@bv 0 n)))
; (x udiv 1) = x
(define-rule bv-udiv-one ((x ?BitVec) (n Int))
  (bvudiv x (@bv 1 n))
  x)
; (x urem 2^k) = 0_(n-k) x[k-1:0]
(define-cond-rule bv-urem-pow2-not-one
  ((x ?BitVec) (v Int) (n Int) (nmp Int) (pm1 Int))
  (def (power (int.log2 v)))
  (and (int.ispow2 v) (> v 1) (= nmp (- n power)) (= pm1 (- power 1)))
  (bvurem x (@bv v n))
  (concat (@bv 0 nmp) (extract pm1 0 x)))

(define-rule bv-urem-one
  ((x ?BitVec) (n Int))
  (bvurem x (@bv 1 n))
  (@bv 0 n))
(define-cond-rule bv-urem-self
  ((x ?BitVec) (w Int))
  (= w (@bvsize x))
  (bvurem x x)
  (@bv 0 w))
; ShiftZero rule
; (0_k >> a) = 0_k
(define-rule bv-shl-zero
  ((a ?BitVec) (n Int))
  (bvshl (@bv 0 n) a)
  (@bv 0 n))
(define-rule bv-lshr-zero
  ((a ?BitVec) (n Int))
  (bvlshr (@bv 0 n) a)
  (@bv 0 n))
(define-rule bv-ashr-zero
  ((a ?BitVec) (n Int))
  (bvashr (@bv 0 n) a)
  (@bv 0 n))

; (bvugt (bvurem T x) x)
;   ==>  (ite (= x 0_k) (bvugt T x) false)
;   ==>  (and (=> (= x 0_k) (bvugt T x)) (=> (not (= x 0_k)) false))
;   ==>  (and (=> (= x 0_k) (bvugt T x)) (= x 0_k))
;   ==>  (and (bvugt T x) (= x 0_k))
;   ==>  (and (bvugt T 0_k) (= x 0_k))
(define-cond-rule bv-ugt-urem
  ((y ?BitVec) (x ?BitVec) (w Int))
  (= w (@bvsize y))
  (bvugt (bvurem y x) x)
  (and
    (= x (@bv 0 w))
    (bvugt y (@bv 0 w))
  ))

(define-cond-rule bv-ult-one
  ((x ?BitVec) (n Int))
  (> (@bvsize x) 0)
  (bvult x (@bv 1 n))
  (= x (@bv 0 n)))

(define-cond-rule bv-merge-sign-extend-1
  ((x ?BitVec) (i Int) (j Int) (k Int))
  (= k (+ i j))
  (sign_extend i (sign_extend j x))
  (sign_extend k x)
  )
(define-cond-rule bv-merge-sign-extend-2
  ((x ?BitVec) (i Int) (j Int) (k Int))
  (and (> j 0) (= k (+ i j)))
  (sign_extend i (zero_extend j x))
  (zero_extend k x)
  )
(define-cond-rule bv-sign-extend-eq-const-1
  ((x ?BitVec) (m Int) (c Int) (nm Int) (mp1 Int) (nm1 Int) (nmm1 Int))
  (def
    (n (@bvsize x))
    (clo (extract nm1 0 (@bv c nm)))
    ; Combines the sign bit c[n-1] and the high part
    (chi (extract nmm1 nm1 (@bv c nm)))
  )
  (and (= mp1 (+ m 1)) (= nm1 (- n 1)) (= nmm1 (- nm 1)))
  (= (sign_extend m x) (@bv c nm))
  (and
    (or (= chi (@bv 0 mp1)) (= chi (bvnot (@bv 0 mp1))))
    (= x clo)))
(define-cond-rule bv-sign-extend-eq-const-2
  ((x ?BitVec) (m Int) (c Int) (nm Int) (mp1 Int) (nm1 Int) (nmm1 Int))
  (def
    (n (@bvsize x))
    (clo (extract nm1 0 (@bv c nm)))
    ; Combines the sign bit c[n-1] and the high part
    (chi (extract nmm1 nm1 (@bv c nm)))
  )
  (and (= mp1 (+ m 1)) (= nm1 (- n 1)) (= nmm1 (- nm 1)))
  (= (@bv c nm) (sign_extend m x))
  (and
    (or (= chi (@bv 0 mp1)) (= chi (bvnot (@bv 0 mp1))))
    (= x clo)))
(define-cond-rule bv-zero-extend-eq-const-1
  ((x ?BitVec) (m Int) (c Int) (nm Int) (nm1 Int) (nmm1 Int))
  (def
    (n (@bvsize x))
    (clo (extract nm1 0 (@bv c nm)))
    (chi (extract nmm1 nm1 (@bv c nm)))
  )
  (and (= nm1 (- n 1)) (= nmm1 (- nm 1)))
  (= (zero_extend m x) (@bv c nm))
  (and
    (= chi (@bv 0 m))
    (= x clo)))
(define-cond-rule bv-zero-extend-eq-const-2
  ((x ?BitVec) (m Int) (c Int) (nm Int) (nm1 Int) (nmm1 Int))
  (def
    (n (@bvsize x))
    (clo (extract nm1 0 (@bv c nm)))
    (chi (extract nmm1 nm1 (@bv c nm)))
  )
  (and (= nm1 (- n 1)) (= nmm1 (- nm 1)))
  (= (@bv c nm) (zero_extend m x))
  (and
    (= chi (@bv 0 m))
    (= x clo)))

(define-cond-rule bv-zero-extend-ult-const-1
  ((x ?BitVec) (m Int) (c Int) (nm Int) (nm1 Int))
  (def
    (n (@bvsize x))
    (clo (extract nm1 0 (@bv c nm)))
  )
  (and (= nm1 (- n 1)) (= (@bv c nm) (zero_extend m clo)))
  (bvult (zero_extend m x) (@bv c nm))
  (bvult x clo))

(define-cond-rule bv-zero-extend-ult-const-2
  ((x ?BitVec) (m Int) (c Int) (nm Int) (nm1 Int))
  (def
    (n (@bvsize x))
    (clo (extract nm1 0 (@bv c nm)))
  )
  (and (= nm1 (- n 1)) (= (@bv c nm) (zero_extend m clo)))
  (bvult (@bv c nm) (zero_extend m x))
  (bvult clo x))

(define-cond-rule bv-sign-extend-ult-const-1
  ((x ?BitVec) (m Int) (c Int) (nm Int) (nm1 Int))
  (def
    (n (@bvsize x))
    (clo (extract nm1 0 (@bv c nm)))
    (a (bvshl (@bv 1 nm) (@bv (- n 1) nm))) ; 1 << (n-1)
    (b (bvshl (bvnot (@bv 0 nm)) (@bv (- n 1) nm))) ; ~0 << (n-1)
  )
  (and (or (bvule (@bv c nm) a) (bvuge (@bv c nm) b)) (= nm1 (- n 1)))
  (bvult (sign_extend m x) (@bv c nm))
  (bvult x clo))
(define-cond-rule bv-sign-extend-ult-const-2
  ((x ?BitVec) (m Int) (c Int) (nm Int) (nm1 Int))
  (def
    (n (@bvsize x))
    (a (bvshl (@bv 1 nm) (@bv (- n 1) nm))) ; 1 << (n-1)
    (b (bvshl (bvnot (@bv 0 nm)) (@bv (- n 1) nm))) ; ~0 << (n-1)
  )
  (and (bvult a (@bv c nm)) (bvule (@bv c nm) b) (= nm1 (- n 1)))
  (bvult (sign_extend m x) (@bv c nm))
  (= (extract nm1 nm1 x) (@bv 0 1)))
(define-cond-rule bv-sign-extend-ult-const-3
  ((x ?BitVec) (m Int) (c Int) (nm Int) (nm1 Int))
  (def
    (n (@bvsize x))
    (clo (extract nm1 0 (@bv c nm)))
    (a (bvshl (@bv 1 nm) (@bv (- n 1) nm))) ; 1 << (n-1)
    (b (bvshl (bvnot (@bv 0 nm)) (@bv (- n 1) nm))) ; ~0 << (n-1)
  )
  (and (or (bvult (@bv c nm) a) (bvuge (@bv c nm) (bvnot a))) (= nm1 (- n 1)))
  (bvult (@bv c nm) (sign_extend m x))
  (bvult clo x))

(define-cond-rule bv-sign-extend-ult-const-4
  ((x ?BitVec) (m Int) (c Int) (nm Int) (nm1 Int))
  (def
    (n (@bvsize x))
    (a (bvshl (@bv 1 nm) (@bv (- n 1) nm))) ; 1 << (n-1)
    (b (bvshl (bvnot (@bv 0 nm)) (@bv (- n 1) nm))) ; ~0 << (n-1)
  )
  (and (bvule (bvnot b) (@bv c nm)) (bvule (@bv c nm) (bvnot a)) (= nm1 (- n 1)))
  (bvult (@bv c nm) (sign_extend m x))
  (= (extract nm1 nm1 x) (@bv 1 1)))
