| 1225 | } |
| 1226 | |
| 1227 | void Memory::store(const Pointer &ptr, |
| 1228 | const vector<pair<unsigned, expr>> &data, |
| 1229 | const set<expr> &undef, uint64_t align) { |
| 1230 | if (data.empty()) |
| 1231 | return; |
| 1232 | |
| 1233 | for (auto &[offset, val] : data) { |
| 1234 | Byte byte(*this, expr(val)); |
| 1235 | escapeLocalPtr(byte.ptrValue(), byte.isPtr() && byte.ptrNonpoison()); |
| 1236 | } |
| 1237 | |
| 1238 | unsigned bytes = data.size() * (bits_byte/8); |
| 1239 | |
| 1240 | auto stored_ty = data_type(data, false); |
| 1241 | auto stored_ty_full = data_type(data, true); |
| 1242 | |
| 1243 | auto fn = [&](MemBlock &blk, const Pointer &ptr, unsigned bid, bool local, |
| 1244 | expr &&cond) { |
| 1245 | auto mem = blk.val; |
| 1246 | |
| 1247 | uint64_t blk_size; |
| 1248 | bool full_write |
| 1249 | = ptr.blockSizeAligned().isUInt(blk_size) && blk_size == bytes; |
| 1250 | |
| 1251 | // optimization: if fully rewriting the block, don't bother with the old |
| 1252 | // contents. Pick a value as the default one. |
| 1253 | // If we are initializing const globals, the size may be larger than the |
| 1254 | // init because the size is rounded up to the alignment. |
| 1255 | // The remaining bytes are poison. |
| 1256 | if (full_write || state->isInitializationPhase()) { |
| 1257 | // optimization: if the access size == byte size, then we don't store |
| 1258 | // data as arrays, but simply as a BV |
| 1259 | if (data.size() == 1) { |
| 1260 | mem = data[0].second; |
| 1261 | } else { |
| 1262 | mem = full_write ? data[0].second : Byte::mkPoisonByte(*this)(); |
| 1263 | } |
| 1264 | if (cond.isTrue()) { |
| 1265 | blk.undef.clear(); |
| 1266 | blk.type = stored_ty_full; |
| 1267 | } else { |
| 1268 | blk.type |= stored_ty_full; |
| 1269 | } |
| 1270 | } else { |
| 1271 | blk.type |= stored_ty; |
| 1272 | } |
| 1273 | |
| 1274 | expr offset = ptr.getShortOffset(); |
| 1275 | |
| 1276 | for (auto &[idx, val] : data) { |
| 1277 | expr off |
| 1278 | = offset + expr::mkUInt(idx >> Pointer::zeroBitsShortOffset(), offset); |
| 1279 | if (!local) |
| 1280 | record_stored_pointer(bid, off); |
| 1281 | |
| 1282 | if (full_write && val.eq(data[0].second)) |
| 1283 | continue; |
| 1284 | mem = mk_store(std::move(mem), off, val); |
no test coverage detected