smt2: flatten FPA-encoded floats to their IEEE bit pattern#9031
smt2: flatten FPA-encoded floats to their IEEE bit pattern#9031tautschnig wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR updates smt2_convt::flatten2bv to support flattening floatbv expressions when using the SMT-LIB FloatingPoint (FPA) theory, addressing crashes when a program type-puns floats (e.g., union/byte-access to read IEEE bit patterns) under --smt2 --fpa.
Changes:
- Add an FPA-specific
flatten2bvpath forfloatbvthat can emit IEEE bit-pattern bit-vectors for float constants. - Recognize and flatten the common “bit-pattern reinterpret” shape
(float)bitsby emitting the underlying same-width bit-vector operand. - Replace the previous blanket
!use_FPA_theoryinvariant with a narrower “unsupported shape” failure for non-constant, non-reinterpret FPA floats.
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## develop #9031 +/- ##
========================================
Coverage 80.60% 80.60%
========================================
Files 1711 1711
Lines 189466 189515 +49
Branches 73 73
========================================
+ Hits 152719 152762 +43
- Misses 36747 36753 +6 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
smt2_convt::flatten2bv is reached when a value has to be turned into a
plain bit-vector, e.g. at a union/byte-access (type-punning) boundary.
For a floatbv operand encoded with the SMT-LIB FloatingPoint theory it
previously asserted !use_FPA_theory and gave up, because that theory has
no float-to-bit-vector operation. As a result any program that reads
the raw bytes of an FPA-encoded float under an FPA solver (--cprover-smt2,
or --z3/--cvc5/--bitwuzla with --fpa) hit an invariant violation -- for
example reading a double's bit pattern via a union { double d; uint64_t i; }.
Two shapes cover the cases that actually arise from type-punning, and
both are emitted without needing a float-to-bit-vector operation:
- a constant: the IEEE interchange bit pattern is exactly the value's
bit-vector representation, so it is emitted as a literal bit-vector;
- a bit-pattern reinterpret (float)bits (a typecast from a same-width
generic bit-vector, as produced when lowering byte operators):
flattening recovers precisely those bits, i.e. the typecast operand.
A non-constant FPA float that is not such a reinterpret would require the
bvfromfloat round-trip (a fresh bit-vector b with to_fp(b) = x), which
has to be registered by find_symbols; that case does not arise from the
byte-/union-lowering paths and is left as a clearly-reported unsupported
case rather than the previous blanket invariant.
SAT mode is unaffected: use_FPA_theory is false there, so the existing
convert_expr(expr) path is taken unchanged.
CI coverage of both new branches is provided by two unit tests in
unit/solvers/smt2/smt2_conv.cpp that drive flatten2bv directly under
solvert::CPROVER_SMT2 (use_FPA_theory == true) -- one with an
FPA-encoded `double` constant, and one with a `(double)<bv64>`
reinterpret typecast. Both unit tests SIGABRT on the previous
invariant if the fix is reverted. The companion regression test under
regression/cbmc/union-double-bits-fpa/ documents the user-visible
union-based scenario; CPROVER's in-tree SMT2 solver does not fully
support the SMT-LIB FloatingPoint theory beyond constant folding, so
that test is tagged `broken-cprover-smt-backend`, but it has been
manually confirmed that with the new flatten2bv emission the formula
is solver-compatible under `--z3 --fpa`.
Co-authored-by: Kiro <kiro-agent@users.noreply.github.com>
|
Can this be generalised beyond constants by using the FPA to bit vector conversion operator? |
The general case is already handled via If we want to handle some future scenario where such a non-constant conversion would not be subject to |
smt2_convt::flatten2bv is reached when a value has to be turned into a plain bit-vector, e.g. at a union/byte-access (type-punning) boundary. For a floatbv operand encoded with the SMT-LIB FloatingPoint theory it previously asserted !use_FPA_theory and gave up, because that theory has no float-to-bit-vector operation. As a result any program that reads the raw bytes of an FPA-encoded float under an FPA solver (--cprover-smt2, or --z3/--cvc5/--bitwuzla with --fpa) hit an invariant violation -- for example reading a double's bit pattern via a union { double d; uint64_t i; }.
Two shapes cover the cases that actually arise from type-punning, and both are emitted without needing a float-to-bit-vector operation:
A non-constant FPA float that is not such a reinterpret would require the bvfromfloat round-trip (a fresh bit-vector b with to_fp(b) = x), which has to be registered by find_symbols; that case does not arise from the byte-/union-lowering paths and is left as a clearly-reported unsupported case rather than the previous blanket invariant.
SAT mode is unaffected: use_FPA_theory is false there, so the existing convert_expr(expr) path is taken unchanged.