| 2093 | } |
| 2094 | |
| 2095 | void Memory::mkLocalDisjAddrAxioms(const expr &allocated, const expr &short_bid, |
| 2096 | const expr &size, const expr &align, |
| 2097 | unsigned align_bits) { |
| 2098 | if (!observesAddresses()) |
| 2099 | return; |
| 2100 | |
| 2101 | unsigned var_bw = bits_ptr_address - align_bits - Pointer::hasLocalBit(); |
| 2102 | auto addr_var = expr::mkFreshVar("local_addr", expr::mkUInt(0, var_bw)); |
| 2103 | state->addQuantVar(addr_var); |
| 2104 | |
| 2105 | if (!Pointer::hasLocalBit()) |
| 2106 | state->addPre(addr_var != 0); |
| 2107 | |
| 2108 | expr blk_addr = addr_var.concat_zeros(align_bits); |
| 2109 | expr full_addr = Pointer::hasLocalBit() |
| 2110 | ? expr::mkUInt(1, 1).concat(blk_addr) : blk_addr; |
| 2111 | |
| 2112 | if (align_bits == 0) { |
| 2113 | auto shift = expr::mkUInt(bits_ptr_address, full_addr) - |
| 2114 | align.zextOrTrunc(bits_ptr_address); |
| 2115 | state->addPre((full_addr << shift) == 0); |
| 2116 | } |
| 2117 | |
| 2118 | // addr + size only overflows for one case when obj is aligned |
| 2119 | expr no_ovfl; |
| 2120 | if (size.ule(align.zextOrTrunc(bits_size_t)).isTrue()) |
| 2121 | no_ovfl = addr_var != expr::mkInt(-1, addr_var); |
| 2122 | else |
| 2123 | no_ovfl |
| 2124 | = blk_addr.add_no_uoverflow( |
| 2125 | size.zextOrTrunc(bits_ptr_address - Pointer::hasLocalBit())); |
| 2126 | state->addPre(allocated.implies(no_ovfl)); |
| 2127 | |
| 2128 | // Disjointness of block's address range with other local blocks |
| 2129 | state->addPre( |
| 2130 | allocated.implies( |
| 2131 | disjoint_local_blocks(*this, full_addr, |
| 2132 | size.zextOrTrunc(bits_ptr_address), |
| 2133 | align, local_blk_addr))); |
| 2134 | |
| 2135 | local_blk_addr.add(short_bid, std::move(blk_addr)); |
| 2136 | } |
| 2137 | |
| 2138 | pair<expr, expr> |
| 2139 | Memory::alloc(const expr *size, uint64_t align, BlockKind blockKind, |
nothing calls this directly
no test coverage detected