// Generated by SharpEmu Gen5MslTranslator. #include using namespace metal; struct Gen5AddressRange { ulong first_page; ulong page_count; device uint* base; }; // Finds the mapped range of a guest address; a miss records the page in the fault bitmap. static inline device uint* sharpemu_resolve_device_address(device const Gen5AddressRange* ranges, uint range_count, device uint* faults, uint fault_words, ulong address, thread bool& valid) { ulong masked = address & 0xFFFFFFFFFFFFul; ulong page = masked >> 14u; uint low = 0u; uint high = range_count; for (uint step = 0u; step < 7u; step++) { uint middle = low + ((high - low) >> 1u); bool move_up = low < high && ranges[middle].first_page <= page; low = move_up ? middle + 1u : low; high = move_up ? high : middle; } valid = false; if (low != 0u) { Gen5AddressRange range = ranges[low - 1u]; if (page - range.first_page < range.page_count) { valid = true; ulong byte_offset = ((page - range.first_page) << 14u) + (masked & 0x3FFFul); return (device uint*)((device uchar*)range.base + byte_offset); } } uint page_index = (uint)page; uint word = page_index >> 5u; if (word < fault_words) { atomic_fetch_or_explicit((device atomic_uint*)(faults + word), 1u << (page_index & 31u), memory_order_relaxed); } return nullptr; } static inline uint sharpemu_load_device_dword(device const Gen5AddressRange* ranges, uint range_count, device uint* faults, uint fault_words, ulong address) { bool valid = false; device uint* word = sharpemu_resolve_device_address(ranges, range_count, faults, fault_words, address, valid); return valid ? *word : 0u; } // An unaligned value assembled from the two aligned dwords it spans. static inline uint sharpemu_load_device_unaligned(device const Gen5AddressRange* ranges, uint range_count, device uint* faults, uint fault_words, ulong address, uint count) { uint alignment = (uint)(address & 3ul); ulong aligned = address & ~3ul; uint shift = alignment * 8u; uint low = sharpemu_load_device_dword(ranges, range_count, faults, fault_words, aligned); uint high = (alignment + count > 4u) ? sharpemu_load_device_dword(ranges, range_count, faults, fault_words, aligned + 4ul) : 0u; return (low >> shift) | (shift == 0u ? 0u : (high << (32u - shift))); } static inline void sharpemu_store_device_dword(device const Gen5AddressRange* ranges, uint range_count, device uint* faults, uint fault_words, ulong address, uint value) { bool valid = false; device uint* word = sharpemu_resolve_device_address(ranges, range_count, faults, fault_words, address, valid); if (valid) { *word = value; } } static inline void sharpemu_store_device_masked_word(device const Gen5AddressRange* ranges, uint range_count, device uint* faults, uint fault_words, ulong address, uint value, uint mask) { if (mask == 0u) { return; } bool valid = false; device uint* word = sharpemu_resolve_device_address(ranges, range_count, faults, fault_words, address, valid); if (!valid) { return; } if (mask == 0xFFFFFFFFu) { *word = value; return; } device atomic_uint* atomic_word = (device atomic_uint*)word; uint observed = atomic_load_explicit(atomic_word, memory_order_relaxed); while (!atomic_compare_exchange_weak_explicit(atomic_word, &observed, (observed & ~mask) | value, memory_order_relaxed, memory_order_relaxed)) { } } // A sub-dword store merges into the dwords it touches. static inline void sharpemu_store_device_bytes(device const Gen5AddressRange* ranges, uint range_count, device uint* faults, uint fault_words, ulong address, uint value, uint count) { uint element_mask = count == 1u ? 0xFFu : 0xFFFFu; uint alignment = (uint)(address & 3ul); ulong aligned = address & ~3ul; uint shift = alignment * 8u; uint carry_shift = 32u - shift; bool crosses = alignment + count > 4u; uint masked = value & element_mask; sharpemu_store_device_masked_word(ranges, range_count, faults, fault_words, aligned, masked << shift, element_mask << shift); sharpemu_store_device_masked_word(ranges, range_count, faults, fault_words, aligned + 4ul, crosses ? (masked >> carry_shift) : 0u, crosses ? (element_mask >> carry_shift) : 0u); } static inline uint sharpemu_atomic_step(device atomic_uint* word, bool increment) { uint observed = atomic_load_explicit(word, memory_order_relaxed); while (!atomic_compare_exchange_weak_explicit(word, &observed, increment ? observed + 1u : observed - 1u, memory_order_relaxed, memory_order_relaxed)) { } return observed; } // Compare-and-swap that retries only spurious failures; returns the value observed. static inline uint sharpemu_atomic_compare_swap(device atomic_uint* word, uint compare, uint value) { uint expected = compare; while (!atomic_compare_exchange_weak_explicit(word, &expected, value, memory_order_relaxed, memory_order_relaxed) && expected == compare) { } return expected; } struct Gen5StageResources { array buffers [[id(0)]]; array buffer_bytes [[id(1)]]; }; static inline uint sharpemu_load_word(device uint* b, uint bytes, uint addr) { if ((addr & 3u) == 0u) { return addr + 4u <= bytes ? b[addr >> 2] : 0u; } uint value = 0u; device const uchar* p = (device const uchar*)b; for (uint i = 0u; i < 4u; i++) { if (addr + i < bytes) { value |= (uint)p[addr + i] << (i * 8u); } } return value; } static inline uint sharpemu_load_bytes(device uint* b, uint bytes, uint addr, uint count, bool signExtend) { uint value = 0u; device const uchar* p = (device const uchar*)b; for (uint i = 0u; i < count; i++) { if (addr + i < bytes) { value |= (uint)p[addr + i] << (i * 8u); } } if (signExtend && count < 4u) { uint shift = 32u - (count * 8u); value = (uint)(((int)(value << shift)) >> shift); } return value; } static inline void sharpemu_store_bytes(device uint* b, uint bytes, uint addr, uint value, uint count) { device uchar* p = (device uchar*)b; for (uint i = 0u; i < count; i++) { if (addr + i < bytes) { p[addr + i] = (uchar)((value >> (i * 8u)) & 0xFFu); } } } static inline void sharpemu_store_masked_word(device uint* b, uint bytes, uint index, uint value, uint mask) { if (mask == 0u || index >= (bytes >> 2)) { return; } if (mask == 0xFFFFFFFFu) { b[index] = value; return; } // The other bits of the word survive stores from neighbouring invocations. device atomic_uint* word = (device atomic_uint*)(b + index); uint observed = atomic_load_explicit(word, memory_order_relaxed); while (!atomic_compare_exchange_weak_explicit(word, &observed, (observed & ~mask) | value, memory_order_relaxed, memory_order_relaxed)) { } } static inline void sharpemu_store_element(device uint* b, uint bytes, uint addr, uint count, uint4 values, uint4 masks) { uint shift = (addr & 3u) * 8u; uint index = addr >> 2; uint carryValue = 0u; uint carryMask = 0u; for (uint k = 0u; k <= count; k++) { uint value = carryValue; uint mask = carryMask; if (k < count) { uint element = values[k] & masks[k]; value |= element << shift; mask |= masks[k] << shift; carryValue = shift == 0u ? 0u : element >> (32u - shift); carryMask = shift == 0u ? 0u : masks[k] >> (32u - shift); } sharpemu_store_masked_word(b, bytes, index + k, value, mask); } } static inline uint sharpemu_ballot(bool value) { return (uint)(uint64_t)simd_ballot(value); } static constant float sharpemu_off_i4_table[16] = { 0.0f, 0.0625f, 0.1250f, 0.1875f, 0.2500f, 0.3125f, 0.3750f, 0.4375f, -0.5000f, -0.4375f, -0.3750f, -0.3125f, -0.2500f, -0.1875f, -0.1250f, -0.0625f, }; kernel void gen5_cs( constant Gen5StageResources& sharpemu_resources [[buffer(0)]], constant uint* sharpemu_push_data [[buffer(1)]], uint3 sharpemu_local_id [[thread_position_in_threadgroup]], uint3 sharpemu_group_id [[threadgroup_position_in_grid]], uint sharpemu_lane [[thread_index_in_simdgroup]]) { uint s[128] = {}; uint v[256] = {}; bool exec = true; bool vcc = false; bool scc = false; uint pc = 0u; bool active = true; uint steps = 0u; device uint* b0 = sharpemu_resources.buffers[0]; uint bias[1] = {}; s[8] = sharpemu_push_data[0]; s[9] = sharpemu_push_data[1]; s[10] = sharpemu_push_data[2]; s[11] = sharpemu_push_data[3]; bias[0] = (sharpemu_push_data[4] >> 0u) & 0xFFu; v[0] = sharpemu_local_id.x; v[1] = sharpemu_local_id.y; v[2] = sharpemu_local_id.z; active = (sharpemu_group_id.x * 32u + sharpemu_local_id.x) < 0xFFFFFFFFu && (sharpemu_group_id.y * 1u + sharpemu_local_id.y) < 0xFFFFFFFFu && (sharpemu_group_id.z * 1u + sharpemu_local_id.z) < 0xFFFFFFFFu; s[106] = 0u; s[107] = 0u; s[126] = sharpemu_ballot(true); s[127] = 0u; while (active) { switch (pc) { case 0u: { uint t0 = 5u; s[0] = t0; uint t1 = 0u; if (exec) { v[1] = t1; } pc = 1u; } break; case 1u: { uint t2 = ((s[0]) + (v[1])); if (exec) { v[1] = t2; } uint t3 = s[0]; uint t4 = 1u; uint t5 = (t3 - t4); s[0] = t5; scc = ((((t3 ^ t4)) & (t3 ^ t5)) >> 31) != 0u; uint t6 = s[0]; uint t7 = 0u; scc = (t6) != (t7); pc = (scc) ? 1u : 2u; } break; case 2u: { uint t8 = ((0x0u + 0u + 0u + (0u * 0u)) + bias[0]); if (exec) { sharpemu_store_bytes(b0, sharpemu_resources.buffer_bytes[0], t8 + 0u, v[1], 4u); } active = false; } break; default: active = false; break; } if (++steps >= 100000u) { active = false; } } }