failbit.h 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140
  1. // SPDX-License-Identifier: GPL-2.0 or GPL-3.0
  2. // Copyright © 2019 Ariadne Devos
  3. #ifndef _sHT_FAILBIT_H
  4. #define _sHT_FAILBIT_H
  5. #include <stddef.h>
  6. #include <sHT/test.h>
  7. /* See doc/failbit.rst */
  8. /* TODO: on-demand: only size_t is supported
  9. TODO: _Generic instead of type arguments */
  10. /* TODO: Sparse */
  11. #define sHT_with_failbit
  12. #define sHT_failbit_limit (((size_t) -1) ^ ((size_t) -1) >> 1)
  13. #ifndef __FRAMAC__
  14. _Static_assert(sHT_failbit_limit != 0, "above macro incorrect");
  15. _Static_assert((sHT_failbit_limit & (sHT_failbit_limit - 1)) == 0, "above macro incorrect");
  16. _Static_assert(sHT_failbit_limit << 1 == 0u, "above macro incorrect");
  17. #else
  18. # include <stdint.h>
  19. #endif
  20. /* SMT provers seem to handle arithmetic better than bitwise
  21. operations. */
  22. /*@ axiomatic Failbit {
  23. predicate good(ℤ v) = 0 <= v < sHT_failbit_limit;
  24. predicate bad(ℤ v) = sHT_failbit_limit <= v <= SIZE_MAX;
  25. lemma msb_bad: \forall ℤ v; bad(v) ==> v & sHT_failbit_limit;
  26. lemma nomsb_good: \forall ℤ v; good(v) ==> !(v & sHT_failbit_limit);
  27. lemma notgood_bad: \forall ℤ v; 0 <= v <= SIZE_MAX ==> (!good(v) ==> bad(v));
  28. lemma notbad_good: \forall ℤ v; 0 <= v <= SIZE_MAX ==> (!bad(v) ==> good(v));
  29. lemma failbit_range: \forall ℤ v; good(v) || bad(v) <==> 0 <= v <= SIZE_MAX;
  30. // ACSL doesn't seem to allow for subtypes
  31. logic ℤ fail_value(ℤ v);
  32. axiom good_value: \forall ℤ v; good(v) ==> fail_value(v) == v;
  33. axiom bad_value:
  34. \forall ℤ v; bad(v) ==> fail_value(v) == v - sHT_failbit_limit;
  35. lemma good_value0: \forall ℤ v; good(v) || bad(v)
  36. ==> fail_value(v) == (v & ~sHT_failbit_limit);
  37. } */
  38. /* no-failure? */
  39. /*@ terminates \true;
  40. assigns \result \from x;
  41. ensures resultNS: \result <==> good(x); */
  42. __attribute__((const))
  43. __attribute__((always_inline))
  44. static inline _Bool
  45. sHT_good(size_t x)
  46. {
  47. return sHT_msb_unset_size_t(x);
  48. }
  49. /* failure? */
  50. /*@ terminates \true;
  51. assigns \result \from x;
  52. ensures resultNS: \result <==> bad(x); */
  53. __attribute__((const))
  54. __attribute__((always_inline))
  55. static inline _Bool
  56. sHT_bad(size_t x)
  57. {
  58. return sHT_msb_set_size_t(x);
  59. }
  60. /** Start the failbit machine in the success state */
  61. /*@ requires r: x < sHT_failbit_limit;
  62. terminates \true;
  63. assigns \result \from x;
  64. ensures good: good(\result);
  65. ensures val: fail_value(\result) == x; */
  66. static inline size_t
  67. sHT_success(size_t x)
  68. {
  69. # define sHT_success_const(x) ((x) + 0)
  70. return x;
  71. }
  72. /** Start the failbit machine in the error state */
  73. /*@ requires r: x < sHT_failbit_limit;
  74. terminates \true;
  75. assigns \result \from x;
  76. ensures bad: !good(\result);
  77. ensures val: fail_value(\result) == x; */
  78. static inline size_t
  79. sHT_fail(size_t x)
  80. {
  81. # define sHT_fail_const(x) ((x) + sHT_failbit_limit)
  82. return x + sHT_failbit_limit;
  83. }
  84. /*@ terminates \true;
  85. assigns \result \from x;
  86. ensures \result == fail_value(x); */
  87. static inline size_t
  88. sHT_fail_value(size_t x)
  89. {
  90. return x & ~sHT_failbit_limit;
  91. }
  92. /* Transfer the failbit of `f` to `n`, with some restrictions. */
  93. /*@ requires zero: fail_value(from) == 0;
  94. requires clean: to < sHT_failbit_limit;
  95. terminates \true;
  96. assigns \result \from from, to;
  97. ensures good: good(\result) <==> good(from);
  98. ensures val: fail_value(\result) == fail_value(to); */
  99. static inline size_t
  100. sHT_transfer_failbit_novalue(size_t from, size_t to)
  101. {
  102. return from + to;
  103. }
  104. /** Fail machine `m` if `c` */
  105. /*@ requires m_rw: \valid(m);
  106. requires m_s: \initialized(m);
  107. terminates \true;
  108. assigns *m \from \old(*m), r;
  109. ensures good: good(*m) <==> good(\old(*m)) && !r;
  110. ensures val: fail_value(*m) == fail_value(\old(*m)); */
  111. __attribute__((always_inline))
  112. static inline void
  113. sHT_fail_if(size_t *m, _Bool r)
  114. {
  115. /* TODO: this requires checking the machine code
  116. for branches! */
  117. *m |= r ? sHT_failbit_limit : 0;
  118. }
  119. #endif