Merge pull request #5934 from Plagman/plagman/multi_key_drifting_mr

DiskCache: support multiple entries per lookup key
This commit is contained in:
Ryan Houdek authored and GitHub committed 2026-09-07 23:38:31 -07:00
commit 566a5e266d
104 files changed
+359 -250

No files matched your search

+246 -139
View File
@@ -16,7 +16,6 @@
#include "FEXCore/fextl/memory.h"
#include <cstdint>
#include <cstring>
#include <charconv>
#include <atomic>
namespace FEXCore {
@@ -44,6 +43,13 @@ namespace DiskCache {
} // namespace MesaFOZ
struct __attribute__((packed)) IndexExtraBlobHeader {
XXH128_hash_t GuestHash; // StoreCacheBlob will assume it's here, care if moving
uint64_t GuestFootprint;
uint32_t GuestSize;
uint32_t GuestExtentsCount;
};
static FileMapperFunc FileMapper = nullptr;
bool FOZFile::Open(const fextl::string& FOZFileName, bool ReadOnly) {
@@ -220,31 +226,29 @@ namespace DiskCache {
const auto* GuestExtents = reinterpret_cast<const uint32_t*>(IndexDataStart + ReadOffset);
ReadOffset += IndexBlobExtra->GuestExtentsCount * sizeof(uint32_t);
if (FOZKey->bytes[39] != 0xFF) {
uint64_t Key;
std::from_chars(reinterpret_cast<const char*>(FOZKey->bytes), reinterpret_cast<const char*>(&FOZKey->bytes[16]), Key, 16);
if (IndexBlobCommon->hash != Key) {
continue;
}
IndexEntry NewEntry {this, IndexBlobCommon->cache_db_file_offset, IndexBlobCommon->size, IndexBlobExtra->GuestSize,
IndexBlobExtra->GuestHash};
if (IndexBlobExtra->GuestExtentsCount) {
NewEntry.GuestExtents.resize(IndexBlobExtra->GuestExtentsCount);
memcpy(NewEntry.GuestExtents.data(), GuestExtents, IndexBlobExtra->GuestExtentsCount * sizeof(uint32_t));
bool ExtentsValid = true;
for (uint32_t i = 0; i < NewEntry.GuestExtents.size(); i += 2) {
if ((uint64_t)NewEntry.GuestExtents[i] + NewEntry.GuestExtents[i + 1] > IndexBlobExtra->GuestSize) {
ExtentsValid = false;
break;
}
NewEntry.GuestExtents.resize(IndexBlobExtra->GuestExtentsCount);
memcpy(NewEntry.GuestExtents.data(), GuestExtents, IndexBlobExtra->GuestExtentsCount * sizeof(uint32_t));
bool ExtentsValid = true;
for (uint32_t i = 0; i < NewEntry.GuestExtents.size(); i += 2) {
if ((uint64_t)NewEntry.GuestExtents[i] + NewEntry.GuestExtents[i + 1] > IndexBlobExtra->GuestSize) {
ExtentsValid = false;
break;
}
if (!ExtentsValid) {
continue;
}
} else {
NewEntry.GuestExtents.push_back(0);
NewEntry.GuestExtents.push_back(IndexBlobExtra->GuestSize);
}
CacheIndex.insert({IndexBlobCommon->hash, {std::move(NewEntry)}});
if (!ExtentsValid) {
continue;
}
auto It = CacheIndex.find(IndexBlobCommon->hash);
if (It == CacheIndex.end()) {
CacheIndex.emplace(IndexBlobCommon->hash, IndexCacheHead {std::move(NewEntry), IndexBlobExtra->GuestFootprint, nullptr});
} else {
if (!It->second.MoreEntries.get()) {
It->second.MoreEntries = fextl::make_unique<fextl::multimap<uint64_t, IndexEntry>>();
}
It->second.MoreEntries->insert({IndexBlobExtra->GuestFootprint, std::move(NewEntry)});
}
} else {
FoundMetadata = true;
}
@@ -265,24 +269,36 @@ namespace DiskCache {
}
}
bool IndexedDB::StoreCacheBlob(const MesaFOZ::foz_payload_key& Key, std::span<const uint8_t> Blob, Index& Index, std::mutex& IndexMutex,
std::span<const uint8_t> IndexBlob) {
bool IndexedDB::StoreCacheBlob(const MesaFOZ::foz_payload_key& UniqueKey, uint64_t LookupKey, std::span<const uint8_t> Blob, Index& Index,
std::mutex& IndexMutex, std::span<const uint8_t> IndexBlob) {
if (ReadOnly) {
// shouldn't happen
return false;
}
uint64_t Hash;
if (Key.bytes[39] != 0xFF) {
std::from_chars(reinterpret_cast<const char*>(Key.bytes), reinterpret_cast<const char*>(&Key.bytes[16]), Hash, 16);
} else {
Hash = ~0;
}
{
std::lock_guard Guard(IndexMutex);
if (Index.contains(Hash)) {
// LogMan::Msg::IFmt("duplicate store {}", Hash);
// shouldn't really happen.. assert or something?
return true;
auto IndexIt = Index.find(LookupKey);
bool Dupe = false;
if (IndexIt != Index.end()) {
if (IndexIt->second.MoreEntries.get()) {
for (auto& [Key, Elem] : *IndexIt->second.MoreEntries) {
if (XXH128_isEqual(Elem.GuestHash, *(const XXH128_hash_t*)(IndexBlob.data()))) {
Dupe = true;
break;
}
}
}
if (!Dupe && XXH128_isEqual(IndexIt->second.MainEntry.GuestHash, *(const XXH128_hash_t*)(IndexBlob.data()))) {
Dupe = true;
}
// could happen if it's seen again while in flight in the store queue
if (Dupe) {
return true;
}
if (IndexIt->second.MoreEntries.get() && IndexIt->second.MoreEntries->size() >= LOOKUP_KEY_MAX_BUCKET_DEPTH) {
return true;
}
}
}
@@ -295,13 +311,13 @@ namespace DiskCache {
// write cache side first so we get offset for index
std::span<const uint8_t> BlobChunks[] = {Blob};
uint64_t BlobOffset = 0;
if (!CacheFOZ.WriteBlob(Key, BlobChunks, BlobOffset)) {
if (!CacheFOZ.WriteBlob(UniqueKey, BlobChunks, BlobOffset)) {
CacheFOZ.Unlock();
IndexFOZ.Unlock();
return false;
}
MesaFOZ::mesa_index_db_file_entry IndexEntry {.hash = Hash,
MesaFOZ::mesa_index_db_file_entry IndexEntry {.hash = LookupKey,
.size = (uint32_t)Blob.size(),
.last_access_time = 0, // todo..
.cache_db_file_offset = BlobOffset};
@@ -311,7 +327,7 @@ namespace DiskCache {
IndexBlob,
};
uint64_t UnusedIndexBlobOffset = 0;
if (!IndexFOZ.WriteBlob(Key, IndexBlobChunks, UnusedIndexBlobOffset)) {
if (!IndexFOZ.WriteBlob(UniqueKey, IndexBlobChunks, UnusedIndexBlobOffset)) {
CacheFOZ.Unlock();
IndexFOZ.Unlock();
return false;
@@ -328,16 +344,19 @@ namespace DiskCache {
const IndexExtraBlobHeader* IndexBlobHeader = reinterpret_cast<const IndexExtraBlobHeader*>(IndexBlob.data());
struct IndexEntry NewEntry {this, BlobOffset, (uint32_t)Blob.size(), IndexBlobHeader->GuestSize, IndexBlobHeader->GuestHash};
if (IndexBlobHeader->GuestExtentsCount) {
NewEntry.GuestExtents.resize(IndexBlobHeader->GuestExtentsCount);
memcpy(NewEntry.GuestExtents.data(), reinterpret_cast<const uint32_t*>(IndexBlob.data() + sizeof(IndexExtraBlobHeader)),
IndexBlobHeader->GuestExtentsCount * sizeof(uint32_t));
} else {
NewEntry.GuestExtents.push_back(0);
NewEntry.GuestExtents.push_back(IndexBlobHeader->GuestSize);
}
NewEntry.GuestExtents.resize(IndexBlobHeader->GuestExtentsCount);
memcpy(NewEntry.GuestExtents.data(), reinterpret_cast<const uint32_t*>(IndexBlob.data() + sizeof(IndexExtraBlobHeader)),
IndexBlobHeader->GuestExtentsCount * sizeof(uint32_t));
std::lock_guard Guard(IndexMutex);
Index.insert_or_assign(Hash, std::move(NewEntry));
auto It = Index.find(LookupKey);
if (It == Index.end()) {
Index.emplace(LookupKey, IndexCacheHead {std::move(NewEntry), IndexBlobHeader->GuestFootprint, nullptr});
} else {
if (!It->second.MoreEntries.get()) {
It->second.MoreEntries = fextl::make_unique<fextl::multimap<uint64_t, struct IndexEntry>>();
}
It->second.MoreEntries->insert({IndexBlobHeader->GuestFootprint, std::move(NewEntry)});
}
return true;
}
@@ -414,9 +433,9 @@ namespace DiskCache {
MesaFOZ::foz_payload_key MetadataKey;
memset(MetadataKey.bytes, 0xFF, sizeof(MetadataKey));
IndexExtraBlobHeader MetaDataHeader = {};
RWCacheDB->StoreCacheBlob(MetadataKey, {BucketBytes.data(), BucketBytes.size()}, Index, IndexLock,
RWCacheDB->StoreCacheBlob(MetadataKey, ~0, {BucketBytes.data(), BucketBytes.size()}, Index, IndexLock,
{reinterpret_cast<uint8_t*>(&MetaDataHeader), sizeof(MetaDataHeader)});
Index.clear();
Index.erase(~0);
}
std::string_view RONames = RODBNames();
@@ -444,7 +463,7 @@ namespace DiskCache {
}
}
uint64_t DiskCache::MakeBlobKey(Core::InternalThreadState* Thread, const uint64_t CodeKey, bool Writable, bool MonoBackpatcher) {
uint64_t DiskCache::MakeLookupKey(Core::InternalThreadState* Thread, const uint64_t CodeKey, bool Writable, bool MonoBackpatcher) {
struct __attribute__((packed)) {
uint64_t CodeKey;
XXH128_hash_t BucketHash;
@@ -510,45 +529,161 @@ namespace DiskCache {
}
auto RangeInfo = CTX->SyscallHandler->QueryGuestExecutableRange(Thread, GuestRIP);
uint64_t Hash =
MakeBlobKey(Thread, *GuestCodeKey, RangeInfo.Writable, GuestRIP == CTX->GetMonoBackPatcherBlock().load(std::memory_order_relaxed));
IndexEntry Entry;
{
std::lock_guard Guard(IndexLock);
auto It = Index.find(Hash);
if (It == Index.end()) {
// definite miss
return std::nullopt;
}
// we can't hold onto the iterator, the map may shift while we don't hold the lock
Entry = It->second;
}
// found a key hash match, could still be a miss, check guest hash
// do we have enough room in our live code to even hash GuestSize worth?
if (RangeInfo.Size == 0 || RangeInfo.Base > GuestRIP) {
return std::nullopt;
}
uint64_t Available = RangeInfo.Base + RangeInfo.Size - GuestRIP;
if (Available < Entry.GuestSize) {
uint64_t LookupKey =
MakeLookupKey(Thread, *GuestCodeKey, RangeInfo.Writable, GuestRIP == CTX->GetMonoBackPatcherBlock().load(std::memory_order_relaxed));
XXH128_hash_t LiveGuestHash;
uint64_t LastFootprintHashed = 0;
bool FirstHash = true; // 0 is probably a valid footprint hash so we need an extra bit there
bool TriedMainEntry = false;
IndexEntry MainEntry;
uint64_t MainEntryFootprint;
fextl::multimap<uint64_t, IndexEntry>::iterator MoreEntriesIt;
fextl::multimap<uint64_t, IndexEntry>* MapPointer = nullptr;
IndexEntry* EntryUnderReview;
uint64_t CurrentFootprint = 0;
{
std::lock_guard Guard(IndexLock);
auto It = Index.find(LookupKey);
if (It == Index.end()) {
// definite miss
return std::nullopt;
}
MainEntry = It->second.MainEntry;
MainEntryFootprint = It->second.MainEntryFootprint;
MapPointer = It->second.MoreEntries.get();
if (MapPointer) {
MoreEntriesIt = It->second.MoreEntries->begin();
}
if (MapPointer && MoreEntriesIt != It->second.MoreEntries->end()) {
EntryUnderReview = &MoreEntriesIt->second;
CurrentFootprint = MoreEntriesIt->first;
} else {
EntryUnderReview = &MainEntry;
CurrentFootprint = MainEntryFootprint;
TriedMainEntry = true;
}
}
// found a lookup key match, check for guest hash match now
bool FoundMatchingHash = false;
bool Advance = false;
while (!FoundMatchingHash) {
if (Advance) {
std::lock_guard Guard(IndexLock);
EntryUnderReview = nullptr;
if (MapPointer && MoreEntriesIt != MapPointer->end()) {
// if the current footprint is also the main entry's footprint, give main entry a shot next
if (!TriedMainEntry && MoreEntriesIt->first == MainEntryFootprint) {
EntryUnderReview = &MainEntry;
CurrentFootprint = MainEntryFootprint;
TriedMainEntry = true;
} else {
MoreEntriesIt++;
}
}
if (!MapPointer || MoreEntriesIt == MapPointer->end()) {
if (TriedMainEntry) {
// ran out
break;
} else {
EntryUnderReview = &MainEntry;
CurrentFootprint = MainEntryFootprint;
TriedMainEntry = true;
}
}
if (!EntryUnderReview && MapPointer && MoreEntriesIt != MapPointer->end()) {
EntryUnderReview = &MoreEntriesIt->second;
CurrentFootprint = MoreEntriesIt->first;
}
}
Advance = true;
// do we have enough room in our live code to even hash GuestSize worth?
if (Available < EntryUnderReview->GuestSize) {
continue;
}
// if (Entry.GuestExtents.size()) {
// LogMan::Msg::IFmt("lookup! length {:d}", Entry.GuestSize);
// for(uint32_t i = 0; i < Entry.GuestExtents.size(); i+=2 ) {
// LogMan::Msg::IFmt("extent {} {}", Entry.GuestExtents[i], Entry.GuestExtents[i]+Entry.GuestExtents[i+1]);
// }
// }
{
IndexEntry& Entry = *EntryUnderReview;
// only renew the hash if the candidate footprint is different than previous
if (FirstHash || LastFootprintHashed != CurrentFootprint) {
XXH3_state_t HashState;
XXH3_128bits_reset(&HashState);
for (uint32_t i = 0; i < Entry.GuestExtents.size(); i += 2) {
XXH3_128bits_update(&HashState, reinterpret_cast<uint8_t*>(GuestRIP) + Entry.GuestExtents[i], Entry.GuestExtents[i + 1]);
}
LiveGuestHash = XXH3_128bits_digest(&HashState);
LastFootprintHashed = CurrentFootprint;
FirstHash = false;
}
if (XXH128_isEqual(LiveGuestHash, Entry.GuestHash)) {
FoundMatchingHash = true;
break;
} else if (Validation) {
fextl::vector<uint8_t> GuestCode(Entry.GuestSize);
if (Entry.Size >= Entry.GuestSize && Entry.DB->ReadCacheBlob(Entry.Offset + Entry.Size - Entry.GuestSize, GuestCode)) {
const uint8_t* CachedGuest = GuestCode.data();
const uint8_t* LiveGuest = reinterpret_cast<const uint8_t*>(GuestRIP);
uint64_t DiffCount = 0;
uint64_t DiffOffset = 0;
for (uint32_t i = 0; i < Entry.GuestExtents.size(); i += 2) {
uint32_t Begin = Entry.GuestExtents[i];
uint32_t End = Begin + Entry.GuestExtents[i + 1];
bool PreviousByteDiff = false;
for (uint32_t Offset = Begin; Offset < End; Offset++) {
if (LiveGuest[Offset] != CachedGuest[Offset]) {
if (DiffCount == 0) {
DiffOffset = Offset;
}
if (!PreviousByteDiff) {
DiffCount++;
}
PreviousByteDiff = true;
} else {
PreviousByteDiff = false;
}
}
}
if (DiffCount) {
uint64_t DiffStart = DiffOffset >= 8 ? DiffOffset - 8 : 0;
uint64_t DiffContextBytes = std::min<uint64_t>(16, Entry.GuestSize - DiffStart);
auto LiveDump = fmt::join(std::span<const uint8_t> {LiveGuest + DiffStart, DiffContextBytes}, " ");
auto CacheDump = fmt::join(std::span<const uint8_t> {CachedGuest + DiffStart, DiffContextBytes}, " ");
auto KeyPrefix = (Region && Region->FileStartVA) ? "file" : "anon";
LogMan::Msg::IFmt("DiskCache: lookup guest hash mismatch key={}-{:x} gsize={}, ndiff={}, first diff: offset={} "
"live=[{:02x}] "
"cached=[{:02x}]",
KeyPrefix, *GuestCodeKey, Entry.GuestSize, DiffCount, DiffOffset, LiveDump, CacheDump);
} else {
LogMan::Msg::IFmt("DiskCache: guest hash mismatch but no diff?");
}
}
}
}
}
if (!FoundMatchingHash || !EntryUnderReview) {
return std::nullopt;
}
XXH128_hash_t LiveGuestHash;
IndexEntry& Entry = *EntryUnderReview;
// if (Entry.GuestExtents.size()) {
// LogMan::Msg::IFmt("lookup! length {:d}", Entry.GuestSize);
// for(uint32_t i = 0; i < Entry.GuestExtents.size(); i+=2 ) {
// LogMan::Msg::IFmt("extent {} {}", Entry.GuestExtents[i], Entry.GuestExtents[i]+Entry.GuestExtents[i+1]);
// }
// }
fextl::vector<uint64_t> GuestPages;
XXH3_state_t HashState;
XXH3_128bits_reset(&HashState);
for (uint32_t i = 0; i < Entry.GuestExtents.size(); i += 2) {
XXH3_128bits_update(&HashState, reinterpret_cast<uint8_t*>(GuestRIP) + Entry.GuestExtents[i], Entry.GuestExtents[i + 1]);
uint64_t FirstPage = (Entry.GuestExtents[i] + GuestRIP) & Utils::FEX_PAGE_MASK;
uint64_t LastPage = (Entry.GuestExtents[i] + GuestRIP + Entry.GuestExtents[i + 1] - 1) & Utils::FEX_PAGE_MASK;
for (uint64_t Page = FirstPage; Page <= LastPage; Page += Utils::FEX_PAGE_SIZE) {
@@ -557,50 +692,6 @@ namespace DiskCache {
}
}
}
LiveGuestHash = XXH3_128bits_digest(&HashState);
if (!XXH128_isEqual(LiveGuestHash, Entry.GuestHash)) {
if (Validation) {
fextl::vector<uint8_t> GuestCode(Entry.GuestSize);
if (Entry.Size >= Entry.GuestSize && Entry.DB->ReadCacheBlob(Entry.Offset + Entry.Size - Entry.GuestSize, GuestCode)) {
const uint8_t* CachedGuest = GuestCode.data();
const uint8_t* LiveGuest = reinterpret_cast<const uint8_t*>(GuestRIP);
uint64_t DiffCount = 0;
uint64_t DiffOffset = 0;
for (uint32_t i = 0; i < Entry.GuestExtents.size(); i += 2) {
uint32_t Begin = Entry.GuestExtents[i];
uint32_t End = Begin + Entry.GuestExtents[i + 1];
bool PreviousByteDiff = false;
for (uint32_t Offset = Begin; Offset < End; Offset++) {
if (LiveGuest[Offset] != CachedGuest[Offset]) {
if (DiffCount == 0) {
DiffOffset = Offset;
}
if (!PreviousByteDiff) {
DiffCount++;
}
PreviousByteDiff = true;
} else {
PreviousByteDiff = false;
}
}
}
if (DiffCount) {
uint64_t DiffStart = DiffOffset >= 8 ? DiffOffset - 8 : 0;
uint64_t DiffContextBytes = std::min<uint64_t>(16, Entry.GuestSize - DiffStart);
auto LiveDump = fmt::join(std::span<const uint8_t> {LiveGuest + DiffStart, DiffContextBytes}, " ");
auto CacheDump = fmt::join(std::span<const uint8_t> {CachedGuest + DiffStart, DiffContextBytes}, " ");
auto KeyPrefix = (Region && Region->FileStartVA) ? "file" : "anon";
LogMan::Msg::IFmt("DiskCache: lookup guest hash mismatch key={}-{:x} gsize={}, ndiff={}, first diff: offset={} live=[{:02x}] "
"cached=[{:02x}]",
KeyPrefix, *GuestCodeKey, Entry.GuestSize, DiffCount, DiffOffset, LiveDump, CacheDump);
} else {
LogMan::Msg::IFmt("DiskCache: guest hash mismatch but no diff?");
}
}
}
return std::nullopt;
}
// this seems to be a full hit, pull from disk and check the entry is big enough to have everything (except GuestCode)
CodeHitData HitData;
@@ -697,18 +788,20 @@ namespace DiskCache {
struct DiskCache::CacheStoreWorkItem final : WorkQueueThread::WorkItem {
DiskCache* Self;
IndexedDB* DB;
MesaFOZ::foz_payload_key Key;
MesaFOZ::foz_payload_key UniqueKey;
uint64_t LookupKey;
fextl::vector<uint8_t> Blob;
fextl::vector<uint8_t> IndexBlob;
CacheStoreWorkItem(DiskCache* Self, IndexedDB* DB, const MesaFOZ::foz_payload_key& Key, fextl::vector<uint8_t>&& Blob,
fextl::vector<uint8_t>&& IndexBlob)
CacheStoreWorkItem(DiskCache* Self, IndexedDB* DB, const MesaFOZ::foz_payload_key& UniqueKey, uint64_t LookupKey,
fextl::vector<uint8_t>&& Blob, fextl::vector<uint8_t>&& IndexBlob)
: Self(Self)
, DB(DB)
, Key(Key)
, UniqueKey(UniqueKey)
, LookupKey(LookupKey)
, Blob(std::move(Blob))
, IndexBlob(std::move(IndexBlob)) {}
void Run() override {
DB->StoreCacheBlob(Key, Blob, Self->Index, Self->IndexLock, IndexBlob);
DB->StoreCacheBlob(UniqueKey, LookupKey, Blob, Self->Index, Self->IndexLock, IndexBlob);
}
};
@@ -790,6 +883,14 @@ namespace DiskCache {
ExactGuestCodeExtents.push_back(CurEndExtent - CurStartExtent);
}
if (ExactGuestCodeExtents.size() == 0) {
ExactGuestCodeExtents.reserve(2);
ExactGuestCodeExtents.push_back(0);
ExactGuestCodeExtents.push_back(GuestCode.size());
}
uint64_t GuestFootprint = XXH3_64bits(ExactGuestCodeExtents.data(), ExactGuestCodeExtents.size() * sizeof(uint32_t));
// if (ExactGuestCodeExtents.size()) {
// LogMan::Msg::IFmt("store! length {:d}", GuestCode.size());
// for(uint32_t i = 0; i < ExactGuestCodeExtents.size(); i+=2 ) {
@@ -813,13 +914,6 @@ namespace DiskCache {
Blob.resize(TotalSize);
uint8_t* BlobData = Blob.data();
auto RangeInfo = CTX->SyscallHandler->QueryGuestExecutableRange(Thread, GuestRIP);
uint64_t BlobKey =
MakeBlobKey(Thread, GuestCodeKey, RangeInfo.Writable, GuestRIP == CTX->GetMonoBackPatcherBlock().load(std::memory_order_relaxed));
MesaFOZ::foz_payload_key Key = {};
fextl::string BlobName = fextl::fmt::format("{:016x}", BlobKey);
memcpy(Key.bytes, BlobName.data(), BlobName.size());
BlobFixedHeader Header {
.GuestSize = (uint32_t)GuestCode.size(),
.HostSize = (uint32_t)CompiledCode.Size,
@@ -828,9 +922,7 @@ namespace DiskCache {
.ThunkRelocCount = ThunkRelocCount,
};
if (ExactGuestCodeExtents.size() == 0) {
Header.GuestHash = XXH3_128bits(GuestCode.data(), GuestCode.size());
} else {
{
XXH3_state_t HashState;
XXH3_128bits_reset(&HashState);
for (uint32_t i = 0; i < ExactGuestCodeExtents.size(); i += 2) {
@@ -925,15 +1017,30 @@ namespace DiskCache {
memcpy(BlobData + GuestCodeOffset, GuestCode.data(), GuestCode.size());
auto RangeInfo = CTX->SyscallHandler->QueryGuestExecutableRange(Thread, GuestRIP);
uint64_t LookupKey =
MakeLookupKey(Thread, GuestCodeKey, RangeInfo.Writable, GuestRIP == CTX->GetMonoBackPatcherBlock().load(std::memory_order_relaxed));
MesaFOZ::foz_payload_key Key = {};
{
XXH3_state_t HashState;
XXH3_128bits_reset(&HashState);
XXH3_128bits_update(&HashState, &Header.GuestHash, sizeof(Header.GuestHash));
XXH3_128bits_update(&HashState, &LookupKey, sizeof(LookupKey));
XXH128_hash_t UniqueKey = XXH3_128bits_digest(&HashState);
fextl::string BlobName = fextl::fmt::format("{:016x}{:016x}", UniqueKey.high64, UniqueKey.low64);
memcpy(Key.bytes, BlobName.data(), BlobName.size());
}
fextl::vector<uint8_t> IndexBlob;
IndexBlob.resize(sizeof(IndexExtraBlobHeader) + ExactGuestCodeExtents.size() * sizeof(uint32_t));
IndexExtraBlobHeader IndexBlobHeader {Header.GuestHash, Header.GuestSize, (uint32_t)ExactGuestCodeExtents.size()};
IndexExtraBlobHeader IndexBlobHeader {Header.GuestHash, GuestFootprint, Header.GuestSize, (uint32_t)ExactGuestCodeExtents.size()};
memcpy(IndexBlob.data(), &IndexBlobHeader, sizeof(IndexExtraBlobHeader));
memcpy(IndexBlob.data() + sizeof(IndexExtraBlobHeader), ExactGuestCodeExtents.data(), ExactGuestCodeExtents.size() * sizeof(uint32_t));
// hand the rest off to the writer thread
Writer->QueueWork(fextl::make_unique<CacheStoreWorkItem>(this, RWCacheDB.get(), Key, std::move(Blob), std::move(IndexBlob)));
Writer->QueueWork(fextl::make_unique<CacheStoreWorkItem>(this, RWCacheDB.get(), Key, LookupKey, std::move(Blob), std::move(IndexBlob)));
return true;
}
+11 -9
View File
@@ -12,6 +12,7 @@
#include <FEXCore/fextl/string.h>
#include <FEXCore/fextl/unordered_set.h>
#include <FEXCore/fextl/robin_map.h>
#include <FEXCore/fextl/map.h>
#include <FEXCore/fextl/vector.h>
#include <stdint.h>
#include <mutex>
@@ -55,10 +56,10 @@ namespace DiskCache {
fextl::vector<uint32_t> GuestExtents;
};
struct __attribute__((packed)) IndexExtraBlobHeader {
XXH128_hash_t GuestHash;
uint32_t GuestSize;
uint32_t GuestExtentsCount;
struct IndexCacheHead {
struct IndexEntry MainEntry;
uint64_t MainEntryFootprint;
fextl::unique_ptr<fextl::multimap<uint64_t, IndexEntry>> MoreEntries; // sorted by guest footprint
};
struct __attribute__((packed)) BlobFixedHeader {
@@ -115,7 +116,7 @@ namespace DiskCache {
CodeHitData& operator=(const CodeHitData&) = delete;
};
using Index = fextl::robin_map<uint64_t, IndexEntry>;
using Index = fextl::robin_map<uint64_t, IndexCacheHead>;
class FOZFile {
public:
@@ -153,13 +154,14 @@ namespace DiskCache {
bool Open(const fextl::string& CacheDBName, bool ReadOnly);
void PopulateIndex(Index& CacheIndex, bool& FoundMetadata);
bool ReadCacheBlob(uint64_t Offset, std::span<uint8_t> OutBlob);
bool StoreCacheBlob(const MesaFOZ::foz_payload_key& Key, std::span<const uint8_t> Blob, Index& CacheIndex, std::mutex& IndexMutex,
std::span<const uint8_t> IndexBlob);
bool StoreCacheBlob(const MesaFOZ::foz_payload_key& UniqueKey, uint64_t LookupKey, std::span<const uint8_t> Blob, Index& CacheIndex,
std::mutex& IndexMutex, std::span<const uint8_t> IndexBlob);
private:
// stores run on the Writer, so returning quick isn't as important
static constexpr uint32_t STORE_LOCK_TIMEOUT_MS = 1000;
static constexpr uint64_t BIG_MAPPING_SIZE = 1ULL << 33;
static constexpr uint32_t LOOKUP_KEY_MAX_BUCKET_DEPTH = 20;
FOZFile CacheFOZ;
uint8_t* CacheFileMapping = nullptr;
@@ -192,7 +194,7 @@ namespace DiskCache {
private:
bool OpenCacheDB(const fextl::string& CacheDBName, bool ReadOnly);
uint64_t MakeBlobKey(Core::InternalThreadState* Thread, const uint64_t ModuleOffset, bool Writable, bool MonoBackpatcher);
uint64_t MakeLookupKey(Core::InternalThreadState* Thread, const uint64_t ModuleOffset, bool Writable, bool MonoBackpatcher);
bool ReadingDiskCache {};
bool WritingDiskCache {};
@@ -221,7 +223,7 @@ namespace DiskCache {
// TODO: This header is in global installed header path, but uses internal headers.
// Migrate this once that is fixed.
static constexpr uint16_t FormatVersion = 18;
static constexpr uint16_t FormatVersion = 19;
FEX_DEFAULT_VISIBILITY uint16_t GetFormatVersion();
} // namespace DiskCache
+1 -1
View File
@@ -8,7 +8,7 @@
"SVE128",
"SVE256"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"roundss xmm0, xmm1, 00000000b": {
@@ -7,7 +7,7 @@
"AFP"
],
"DisabledHostFeatures": [],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"cvtpi2ps xmm0, [rax]": {
@@ -9,7 +9,7 @@
"DisabledHostFeatures": [
"RPRES"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"cvtsi2ss xmm0, eax": {
@@ -7,7 +7,7 @@
"AFP"
],
"DisabledHostFeatures": [],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"cvtsi2sd xmm0, eax": {
@@ -8,7 +8,7 @@
"SVE128",
"SVE256"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"cvtpi2ps xmm0, [rax]": {
@@ -9,7 +9,7 @@
"SVE256",
"RPRES"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"cvtsi2ss xmm0, eax": {
@@ -8,7 +8,7 @@
"SVE128",
"SVE256"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"cvtsi2sd xmm0, eax": {
@@ -9,7 +9,7 @@
"DisabledHostFeatures": [
"RPRES"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"vsqrtss xmm0, xmm1, xmm2": {
@@ -7,7 +7,7 @@
"AFP"
],
"DisabledHostFeatures": [],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"vroundss xmm0, xmm1, 00000000b": {
@@ -7,7 +7,7 @@
"SVE256",
"SVE128"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"vfmaddsubps xmm0, xmm1, xmm2, xmm3": {
@@ -13,7 +13,7 @@
"SVE256",
"SVE128"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"vmovups xmm0, xmm0": {
@@ -9,7 +9,7 @@
"SVE256",
"SVE128"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"vaddsubpd xmm0, xmm1, xmm2": {
@@ -10,7 +10,7 @@
"FLAGM2",
"SVE256"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"vmovntps [rax], xmm0": {
@@ -10,7 +10,7 @@
"SVE128",
"SVE256"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"vucomiss xmm0, xmm1": {
@@ -9,7 +9,7 @@
"SVE128",
"SVE256"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"vpshufb xmm0, xmm1, xmm2": {
@@ -8,7 +8,7 @@
"SVE256",
"SVE128"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"vfmadd132ss xmm0, xmm1, xmm2": {
@@ -10,7 +10,7 @@
"FLAGM2",
"SVE256"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"vmovntdqa xmm0, [rax]": {
@@ -11,7 +11,7 @@
"SVE256",
"SVEBITPERM"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"vtestps xmm0, xmm1": {
@@ -7,7 +7,7 @@
"SVE256",
"SVE128"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"vpermq ymm0, ymm1, 1": {
@@ -8,7 +8,7 @@
"AFP",
"SVE256"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"vblendvps xmm0, xmm1, xmm2, xmm3": {
@@ -9,7 +9,7 @@
"SVE256",
"SVE128"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"vpsrlw xmm0, xmm1, 0": {
+1 -1
View File
@@ -9,7 +9,7 @@
"FLAGM",
"FLAGM2"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"lock add byte [rax], cl": {
@@ -9,7 +9,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"sha1nexte xmm0, xmm1": {
@@ -9,7 +9,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"sha1nexte xmm0, xmm1": {
@@ -9,7 +9,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"pclmulqdq xmm0, xmm1, 00000b": {
+1 -1
View File
@@ -10,7 +10,7 @@
"AFP",
"RPRES"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Comment": [
"These 3DNow! instructions are optimal assuming that FEX doesn't SRA MMX registers",
@@ -8,7 +8,7 @@
"RPRES",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Comment": [
"Instructions that explicitly push against the limits of ARM's loadstore instructions"
@@ -8,7 +8,7 @@
"RPRES",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Comment": [
"Instructions that explicitly push against the limits of ARM's loadstore instructions"
@@ -13,7 +13,7 @@
"RPRES",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Comment": [
"These are instruction combinations that could be more optimal if FEX optimized for them"
@@ -11,7 +11,7 @@
"RPRES",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Comment": [
"These are instruction combinations that could be more optimal if FEX optimized for them"
@@ -9,7 +9,7 @@
"SVE256",
"RPRES"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Comment": [
"These are instruction combinations that could be more optimal if FEX optimized for them"
@@ -14,7 +14,7 @@
"RPRES",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Comment": [
"These are instruction combinations that could be more optimal if FEX optimized for them"
@@ -14,7 +14,7 @@
"RPRES",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Comment": [
"These are instruction combinations that could be more optimal if FEX optimized for them"
@@ -12,7 +12,7 @@
"RPRES",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Comment": [],
"Instructions": {
@@ -10,7 +10,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"lock add byte [rax], cl": {
@@ -9,7 +9,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"Chained add": {
@@ -10,7 +10,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"ptest xmm0, xmm1": {
@@ -10,7 +10,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"The Witcher 3": {
@@ -10,7 +10,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"Sonic Mania movie player": {
@@ -10,7 +10,7 @@
"SVE128",
"SVE256"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"FMOD scalar loop": {
@@ -13,7 +13,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"The Sims 1 hot block": {
@@ -10,7 +10,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"add bl, cl": {
@@ -10,7 +10,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"add al, 1": {
@@ -10,7 +10,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"push es": {
@@ -11,7 +11,7 @@
"RPRES",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"ucomiss xmm0, xmm1": {
@@ -11,7 +11,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"sgdt [rax]": {
@@ -11,7 +11,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"xgetbv": {
@@ -11,7 +11,7 @@
"AFP",
"FCMA"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"ucomisd xmm0, xmm1": {
@@ -12,7 +12,7 @@
"AFP",
"CSSC"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"popcnt ax, bx": {
@@ -12,7 +12,7 @@
"RPRES",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"popcnt ax, bx": {
@@ -12,7 +12,7 @@
"RPRES",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"vucomiss xmm0, xmm1": {
@@ -10,7 +10,7 @@
"AFP",
"SVEBITPERM"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"vtestps xmm0, xmm1": {
@@ -9,7 +9,7 @@
"DisabledHostFeatures": [
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"blsr eax, ebx": {
@@ -10,7 +10,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"Block1": {
@@ -10,7 +10,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"Block1": {
@@ -10,7 +10,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"Block1": {
@@ -10,7 +10,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"Block1": {
+1 -1
View File
@@ -11,7 +11,7 @@
"CSSC",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"fadd dword [rax]": {
@@ -13,7 +13,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"Block1": {
@@ -13,7 +13,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"Block1": {
@@ -13,7 +13,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"Block1": {
@@ -13,7 +13,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"Block1": {
@@ -13,7 +13,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"fadd dword [rax]": {
+1 -1
View File
@@ -10,7 +10,7 @@
"FLAGM2",
"CRYPTO"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"pshufb mm0, mm1": {
+1 -1
View File
@@ -8,7 +8,7 @@
"AFP",
"CRYPTO"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Comment": [
"SSE4.2 string instructions are skipped here.",
@@ -8,7 +8,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"dpps xmm0, xmm1, 00000000b": {
@@ -11,7 +11,7 @@
"FLAGM",
"FLAGM2"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"rep movsb": {
+1 -1
View File
@@ -10,7 +10,7 @@
"FLAGM2",
"MOPS"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"add bl, cl": {
@@ -9,7 +9,7 @@
"FLAGM",
"FLAGM2"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Comment": [
"Instructions in this table that are marked optimal don't have their flag calculation part of this assumption",
@@ -9,7 +9,7 @@
"FlagM",
"FlagM2"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"push es": {
+1 -1
View File
@@ -9,7 +9,7 @@
"SVE128",
"SVE256"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"pfrcpv mm0, mm1": {
@@ -9,7 +9,7 @@
"SVE128",
"SVE256"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"rsqrtps xmm0, xmm1": {
@@ -9,7 +9,7 @@
"SVE128",
"SVE256"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"rsqrtss xmm0, xmm1": {
@@ -8,7 +8,7 @@
"AFP"
],
"DisabledHostFeatures": [],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"vrsqrtps xmm0, xmm1": {
+1 -1
View File
@@ -6,7 +6,7 @@
"SVE128",
"SVE256"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {}
}
@@ -33,7 +33,7 @@
" - 1b: ECX = MSB",
"[7] - Reserved"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"pcmpestrm xmm0, xmm1, 0_0_00_00_00b": {
+1 -1
View File
@@ -12,7 +12,7 @@
"FLAGM",
"FLAGM2"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Comment": [
"MMX instructions are defined as optimal without SRA being used for these instructions.",
@@ -11,7 +11,7 @@
"FLAGM",
"FLAGM2"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"sgdt [rax]": {
@@ -11,7 +11,7 @@
"FLAGM",
"FLAGM2"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"xgetbv": {
@@ -7,7 +7,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"push fs": {
@@ -12,7 +12,7 @@
"FLAGM",
"FLAGM2"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"movupd xmm0, xmm0": {
@@ -9,7 +9,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"addsubpd xmm0, xmm1": {
@@ -8,7 +8,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"psrlw xmm0, xmm1": {
@@ -7,7 +7,7 @@
"AFP"
],
"DisabledHostFeatures": [],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"pmulhuw xmm0, xmm1": {
@@ -12,7 +12,7 @@
"FRINTTS",
"CSSC"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"movss xmm0, xmm1": {
@@ -10,7 +10,7 @@
"FCMA",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"movsd xmm0, xmm1": {
@@ -9,7 +9,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"addsubps xmm0, xmm1": {
@@ -10,7 +10,7 @@
"FCMA",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"cvtpd2dq xmm0, xmm1": {
@@ -12,7 +12,7 @@
"FLAGM",
"FLAGM2"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"cvttss2si eax, xmm0": {
@@ -8,7 +8,7 @@
"SVE256",
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"movmskps eax, xmm0": {
+1 -1
View File
@@ -13,7 +13,7 @@
"FLAGM2",
"FRINTTS"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"vmovups xmm0, xmm0": {
@@ -8,7 +8,7 @@
"FCMA"
],
"DisabledHostFeatures": [],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"vaddsubpd xmm0, xmm1, xmm2": {
@@ -13,7 +13,7 @@
"FLAGM",
"FLAGM2"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"vcvttss2si eax, xmm0": {
+1 -1
View File
@@ -11,7 +11,7 @@
"FLAGM2",
"SVEBITPERM"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"vpshufb xmm0, xmm1, xmm2": {
@@ -11,7 +11,7 @@
"FLAGM",
"FLAGM2"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"pext eax, ebx, ecx": {
+1 -1
View File
@@ -8,7 +8,7 @@
"DisabledHostFeatures": [
"AFP"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"vpermq ymm0, ymm1, 1": {
@@ -9,7 +9,7 @@
"FLAGM",
"FLAGM2"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"vpsrlw xmm0, xmm1, 0": {
@@ -11,7 +11,7 @@
"FLAGM2",
"RPRES"
],
"BinaryCacheVersion": 18
"BinaryCacheVersion": 19
},
"Instructions": {
"fstp tword [rax]": {
Loaded 100 of 104 files, more files were not shown because too many files have changed in this diff. Show more