| 1432 | } |
| 1433 | |
| 1434 | expr Memory::mkSubByteZExtStoreCond(const Byte &val, const Byte &val2) const { |
| 1435 | bool mk_axiom = &val == &val2; |
| 1436 | |
| 1437 | // optimization: the initial block is assumed to follow the ABI already. |
| 1438 | if (!mk_axiom && isInitialMemBlock(val.p, true)) |
| 1439 | return true; |
| 1440 | |
| 1441 | bool always_1_byte = bits_byte >= (1u << num_sub_byte_bits); |
| 1442 | auto stored_bits = val.numStoredBits(); |
| 1443 | auto num_bytes |
| 1444 | = always_1_byte ? expr::mkUInt(0, size_byte_number()) |
| 1445 | : stored_bits.udiv(expr::mkUInt(bits_byte, stored_bits)) |
| 1446 | .zextOrTrunc(size_byte_number()); |
| 1447 | auto leftover_bits |
| 1448 | = (always_1_byte ? stored_bits |
| 1449 | : stored_bits.urem(expr::mkUInt(bits_byte, stored_bits)) |
| 1450 | ).zextOrTrunc(bits_byte); |
| 1451 | |
| 1452 | return val.isPtr() || |
| 1453 | (mk_axiom ? expr(false) : !val.boolNonptrNonpoison()) || |
| 1454 | stored_bits == 0 || |
| 1455 | val.byteNumber() != num_bytes || |
| 1456 | val2.nonptrValue().lshr(leftover_bits) == 0; |
| 1457 | } |
| 1458 | |
| 1459 | void Memory::mkNonlocalValAxioms(const expr &block) const { |
| 1460 | expr offset = expr::mkQVar(0, Pointer::bitsShortOffset()); |
nothing calls this directly
no test coverage detected