theory CheckBV64
  use bv.BV64
  use int.Int as Int

  constant one   : t                                         = 1
  constant two   : t                                         = 2
  constant sz    : int                                       = 64
  constant mx    : int                                       = 0xFFFF_FFFF_FFFF_FFFF
  constant md    : int                                       = 0x1_0000_0000_0000_0000
  constant lastb : t                                         = 0x8000_0000_0000_0000

  goal ok_zero   : zeros                                     = (0:t)
  goal ok_ones   : ones                                      = (of_int mx)
  goal ok_zero2  : t'int zeros                               = 0
  goal ok_ones2  : t'int ones                                = mx
  goal ok_size   : size                                      = sz
  goal ok_max    : t'maxInt                                     = mx
  goal ok_tpsize : two_power_size                            = md

  goal ok1       : add ones one                              = zeros
  goal ok2       : sub zeros one                             = ones
  goal ok3       : neg ones                                  = one
  goal ok5       : mul one two                               = two
  goal ok6       : mul ones ones                             = one
  goal ok7       : udiv one two                              = zeros
  goal ok8       : urem one two                              = one
  goal ok9       : lsl_bv one one                            = two
  goal ok10      : lsl_bv ones one                           = sub ones one
  goal ok12      : lsr_bv one two                            = zeros
  goal ok13      : lsr_bv ones (sub (of_int sz) one)         = one
  goal ok14      : asr_bv one two                            = zeros
  goal ok15      : asr_bv ones two                           = ones
  goal ok16      : bw_and ones one                           = one
  goal ok17      : bw_or  ones one                           = ones
  goal ok18      : bw_xor ones one                           = sub ones one
  goal ok19      : bw_not ones                               = zeros
  goal ok20      : rotate_right_bv one one                   = lastb
  goal ok21      : rotate_right_bv ones two                  = ones
  goal ok22      : rotate_left_bv lastb one                  = one
  goal ok23      : rotate_left_bv ones two                   = ones
  goal ok24      : lsl_bv one (add (of_int sz) one)          = zeros
  goal ok25      : lsr_bv lastb (add (of_int sz) one)        = zeros
  goal ok26      : asr_bv lastb (add (of_int sz) one)        = ones
  goal ok27      : rotate_right_bv one (add (of_int sz) one) = lastb
  goal ok28      : rotate_left_bv one (add (of_int sz) one)  = two

  goal trap      : of_int md                                 = zeros

  goal smoke1    : neg lastb                                 = zeros
  goal smoke2    : udiv one zeros                            = zeros
  goal smoke3    : urem one zeros                            = zeros
  goal smoke4    : lsl_bv ones one                           = ones
  goal smoke5    : ugt (lsr_bv ones one) lastb
  goal smoke6    : ule (asr_bv lastb one) lastb
  goal smoke7    : rotate_right_bv one one                   = zeros
  goal smoke8    : rotate_left_bv lastb one                  = zeros

  (* from example/logic/bitvectors.why *)

  constant b0000  : t                                        = 0b0000
  constant b0001  : t                                        = 0b0001
  constant b0010  : t                                        = 0b0010
  constant b0011  : t                                        = 0b0011
  constant b0110  : t                                        = 0b0110
  constant b0101  : t                                        = 0b0101
  constant b0111  : t                                        = 0b0111
  constant b1100  : t                                        = 0b1100
  constant b11100 : t                                        = 0b11100

  constant size_sub_one : int                                = Int.(-) size 1

  goal g1 : bw_and b0011 b0110                               = b0010
  goal f1 : bw_and b0011 b0110                               = b0011

  goal g2 :  bw_or b0011 b0110                               = b0111
  goal f2 :  bw_or b0011 b0110                               = b0110

  goal g3 :  bw_xor b0011 b0110                              = b0101
  goal g4 :  bw_not b0011                                    = (0xFFFFFFFFFFFFFFFC:t)

  goal g3a : lsr_bv b0111 (2:t)                              = b0001
  goal g3b : lsr_bv ones (of_int size_sub_one)               = b0001
  goal f3  : lsr_bv ones (0x100000001:t)                     = (0x7FFFFFFF:t)

  goal g4a : lsl_bv b0111 (2:t)                              = b11100
  goal g4b : lsl_bv b0001 (31:t)                             = (0x80000000:t)

  goal g5a : asr_bv b0111 (2:t)                              = b0001
  goal g5b : asr_bv ones (of_int (Int.(-) size 1))           = ones

  goal g7 : t'int b11100                                   = 28
  goal f7 : t'int ones                                     = Int.(-_) 1

  goal g8a : nth_bv b0110 (2:t)                              = True
  goal g8b : nth_bv b0110 (3:t)                              = False

  goal Nth_Bv_bw_and:
    forall v1 v2 n. ult n size_bv ->
      nth_bv (bw_and v1 v2) n                                = andb (nth_bv v1 n) (nth_bv v2 n)

  goal Nth_Bv_bw_or:
    forall v1 v2 n. ult n size_bv ->
      nth_bv (bw_or v1 v2) n                                 = orb (nth_bv v1 n) (nth_bv v2 n)

  goal Nth_Bv_bw_xor:
    forall v1 v2 n. ult n size_bv ->
      nth_bv (bw_xor v1 v2) n                                = xorb (nth_bv v1 n) (nth_bv v2 n)

  goal Nth_Bv_bw_not:
    forall v n. ult n size_bv ->
      nth_bv (bw_not v) n                                    = notb (nth_bv v n)

  goal not_not : forall v:t. bw_not (bw_not v)               = v

  goal not_and : forall v1 v2:t.
    bw_not (bw_and v1 v2)                                    = bw_or (bw_not v1) (bw_not v2)

  goal Lsr_Bv_nth_bv_low: forall b n s.
    ult s size_bv -> ult n size_bv -> ult (add n s) size_bv ->
      nth_bv (lsr_bv b s) n                                  = nth_bv b (add n s)

  goal Lsr_Bv_nth_bv_high: forall b n s.
    ult s size_bv -> ult n size_bv -> uge (add n s) size_bv ->
      nth_bv (lsr_bv b s) n                                  = False

  goal Asr_Bv_nth_bv_low: forall b n s.
    ult s size_bv -> ult n size_bv -> ult (add n s) size_bv ->
       nth_bv (asr_bv b s) n                                 = nth_bv b (add n s)

  goal Asr_Bv_nth_bv_high: forall b n s.
    ult s size_bv -> ult n size_bv -> uge (add n s) size_bv ->
      nth_bv (asr_bv b s) n                                  = nth_bv b (sub size_bv one)

  goal Lsl_Bv_nth_bv_high: forall b n s.
    ult s size_bv -> ult n size_bv -> ult (sub n s) size_bv ->
      nth_bv (lsl_bv b s) n                                  = nth_bv b (sub n s)

  goal Lsl_Bv_nth_bv_low: forall b n s.
    ult s size_bv -> ult n size_bv -> uge (sub n s) size_bv ->
      nth_bv (lsl_bv b s) n                                  = False

end

theory CheckBV32
  use bv.BV32
  use int.Int as Int

  constant one   : t                                         = 1
  constant two   : t                                         = 2
  constant sz    : int                                       = 32
  constant mx    : int                                       = 0xFFFFFFFF
  constant md    : int                                       = 0x100000000
  constant lastb : t                                         = 0x80000000

  goal ok_zero   : zeros                                     = (0:t)
  goal ok_ones   : ones                                      = (of_int mx)
  goal ok_zero2  : t'int zeros                               = 0
  goal ok_ones2  : t'int ones                                = mx
  goal ok_size   : size                                      = sz
  goal ok_max    : t'maxInt                                     = mx
  goal ok_tpsize : two_power_size                            = md

  goal ok1       : add ones one                              = zeros
  goal ok2       : sub zeros one                             = ones
  goal ok3       : neg ones                                  = one
  goal ok5       : mul one two                               = two
  goal ok6       : mul ones ones                             = one
  goal ok7       : udiv one two                              = zeros
  goal ok8       : urem one two                              = one
  goal ok9       : lsl_bv one one                            = two
  goal ok10      : lsl_bv ones one                           = sub ones one
  goal ok12      : lsr_bv one two                            = zeros
  goal ok13      : lsr_bv ones (sub (of_int sz) one)         = one
  goal ok14      : asr_bv one two                            = zeros
  goal ok15      : asr_bv ones two                           = ones
  goal ok16      : bw_and ones one                           = one
  goal ok17      : bw_or  ones one                           = ones
  goal ok18      : bw_xor ones one                           = sub ones one
  goal ok19      : bw_not ones                               = zeros
  goal ok20      : rotate_right_bv one one                   = lastb
  goal ok21      : rotate_right_bv ones two                  = ones
  goal ok22      : rotate_left_bv lastb one                  = one
  goal ok23      : rotate_left_bv ones two                   = ones
  goal ok24      : lsl_bv one (add (of_int sz) one)          = zeros
  goal ok25      : lsr_bv lastb (add (of_int sz) one)        = zeros
  goal ok26      : asr_bv lastb (add (of_int sz) one)        = ones
  goal ok27      : rotate_right_bv one (add (of_int sz) one) = lastb
  goal ok28      : rotate_left_bv one (add (of_int sz) one)  = two

  goal trap      : of_int md                                 = zeros

  goal smoke1    : neg lastb                                 = zeros
  goal smoke2    : udiv one zeros                            = zeros
  goal smoke3    : urem one zeros                            = zeros
  goal smoke4    : lsl_bv ones one                           = ones
  goal smoke5    : ugt (lsr_bv ones one) lastb
  goal smoke6    : ule (asr_bv lastb one) lastb
  goal smoke7    : rotate_right_bv one one                   = zeros
  goal smoke8    : rotate_left_bv lastb one                  = zeros
end

theory CheckBV16
  use bv.BV16
  use int.Int as Int

  constant one   : t                                         = 1
  constant two   : t                                         = 2
  constant sz    : int                                       = 16
  constant mx    : int                                       = 65535
  constant md    : int                                       = 65536
  constant lastb : t                                         = 32768

  goal ok_zero   : zeros                                     = (0:t)
  goal ok_ones   : ones                                      = (of_int mx)
  goal ok_zero2  : t'int zeros                               = 0
  goal ok_ones2  : t'int ones                                = mx
  goal ok_size   : size                                      = sz
  goal ok_max    : t'maxInt                                     = mx
  goal ok_tpsize : two_power_size                            = md

  goal ok1       : add ones one                              = zeros
  goal ok2       : sub zeros one                             = ones
  goal ok3       : neg ones                                  = one
  goal ok5       : mul one two                               = two
  goal ok6       : mul ones ones                             = one
  goal ok7       : udiv one two                              = zeros
  goal ok8       : urem one two                              = one
  goal ok9       : lsl_bv one one                            = two
  goal ok10      : lsl_bv ones one                           = sub ones one
  goal ok12      : lsr_bv one two                            = zeros
  goal ok13      : lsr_bv ones (sub (of_int sz) one)         = one
  goal ok14      : asr_bv one two                            = zeros
  goal ok15      : asr_bv ones two                           = ones
  goal ok16      : bw_and ones one                           = one
  goal ok17      : bw_or  ones one                           = ones
  goal ok18      : bw_xor ones one                           = sub ones one
  goal ok19      : bw_not ones                               = zeros
  goal ok20      : rotate_right_bv one one                   = lastb
  goal ok21      : rotate_right_bv ones two                  = ones
  goal ok22      : rotate_left_bv lastb one                  = one
  goal ok23      : rotate_left_bv ones two                   = ones
  goal ok24      : lsl_bv one (add (of_int sz) one)          = zeros
  goal ok25      : lsr_bv lastb (add (of_int sz) one)        = zeros
  goal ok26      : asr_bv lastb (add (of_int sz) one)        = ones
  goal ok27      : rotate_right_bv one (add (of_int sz) one) = lastb
  goal ok28      : rotate_left_bv one (add (of_int sz) one)  = two

  goal trap      : of_int md                                 = zeros

  goal smoke1    : neg lastb                                 = zeros
  goal smoke2    : udiv one zeros                            = zeros
  goal smoke3    : urem one zeros                            = zeros
  goal smoke4    : lsl_bv ones one                           = ones
  goal smoke5    : ugt (lsr_bv ones one) lastb
  goal smoke6    : ule (asr_bv lastb one) lastb
  goal smoke7    : rotate_right_bv one one                   = zeros
  goal smoke8    : rotate_left_bv lastb one                  = zeros
end

theory CheckBV8
  use bv.BV8
  use int.Int as Int

  constant one   : t                                         = 1
  constant two   : t                                         = 2
  constant sz    : int                                       = 8
  constant mx    : int                                       = 255
  constant md    : int                                       = 256
  constant lastb : t                                         = 128

  goal ok_zero   : zeros                                     = (0:t)
  goal ok_ones   : ones                                      = (of_int mx)
  goal ok_zero2  : t'int zeros                               = 0
  goal ok_ones2  : t'int ones                                = mx
  goal ok_size   : size                                      = sz
  goal ok_max    : t'maxInt                                     = mx
  goal ok_tpsize : two_power_size                            = md

  goal ok1       : add ones one                              = zeros
  goal ok2       : sub zeros one                             = ones
  goal ok3       : neg ones                                  = one
  goal ok5       : mul one two                               = two
  goal ok6       : mul ones ones                             = one
  goal ok7       : udiv one two                              = zeros
  goal ok8       : urem one two                              = one
  goal ok9       : lsl_bv one one                            = two
  goal ok10      : lsl_bv ones one                           = sub ones one
  goal ok12      : lsr_bv one two                            = zeros
  goal ok13      : lsr_bv ones (sub (of_int sz) one)         = one
  goal ok14      : asr_bv one two                            = zeros
  goal ok15      : asr_bv ones two                           = ones
  goal ok16      : bw_and ones one                           = one
  goal ok17      : bw_or  ones one                           = ones
  goal ok18      : bw_xor ones one                           = sub ones one
  goal ok19      : bw_not ones                               = zeros
  goal ok20      : rotate_right_bv one one                   = lastb
  goal ok21      : rotate_right_bv ones two                  = ones
  goal ok22      : rotate_left_bv lastb one                  = one
  goal ok23      : rotate_left_bv ones two                   = ones
  goal ok24      : lsl_bv one (add (of_int sz) one)          = zeros
  goal ok25      : lsr_bv lastb (add (of_int sz) one)        = zeros
  goal ok26      : asr_bv lastb (add (of_int sz) one)        = ones
  goal ok27      : rotate_right_bv one (add (of_int sz) one) = lastb
  goal ok28      : rotate_left_bv one (add (of_int sz) one)  = two

  goal trap      : of_int md                                 = zeros

  goal smoke1    : neg lastb                                 = zeros
  goal smoke2    : udiv one zeros                            = zeros
  goal smoke3    : urem one zeros                            = zeros
  goal smoke4    : lsl_bv ones one                           = ones
  goal smoke5    : ugt (lsr_bv ones one) lastb
  goal smoke6    : ule (asr_bv lastb one) lastb
  goal smoke7    : rotate_right_bv one one                   = zeros
  goal smoke8    : rotate_left_bv lastb one                  = zeros
end





theory Extras

  use bv.BV64

  lemma mod_mult: forall x [@model] a [@model] b [@model].
      ule zeros x ->
      ult zeros a ->
      ult zeros b ->
      ule a (0xffff_ffff:t) ->
      ule b (0xffff_ffff:t) ->
      urem (urem x (mul a b)) a = urem x a



end
