arithmetic.h 1.4 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253
  1. // SPDX-License-Identifier: GPL-2.0 or GPL-3.0
  2. // Copyright © 2019 Ariadne Devos
  3. #ifndef _sHT_LOGIC_ARITHMETIC
  4. #define _sHT_LOGIC_ARITHMETIC
  5. #include <stdint.h>
  6. #include <sHT/logic/failbit.h>
  7. /** Non-overflowing integer multiply-add */
  8. /*@ requires NS ==> a * b + c <= UINT32_MAX;
  9. terminates \true;
  10. assigns \result \from a, b, c;
  11. ensures NS ==> \result == a * b + c; */
  12. static inline uint32_t
  13. sHT_muladd_nooverflowNS_u32(uint32_t a, uint32_t b, uint32_t c)
  14. {
  15. return a * b + c;
  16. }
  17. /** The variable really is in ℕ (for proofs), but
  18. the range supported by the computer is limited.
  19. The actual value the code sees may wrap-around,
  20. so that must always be checked -- with the following
  21. functions. */
  22. #define sHT_overflowing
  23. /** Calculate a * b + c, tracking overflow
  24. (a, b, c : T, ret : T *, T ⊂ ℕ)
  25. Requires:
  26. - good(*m) <-> { a, b, c } ⊂ \bounds(T)
  27. - (read ^ write) (*ret)
  28. - (read ^ write ^ set) (*mask)
  29. Invariant:
  30. - failvalue(*m)
  31. Ensures:
  32. - good(*m) := good(old *m) ^ (a * b + c ∈ \bounds(T))
  33. - ret = a * b + c */
  34. #define sHT_muladd_overflow(T, ret, a, b, c, m) \
  35. do { \
  36. /* Computation is correct, failure is always maintained,
  37. a, b and c are non-negative so failure is set on overflow. */ \
  38. sHT_fail_if((m), __builtin_mul_overflow((a), (b), (ret))); \
  39. sHT_fail_if((m), __builtin_add_overflow(*(ret), (c), (ret))); \
  40. } while (0)
  41. #endif