| 1373 | } |
| 1374 | |
| 1375 | void Memory::record_store(const Pointer &p, const smt::expr &bytes) { |
| 1376 | assert(has_initializes_attr); |
| 1377 | |
| 1378 | auto is_local = p.isLocal(); |
| 1379 | if (is_local.isTrue()) |
| 1380 | return; |
| 1381 | |
| 1382 | unsigned bytes_per_byte = bits_byte / 8; |
| 1383 | expr bid = p.getShortBid(); |
| 1384 | expr offset = p.getShortOffset(); |
| 1385 | uint64_t bytes_i; |
| 1386 | if (bytes.isUInt(bytes_i) && (bytes_i / bytes_per_byte) <= 8) { |
| 1387 | for (uint64_t off = 0; off < (bytes_i / bytes_per_byte); ++off) { |
| 1388 | expr off_expr = expr::mkUInt(off, offset); |
| 1389 | has_stored_arg |
| 1390 | = expr::mkIf(is_local, |
| 1391 | has_stored_arg, |
| 1392 | has_stored_arg.store(bid.concat(offset + off_expr), true)); |
| 1393 | } |
| 1394 | } else { |
| 1395 | expr var = expr::mkQVar(0, bid.concat(offset)); |
| 1396 | expr var_bid = var.extract(var.bits()-1, offset.bits()); |
| 1397 | expr var_off = var.trunc(offset.bits()); |
| 1398 | |
| 1399 | expr bytes_div = bytes.zextOrTrunc(offset.bits()) |
| 1400 | .udiv(expr::mkUInt(bytes_per_byte, bytes)); |
| 1401 | has_stored_arg |
| 1402 | = expr::mkIf(is_local, |
| 1403 | has_stored_arg, |
| 1404 | expr::mkLambda(var, "#bid_off", |
| 1405 | (bid == var_bid && |
| 1406 | var_off.uge(offset) && |
| 1407 | var_off.ult(offset + bytes_div)) || |
| 1408 | has_stored_arg.load(var))); |
| 1409 | } |
| 1410 | } |
| 1411 | |
| 1412 | static bool memory_unused() { |
| 1413 | return num_locals_src == 0 && num_locals_tgt == 0 && num_nonlocals == 0; |
no test coverage detected